Technical whitepaper — PodHeitor ADABAS for Bacula

Online backup and restore of Software AG ADABAS via the native adabck/adaopr/adavfy/adarec utilities, with Level F (full) streaming, Level I (PLOG archiving) with safety gate, checkpoint-based PITR, signal-safe cancel, and per-subprocess wall-clock timeouts.

Companion document to the PodHeitor ADABAS plugin page.

1. The problem: stock Bacula can’t back up ADABAS

ADABAS is one of the rare hierarchical NoSQL databases that survives in mainframe-derived workloads (telecom, government, insurance). Stock Bacula has no ADABAS plugin. Bacula Enterprise lists no ADABAS plugin in any public manual (verified across BE 6.x → 18.x). The alternatives:

  • Shell wrapper scripts around adabck DUMP=* — common in the field but fragile: no RAII for EXT_BACKUP=PREPARE/CONTINUE (leaving the nucleus in an inconsistent frozen state if the script dies), no PLOG wrap detection, no signal-safe cleanup, no manifest cataloging.
  • NetBackup / Commvault ADABAS agents — expensive and outside the Bacula world.

PodHeitor ADABAS fills that gap with first-class integration to native utilities. One-line value proposition: “Configure a Bacula job. ADABAS is restored to a consistent point-in-time with a single bconsole restore.”

2. Architectural model

Bacula Director  ───  Plugin = "podheitor-adabas: dbid=12"
       │
       ▼
Bacula File Daemon (bacula-fd)
  └── /opt/bacula/plugins/podheitor-adabas-fd.so   (Rust cdylib)
        │ PTCOMM (length-prefixed packets via stdin/stdout)
        ▼
   /opt/bacula/bin/podheitor-adabas-backend       (Rust binary)
       ├── main.rs          PTCOMM 5-phase handshake
       ├── config.rs        plugin string + config-file merge
       ├── backup.rs        Level F orchestration
       ├── incremental.rs   Level I (PLOG archiving) orchestration
       ├── restore.rs       Phase A→E restore orchestration
       ├── adabck.rs        DUMP + RESTORE subprocess wrappers
       ├── adaopr.rs        Operator: status + EXT_BACKUP + RAII guard
       ├── adavfy.rs        Post-restore consistency verify
       ├── adarec.rs        PLOG apply (license-gated on CE)
       ├── plog.rs          PLOG discovery + sequence-wrap detection
       ├── state.rs         Plugin state file (archived + pending_delete)
       ├── stream.rs        Fixed 1 MiB buffer child_stdout → PTCOMM
       └── subproc.rs       Bounded-wait helper (timeouts)

ADABAS host (same machine as bacula-fd)
  adabck / adaopr / adavfy / adarec
  DBID=<N> ASSO / DATA / WORK containers

Critical invariants:

  • The Rust backend runs on the same Linux host as ADABAS. ADABAS IPC is SysV message queue — cannot be tunnelled across machines.
  • Bacula’s Storage Daemon can be anywhere; the plugin just streams PTCOMM packets.
  • Every subprocess has a bounded wall-clock timeout (plan §19). A runaway utility cannot wedge the Bacula job.

3. Capabilities

Capability Status
Full (Level F) online backup via adabck DUMP=* streamed to Bacula ✅ CE-validated end-to-end
Incremental (Level I) PLOG archiving with sequence-wrap detection + safety-gated delete ✅ orchestration CE-validated; real PLOG emission needs licensed ADABAS
Multi-DBID jobs with best-effort aggregate reporting ✅ CE-validated
Full restore via adabck RESTORE=* with staged-file + BackupManifest reconstruction ✅ orchestration CE-validated; actual DB restore requires nucleus-offline (license-gated)
Point-in-time restore via adarec CHECKPOINT=(first,last) ✅ code paths + unit tests; live replay license-gated
Stream mode: stdout (BCK001=-, default) and tempfile fallback ✅ both validated
Configurable timeouts (status / backup / restore / adarec / verify)
Log verbosity via ADABAS_LOG_LEVEL env
Signal-safe cancel (SIGTERM/SIGINT → unwind staged files)

4. EXT_BACKUP RAII guard — critical invariant

ADABAS’s “transactional consistency” flow is: adaopr EXT_BACKUP=PREPARE, then adabck DUMP=*, then adaopr EXT_BACKUP=CONTINUE. If the middle step crashes and CONTINUE never runs, the nucleus stays in a frozen waiting state — production goes down.

adaopr.rs pairs PREPARE/CONTINUE via Rust’s RAII: the ExtBackupGuard struct calls PREPARE in its constructor and CONTINUE in Drop. Even a panic or signal-induced unwinding guarantees CONTINUE — the nucleus is never left frozen.

5. PLOG archiving and safety-gated delete

Level I (Incremental) jobs discover PLOGs rotated since the previous job, archive each, and mark for deletion. The deletion only happens in a subsequent job, after the previous one is proven cataloged successfully. This gives the operator one full job cycle to abort before losing local copies.

PLOG wrap detection: if the sequential sequence skips (because ADABAS rotated and discarded a PLOG before we archived it), the plugin aborts with a clear message — without trying to continue and producing an inconsistent chain.

6. Plugin string parameters

Parameter Default Description
dbid (required) Single ADABAS database ID
dbids Comma-separated list for multi-DB jobs: dbids=12,13,14
external_backup yes Wrap DUMP in adaopr EXT_BACKUP=PREPARE/CONTINUE for transactional consistency. Must be no on CE
plog yes Archive PLOGs during Level I jobs. No-op on CE
stream_mode auto auto (= stdout), stdout, or tempfile fallback
buffer_size 8m Streaming buffer (accepts K/M/G suffixes)
allow_destructive_restore no Required gate for restore. Without this, restore refuses to overwrite an existing DB
verify_after_restore yes Run adavfy DBID=<N> after restore
restore_to_checkpoint PITR target: "first,last" checkpoint names
backup_timeout_secs 14400 Wall-clock bound on DUMP (4h)
restore_timeout_secs 14400 Wall-clock bound on RESTORE (4h)
adarec_timeout_secs 1800 Per-PLOG wall-clock on adarec (30 min)
plog_ship_retries 2 Max retries (exponential backoff) on transient PLOG ship failure. Full backup is never retried — ADR-009

7. Destructive restore with gate

Restore overwrites the existing DBID — destructive operation. The plugin refuses unless the operator explicitly passes:

pluginoptions "podheitor-adabas: dbid=12 allow_destructive_restore=yes"

Without that flag, the job aborts with a clear message. PITR carries the same gate:

pluginoptions "podheitor-adabas: dbid=12 allow_destructive_restore=yes restore_to_checkpoint=SYNC,W8NW"

8. Community Edition limitations

ADABAS Community Edition is free but has behavioural restrictions that affect backup semantics. The plugin code path is correct for licensed ADABAS; CE simply fails to drive portions of it:

Restriction Impact
No PLOG support (PLOG=<reset> at startup) Level I jobs find 0 candidate PLOGs. Orchestration tested via synthetic fixtures
EXT_BACKUP=PREPARE + adabck DUMP=* deadlock On CE, PREPARE before DUMP causes do_msgrcv waiting for IPC. Use external_backup=no on CE
adabck RESTORE=* requires nucleus offline CE’s single nucleus can’t be cleanly stopped/restarted from a container entrypoint
adarec (PLOG apply) requires PLOGs Consequently license-gated

9. Documented anti-patterns

  • Don’t use : as a parameter separator. Parameters are space-separated; : only follows podheitor-adabas. Common pitfall.
  • Don’t run external_backup=yes on CE. Guaranteed deadlock.
  • Don’t hand-edit the state file (/opt/bacula/working/podheitor-adabas-state/dbid-<N>.json). The plugin uses write-then-rename for atomicity; manual edits corrupt archived/pending_delete tracking.
  • Don’t disable panic = "abort" in release profile. A panic crossing FFI via pluginIO is UB.

10. License posture

The plugin ships under AGPLv3 — same license as Bacula Community Edition. Open-source compatible at no cost, and the basis for commercial deploys under proprietary single-license agreements for customers requiring legal isolation.

Ready to evaluate?

30-day free trial for qualified ADABAS instances (CE 7.x or licensed 8.x+). We guarantee at least 50% off vs Bacula Enterprise (which has no ADABAS plugin), Veeam, or Commvault, with more features — including PLOG safety gate and EXT_BACKUP RAII that shell scripts will never deliver.

Heitor Faria — Founder, PodHeitor International
[email protected]
☎ +1 (789) 726-1749 · +55 (61) 98268-4220 (WhatsApp)
🔗 PodHeitor ADABAS plugin page

Disponível em: pt-brPortuguês (Portuguese (Brazil))enEnglishesEspañol (Spanish)

Leave a Reply