Backup e restore online de Software AG ADABAS via utilitários nativos adabck/adaopr/adavfy/adarec, com Level F (full) streaming, Level I (PLOG archiving) com gate de safety, PITR por checkpoint, signal-safe cancel, e timeouts wall-clock por subprocesso.
Documento técnico complementar à página do plugin PodHeitor ADABAS.
1. Problema: backup de ADABAS sob Bacula stock é impossível
ADABAS é uma das raras bases NoSQL hierárquicas que sobrevivem em mainframe-derived workloads (telecom, governo, seguros). Bacula stock não tem nenhum plugin para ADABAS. Bacula Enterprise não lista plugin ADABAS em nenhum manual público (verificado em BE 6.x → 18.x). As alternativas:
- Scripts shell wrappers em torno de
adabck DUMP=*— comuns em campo, mas frágeis: sem RAII deEXT_BACKUP=PREPARE/CONTINUE(deixam o nucleus em estado inconsistente se o script morrer), sem detecção de wrap em PLOG, sem signal-safe cleanup, sem manifest cataloging. - NetBackup / Commvault agentes ADABAS — caros e fora do mundo Bacula.
O PodHeitor ADABAS preenche esse buraco com integração first-class aos utilitários nativos, valor de proposta one-line: “configure um Bacula job. ADABAS é restaurado a um ponto-no-tempo consistente com um único bconsole restore.”
2. Modelo arquitetural
Bacula Director ─── Plugin = "podheitor-adabas: dbid=12"
│
▼
Bacula File Daemon (bacula-fd)
└── /opt/bacula/plugins/podheitor-adabas-fd.so (cdylib Rust)
│ PTCOMM (length-prefixed packets via stdin/stdout)
▼
/opt/bacula/bin/podheitor-adabas-backend (binário Rust)
├── main.rs PTCOMM 5-phase handshake
├── config.rs merge plugin string + config-file
├── backup.rs orquestração Level F
├── incremental.rs orquestração Level I (PLOG archiving)
├── restore.rs restore Phase A→E
├── adabck.rs wrappers de subprocesso DUMP + RESTORE
├── adaopr.rs Operator: status + EXT_BACKUP + RAII guard
├── adavfy.rs verify de consistência pós-restore
├── adarec.rs PLOG apply (license-gated em CE)
├── plog.rs discovery de PLOG + detecção de wrap
├── state.rs state file (archived + pending_delete)
├── stream.rs buffer fixo 1 MiB child_stdout → PTCOMM
└── subproc.rs helper bounded-wait (timeouts)
ADABAS host (mesma máquina que bacula-fd)
adabck / adaopr / adavfy / adarec
DBID=<N> ASSO / DATA / WORK containers
Invariantes críticas:
- O backend Rust roda na mesma máquina Linux que ADABAS. ADABAS IPC é SysV message queue — não atravessa máquinas.
- O Storage Daemon do Bacula pode estar em qualquer lugar; o plugin só streama PTCOMM packets.
- Cada subprocesso tem wall-clock timeout (plan §19). Um utilitário runaway não pode wedgar o job Bacula.
3. Capabilities
| Capability | Status |
|---|---|
Full (Level F) backup online via adabck DUMP=* streamed para Bacula |
✅ CE-validado E2E |
| Incremental (Level I) PLOG archiving com detecção de wrap + safety-gated delete | ✅ orchestration CE-validada; emissão real de PLOG requer ADABAS licenciado |
| Multi-DBID jobs com reporting agregado best-effort | ✅ CE-validado |
Full restore via adabck RESTORE=* com staged-file + reconstrução de BackupManifest |
✅ orchestration CE-validada; restore real requer nucleus-offline (license-gated) |
PITR via adarec CHECKPOINT=(first,last) |
✅ code paths + unit tests; replay live license-gated |
Stream mode: stdout (BCK001=-, default) e tempfile fallback |
✅ ambos validados |
| Timeouts configuráveis (status / backup / restore / adarec / verify) | ✅ |
Verbosidade de log via env ADABAS_LOG_LEVEL |
✅ |
| Cancel signal-safe (SIGTERM/SIGINT → unwind de staged files) | ✅ |
4. EXT_BACKUP RAII guard — invariante crítica
O fluxo “transactional consistency” do ADABAS é: adaopr EXT_BACKUP=PREPARE, então adabck DUMP=*, então adaopr EXT_BACKUP=CONTINUE. Se o middle step crashar e o CONTINUE não for chamado, o nucleus fica em estado frozen aguardando — produção morre.
O adaopr.rs implementa o pareamento PREPARE/CONTINUE via guarda RAII de Rust: a struct ExtBackupGuard chama PREPARE em construção e CONTINUE em Drop. Mesmo um panic ou signal-induced unwinding garante o CONTINUE — o nucleus nunca fica preso.
5. PLOG archiving e safety-gated delete
Level I (Incremental) jobs descobrem PLOGs rotacionados desde o último job, archivam cada um, e marcam para delete. O delete só acontece num job subsequente, depois de comprovado que o anterior foi catalogado com sucesso. Isso dá ao operador um ciclo completo de job para abortar antes de perder cópias locais.
Detecção de wrap em PLOG: se a sequência sequencial salta (porque o ADABAS rotacionou e descartou um PLOG sem a gente archivar), o plugin aborta com mensagem clara — sem tentar continuar e produzir uma chain inconsistente.
6. Plugin string parameters
| Parameter | Default | Descrição |
|---|---|---|
dbid |
(required) | ID único de DB ADABAS |
dbids |
— | Lista comma-separated para multi-DB jobs: dbids=12,13,14 |
external_backup |
yes |
Wrap DUMP em adaopr EXT_BACKUP=PREPARE/CONTINUE para consistência transacional. Deve ser no em CE |
plog |
yes |
Archiva PLOGs em jobs Level I. No-op em CE |
stream_mode |
auto |
auto (= stdout), stdout, ou tempfile fallback |
buffer_size |
8m |
Buffer de streaming (aceita sufixos K/M/G) |
allow_destructive_restore |
no |
Gate obrigatório para restore. Sem isso, restore se recusa a sobrescrever DB existente |
verify_after_restore |
yes |
Roda adavfy DBID=<N> após restore |
restore_to_checkpoint |
— | Target PITR: nomes de checkpoint "first,last" |
backup_timeout_secs |
14400 | Wall-clock bound em DUMP (4h) |
restore_timeout_secs |
14400 | Wall-clock bound em RESTORE (4h) |
adarec_timeout_secs |
1800 | Wall-clock per-PLOG em adarec (30 min) |
plog_ship_retries |
2 | Max retries (exponential backoff) em transient PLOG ship failure. Full backup nunca é retried — ADR-009 |
7. Restore destrutivo com gate
Restore overwrites DBID existente — operação destrutiva. O plugin se recusa a executar a menos que o operador passe explicitamente:
pluginoptions "podheitor-adabas: dbid=12 allow_destructive_restore=yes"
Sem esse flag, o job aborta com mensagem clara. PITR ganha o mesmo gate:
pluginoptions "podheitor-adabas: dbid=12 allow_destructive_restore=yes restore_to_checkpoint=SYNC,W8NW"
8. Community Edition limitations
ADABAS Community Edition é grátis mas tem restrições comportamentais que afetam semântica de backup. O plugin é correto para ADABAS licenciado; CE simplesmente falha em portions:
| Restrição | Impacto |
|---|---|
Sem suporte a PLOG (PLOG=<reset> em startup) |
Jobs Level I encontram 0 PLOGs candidatos. Orchestration testada via fixtures sintéticos |
EXT_BACKUP=PREPARE + adabck DUMP=* deadlock |
Em CE, PREPARE antes de DUMP causa do_msgrcv aguardando IPC. Use external_backup=no em CE |
adabck RESTORE=* requer nucleus offline |
Single nucleus de CE não pode ser cleanly stopped/restarted no entrypoint do container |
adarec (PLOG apply) requer PLOGs |
Consequentemente license-gated |
9. Anti-patterns documentados
- Não use
:como separador de parâmetros. Parâmetros são space-separated;:só aparece apóspodheitor-adabas. Pegadinha comum. - Não rode
external_backup=yesem CE. Deadlock garantido. - Não edite o state file à mão (
/opt/bacula/working/podheitor-adabas-state/dbid-<N>.json). O plugin usa write-then-rename para atomicidade; edits manuais corrompem o tracking de archived/pending_delete. - Não desabilite
panic = "abort"no profile release. Panic atravessando FFI viapluginIOé UB.
10. License posture
O plugin é distribuído sob AGPLv3 — mesma licença do Bacula Community Edition. Compatível para uso open-source sem custo, e a base para os deploys comerciais sob acordo proprietary single-license para clientes que necessitam isolamento legal.
Pronto para avaliar?
Trial gratuito de 30 dias para instâncias ADABAS qualificadas (CE 7.x ou licensed 8.x+). Garantimos no mínimo 50% de desconto vs Bacula Enterprise (que nem tem plugin ADABAS), Veeam, ou Commvault, com mais funcionalidades — incluindo PLOG safety gate e RAII de EXT_BACKUP que scripts shell jamais entregam.
Heitor Faria — Fundador, PodHeitor International
✉ [email protected]
☎ +1 (789) 726-1749 · +55 (61) 98268-4220 (WhatsApp)
🔗 Página do plugin PodHeitor ADABAS
Disponível em:
Português
English (Inglês)
Español (Espanhol)