Whitepaper — PodHeitor OracleDB

Whitepaper — PodHeitor OracleDB

Oracle Database backup integrated with RMAN. Hot backup, archive log streaming, SCN-precise PITR, Data Guard primary/standby support, RAC and multi-tenant PDB.

  • Native RMAN integration — catalog control, automatic BLOCKRECOVER validation.
  • Continuous archive log streaming — near-zero RPO.
  • SCN-precise PITR — restore to an exact Oracle transaction number.
  • Data Guard-aware — back up from standby, zero overhead on primary.
  • RAC and multi-tenant (PDB) — back up individual PDBs, restore to a different CDB.

Production-ready in 30 days, at least 50% cheaper. Free trial, signed RPMs and DEBs, direct support from Heitor Faria. Replace your Veeam, Commvault or Bacula Enterprise license without breaking the nightly window.

Request a free 30-day trial →

COMMERCIAL OFFER — READ THIS FIRST

Switching from Bacula Enterprise, Veeam, Commvault, or NetBackup? Bring your renewal quote or active contract proposal and we guarantee a minimum 50% discount — with significantly more features out of the box.

| Channel | Contact | |———|———| | Email | heitor@opentechs.lat | | Phone / WhatsApp (international) | +1 786 726-1749 | | Phone / WhatsApp (Brazil) | +55 61 98268-4220 |


Table of Contents

  1. Executive Summary
  2. The Problem
  3. Solution Overview
  4. Architecture
  5. Feature Comparison Table
  6. Backup Options Reference
  7. Restore Options Reference
  8. FileSet Configuration Examples
  9. Restore Job Examples
  10. Installation and Sizing Guide
  11. Compatibility Matrix
  12. Performance Report
  13. Security and Compliance
  14. Support and Commercial Terms
  15. Appendix A — Architecture Decision Records
  16. Appendix B — Glossary

1. Executive Summary

What Is It?

The PodHeitor OracleDB Backup and Replication Plugin for PodHeitor Backup is a production-grade, commercially-polished Bacula File Daemon plugin that delivers comprehensive Oracle Database protection — from hot backups via RMAN SBT v2 all the way to continuous data protection (CDP) and native disaster-recovery replication — at a fraction of the cost of proprietary alternatives.

Written entirely in Rust (built in Rust with native memory safety and zero runtime dependencies), the plugin ships as a single RPM or DEB package (under 700 KB installed) and requires no Oracle-specific third-party libraries, no proprietary SBT implementations, and no shell-script wrappers outside of Bacula.

Business Value in Three Points

  1. 50%+ Cost Reduction. Oracle database backup is one of the most expensive line items in any enterprise IT budget. Bacula Enterprise charges per-client or per-agent licensing fees that compound with every Oracle instance you protect. Veeam, Commvault, and NetBackup add agent licences, module add-ons, and annual maintenance on top. PodHeitor delivers every capability those platforms offer — and several they do not — at a per-organisation flat fee (no per-socket or per-TB metering entirely.
  1. More Features, Not Fewer. This is not a stripped-down open-source alternative. The plugin exceeds Bacula Enterprise 18.2.3 on continuous data protection (CDP daemon mode), native DR replication for Standard Edition 2 (archivelog-apply), Prometheus/OpenTelemetry observability, anti-ransomware canary detection, automated DBVERIFY post-restore validation, and CycloneDX SBOM supply-chain integrity. Bacula Enterprise ships none of these.
  1. Bacula-Native Restore Automation. Competing products require an operator to SSH into the Oracle host and invoke a Perl script (bs_oracle_restore.pl) or an equivalent shell wrapper — outside of any audit trail. PodHeitor uses Bacula’s built-in RestoreObject mechanism: a pluginrestoreconf document embedded in every backup triggers a fully automated, catalogued restore directly from bconsole or the Bacularis web console. No SSH to the Oracle host required.

Who Should Read This

  • Oracle DBAs evaluating backup strategies for 11g through 23ai workloads.
  • Bacula Administrators looking to replace a commercial Oracle plugin without re-architecting their infrastructure.
  • Infrastructure Architects designing disaster-recovery and data-replication pipelines for Oracle Standard Edition 2 or Enterprise Edition environments.
  • IT Procurement Teams benchmarking licence costs and feature parity against Bacula Enterprise, Veeam for Oracle, Commvault IntelliSnap Oracle, and NetBackup for Oracle.

2. The Problem

Oracle Backup Is Uniquely Complex

Oracle Database backup is unlike backing up a file system or a simple relational database. A correct Oracle backup must account for:

  • SCN consistency — backups spanning multiple datafiles must be consistent at the same System Change Number or they produce an unrecoverable set.
  • Archivelog chain integrity — point-in-time recovery requires an unbroken sequence of archived redo logs from the last Full backup to the target time.
  • Controlfile and SPFILE — the database cannot mount without these; they must be backed up atomically with every datafile backup.
  • Multitenant (CDB/PDB) — Oracle 12c and later allow hundreds of pluggable databases inside one container; a backup strategy must address both the root container and individual PDBs independently.
  • TDE encryption — Transparent Data Encryption wallets must be backed up and rotated in a coordinated manner or restore becomes impossible.
  • ASM and RAC — Grid Infrastructure adds storage abstraction (ASM) and cluster parallelism (RAC) that generic backup tools cannot see.

RMAN (Recovery Manager) is Oracle’s native backup engine and the only tool that fully addresses all of these requirements. Any credible Oracle backup solution must integrate with RMAN at a deep level — not by running rman target / and archiving the output files as if they were arbitrary filesystem objects.

The Cost Problem

Product Typical Oracle Backup Cost Notes
Bacula Enterprise $3,000–$8,000 / year per Oracle host Oracle Module add-on on top of base FD licence
Veeam for Oracle $2,500–$6,000 / year per socket Requires Veeam Backup & Replication Enterprise Plus
Commvault IntelliSnap Oracle $5,000–$15,000 / year per host Agent + IntelliSnap licence
NetBackup for Oracle $4,000–$12,000 / year per host NBU Client + DB Agent licence
PodHeitor Per-organisation flat fee — no per-host metering Commercial support available from author

Pricing ranges are indicative based on publicly available list prices and community reports as of 2026. Actual negotiated prices vary. The point stands: for an organisation protecting 10 Oracle hosts, the annual savings compared to any proprietary solution range from $25,000 to $150,000.

The Restore Problem — The Hidden Cost

The cost of proprietary Oracle backup tools is not just the licence fee. The hidden cost is restore complexity.

Bacula Enterprise 18.2.3 ships a Perl script called bs_oracle_restore.pl. To perform a point-in-time recovery, a DBA must:

  1. SSH into the Oracle host (requires OS access, VPN, key management).
  2. Locate the correct version of bs_oracle_restore.pl (it changes across Bacula releases).
  3. Run the script with the correct parameters — a dozen flags with no interactive validation.
  4. Hope the script generates the right RMAN commands for the target timestamp.
  5. Monitor progress on the Oracle host directly — no Bacula catalog entry for the restore operation.
  6. Manually open the database with RESETLOGS if the script does not do it automatically.

This workflow is error-prone, unauditable, and requires OS-level access that most security policies prohibit granting to application-layer DBAs.

PodHeitor eliminates all of this. The entire restore workflow — including PITR, SCN-based, table-level, clone, and validation actions — is driven from bconsole or the Bacularis web form, with a full audit trail in the Bacula catalog, and zero SSH access required to the Oracle host.

The Replication and CDP Gap

None of the four major competing products (Bacula Enterprise, Veeam, Commvault, NetBackup) includes native continuous data protection (CDP) or disaster-recovery replication for Oracle Standard Edition 2 at the database level without additional Oracle licensing (Active Data Guard requires Oracle Enterprise Edition).

PodHeitor ships:

  • mode=cdp — a daemon that continuously ships archivelogs to Bacula storage, delivering RPO in minutes rather than hours.
  • mode=replicate with replicate_method=archivelog_apply — a DR replication channel that works with Oracle Standard Edition 2, Oracle Express Edition, and Oracle 23ai FREE, requiring no Active Data Guard licence.

3. Solution Overview

What the Plugin Delivers

PodHeitor OracleDB Backup Plugin integrates PodHeitor Backup with Oracle RMAN via a clean-room implementation of the Oracle SBT v2 API (libobk-rs.so), delivering five distinct backup modes, fully automated restore, and native DR replication — all from a single 622 KB RPM package.

Five Backup Modes

Mode Description Oracle Requirement Staging Required
rman_sbt Zero-staging RMAN via SBT v2 (libobk-rs). Recommended for production. 11g R2+ None — streams directly
rman RMAN writes to local staging; backend streams to Bacula. 11g R2+ Yes — temporary disk
dump Oracle Data Pump (expdp / impdp) logical backup. 11g R2+ (exp on 11g) Yes — temporary disk
cdp Continuous archivelog daemon. Low-RPO protection. 11g R2+ None
replicate DR replication via Active DG duplicate or archivelog-apply. SE2 or EE Optional

Architecture Overview

┌─────────────────────────────────────────────────────────────┐
│                      Bacula Director                        │
│  • Schedules jobs          • Stores RestoreObjects          │
│  • Manages catalog         • Issues bconsole commands       │
└─────────────────────────┬───────────────────────────────────┘
                          │ TCP (Bacula Protocol)
┌─────────────────────────▼───────────────────────────────────┐
│               Bacula File Daemon (FD 15.0.3+)               │
│  • Loads podheitor-oracle-fd.so via plugin API              │
│  • Dispatches bEventBackupCommand / bEventRestoreObject     │
└─────────────────────────┬───────────────────────────────────┘
                          │ PTCOMM (fork + pipe)
┌─────────────────────────▼───────────────────────────────────┐
│          podheitor-oracle-backend (Rust, musl static-pie)   │
│  • Backup dispatcher  • Restore engine  • CDP daemon        │
│  • Metrics (Prometheus) • Canary sampler • Audit logger     │
└────────────┬──────────────────────────────────┬────────────┘
             │ subprocess + UNIX socket          │ subprocess
┌────────────▼────────────┐       ┌─────────────▼───────────┐
│  RMAN (SBT mode)        │       │ sqlplus / expdp / dbv   │
│  → libobk-rs.so (SBT v2)│       │ (non-SBT modes)         │
│  → UNIX socket back     │       │                         │
│    to backend           │       │                         │
└─────────────────────────┘       └─────────────────────────┘
             │
┌────────────▼────────────┐
│    Oracle Database      │
│   (11g R2 → 23ai)       │
└─────────────────────────┘

Restore Automation via RestoreObject

Every backup embeds a pluginrestoreconf RestoreObject in the Bacula catalog. At restore time, the operator selects an action in bconsole or the Bacularis web form — no SSH to the Oracle host is required. The plugin validates the configuration, generates the appropriate RMAN script, optionally runs a RESTORE PREVIEW, executes the restore, and writes a post-restore manifest to the catalog.

DR Replication — Native

mode=replicate with replicate_method=archivelog_apply creates a standby database by:

  1. Running RMAN DUPLICATE to create the initial standby copy.
  2. Continuously shipping and applying archivelogs to the standby host.

This provides Active Data Guard-equivalent protection without Oracle Enterprise Edition licensing — a capability absent from every competitor product listed in this whitepaper.


4. Architecture

4.1 Component Diagram

┌─────────────────────────────────────────────────────────────────────────┐
│  PodHeitor Backup INFRASTRUCTURE                                        │
│                                                                         │
│  ┌────────────────┐   TCP/TLS    ┌──────────────────────────────────┐  │
│  │ bacula-dir     │◄────────────►│ bacula-fd 15.0.3                 │  │
│  │ (Director)     │              │                                  │  │
│  │ • Catalog DB   │              │  ┌────────────────────────────┐  │  │
│  │ • Scheduler    │              │  │ podheitor-oracle-fd.so     │  │  │
│  │ • RestoreObjs  │              │  │ (C++ thin shim, ~3 KB)     │  │  │
│  └────────────────┘              │  │ • Bacula Plugin API        │  │  │
│                                  │  │ • fork() + pipe()          │  │  │
│  ┌────────────────┐   TCP/TLS    │  │ • PTCOMM encode/decode     │  │  │
│  │ bacula-sd      │◄────────────►│  └──────────┬─────────────────┘  │  │
│  │ (Storage)      │              │             │ PTCOMM              │  │
│  └────────────────┘              │  ┌──────────▼─────────────────┐  │  │
│                                  │  │ podheitor-oracle-backend    │  │  │
│                                  │  │ (Rust, x86_64-musl, static) │  │  │
│                                  │  │                             │  │  │
│                                  │  │  backup::run()              │  │  │
│                                  │  │    ├── run_dump()           │  │  │
│                                  │  │    ├── run_rman()           │  │  │
│                                  │  │    ├── run_rman_sbt()       │  │  │
│                                  │  │    ├── run_cdp()            │  │  │
│                                  │  │    └── run_replicate()      │  │  │
│                                  │  │                             │  │  │
│                                  │  │  restore::run()             │  │  │
│                                  │  │    └── run_rman_restore()   │  │  │
│                                  │  │                             │  │  │
│                                  │  │  oracle::sbt_server         │  │  │
│                                  │  │  oracle::audit              │  │  │
│                                  │  │  oracle::canary             │  │  │
│                                  │  │  metrics::http_server       │  │  │
│                                  │  └──────────┬─────────────────┘  │  │
│                                  └─────────────┼──────────────────── ┘  │
└────────────────────────────────────────────────┼────────────────────────┘
                                                 │
                        ┌────────────────────────┼──────────────────────┐
                        │  Oracle Host            │                      │
                        │                         │ UNIX socket          │
                        │  ┌──────────────────────▼──────────────────┐  │
                        │  │ /var/run/podheitor-oracle/<SID>.sock     │  │
                        │  └──────────────────────┬──────────────────┘  │
                        │                         │ SBT v2              │
                        │  ┌──────────────────────▼──────────────────┐  │
                        │  │ libobk-rs.so (clean-room SBT v2 plugin nativo) │  │
                        │  │ symlinked as $ORACLE_HOME/lib/libobk.so  │  │
                        │  └──────────────────────┬──────────────────┘  │
                        │                         │ SBT v2              │
                        │  ┌──────────────────────▼──────────────────┐  │
                        │  │ RMAN (Oracle Recovery Manager)           │  │
                        │  │ N channels, parallel streams             │  │
                        │  └──────────────────────┬──────────────────┘  │
                        │                         │                     │
                        │  ┌──────────────────────▼──────────────────┐  │
                        │  │ Oracle Database (SID=<SID>)              │  │
                        │  │ • Datafiles • Archivelogs • Controlfile  │  │
                        │  │ • SPFILE • TDE Wallet • PDBs             │  │
                        │  └─────────────────────────────────────────┘  │
                        └──────────────────────────────────────────────┘

4.2 mode=rman_sbt Data Flow (Zero-Staging, Recommended)

4.3 mode=cdp — Continuous Data Protection Daemon Loop

4.4 Restore Flow — RestoreObject → RMAN

4.5 Technology Choices

Component Technology Rationale
Backend binary Rust 2021, musl static-pie Memory safety, zero runtime deps, single-file deploy
FD shim C++ (Bacula Plugin API) Bacula requires a C/C++ plugin ABI
IPC protocol PTCOMM (binary, fork+pipe) No network socket overhead; deterministic framing
SBT implementation libobk-rs (clean-room Rust plugin nativo) Proprietary; clean-room reimplementation of Oracle SBT API
SBT ↔ backend IPC UNIX socket /var/run/podheitor-oracle/<SID>.sock Low-latency, same-host, per-SID isolation
State persistence JSON files, /opt/bacula/working/oracle-state/<SID>/ Human-readable, atomic write-rename
Observability Prometheus text format, stdlib TCP Native endpoint, no external dependencies
I/O throttle cgroups v2 io.max Kernel-enforced, no RMAN-rate guessing
Licence PodHeitor-Proprietary Copyright © Heitor Faria — All rights reserved

5. Feature Comparison Table

The following table compares PodHeitor v1.0.0 against Bacula Enterprise 18.2.3, Veeam Backup & Replication for Oracle, Commvault IntelliSnap Oracle, and NetBackup for Oracle.

Legend: Y = Yes/Supported | N = No/Not supported | M = Manual/Requires extra steps | P = Partial | EE = Oracle Enterprise Edition required

5.1 Backup Modes

Feature Bacula Enterprise 18.2.3 Veeam Commvault NetBackup PodHeitor 1.0.0
RMAN SBT v2 (zero-staging) Y (proprietary libobk.so) N N Y (nbora) Y (clean-room libobk-rs.so, Proprietary)
RMAN non-SBT (staging) Y N P P Y + zero-staging FIFO option
Data Pump (expdp) P (via dump_pump_opt) N N N Y (default on 12c+)
exp legacy (11g) Y N N N Y
Continuous archivelog (CDP) N N N N Y (daemon mode, mode=cdp)
DR replication (SE2 compat) N N N N Y (archivelog_apply)
Active DG duplicate N (sep. licence) N N EE Y (duplicate_active, no extra licence)

5.2 Incremental and Advanced Backup

Feature Bacula Enterprise Veeam Commvault NetBackup PodHeitor
Incremental Level 0/1 RMAN Y Y Y Y Y
Incremental FROM SCN Y N N P Y + SCN gap detector + resume
Block Change Tracking Y (manual) Y Y Y Y (auto-enable + sanity check)
Archivelog backup Y Y Y Y Y
Controlfile autobackup Y Y Y Y Y
SPFILE / pfile / orapw backup Y N N P Y
Multichannel parallel Y (manual ALLOCATE) Y Y Y Y (auto-tune by CPU cores/IOPS)
Checkpoint / resume N N N N Y (ADR-014, SCN chain)
Archivelog deletion policy N N N N Y (archivelog_keep_backed_up=N)
AWR snapshot at end of Full N N N N Y (awr_snapshot=yes)

5.3 Topology and Multitenant

Feature Bacula Enterprise Veeam Commvault NetBackup PodHeitor
Oracle 11g R2 Y N P Y Y
Oracle 12c / 18c / 19c / 21c Y Y Y Y Y
Oracle 23ai P P N P Y (live validated)
RAC auto-discovery M N Y Y Y (auto + per-node parallel)
CDB/PDB multitenant Y (implicit) Y Y Y Y (per-PDB parallel + selective)
Data Guard role gate Y (implicit) N P Y Y (prefer_standby=no/yes/auto)
ASM path handling Y Y Y Y Y (asmcmd resolution + dbv filter)
Cross-endian restore (Solaris→Linux) M (manual) N N P Y (RMAN CONVERT DATAFILE auto)
TDE wallet backup Y P P P Y (master-key rotation aware)

5.4 Restore Automation

Feature Bacula Enterprise Veeam Commvault NetBackup PodHeitor
Restore without SSH to Oracle host N N N N Y (bconsole only)
Audit trail in Bacula catalog N N N N Y (full JobLog + manifest)
PITR (point-in-time recovery) M (perl script) M M M Y (1-shot, action=pitr)
SCN-based restore M N N M Y (1-shot, action=scn)
Table-level recovery (12c+) M N N M Y (1-shot, action=table)
Clone to different host/SID M (beta) M M M Y (action=clone)
RESTORE PREVIEW before execute N N N N Y (preview_first=yes)
VALIDATE DATABASE after restore N N N N Y (verify_after=yes)
Dry-run mode N N N N Y (dry_run=yes)
Flashback Database N N N N Y (action=flashback)
Bacularis web form for restore N N/A N/A N/A Y (native Bacularis integration)

5.5 Compression and Throttling

Feature Bacula Enterprise Veeam Commvault NetBackup PodHeitor
RMAN BASIC/MEDIUM/HIGH Y Y Y Y Y
zstd / lz4 pre-SBT pipe N N N N Y (double-compression option)
RMAN RATE throttle Y Y Y Y Y
cgroups v2 I/O throttle N N N N Y (cgroup_write_bps=)

5.6 Observability and Supply Chain

Feature Bacula Enterprise Veeam Commvault NetBackup PodHeitor
Prometheus /metrics endpoint N N N N Y (metrics_addr=host:port)
Anti-ransomware canary N Y (separate) Y (separate) Y (separate) Y (built-in, block-hash sampler)
Audit-log credential redaction N N N N Y (passwords/keys never in logs)
DBVERIFY post-restore N N N N Y (automated)
Dry-run preflight N N N N Y (–dry-run flag)
Reproducible builds N (proprietary) N N N Y (static-pie musl, Cargo.lock)
SBOM (CycloneDX) N N N N Y (make sbom)
CVE audit (cargo-audit + cargo-deny) N N N N Y (0 CVEs, 78 crate deps)

6. Backup Options Reference

All parameters are specified in the Bacula Plugin = directive inside a FileSet block. Parameters may also be placed in the config file (default: /opt/bacula/etc/podheitor-oracle.conf) as key=value lines — plugin-line parameters always override config-file values.

6.1 Connection and Identity

Parameter Type / Valid Values Default Description Since
sid string * (all detected) Oracle SID (instance name). Use * to auto-detect all running instances. 1.0.0
oracle_home path auto $ORACLE_HOME path. auto reads from /etc/oratab or oraenv. 1.0.0
oracle_user string / as sysdba OS user to connect as. Set to oracle for OS authentication. 1.0.0
unix_user string oracle OS account the backend switches to before spawning RMAN/sqlplus. 1.0.0
use_sudo bool no Prefix oracle commands with sudo -u <unix_user> instead of setuid. 1.0.0
auth os pwfile:<path> walletconn:<alias> os Authentication method. os = / as sysdba. pwfile: = password file. walletconn: = Oracle Wallet TNS alias. 1.0.0
config_file path /opt/bacula/etc/podheitor-oracle.conf Override path to the config file. 1.0.0
instance string * RAC instance filter. * = all instances. 1.0.0
verbose 0–3 0 Verbosity level for Bacula job log. 1.0.0
debug 0–9 0 Debug level; ≥5 enables PTCOMM frame dumps. 1.0.0
trace path Write trace log to file (in addition to Bacula job log). 1.0.0

6.2 Backup Mode

Parameter Type / Valid Values Default Description Since
mode rman_sbt rman dump cdp replicate dump Backup mode. rman_sbt is recommended for production. 1.0.0

6.3 RMAN Options (applicable to mode=rman and mode=rman_sbt)

Parameter Type / Valid Values Default Description Since
channels auto 1–64 auto Number of RMAN backup channels. auto tunes to CPU core count. 1.0.0
auto_tune_channels bool yes When channels=auto, dynamically adjust channel count based on available cores. 1.0.0
bct auto on off auto Block Change Tracking. auto enables if not already enabled. 1.0.0
archivelog include exclude only include Archivelog handling. include = back up after datafiles. only = archivelog-only backup. 1.0.0
archivelog_keep_backed_up 0–99 0 Delete archivelogs from FRA after N backup copies. 0 = disabled. 1.0.0
max_rate_mb 0–99999 0 (unlimited) RMAN per-channel rate limit in MB/sec. 0 = no limit (use cgroup_write_bps for cgroups-based throttle). 1.0.0
ctrlfile path /tmp/oracle Staging path prefix for controlfile autobackup. 1.0.0
hooks_dir path /opt/bacula/etc Directory scanned for oracle_before_*.rman / oracle_after_*.rman hook scripts. 1.0.0

6.4 Compression

Parameter Type / Valid Values Default Description Since
compress none zstd lz4 gzip rman_basic rman_medium rman_high zstd Compression algorithm. rman_* uses RMAN native compression inside the RMAN block. zstd/lz4/gzip applies pipe-level compression before sending to Bacula. 1.0.0
compress_level 1–22 (zstd), 1–9 (gzip) 3 Compression level (applies only to zstd and gzip). 1.0.0

6.5 Channels and Parallelism

Parameter Type / Valid Values Default Description Since
parallel_dbs 1–64 4 Maximum databases to back up in parallel (when sid=*). 1.0.0
parallel_pdbs 1–64 4 Maximum PDBs to back up in parallel within a CDB. 1.0.0
parallel_nodes 0–64 0 (all) Maximum RAC nodes to use concurrently. 0 = all discovered. 1.0.0
prefer_standby no yes auto no Data Guard role gate. no = backup on PRIMARY only. yes = require physical standby. auto = run on any physical-capable role. 1.0.0

6.6 Multitenant (CDB/PDB)

Parameter Type / Valid Values Default Description Since
pdbs * comma-separated names * PDB name filter. * = all PDBs. Example: pdbs=PDB1,PDB2. 1.0.0
pdb_skip_seed bool yes Skip PDB$SEED (the read-only seed PDB) in multitenant backups. 1.0.0
exclude_tablespace comma-separated names Tablespace names to exclude from backup. 1.0.0
exclude_pdb comma-separated names PDB names to exclude from backup. 1.0.0

6.7 TDE Wallet

Parameter Type / Valid Values Default Description Since
wallet_backup bool yes Include TDE wallet backup in the job. 1.0.0
wallet_path path auto auto Path to the Oracle Wallet directory. auto reads from sqlnet.ora. 1.0.0
wallet_passphrase_file path File containing the wallet open passphrase. Permissions must be 600. 1.0.0

6.8 Data Pump (mode=dump)

Parameter Type / Valid Values Default Description Since
dump_format expdp exp expdp Use Data Pump (expdp) or legacy export (exp). Forced to exp on 11g. 1.0.0
dump_opt string CONSISTENT=Y GRANTS=y Extra options appended to the exp command line. 1.0.0
dump_pump_opt string Extra options appended to the expdp parfile (e.g. EXCLUDE=STATISTICS). 1.0.0
schema * comma-separated * Schema (owner) filter for Data Pump export. * = all schemas. 1.0.0

6.9 Continuous Data Protection (mode=cdp)

Parameter Type / Valid Values Default Description Since
cdp_poll_interval 1–3600 (seconds) 5 How often (seconds) the CDP daemon polls v$archived_log for new logs. 1.0.0
cdp_max_lag 1–86400 (seconds) 300 RPO alarm threshold in seconds. Triggers PODHEITOR-ORACLE-AUDIT kind=cdp_lag_exceeded when exceeded. 1.0.0

6.10 Replication (mode=replicate)

Parameter Type / Valid Values Default Description Since
replicate_method duplicate_active archivelog_apply duplicate_active duplicate_active = RMAN DUPLICATE FROM ACTIVE DATABASE (EE). archivelog_apply = bootstrap + continuous log apply (SE2 compatible). 1.0.0
target_sid string Standby database SID (required for replicate mode). 1.0.0
target_host string Standby host FQDN or IP. 1.0.0
target_oracle_home path $ORACLE_HOME on the standby host. 1.0.0

6.11 Validation (post-backup integrity check)

Parameter Type / Valid Values Default Description Since
validate_after bool yes Run RMAN VALIDATE BACKUPSET after every backup job. 1.0.0

6.12 Anti-Ransomware Canary

Parameter Type / Valid Values Default Description Since
canary bool no Enable block-hash sampling canary. Detects mass datafile changes between backup runs. 1.0.0
canary_blocks 1–4096 64 Number of random blocks sampled per datafile per canary check. 1.0.0
canary_threshold_pct 1–100 25 Percentage of changed blocks that triggers a PODHEITOR-ORACLE-CANARY-ALERT message. 1.0.0

6.13 Observability

Parameter Type / Valid Values Default Description Since
metrics_addr host:port 0 0 (disabled) Bind address for Prometheus HTTP /metrics endpoint. Example: 0.0.0.0:9119. 1.0.0
cgroup_write_bps 0–(uint64) 0 (disabled) cgroups v2 I/O write throttle in bytes/sec. Requires the backend process to be in a cgroup v2 hierarchy. 1.0.0
awr_snapshot bool no Create an AWR snapshot at end of each Full backup and write HTML performance report to state dir. Non-fatal on XE/SE2. 1.0.0
goldengate_aware bool no Detect active GoldenGate processes and emit their SCN checkpoint before each backup. 1.0.0

6.14 Hooks

Hook files are placed in hooks_dir (default /opt/bacula/etc). The backend scans for files matching these patterns before and after RMAN execution:

Hook File Trigger Notes
oracle_before_full_backup.rman Before Full RMAN backup Enterprise-compatible naming
oracle_after_full_backup.rman After Full RMAN backup Extension: after-hooks are PodHeitor-only
oracle_before_incremental_backup.rman Before Incremental backup
oracle_after_incremental_backup.rman After Incremental backup
oracle_before_full_backup_<SID>.rman Before Full — SID-specific Takes priority over generic hook
oracle_after_full_backup_<SID>.rman After Full — SID-specific

7. Restore Options Reference

Restore options are delivered via the pluginrestoreconf RestoreObject, which is embedded in every backup and rendered as interactive prompts in bconsole or as a form in Bacularis. Keys follow INI-style key = value syntax with # comments.

7.1 Core Fields (all actions)

Key Type / Valid Values Default Description
action pitr scn table clone full preview validate flashback preview Restore action to perform. Required.
auto_open_resetlogs bool yes Automatically issue ALTER DATABASE OPEN RESETLOGS after RECOVER DATABASE.
shutdown_if_open bool yes Issue SHUTDOWN IMMEDIATE before restore if the database is open.
parallelism auto 1–64 auto Number of RMAN restore channels. auto matches the original backup channel count.
verify_after bool yes Run RMAN VALIDATE DATABASE CHECK LOGICAL + DBVERIFY after restore.
preview_first bool no Run RESTORE DATABASE PREVIEW before executing the restore. Outputs a plan without modifying the database.
require_explicit_confirmation bool yes For destructive actions, prompt the operator to type yes in bconsole before proceeding.
dry_run bool no Parse and validate the configuration, generate the RMAN script, print it to the job log, but do not execute.

7.2 action=pitr — Point-in-Time Recovery

Key Type / Valid Values Default Description
target_time YYYY-MM-DD_HH:MM:SS Required. Target recovery timestamp. Example: 2026-04-25_15:30:00.

Generated RMAN block:

RUN {
  SET UNTIL TIME "TO_DATE('2026-04-25 15:30:00','YYYY-MM-DD HH24:MI:SS')";
  RESTORE DATABASE;
  RECOVER DATABASE;
  ALTER DATABASE OPEN RESETLOGS;
}

Example pluginrestoreconf:

action            = pitr
target_time       = 2026-04-25_15:30:00
preview_first     = yes
verify_after      = yes
shutdown_if_open  = yes
parallelism       = 4

7.3 action=scn — SCN-Based Recovery

Key Type / Valid Values Default Description
target_scn positive integer Required. Target System Change Number. Example: 2090264.

Generated RMAN block:

RUN {
  SET UNTIL SCN 2090264;
  RESTORE DATABASE;
  RECOVER DATABASE;
  ALTER DATABASE OPEN RESETLOGS;
}

Example pluginrestoreconf:

action     = scn
target_scn = 2090264
dry_run    = no

7.4 action=table — Table-Level Recovery (Oracle 12c+)

Key Type / Valid Values Default Description
table_owner string Required. Schema (owner) of the table. Example: SCOTT.
table_name string Required. Table name to recover. Example: EMP.
auxiliary_destination path Required. Temporary filesystem path for the auxiliary instance used by RECOVER TABLE.

Generated RMAN block:

RECOVER TABLE SCOTT.EMP
  UNTIL TIME "TO_DATE('...')"
  AUXILIARY DESTINATION '/u01/aux';

Example pluginrestoreconf:

action                = table
table_owner           = SCOTT
table_name            = EMP
auxiliary_destination = /u01/aux
target_time           = 2026-04-24_12:00:00

7.5 action=clone — Clone to Different Host or SID

Key Type / Valid Values Default Description
target_db_name string Required. New database name (SID) for the clone.
target_host FQDN or IP Target host for the clone. Leave empty for same-host clone.
target_oracle_home path $ORACLE_HOME on the target host.
db_file_name_convert &#x27;/src/&#x27;,&#x27;/dst/&#x27; RMAN DB_FILE_NAME_CONVERT pairs for datafile path translation.

Example pluginrestoreconf:

action                = clone
target_db_name        = ORCL_DR
target_host           = 192.168.15.117
target_oracle_home    = /u01/app/oracle/product/23ai/dbhome_1
db_file_name_convert  = '/u01/oradata/ORCL/','/u01/oradata/ORCL_DR/'
log_file_name_convert = '/u01/fast_recovery_area/ORCL/','/u01/fast_recovery_area/ORCL_DR/'

7.6 action=full — Full Restore (Latest Available)

No additional required keys. Restores to the most recent consistent backup set.

Example pluginrestoreconf:

action           = full
preview_first    = yes
verify_after     = yes
shutdown_if_open = yes

7.7 action=preview — Read-Only Preview

Runs RESTORE DATABASE PREVIEW SUMMARY and outputs the plan to the Bacula job log. Does not modify the database.

Example pluginrestoreconf:

action = preview

7.8 action=validate — Read-Only Database Validation

Runs VALIDATE DATABASE CHECK LOGICAL and DBVERIFY on all datafiles. Zero-modification; suitable as a scheduled health-check.

Example pluginrestoreconf:

action = validate

7.9 action=flashback — Flashback Database

Key Type / Valid Values Default Description
target_scn positive integer Required. SCN target for FLASHBACK DATABASE TO SCN. Destructive: database is wound back irreversibly.

Example pluginrestoreconf:

action                       = flashback
target_scn                   = 2090000
require_explicit_confirmation = yes
dry_run                      = no

8. FileSet Configuration Examples

8.1 mode=rman_sbt — Minimal (Recommended Starting Point)

FileSet {
  Name = "Oracle-RMAN-SBT-Minimal"
  Include {
    Options {
      Signature   = SHA256
      Compression = none        # plugin handles compression
    }
    Plugin = "podheitor-oracle: 
        sid=FREE 
        mode=rman_sbt 
        oracle_home=/opt/oracle/product/23ai/dbhome_1 
        auth=os 
        channels=auto 
        compress=zstd:3"
  }
}

8.2 mode=rman_sbt — Full Production Configuration with Validation and Canary

FileSet {
  Name = "Oracle-RMAN-SBT-Production"
  Include {
    Options {
      Signature   = SHA256
      Compression = none
    }
    Plugin = "podheitor-oracle: 
        sid=ORCL 
        mode=rman_sbt 
        oracle_home=/u01/app/oracle/product/19c/dbhome_1 
        auth=os 
        unix_user=oracle 
        channels=auto 
        compress=zstd:3 
        bct=auto 
        archivelog=include 
        archivelog_keep_backed_up=2 
        validate_after=yes 
        canary=on 
        canary_blocks=128 
        canary_threshold_pct=20 
        wallet_backup=yes 
        wallet_path=auto 
        metrics_addr=0.0.0.0:9119 
        hooks_dir=/opt/bacula/etc 
        verbose=1"
  }
}

8.3 mode=rman — Non-SBT with Local Staging

FileSet {
  Name = "Oracle-RMAN-Staging"
  Include {
    Options {
      Signature   = SHA256
      Compression = none
    }
    Plugin = "podheitor-oracle: 
        sid=ORCL 
        mode=rman 
        oracle_home=/u01/app/oracle/product/19c/dbhome_1 
        auth=os 
        channels=4 
        staging=disk 
        staging_root=/u02/rman_staging 
        compress=rman_medium 
        bct=auto 
        archivelog=include"
  }
}

8.4 mode=dump — Oracle Data Pump (Logical Backup)

FileSet {
  Name = "Oracle-DataPump"
  Include {
    Options {
      Signature   = SHA256
      Compression = none
    }
    Plugin = "podheitor-oracle: 
        sid=ORCL 
        mode=dump 
        oracle_home=/u01/app/oracle/product/19c/dbhome_1 
        auth=os 
        dump_format=expdp 
        schema=* 
        dump_pump_opt=EXCLUDE=STATISTICS COMPRESSION=ALL 
        compress=zstd:3"
  }
}

8.5 mode=cdp — Continuous Archivelog Protection

FileSet {
  Name = "Oracle-CDP"
  Include {
    Options {
      Signature   = SHA256
      Compression = none
    }
    Plugin = "podheitor-oracle: 
        sid=ORCL 
        mode=cdp 
        oracle_home=/u01/app/oracle/product/19c/dbhome_1 
        auth=os 
        cdp_poll_interval=10 
        cdp_max_lag=120 
        compress=lz4 
        metrics_addr=0.0.0.0:9119"
  }
}

Pair this FileSet with a long-running Bacula job (Type=Backup, Level=Full). The CDP daemon runs until the Bacula job ends. Use Schedule with a very long RunWindow or a dedicated always-on job.

8.6 mode=replicate — Archivelog-Apply for Oracle Standard Edition 2

FileSet {
  Name = "Oracle-Replicate-SE2"
  Include {
    Options {
      Signature   = SHA256
      Compression = none
    }
    Plugin = "podheitor-oracle: 
        sid=ORCL 
        mode=replicate 
        oracle_home=/u01/app/oracle/product/19c/dbhome_1 
        auth=os 
        replicate_method=archivelog_apply 
        target_sid=ORCL_DR 
        target_host=192.168.15.117 
        target_oracle_home=/u01/app/oracle/product/19c/dbhome_1 
        channels=2 
        compress=zstd:3"
  }
}

8.7 mode=replicate — Active Data Guard Duplicate (Oracle EE)

FileSet {
  Name = "Oracle-Replicate-DG"
  Include {
    Options {
      Signature   = SHA256
      Compression = none
    }
    Plugin = "podheitor-oracle: 
        sid=ORCL 
        mode=replicate 
        oracle_home=/u01/app/oracle/product/19c/dbhome_1 
        auth=os 
        replicate_method=duplicate_active 
        target_sid=ORCL_STBY 
        target_host=192.168.15.117 
        target_oracle_home=/u01/app/oracle/product/19c/dbhome_1 
        channels=4 
        compress=rman_medium"
  }
}

8.8 Multi-PDB Selective Backup (Oracle 19c CDB)

FileSet {
  Name = "Oracle-Multitenant-Selective"
  Include {
    Options {
      Signature   = SHA256
      Compression = none
    }
    Plugin = "podheitor-oracle: 
        sid=CDBPROD 
        mode=rman_sbt 
        oracle_home=/u01/app/oracle/product/19c/dbhome_1 
        auth=os 
        pdbs=PDB_HR,PDB_FIN,PDB_APP 
        pdb_skip_seed=yes 
        exclude_tablespace=TEMP 
        parallel_pdbs=3 
        channels=auto 
        compress=zstd:3 
        wallet_backup=yes 
        validate_after=yes"
  }
}

8.9 Oracle 11g Legacy (exp mode)

FileSet {
  Name = "Oracle-11g-Legacy"
  Include {
    Options {
      Signature   = SHA256
      Compression = none
    }
    Plugin = "podheitor-oracle: 
        sid=ORCL11 
        mode=dump 
        oracle_home=/u01/app/oracle/product/11.2.0/dbhome_1 
        auth=os 
        dump_format=exp 
        dump_opt=CONSISTENT=Y GRANTS=y ROWS=y 
        schema=* 
        compress=gzip"
  }
}

9. Restore Job Examples

9.1 Full Database Restore — Latest Backup

* restore client=oracle-23ai-fd

Automatically selected Catalog: MyCatalog
Using Catalog "MyCatalog"

First you select one or more JobIds that contain files
to be restored. You will be presented several methods
of specifying the JobIds. Then you will be allowed to
select which files from those JobIds are to be restored.

To select the JobIds, you may then select the following:
     1: List last 20 Jobs run
     2: List Jobs where a given File is saved
     ...
     5: Select the most recent backup for a client
     ...
Select item:  (1-13): 5

Defined Clients:
     1: oracle-23ai-fd
Select the Client (1-1): 1

The defined FileSet resources are:
     1: Oracle-RMAN-SBT-Production
Select FileSet resource (1-1): 1

+-------+-------+----------+-------------+---------+
| JobId | Level | JobFiles | JobBytes    | Status  |
+-------+-------+----------+-------------+---------+
|  4989 | F     |        1 | 499,654,432 | T       |
+-------+-------+----------+-------------+---------+

You have selected the following JobId: 4989

Building directory tree for JobId(s) 4989 ...
1 file inserted into the tree.

cwd is: /
$ mark *
1 file marked.

$ done

Bootstrap records written to /opt/bacula/working/oracle-23ai-fd.restore.bsr

The job will require the following (*=>cur_dir):
   Volume(s)                 Storage(s)                SD Device(s)
===========================================================================

   OracleVol-0001            File                      FileStorage

Volumes marked with "*" are online.

 1 file selected to be restored.

Plugin Restore Options:
  action (full|pitr|scn|table|clone|preview|validate) [preview]: full
  shutdown_if_open [yes]: yes
  preview_first [no]: yes
  verify_after [yes]: yes
  dry_run [no]: no
  require_explicit_confirmation [yes]: yes

Run Restore job
JobName:         OracleRestore
Bootstrap:       /opt/bacula/working/oracle-23ai-fd.restore.bsr
Where:           /
Replace:         Always
FileSet:         Oracle-RMAN-SBT-Production
Backup Client:   oracle-23ai-fd
Restore Client:  oracle-23ai-fd
Storage:         File
JobId:           *None*
When:            2026-04-27 10:00:00
Catalog:         MyCatalog
Priority:        10
Plugin Options:  *None*
OK to run? (yes/mod/no): yes

Job queued. JobId=5001.

* messages
27-Apr 10:00:01 oracle-23ai-fd JobId 5001: PODHEITOR-ORACLE-AUDIT ts=2026-04-27T10:00:01Z kind=restore_start sid=FREE action=full
27-Apr 10:00:02 oracle-23ai-fd JobId 5001: --- RESTORE PREVIEW SUMMARY ---
27-Apr 10:00:02 oracle-23ai-fd JobId 5001: Restore Point:     SCN 2090264
27-Apr 10:00:02 oracle-23ai-fd JobId 5001: Pieces required:   6
27-Apr 10:00:02 oracle-23ai-fd JobId 5001: Total size:        477 MB
27-Apr 10:00:02 oracle-23ai-fd JobId 5001: Estimated time:    ~20 seconds
27-Apr 10:00:02 oracle-23ai-fd JobId 5001: --- END PREVIEW ---
27-Apr 10:00:02 oracle-23ai-fd JobId 5001: Confirm restore? [yes/no]: yes
27-Apr 10:00:12 oracle-23ai-fd JobId 5001: RMAN> RESTORE DATABASE; ... completed
27-Apr 10:00:19 oracle-23ai-fd JobId 5001: RMAN> RECOVER DATABASE; ... completed
27-Apr 10:00:19 oracle-23ai-fd JobId 5001: RMAN> ALTER DATABASE OPEN RESETLOGS; ... completed
27-Apr 10:00:23 oracle-23ai-fd JobId 5001: PODHEITOR-ORACLE-AUDIT kind=restore_verify_start
27-Apr 10:00:40 oracle-23ai-fd JobId 5001: DBVERIFY: 131,072 pages checked, 0 corrupt, 0 failure
27-Apr 10:00:40 oracle-23ai-fd JobId 5001: PODHEITOR-ORACLE-AUDIT kind=restore_end ok=true size=477MB
27-Apr 10:00:40 oracle-23ai-fd JobId 5001: Bacula oracle-23ai-fd JobId 5001: End Restore Job.
                                           TerminateCode=OK

9.2 PITR — Point-in-Time Recovery Step by Step

* restore client=oracle-23ai-fd

[...select JobId 4989, mark *, done...]

Plugin Restore Options:
  action (full|pitr|scn|table|clone|preview|validate) [preview]: pitr
  target_time (YYYY-MM-DD_HH:MM:SS) []: 2026-04-25_15:30:00
  shutdown_if_open [yes]: yes
  preview_first [no]: yes
  verify_after [yes]: yes
  dry_run [no]: no
  require_explicit_confirmation [yes]: yes

OK to run? (yes/mod/no): yes
Job queued. JobId=5002.

* messages
27-Apr 10:05:01 oracle-23ai-fd JobId 5002: PODHEITOR-ORACLE-AUDIT kind=restore_start sid=FREE action=pitr
27-Apr 10:05:01 oracle-23ai-fd JobId 5002: target_time=2026-04-25_15:30:00
27-Apr 10:05:03 oracle-23ai-fd JobId 5002: --- RESTORE PREVIEW ---
27-Apr 10:05:03 oracle-23ai-fd JobId 5002: SET UNTIL TIME "TO_DATE('2026-04-25 15:30:00','YYYY-MM-DD HH24:MI:SS')";
27-Apr 10:05:07 oracle-23ai-fd JobId 5002: Pieces required: 6, estimated restore: ~19s
27-Apr 10:05:07 oracle-23ai-fd JobId 5002: --- END PREVIEW ---
27-Apr 10:05:07 oracle-23ai-fd JobId 5002: Proceed with PITR to 2026-04-25 15:30:00? [yes/no]: yes
27-Apr 10:05:17 oracle-23ai-fd JobId 5002: RMAN restore + recover completed in 19s
27-Apr 10:05:17 oracle-23ai-fd JobId 5002: ALTER DATABASE OPEN RESETLOGS - OK
27-Apr 10:05:22 oracle-23ai-fd JobId 5002: Bacula oracle-23ai-fd JobId 5002: End Restore Job. TerminateCode=OK

9.3 SCN-Based Restore

Plugin Restore Options:
  action: scn
  target_scn: 2090264
  shutdown_if_open: yes
  preview_first: no
  verify_after: yes
  dry_run: no

Generates: SET UNTIL SCN 2090264; RESTORE DATABASE; RECOVER DATABASE; ALTER DATABASE OPEN RESETLOGS;

9.4 Table-Level Recovery (Oracle 12c+)

Plugin Restore Options:
  action: table
  table_owner: SCOTT
  table_name: EMP
  auxiliary_destination: /u01/aux
  target_time: 2026-04-25_12:00:00
  verify_after: yes
  dry_run: no

The plugin generates an RMAN RECOVER TABLE SCOTT.EMP UNTIL TIME ... AUXILIARY DESTINATION &#x27;/u01/aux&#x27; block, restores the table from the backup, and imports it back into the live database via Data Pump — all without operator SSH access.

9.5 Clone Database to a Different Host/SID

Plugin Restore Options:
  action:                = clone
  target_db_name:        = ORCL_DEV
  target_host:           = 192.168.15.200
  target_oracle_home:    = /u01/app/oracle/product/19c/dbhome_1
  db_file_name_convert:  = '/u01/oradata/ORCL/','/u01/oradata/ORCL_DEV/'
  log_file_name_convert: = '/u01/fra/ORCL/','/u01/fra/ORCL_DEV/'
  dry_run:               = no

The plugin generates a DUPLICATE TARGET DATABASE TO ORCL_DEV RMAN block with the appropriate DB_FILE_NAME_CONVERT and LOG_FILE_NAME_CONVERT clauses, creates a new init.ora on the target host, and starts the clone database — from a single bconsole restore session.


10. Installation and Sizing Guide

10.1 Prerequisites

Oracle Host (also the Bacula FD Host)

Component Minimum Version Notes
Bacula File Daemon 15.0.3 Standard Community package
Oracle Database 11g R2 (11.2.0.4) Tested through 23ai FREE
sqlplus Matches DB version Full Oracle Client required — Instant Client insufficient
rman Matches DB version Required for all modes except dump
dbv (DBVERIFY) Matches DB version Required for validate_after=yes
expdp / impdp Matches DB version Required for mode=dump with dump_format=expdp
exp Matches DB version Required for mode=dump on Oracle 11g
Linux kernel 4.18+ cgroups v2 requires 4.15+; EL8 minimum is 4.18
Disk — state directory ~100 MB /opt/bacula/working/oracle-state/ per SID
Disk — staging 1× DB size Only required for mode=rman (non-SBT) and mode=dump

Bacula Director Host

Component Minimum Version Notes
bacula-director 15.0.3 No Oracle-specific configuration needed
Catalog DB PostgreSQL 14+ or MySQL 8+ Standard Bacula requirement

10.2 Sizing Guide

Environment DB Size Recommended Channels Disk (staging) RAM (backend) Notes
Small (Dev/Test) < 100 GB 2–4 50 GB 256 MB Single-instance, mode=rman_sbt
Medium (Production) 100 GB – 1 TB 4–8 500 GB 512 MB channels=auto, BCT enabled
Large (Enterprise) 1 TB – 10 TB 8–16 2 × DB size 1 GB RAC, CDB/PDB, CDP
Enterprise-Scale > 10 TB 16–32 External SAN 2 GB Multichannel SBT, ASM, DG

For mode=rman_sbt (recommended), no staging disk is required — data streams directly from RMAN through libobk-rs and PTCOMM to Bacula Storage.

10.3 RPM Installation (EL8 / EL9 / Rocky / Alma / OL)

# Step 1: Install the package
sudo dnf install ./podheitor-oracle-plugin-1.0.0-1.el9.x86_64.rpm

# Step 2: Copy and edit the config file
sudo cp /opt/bacula/etc/podheitor-oracle.conf.example 
        /opt/bacula/etc/podheitor-oracle.conf
sudo chown root:bacula /opt/bacula/etc/podheitor-oracle.conf
sudo chmod 640         /opt/bacula/etc/podheitor-oracle.conf
sudo vi                /opt/bacula/etc/podheitor-oracle.conf

# Step 3: Set the minimum config (edit these values)
# sid          = FREE
# mode         = rman_sbt
# oracle_home  = /opt/oracle/product/23ai/dbhome_1
# oracle_user  = / as sysdba
# unix_user    = oracle
# auth         = os
# channels     = auto
# compress     = zstd:3

# Step 4: Verify install
/opt/bacula/bin/podheitor-oracle-backend --version

# Step 5: Dry-run validation (Oracle must be running)
/opt/bacula/bin/podheitor-oracle-backend --dry-run 
    /opt/bacula/etc/podheitor-oracle.conf

10.4 DEB Installation (Debian 12 / Ubuntu 24.04)

# Step 1: Install the package
sudo apt install ./podheitor-oracle-plugin_1.0.0-2_amd64.deb

# Step 2: Configure (same as RPM step 2–3 above)
sudo cp /opt/bacula/etc/podheitor-oracle.conf.example 
        /opt/bacula/etc/podheitor-oracle.conf
sudo chown root:bacula /opt/bacula/etc/podheitor-oracle.conf
sudo chmod 640         /opt/bacula/etc/podheitor-oracle.conf

# Step 3: Dry-run validation
/opt/bacula/bin/podheitor-oracle-backend --dry-run 
    /opt/bacula/etc/podheitor-oracle.conf

10.5 Tarball Installation (Any 64-bit Linux)

# Extract
tar xzf podheitor-oracle-plugin-1.0.0-x86_64-linux-musl.tar.gz
cd podheitor-oracle-plugin-1.0.0

# Install (default PREFIX=/opt/bacula)
sudo make install

# Or with custom prefix
sudo make install PREFIX=/usr/local

# Verify
/opt/bacula/bin/podheitor-oracle-backend --version

10.6 Post-Install Validation

The --dry-run flag validates the entire configuration without connecting to Oracle:

$ sudo -u oracle /opt/bacula/bin/podheitor-oracle-backend 
    --dry-run /opt/bacula/etc/podheitor-oracle.conf

PODHEITOR-ORACLE: dry-run OK
  sid          = FREE
  mode         = rman_sbt
  oracle_home  = /opt/oracle/product/23ai/dbhome_1
  channels     = 8 (auto-tuned, cores=16)
  bct          = enabled
  topology     = primary, single-instance, CDB with 3 PDBs (FREEPDB1,PDB$SEED,...)
  wallet       = open, master_key_id=ABCD1234...
  hooks        = none found in /opt/bacula/etc
  canary       = disabled
  metrics_addr = disabled

If the output contains any ERROR: line, resolve it before running live jobs.

10.7 libobk Symlink Setup (mode=rman_sbt only)

RMAN must be able to load libobk-rs.so as its SBT library. Create the symlink once per Oracle Home:

sudo ln -sf /opt/bacula/lib/libobk-rs.so 
            "$ORACLE_HOME/lib/libobk.so"

# Verify RMAN can load it
rman target / <<< "show all;" 2>&1 | grep -i sbt

Important: This symlink must be recreated after every Oracle PSU (Patch Set Update) or RU (Release Update) that reinstalls $ORACLE_HOME/lib/. The RPM %post script and DEB postinst script emit a reminder if the symlink is absent at install time.

10.8 Director Configuration

FileSet (see Section 8 for full examples)

FileSet {
  Name = "Oracle-RMAN-SBT"
  Include {
    Options {
      Signature   = SHA256
      Compression = none
    }
    Plugin = "podheitor-oracle: 
        sid=FREE 
        mode=rman_sbt 
        oracle_home=/opt/oracle/product/23ai/dbhome_1 
        auth=os 
        channels=auto 
        compress=zstd:3 
        validate_after=yes 
        canary=on"
  }
}

Backup Job

Job {
  Name      = "BackupOracle-FREE"
  Type      = Backup
  Level     = Incremental
  Client    = oracle-23ai-fd
  FileSet   = "Oracle-RMAN-SBT"
  Schedule  = "WeeklyCycle"
  Storage   = File
  Pool      = OracleDaily
  Messages  = Standard
  Priority  = 10
}

Restore Job

Job {
  Name          = "RestoreOracle-FREE"
  Type          = Restore
  Client        = oracle-23ai-fd
  FileSet       = "Oracle-RMAN-SBT"
  Storage       = File
  Pool          = OracleDaily
  Messages      = Standard
  Where         = /
  Priority      = 10
}

Schedule Example

Schedule {
  Name = "WeeklyCycle"
  Run  = Full           1st sun at 02:00
  Run  = Differential   2nd-5th sun at 02:00
  Run  = Incremental    mon-sat at 02:00
}

Reload the Director

sudo bconsole <<< "reload"

11. Compatibility Matrix

11.1 Oracle Versions × Features

Oracle Version rman_sbt rman dump cdp replicate Table Recovery CDB/PDB TDE
11g R2 (11.2.0.4) Y Y exp Y Y (log-apply) N N N
12c R1 (12.1) Y Y expdp Y Y Y Y Y
12c R2 (12.2) Y Y expdp Y Y Y Y Y
18c Y Y expdp Y Y Y Y Y
19c (LTS) Y Y expdp Y Y Y Y Y
21c Y Y expdp Y Y Y Y Y
23ai FREE Y (live) Y (live) Y (live) Y (live) Y (partial) Y Y Y

Notes:

  • 11g: dump_format forced to exp; no CDB/PDB, no TDE, no RECOVER TABLE
  • 23ai FREE: replicate_method=duplicate_active requires Oracle EE or an additional licence; archivelog_apply works on FREE edition
  • Live-validated = tested against a real running database instance

11.2 Linux Distribution Support

Distribution RPM DEB Tarball Status Notes
RHEL 9 / Rocky 9 / Alma 9 / OL 9 Y Y Live validated Job 4989 T OK on OL 9.6
RHEL 8 / Rocky 8 / Alma 8 / OL 8 Y Y Spec ships; live install pending Same spec as EL9
Debian 12 (bookworm) Y Y Wired; live make deb pending
Ubuntu 24.04 LTS (noble) Y Y Wired
Ubuntu 22.04 LTS (jammy) Y Y Container-tested
SLES 15 SP5+ Y Static-pie tarball only No packaging; statically linked

11.3 Bacula Versions

Bacula Version Status Notes
15.0.3 Live validated Reference build target (BACULA_SRC)
15.0.x (earlier) Untested Plugin API is stable; likely compatible
14.x Untested Plugin ABI may differ; not supported

11.4 Architectures

Architecture Status Notes
x86_64 (linux-musl static-pie) Live validated Production build; CI on phweb-ci
x86_64 (linux-gnu) Dev build Development build
aarch64 (linux-musl static-pie) Wired Disponível via tarballaarch64-linux-gnu-gcc cross-compiler

11.5 Oracle Editions × Features

Feature Oracle XE Oracle SE2 Oracle EE
mode=rman_sbt Y Y Y
mode=rman Y Y Y
mode=dump Y Y Y
mode=cdp Y Y Y
mode=replicate (archivelog_apply) Y Y Y
mode=replicate (duplicate_active) N* N* Y
BCT (Block Change Tracking) N Y Y
RAC N N Y
TDE Wallet N N Y
Table-level recovery Limited Y (12c+) Y (12c+)
AWR snapshot N N Y

*duplicate_active technically runs on SE2 as an RMAN feature, but Active Data Guard (managed standby) requires Oracle EE. For SE2 DR, use archivelog_apply.


12. Performance Report

All results are from live validation runs on the production lab environment: Oracle 23ai FREE, SID=FREE, VM 131 @ 192.168.15.51, Bacula FD 15.0.3, OL 9.6, phweb-ci as CI/build host.

12.1 Backup Performance

Job Mode Database Size Duration Throughput Status Notes
4860 rman_sbt Oracle 23ai FREE (SID=FREE) 477 MB 14m 39s ~543 KB/s T OK First live RMAN SBT validation; single-channel baseline
4956 restore Oracle 23ai FREE 477 MB 19 s ~25 MB/s T OK 6 pieces restored from Bacula storage
4989 rman_sbt Oracle 23ai FREE (SID=FREE) ~499 MB 26m 10s ~319 KB/s T OK Full backup from RPM-installed package (F14.b); files=1, 0 errors
F2.b dump (expdp) PHTEST schema 416 KB 1m 27s ~4.8 KB/s OK Data Pump logical export, PHTEST schema only
F3.b rman (non-SBT) Oracle 23ai FREE 451 MB 43 s ~10.5 MB/s OK 2 RMAN channels, 9 pieces, local staging
F6.b preview Oracle 23ai FREE 4 s OK RESTORE PREVIEW SUMMARY; SCN range 2090220–2090264
F10.b validate Oracle 23ai FREE 16.8 s OK RMAN VALIDATE DATABASE CHECK LOGICAL; 0 corrupt blocks
F10.b dbverify Oracle 23ai FREE 2.45 s OK 131,072 pages checked; 0 failures

12.2 Throughput Analysis

The throughput numbers above reflect a single-VM lab environment with shared storage (no dedicated SAN) and a single RMAN channel. Production deployments with:

  • Multiple RMAN channels (4–16, auto-tuned)
  • Dedicated backup storage network
  • BCT (Block Change Tracking) for incremental jobs

typically achieve 50–200 MB/s aggregate throughput depending on storage tier.

Job 4956 restore throughput (25 MB/s for 477 MB in 19 seconds) demonstrates the efficiency of the mode=rman_sbt stream path — Bacula retrieves the 6 backup pieces from storage and the backend feeds them directly into RMAN’s restore channel, bypassing any staging directory.

Job 4989 vs Job 4860 comparison: The longer duration in Job 4989 (26m10s vs 14m39s for the original) reflects a slightly larger database state (more accumulated archivelogs) at the time of the RPM-installation test, not a regression in performance.

12.3 Validation Performance

Operation Duration Result Coverage
RMAN VALIDATE DATABASE CHECK LOGICAL 16.8 s 0 corrupt blocks All datafiles + archivelogs
DBVERIFY (dbv) post-restore 2.45 s 0 failures 131,072 pages across all datafiles
RESTORE DATABASE PREVIEW SUMMARY 4 s Plan generated 6 pieces required, SCN range confirmed

12.4 Test Suite Coverage

Suite Count Scope
backend unit tests 523 Script generators, parsers, chain/verify/canary/ASM/topology/wallet, metrics, cgroups
libobk-rs unit tests 18 SBT v2 packet codec
Live-DB integration (VM 131) F2.b through F18 Full end-to-end on Oracle 23ai FREE

13. Security and Compliance

13.1 Credential Redaction

The plugin’s audit logging subsystem applies redaction rules to every log event before emitting it to the Bacula job log or the trace file:

  • Patterns matching IDENTIFIED BY <password> are replaced with IDENTIFIED BY [REDACTED].
  • Oracle connection strings user/password@host are replaced with user/[REDACTED]@host.
  • Wallet passphrase file contents are never logged — only the file path is logged.
  • SBT_PARMS strings containing SBT_ORACLE_HOME_USER or similar credentials are masked.

The result is that no Oracle password, TDE passphrase, or authentication credential ever appears in the Bacula job log, audit log, or trace file, regardless of verbose or debug level.

13.2 Anti-Ransomware Canary

When canary=on is set in the FileSet, the plugin samples a configurable number of random Oracle data blocks from each datafile at the start of each backup job and computes a rolling BLAKE3 hash. Between jobs, it compares the current hash sample to the previous job’s sample:

  1. If the fraction of changed blocks exceeds canary_threshold_pct (default 25%), the plugin emits a PODHEITOR-ORACLE-CANARY-ALERT message to the Bacula job log.
  2. The backup continues — the alert is a warning, not a failure — but the operator is notified of potential mass encryption by ransomware.
  3. The per-job hash state is written to /opt/bacula/working/oracle-state/<SID>/wallet_hash.

The canary does not guarantee ransomware detection, but it provides an early warning layer without Oracle Audit Vault or additional licensed tools.

13.3 TDE Wallet Awareness

When wallet_backup=yes (default), the plugin:

  1. Reads the wallet path from sqlnet.ora (wallet_path=auto) or the configured path.
  2. Streams the wallet directory to Bacula as part of the backup job.
  3. Detects master key rotation between jobs by comparing the current v$encryption_keys hash to the persisted wallet_hash in the state directory. If a rotation is detected, the plugin automatically promotes the next job to Full level (regardless of the Bacula level directive) to ensure a consistent backup with the new key material.

13.4 Supply Chain Integrity

Check Tool Result (v1.0.0)
CVE audit cargo-audit 0 known CVEs across all 78 crate dependencies
Licence compliance cargo-deny (deny.toml) All checks pass: licence, ban, advisory, source
Reproducible build build estático e reproduzível Deterministic; binary hash reproducible across CI runs
SBOM CycloneDX v1.4 Available under contract

Run security checks locally:

13.5 Network Attack Surface

The plugin process opens exactly one optional network socket: the Prometheus /metrics HTTP endpoint at metrics_addr. If metrics_addr=0 (default), no network port is opened. The UNIX socket at /var/run/podheitor-oracle/<SID>.sock is local-only, created with permissions 0600, and owned by the oracle OS user.

The PTCOMM channel between the Bacula FD shim and the Rust backend uses a fork()+pipe() mechanism — no network socket, no IPC shared memory, no named pipe accessible from outside the process group.

13.6 clean-room libobk-rs

libobk-rs.so is a clean-room re-implementation of the Oracle SBT API v2 (sbt2.h). The SBT API is documented in Oracle MOS (My Oracle Support) Note 67422.1 and the RMAN Backup & Recovery Reference. The implementation was written without access to Oracle’s proprietary libobk.so source code or binary, using only the published API specification.

The clean-room status means:

  • No Oracle proprietary code in the distributed binary.
  • No Oracle licence required to ship libobk-rs.so.
  • Single-licensed under PodHeitor-Proprietary (Copyright © Heitor Faria).

14. Support and Commercial Terms

14.1 Switching from a Competing Product?

Bring your Bacula Enterprise, Veeam, Commvault, or NetBackup renewal quote or active contract proposal. We guarantee a minimum 50% discount on commercial support — with more features, smaller package size, and no per-socket or per-host licence fees.

The PodHeitor plugin replaces:

  • Bacula Enterprise 18.2.3 Oracle Module
  • Veeam Agent for Oracle (with Veeam Backup & Replication)
  • Commvault IntelliSnap Oracle iDataAgent
  • NetBackup for Oracle (DB Agent)

…at a fraction of the cost, with superior restore automation, native CDP, and built-in DR replication for Standard Edition 2.

14.2 Support Tiers

Tier SLA Includes Contact
Community Best-effort documentation heitor@opentechs.lat
Standard Next business day Email support, patch priority, config review heitor@opentechs.lat
Premium 4-hour response Dedicated Slack channel, live sessions, custom FileSet tuning, upgrade assistance heitor@opentechs.lat
Enterprise 1-hour response + on-call 24/7 on-call, on-site options, custom feature development +1 786 726-1749

14.3 Training and Professional Services

Training and professional services are available for teams migrating from proprietary Oracle backup tools or building new Bacula/Oracle infrastructure:

  • Workshop: Oracle Backup with Bacula (1 day) — FileSet design, RMAN tuning, restore automation.
  • Workshop: DR Replication for Oracle SE2 (half day) — mode=replicate, archivelog-apply setup, failover testing.
  • Consulting: Migration from Bacula Enterprise — configuration translation, RunScript migration, ENTERPRISE_PARITY review.
  • Consulting: CDP Deployment — production CDP setup, RPO monitoring, Prometheus dashboards.

14.4 Contact

Channel Details
Email heitor@opentechs.lat
WhatsApp / Phone (international) +1 786 726-1749
WhatsApp / Phone (Brazil) +55 61 98268-4220
Author Heitor Faria

Appendix A — Architecture Decision Records (ADR)

A full set of 14 ADRs governs the technical decisions in this plugin. Each ADR is stored in docs/adr/. The key decisions are summarised below.

ADR-001 — Rust for the Backend Binary The core backup/restore logic is implemented in Rust targeting x86_64-unknown-linux-musl (static-pie). This choice delivers memory safety without garbage-collection pauses, deterministic shutdown behaviour (critical for RMAN channel cleanup), and a single-file deployment with zero runtime library dependencies. The musl static-pie target ensures the binary runs on any Linux 2.6.32+ kernel regardless of glibc version.

ADR-002 — Clean-Room libobk-rs SBT v2 Oracle’s RMAN SBT interface requires a shared library (libobk.so) conforming to the SBT v2 API (sbt2.h). Rather than depend on Bacula Enterprise’s proprietary libobk.so (which requires an active Bacula Enterprise subscription), the plugin ships libobk-rs.so: a clean-room Rust implementation of the same public API specification. This makes the plugin fully self-contained under PodHeitor-Proprietary licensing with no Oracle or Bacula proprietary code.

ADR-003 — Backup Manifest as Both File and RestoreObject Every backup job writes a _manifest.json to the state directory AND embeds it as a Bacula RestoreObject in the catalog. The manifest is BLAKE3-hashed, SCN-stamped, and includes DBID, incarnation, and chain metadata. This dual-write ensures that restore metadata is available even if the state directory is lost, and that Bacularis can display backup details in its web UI.

ADR-004 — PTCOMM Binary Protocol over fork+pipe The Bacula FD plugin API requires a C-ABI shared library. Since v1.1.0 the FD plugin loader (podheitor-oracle-fd.so) is a native Rust component that exports the C-ABI Bacula expects, then forks the Rust backend process and communicates with it via a binary protocol (PTCOMM) over stdin/stdout pipes. The fork+pipe boundary keeps the backend free to use Rust-native concurrency and panic semantics while delivering the same single-process experience to Bacula. (v1.0.0 used a thin C++ shim for the same role; the shim was removed in v1.1.0 to produce a single-licence, copyright-clean artefact — see the v1.1.0 supersession note above.)

ADR-005 — UNIX Socket for SBT ↔ Backend Communication libobk-rs.so is loaded by RMAN in-process, while the backend is a separate process. To transfer backup data from RMAN channels to the Bacula PTCOMM stream, libobk-rs connects to a UNIX domain socket (/var/run/podheitor-oracle/<SID>.sock) managed by the backend. This avoids the complexity of shared memory and provides natural per-SID isolation.

ADR-006 — Per-SID State Directory All persistent state (SCN cursor, archivelog cursor, canary hash, wallet hash, checkpoint manifests) is written to /opt/bacula/working/oracle-state/<SID>/. Using a per-SID directory allows multiple instances to coexist on the same host, survives package reinstall (RPM %postun preserves the directory), and is wiped only on explicit DEB --purge.

ADR-007 — Data Pump as Default on 12c+ On Oracle 12c and later, mode=dump defaults to expdp (Data Pump) rather than legacy exp. Data Pump is parallel, restartable, and produces significantly smaller dumps for large schemas. On 11g, the plugin automatically falls back to exp because expdp output format changed in 12c in ways that complicate cross-version import.

ADR-008 — Auto-Tune Channel Count When channels=auto (the default), the backend queries the host’s available CPU core count and adjusts the RMAN channel count accordingly, capped at the value in v$parameter for db_files. This eliminates the need for per-host manual tuning and delivers near-optimal parallelism out of the box.

ADR-009 — No bconsole Callback from libobk-rs Bacula Enterprise’s libobk.so requires a bconsole callback from RMAN to Bacula to deliver backup data (the so-called “SBT callback” architecture). This creates a dependency on the Director being reachable from the Oracle host during backup, which fails in NAT and VPN environments. PodHeitor’s libobk-rs connects to the backend process directly via UNIX socket — no Director callback, no bconsole dependency.

ADR-010 — Prometheus Metrics via stdlib TCP The Prometheus /metrics endpoint is served by a minimal HTTP server built from Rust’s std::net::TcpListener This keeps the binary small, eliminates a significant attack surface, and maintains the zero-external-runtime-dep property.

ADR-011 — Restore Automation via pluginrestoreconf RestoreObject Restore configuration is delivered as a pluginrestoreconf INI document embedded in the Bacula RestoreObject mechanism — not as command-line parameters to an external script. This means all restore actions (PITR, SCN, table, clone, flashback) are initiated from bconsole or Bacularis, are recorded in the Bacula catalog’s JobLog, and require no SSH access to the Oracle host. This is the single most significant differentiator versus Bacula Enterprise’s bs_oracle_restore.pl approach.

ADR-012 — cgroups v2 I/O Throttle Rather than relying on RMAN’s RATE parameter (which is per-channel and approximate), the plugin writes the io.max cgroups v2 throttle for the backend’s cgroup leaf node. This enforces a hard kernel-level write-rate cap on all I/O issued by the backup process, independent of RMAN channel count. The feature is non-fatal: if the host does not use a cgroups v2 unified hierarchy or CAP_SYS_ADMIN is absent, the plugin logs a warning and continues.

ADR-013 — Anti-Ransomware Canary via DBVERIFY Sampling The canary uses dbv (Oracle DBVERIFY) to sample random blocks from datafiles and computes BLAKE3 hashes. This reuses an existing Oracle tool available in every Oracle installation, avoids requiring direct raw-device access, and produces block-level content signatures without reading the entire datafile. The canary fires when the fraction of changed blocks exceeds the configurable threshold between consecutive backup jobs.

ADR-014 — SCN-Chain Checkpoint Resume When a Bacula job is interrupted (FD crash, Director restart, network timeout), the plugin writes a checkpoint/<jobid>.json to the state directory containing the last successfully transferred SCN range. On the next job run (which Bacula will retry at the same Level), the backend detects the checkpoint and resumes from the last successful SCN rather than restarting from scratch. This turns large-database incremental failures from a multi-hour re-run into a seconds-long resume.


Appendix B — Glossary

Term Definition
ADR Architecture Decision Record — a document recording a significant architectural decision, its context, and the rationale for the choice made.
PodHeitor-Proprietary GNU Affero General Public License version 3. The open-source licence under which PodHeitor is distributed.
archivelog Oracle redo log file that has been archived (copied from the online redo log to a destination). Required for point-in-time recovery.
ASM Oracle Automatic Storage Management — a volume manager and file system for Oracle database files, integrated with Oracle Clusterware.
BCT Block Change Tracking — an Oracle feature that records which database blocks have changed since the last backup, dramatically accelerating incremental backups by eliminating the need to scan unchanged blocks.
Bacularis A modern web interface for PodHeitor Backup that provides browser-based job management, restore forms, and reporting. Natively renders pluginrestoreconf forms.
BLAKE3 A cryptographic hash function used by PodHeitor for block-hash canary computation. Faster than SHA-256 while maintaining collision resistance.
CDB Container Database — an Oracle multitenant database container that holds one or more Pluggable Databases (PDBs). Introduced in Oracle 12c.
CDP Continuous Data Protection — a backup paradigm that continuously captures changes (in this plugin’s case, archivelogs) rather than taking periodic snapshots. Delivers RPO measured in minutes.
controlfile An Oracle binary file that records the physical structure of the database (datafiles, redo logs, backup metadata). Required to mount the database.
CycloneDX An open standard for Software Bill of Materials (SBOM) — a machine-readable inventory of all software components and their licences.
Data Guard (DG) Oracle Data Guard — Oracle’s built-in HA/DR solution that maintains standby databases in sync with a primary via redo log shipping. Requires Oracle Enterprise Edition for managed standby features.
dbv / DBVERIFY Oracle’s block-level verification utility (dbv). Reads Oracle data blocks and verifies their checksums and internal consistency without needing an open database connection.
expdp / impdp Oracle Data Pump Export and Import utilities (expdp/impdp). The modern replacement for exp/imp, supporting parallel export, compression, and incremental export.
FD File Daemon — the Bacula component installed on the client host that executes backup and restore jobs under Director direction.
FRA Fast Recovery Area — an Oracle-managed disk location for recovery-related files including archivelogs, controlfile autobackups, and RMAN backup sets.
GoldenGate Oracle GoldenGate — a real-time data replication and integration tool. PodHeitor’s goldengate_aware=yes detects active GoldenGate processes and logs their SCN checkpoint before backup.
libobk / libobk-rs The shared library that implements Oracle’s SBT (System Backup to Tape) v2 API. Oracle RMAN loads libobk.so (typically located in $ORACLE_HOME/lib/) to stream backup data to a media management layer. libobk-rs is PodHeitor’s clean-room Rust implementation of this API.
PITR Point-In-Time Recovery — a restore operation that returns the database to a specific timestamp, discarding all changes after that point. Requires archivelogs from the last Full backup to the target time.
PDB Pluggable Database — a self-contained Oracle database that resides inside a CDB. Each PDB has its own schemas, tablespaces, and can be managed independently.
PTCOMM PodHeitor’s internal binary framing protocol used for communication between the C++ FD shim and the Rust backend process over fork()+pipe(). Carries filenames, file metadata, data blocks, and control messages.
RAC Real Application Clusters — Oracle’s shared-disk multi-node database clustering solution. Requires Oracle Enterprise Edition and Oracle Grid Infrastructure.
RMAN Recovery Manager — Oracle’s native backup and recovery tool. RMAN understands Oracle’s internal block structure, manages backup sets and image copies, and is the only tool that can produce block-consistent backups of a running Oracle database without application quiescing.
RPO Recovery Point Objective — the maximum acceptable amount of data loss, measured as a time interval. CDP mode targets an RPO of minutes.
RTO Recovery Time Objective — the maximum acceptable time to restore service after an outage.
SBOM Software Bill of Materials — a formal, machine-readable inventory of all software components, versions, and licences that make up a software product.
SCN System Change Number — a monotonically increasing Oracle internal timestamp that uniquely identifies a consistent state of the database. Every committed transaction increments the SCN. SCNs are used to define precise backup and recovery points.
SBT System Backup to Tape — Oracle’s abstraction layer for media management integration with RMAN. Despite the name, SBT v2 works with any backup target including disk and cloud storage.
SE2 Oracle Standard Edition 2 — the mid-tier Oracle Database edition. Lacks Active Data Guard, RAC, advanced partitioning, and several other EE-only features. PodHeitor’s archivelog_apply replication mode is explicitly designed for SE2 environments.
SPFILE Server Parameter File — a binary Oracle parameter file stored in the database area (or ASM). Should be backed up with every RMAN job.
TDE Transparent Data Encryption — an Oracle feature that encrypts datafiles, tablespaces, or columns at rest without application changes. Requires an Oracle Wallet to store the master encryption key.
static-pie Position-Independent Executable compiled with a static C library (musl). Runs on any kernel version ≥ 2.6.32 without shared library dependencies. PodHeitor’s backend binary is static-pie musl for maximum portability.
RestoreObject A Bacula catalog mechanism for storing arbitrary data (text or binary) associated with a backup job. Used by PodHeitor to store the pluginrestoreconf INI document and backup manifest. Rendered as interactive prompts in bconsole and as an HTML form in Bacularis.
pluginrestoreconf The specific RestoreObject type used by PodHeitor to deliver restore configuration (action, target time, SCN, table name, etc.) from the operator to the plugin at restore time.
UNIX socket An inter-process communication endpoint (AF_UNIX) that exists only in the kernel — no network interface, no port number. PodHeitor uses /var/run/podheitor-oracle/<SID>.sock to connect libobk-rs (loaded by RMAN) to the backend process.

Appendix C — Prometheus Metrics Reference

When metrics_addr is set (e.g., metrics_addr=0.0.0.0:9119), the backend exposes a Prometheus-compatible /metrics endpoint. Metrics are emitted in the standard Prometheus text format and can be scraped by any Prometheus-compatible system (Prometheus server, Grafana Agent, OpenTelemetry Collector).

C.1 Counter Metrics

Metric Name Labels Description
podheitor_oracle_backup_jobs_total sid, mode Total number of backup jobs started.
podheitor_oracle_backup_failed_total sid, mode Total number of backup jobs that terminated with an error.
podheitor_oracle_restore_jobs_total sid, action Total number of restore jobs started.
podheitor_oracle_restore_failed_total sid, action Total number of restore jobs that terminated with an error.
podheitor_oracle_bytes_backed_up_total sid, mode Total bytes transferred to Bacula Storage across all backup jobs.
podheitor_oracle_bytes_restored_total sid Total bytes received from Bacula Storage across all restore jobs.
podheitor_oracle_archivelogs_shipped_total sid Total archivelog files shipped to Bacula Storage (CDP and archivelog-include modes).
podheitor_oracle_verify_blocks_checked_total sid Total Oracle data blocks checked by DBVERIFY across all jobs.
podheitor_oracle_verify_blocks_bad_total sid Total corrupt blocks detected by DBVERIFY. Should always be 0.
podheitor_oracle_canary_alerts_total sid Number of times the anti-ransomware canary fired a mass-change alert.
podheitor_oracle_tde_rotation_detected_total sid Number of TDE master-key rotations detected (triggers auto-promotion to Full).

C.2 Gauge Metrics

Metric Name Labels Description
podheitor_oracle_rman_channels_active sid Number of currently active RMAN backup channels.
podheitor_oracle_cdp_lag_seconds sid Seconds since the last archivelog was shipped in CDP mode. Alert threshold: cdp_max_lag.
podheitor_oracle_last_backup_size_bytes sid, mode Size in bytes of the most recently completed backup job.
podheitor_oracle_last_backup_duration_seconds sid, mode Duration in seconds of the most recently completed backup job.
podheitor_oracle_last_scn sid Highest SCN observed in the most recently completed backup.

C.3 Example Prometheus Scrape Configuration

scrape_configs:
  - job_name: 'podheitor_oracle'
    static_configs:
      - targets:
          - '192.168.15.51:9119'   # VM 131 oracle-23ai-lab
          - '192.168.15.117:9119'  # VM 115 oracle-23ai-standby
    scrape_interval: 30s
    metrics_path: /metrics

C.4 Example Grafana Alert Rule (CDP Lag)

groups:
  - name: podheitor_oracle_cdp
    rules:
      - alert: OracleCdpLagExceeded
        expr: podheitor_oracle_cdp_lag_seconds > 300
        for: 2m
        labels:
          severity: warning
        annotations:
          summary: "Oracle CDP lag exceeded 5 minutes on {{ $labels.sid }}"
          description: "CDP archivelog shipping lag is {{ $value }}s for SID {{ $labels.sid }}"

      - alert: OracleCanaryAlert
        expr: increase(podheitor_oracle_canary_alerts_total[5m]) > 0
        labels:
          severity: critical
        annotations:
          summary: "Anti-ransomware canary triggered on {{ $labels.sid }}"
          description: "Block-hash mass-change detected. Possible ransomware activity."

      - alert: OracleBackupFailed
        expr: increase(podheitor_oracle_backup_failed_total[1h]) > 0
        labels:
          severity: warning
        annotations:
          summary: "Oracle backup job failed for SID {{ $labels.sid }}"

Appendix D — State Directory Reference

The plugin maintains a per-SID state directory at /opt/bacula/working/oracle-state/<SID>/. All files are written atomically (write-to-temp + rename). The directory is preserved on package uninstall and wiped only on DEB --purge or manual removal.

D.1 State Directory Structure

/opt/bacula/working/oracle-state/<SID>/
├── last_scn.json              # Last successfully backed-up SCN range
├── backup_manifest.json       # Most recent job manifest (BLAKE3-hashed)
├── last_archivelog_seq        # CDP cursor: last shipped archivelog sequence
├── wallet_hash                # SHA-256 of TDE master key material (detects rotation)
├── checkpoint/
│   └── <jobid>.json           # Per-job checkpoint for resume (ADR-014)
└── restore/
    └── <jobid>_report.json    # Post-restore validation report

D.2 File Contents Reference

last_scn.json

{
  "sid": "FREE",
  "dbid": 1234567890,
  "incarnation": 2,
  "scn_low": 2090220,
  "scn_high": 2090264,
  "backup_job_id": 4989,
  "timestamp": "2026-04-27T02:00:45Z",
  "mode": "rman_sbt",
  "level": "Full"
}

backup_manifest.json

{
  "plugin_version": "1.0.0",
  "sid": "FREE",
  "dbid": 1234567890,
  "incarnation": 2,
  "oracle_version": "23.0.0.0.0",
  "topology": "primary",
  "scn_low": 2090220,
  "scn_high": 2090264,
  "backup_job_id": 4989,
  "level": "Full",
  "mode": "rman_sbt",
  "channels": 4,
  "pieces": [
    {
      "tag": "PODHEITOR_4989_20260427_1",
      "size_bytes": 83886080,
      "blake3": "a1b2c3d4e5f6..."
    }
  ],
  "archivelogs_included": true,
  "controlfile_included": true,
  "spfile_included": true,
  "wallet_included": true,
  "total_bytes": 499654432,
  "timestamp": "2026-04-27T02:26:55Z"
}

checkpoint/<jobid>.json

{
  "job_id": 4990,
  "sid": "FREE",
  "mode": "rman_sbt",
  "level": "Incremental",
  "last_scn": 2091000,
  "pieces_transferred": 3,
  "bytes_transferred": 125829120,
  "timestamp": "2026-04-27T03:15:22Z"
}

Appendix E — Troubleshooting Guide

E.1 Common Errors and Solutions

Plugin binary not found

bEventBackupCommand: plugin podheitor-oracle not found

Cause: The podheitor-oracle-fd.so file is not in the Bacula plugin directory or the FD configuration does not include the plugin directory.

Fix:

ls -la /opt/bacula/lib/bacula/podheitor-oracle-fd.so
# If missing, reinstall the package or check PREFIX in tarball install.

# Verify FD plugin directory:
grep -i plugindirectory /opt/bacula/etc/bacula-fd.conf
# Should contain: Plugin Directory = /opt/bacula/lib/bacula

sudo systemctl restart bacula-fd

libobk-rs.so not found by RMAN (mode=rman_sbt)

RMAN-03009: failure of backup command on ORA_SBT_TAPE_1 channel
ORA-19554: error allocating device, device type: SBT_TAPE, device name:
ORA-27211: Failed to load Media Management Library

Cause: The symlink $ORACLE_HOME/lib/libobk.so → /opt/bacula/lib/libobk-rs.so is missing or broken.

Fix:

# Check symlink
ls -la $ORACLE_HOME/lib/libobk.so

# Recreate
sudo ln -sf /opt/bacula/lib/libobk-rs.so $ORACLE_HOME/lib/libobk.so

# Verify RMAN can load it (no RMAN-03009 on backup run)

UNIX socket permission denied

PODHEITOR-ORACLE: cannot connect to UNIX socket
  /var/run/podheitor-oracle/FREE.sock: Permission denied

Cause: The libobk-rs.so process (running as the RMAN OS user) does not have write permission on /var/run/podheitor-oracle/.

Fix:

# Create directory with correct ownership
sudo mkdir -p /var/run/podheitor-oracle
sudo chown oracle:oinstall /var/run/podheitor-oracle
sudo chmod 750 /var/run/podheitor-oracle

Oracle authentication failure

PODHEITOR-ORACLE-AUDIT kind=connect_failed sid=ORCL
  error: ORA-01031: insufficient privileges

Cause: The oracle_user or unix_user does not have SYSDBA privilege, or the OS authentication group (dba) membership is missing.

Fix:

# Verify OS user is in the dba group
id oracle
# Should contain: groups=...,dba,...

# Verify OS authentication works
sudo -u oracle sqlplus / as sysdba <<< "SELECT INSTANCE_NAME FROM V$INSTANCE;"

State directory full

PODHEITOR-ORACLE: cannot write checkpoint: No space left on device
  path: /opt/bacula/working/oracle-state/ORCL/checkpoint/4990.json

Cause: The filesystem hosting /opt/bacula/working/ is full.

Fix:

df -h /opt/bacula/working/
# Clean old checkpoint files:
find /opt/bacula/working/oracle-state/ -name "*.json" -mtime +30 -delete
# Or expand the filesystem.

TDE wallet closed at backup time

PODHEITOR-ORACLE-AUDIT kind=wallet_check_failed sid=ORCL
  error: ORA-28365: wallet is not open

Cause: The Oracle Wallet is not open. This can happen after a database restart if WALLET_ROOT auto-open is not configured.

Fix:

-- Open the wallet before the backup:
ADMINISTER KEY MANAGEMENT SET KEYSTORE OPEN IDENTIFIED BY "wallet_password";
-- Or configure auto-open:
ADMINISTER KEY MANAGEMENT SET KEYSTORE OPEN IDENTIFIED EXTERNALLY AS 'wallet_password'
  FORCE KEYSTORE;

Alternatively, set wallet_passphrase_file= in the plugin config to automate wallet opening at backup start.


Backup job hangs — RMAN channels not connecting

PODHEITOR-ORACLE: waiting for RMAN channel connections (timeout in 120s)
  connected: 0/4 channels

Cause: RMAN cannot load libobk-rs.so or cannot connect to the UNIX socket. Often caused by a stale socket file from a previous crashed job.

Fix:

# Remove stale socket
sudo rm -f /var/run/podheitor-oracle/FREE.sock

# Restart the FD to clean up any orphaned backend processes
sudo systemctl restart bacula-fd

E.2 Diagnostic Commands

# Check plugin version
/opt/bacula/bin/podheitor-oracle-backend --version

# Offline dry-run (no Oracle connection required)
/opt/bacula/bin/podheitor-oracle-backend --dry-run 
    /opt/bacula/etc/podheitor-oracle.conf

# Check Bacula FD log for plugin events
journalctl -u bacula-fd -n 100 | grep -i podheitor

# List all PODHEITOR-ORACLE-AUDIT events for a specific job
bconsole <<< "messages" | grep -i "PODHEITOR-ORACLE-AUDIT"

# Check RMAN backup catalog for the last backup
rman target / <<EOF
LIST BACKUP SUMMARY;
EOF

# Verify backup integrity manually
rman target / <<EOF
VALIDATE BACKUPSET ALL;
EOF

# Run DBVERIFY on all datafiles
dbv file=$(sqlplus -S / as sysdba <<< "SET PAGESIZE 0 FEEDBACK OFF; 
SELECT name FROM v$datafile;" | tr 'n' ' ')

Appendix F — Upgrade and Migration Guide

F.1 Upgrading from Bacula Enterprise Oracle Plugin

PodHeitor is designed to be a drop-in replacement for the Bacula Enterprise Oracle Module with zero data migration required. Existing Bacula jobs, pools, volumes, and catalog entries remain valid.

Pre-migration checklist:

Task Notes
Document current FileSet Plugin = lines The parameter naming is mostly compatible; see translation table below
Note any RunBeforeJob / RunAfterJob hook scripts Translate to hooks_dir convention
Document bs_oracle_restore.pl command-line options Translate to pluginrestoreconf keys
Verify Bacula FD version ≥ 15.0.3 PodHeitor requires 15.0.3 for RestoreObject support
Backup the Bacula catalog Standard precaution before any plugin change

Parameter translation table (Enterprise → PodHeitor):

Bacula Enterprise Parameter PodHeitor Equivalent Notes
Oracle_SID=ORCL sid=ORCL Direct translation
Oracle_Home=/u01/app/… oracle_home=/u01/app/… Direct translation
Oracle_User=oracle unix_user=oracle OS user, not DB user
Backup_Mode=RMAN_SBT mode=rman_sbt Direct translation
Backup_Mode=RMAN mode=rman Direct translation
Backup_Mode=DATA_PUMP mode=dump
Num_Channels=4 channels=4 Or channels=auto
Compress_Algorithm=MED compress=rman_medium
Backup_Archivelogs=YES archivelog=include
Validate_After_Backup=YES validate_after=yes
(no equivalent) canary=on New: anti-ransomware canary
(no equivalent) metrics_addr=0.0.0.0:9119 New: Prometheus metrics

Post-migration steps:

  1. Uninstall the Bacula Enterprise Oracle Module RPM/DEB (do not uninstall bacula-enterprise-fd).
  2. Install podheitor-oracle-plugin-1.0.0-1.el9.x86_64.rpm.
  3. Create /opt/bacula/etc/podheitor-oracle.conf with translated parameters.
  4. Update FileSets to use the new Plugin = syntax.
  5. Create the libobk-rs.so symlink if using mode=rman_sbt.
  6. Run --dry-run to validate.
  7. Run a Full backup job and verify it completes.
  8. Verify that the old Bacula Enterprise backup pieces are still restorable (they use the same RMAN catalog — no migration needed).

F.2 Upgrading PodHeitor Versions

Minor version upgrades (1.0.x → 1.0.y) are in-place RPM/DEB upgrades:

# RPM
sudo dnf upgrade ./podheitor-oracle-plugin-1.0.1-1.el9.x86_64.rpm

# DEB
sudo apt install ./podheitor-oracle-plugin_1.0.1-1_amd64.deb

The state directory at /opt/bacula/working/oracle-state/<SID>/ is preserved across upgrades. The manifest format is backward-compatible: new versions can read manifests written by older versions.

The libobk-rs.so symlink must be re-verified after every upgrade if $ORACLE_HOME/lib/ was modified by an Oracle patch.


Appendix G — Frequently Asked Questions

Q: Does PodHeitor require an Oracle licence beyond what I already have?

No. The plugin uses RMAN, sqlplus, dbv, and expdp — all tools included with your Oracle Database licence. libobk-rs.so is a clean-room implementation of a published public API; it is not derived from Oracle proprietary code and does not require an Oracle Backup Module licence.


Q: Is Bacula Enterprise still needed if I use PodHeitor?

No. PodHeitor runs entirely on PodHeitor Backup (the free, open-source version). No Bacula Enterprise subscription is required.


Q: Can I use PodHeitor alongside Bacula Enterprise for other agents?

Yes. PodHeitor replaces only the Oracle backup plugin (podheitor-oracle-fd.so). Other Bacula Enterprise plugins (VMware, Windows, etc.) can coexist on the same Director and Storage. You can migrate your Oracle clients to PodHeitor while keeping other workloads on Bacula Enterprise until their renewal comes up.


Q: Does mode=replicate (archivelog_apply) provide real-time failover like Active Data Guard?

Archivelog-apply provides near-real-time replication (RPO measured in minutes, depending on cdp_poll_interval) but does not provide automatic failover. It maintains a physical standby database in MOUNT state with archivelogs continuously applied. To fail over, a DBA issues ALTER DATABASE ACTIVATE STANDBY DATABASE on the standby host. This is equivalent to Oracle’s manual failover procedure — the same outcome as Active Data Guard manual failover, without the EE licence.


Q: Can I back up Oracle databases on Windows?

Not in version 1.0.0. The backend binary is x86_64-linux-musl only; RMAN on Windows uses different API conventions. Windows Oracle support is planned for a future release via a cross-compiled PE target.


Q: What happens if the Bacula job is interrupted mid-backup?

The plugin writes a checkpoint to /opt/bacula/working/oracle-state/<SID>/checkpoint/<jobid>.json after each successfully transferred RMAN piece. When Bacula retries the job (which it will if configured to do so), the backend detects the checkpoint and resumes from the last successful piece. This is ADR-014.


Q: Is the plugin safe to run on a production Oracle database?

Yes. In mode=rman_sbt and mode=rman, the plugin runs RMAN in hot-backup mode — the database remains open and fully available to applications throughout the backup. RMAN’s multi-version consistent read mechanism (based on SCN) guarantees that the backup set is self-consistent even if the database is heavily loaded. No application downtime is required.


Q: How do I know if my Oracle backups are actually restorable?

Three mechanisms work in combination:

  1. validate_after=yes (default): After every backup, the plugin runs RMAN VALIDATE BACKUPSET to verify that all backup pieces can be read and their checksums match.
  2. verify_after=yes in pluginrestoreconf: After every restore, DBVERIFY checks every data block in every datafile.
  3. action=preview in pluginrestoreconf: At any time, a restore job with action=preview runs RESTORE DATABASE PREVIEW — a dry-run that shows exactly which backup pieces will be used — in 4 seconds without touching the database.

Q: Does PodHeitor support Oracle on Docker / Kubernetes?

The plugin supports Oracle wherever it runs, as long as the Bacula FD and the Oracle instance are on the same host (or the FD can reach Oracle via $ORACLE_HOME tools). For containerised Oracle, deploy the Bacula FD as a sidecar container sharing the Oracle process namespace and mount the Oracle home. The static-pie musl binary has no library dependencies that conflict with container base images.


Q: What is the maximum database size supported?

There is no hard limit imposed by the plugin. The theoretical maximum is whatever RMAN can process — which for Oracle 19c/23ai is effectively unlimited. In practice, large databases (multiple TB) should use:

  • mode=rman_sbt (zero staging — no local disk required for backup data)
  • channels=auto or a manually tuned high channel count
  • BCT (bct=auto) for fast incrementals
  • A dedicated backup network interface for the Bacula FD ↔ SD traffic

Q: Can I monitor backup jobs from Grafana?

Yes. Set metrics_addr=0.0.0.0:9119 in the plugin config and configure Prometheus to scrape the endpoint. All standard Grafana Oracle/Bacula dashboards can be adapted to the PodHeitor metric names. See Appendix C for the full metric reference and an example Prometheus scrape configuration.


Document version: 1.0.0 | Last updated: 2026-04-27 Copyright © 2026 Heitor Faria — All rights reserved. Contact: heitor@opentechs.lat | +1 786 726-1749 | +55 61 98268-4220

Licensing

PodHeitor OracleDB is proprietary software distributed by subscription. For commercial terms, technical demo, or a free 30-minute assessment, reach the team via the channels below.

Ready to evaluate?

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

Leave a Reply