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.
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
- Executive Summary
- The Problem
- Solution Overview
- Architecture
- Feature Comparison Table
- Backup Options Reference
- Restore Options Reference
- FileSet Configuration Examples
- Restore Job Examples
- Installation and Sizing Guide
- Compatibility Matrix
- Performance Report
- Security and Compliance
- Support and Commercial Terms
- Appendix A — Architecture Decision Records
- 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
- 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.
- 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.
- 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: apluginrestoreconfdocument embedded in every backup triggers a fully automated, catalogued restore directly frombconsoleor 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:
- SSH into the Oracle host (requires OS access, VPN, key management).
- Locate the correct version of
bs_oracle_restore.pl(it changes across Bacula releases). - Run the script with the correct parameters — a dozen flags with no interactive validation.
- Hope the script generates the right RMAN commands for the target timestamp.
- Monitor progress on the Oracle host directly — no Bacula catalog entry for the restore operation.
- 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=replicatewithreplicate_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:
- Running RMAN DUPLICATE to create the initial standby copy.
- 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 |
'/src/','/dst/' |
— | 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 '/u01/aux' 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_formatforced toexp; no CDB/PDB, no TDE, noRECOVER TABLE - 23ai FREE:
replicate_method=duplicate_activerequires Oracle EE or an additional licence;archivelog_applyworks 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 withIDENTIFIED BY [REDACTED]. - Oracle connection strings
user/password@hostare replaced withuser/[REDACTED]@host. - Wallet passphrase file contents are never logged — only the file path is logged.
SBT_PARMSstrings containingSBT_ORACLE_HOME_USERor 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:
- If the fraction of changed blocks exceeds
canary_threshold_pct(default 25%), the plugin emits aPODHEITOR-ORACLE-CANARY-ALERTmessage to the Bacula job log. - The backup continues — the alert is a warning, not a failure — but the operator is notified of potential mass encryption by ransomware.
- 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:
- Reads the wallet path from
sqlnet.ora(wallet_path=auto) or the configured path. - Streams the wallet directory to Bacula as part of the backup job.
- Detects master key rotation between jobs by comparing the current
v$encryption_keyshash to the persistedwallet_hashin 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 |
|---|---|
| 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:
- Uninstall the Bacula Enterprise Oracle Module RPM/DEB (do not uninstall
bacula-enterprise-fd). - Install
podheitor-oracle-plugin-1.0.0-1.el9.x86_64.rpm. - Create
/opt/bacula/etc/podheitor-oracle.confwith translated parameters. - Update FileSets to use the new
Plugin =syntax. - Create the
libobk-rs.sosymlink if usingmode=rman_sbt. - Run
--dry-runto validate. - Run a Full backup job and verify it completes.
- 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:
validate_after=yes(default): After every backup, the plugin runsRMAN VALIDATE BACKUPSETto verify that all backup pieces can be read and their checksums match.verify_after=yesinpluginrestoreconf: After every restore, DBVERIFY checks every data block in every datafile.action=previewinpluginrestoreconf: At any time, a restore job withaction=previewrunsRESTORE 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=autoor 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?
- 💬 WhatsApp: +1 (786) 726-1749
- ✉️ Email: heitor@opentechs.lat
- 🩺 Free assessment — 30 min with Heitor Faria
Disponível em:
Português (Portuguese (Brazil))
English
Español (Spanish)