Technical whitepaper — PodHeitor MSSQL for Bacula

VDI on Windows, TDS/FIFO on Linux, BACKUP TO URL for Azure SQL MI, up-to-64-way striped parallel I/O, three native replication modes (log shipping / AG bootstrap / fanout), instant recovery, and SSAS/SSRS/SSIS coverage.

Technical companion to the PodHeitor MSSQL plugin page.

1. The problem: Bacula Enterprise’s MSSQL plugin is Windows-only and single-stripe

Bacula Enterprise’s MSSQL plugin exists, but:

  • Windows-only with VDI — no SQL Server on Linux coverage (officially Microsoft-supported since 2017).
  • No striped parallel I/O — 1 TB+ VLDBs suffer with single-stream throughput.
  • No Always On AG awareness beyond the basics — no auto-selection of readable secondary, no AG reseed.
  • No native replication — log shipping, AG bootstrap and 1→N fanout require external scripting.
  • No instant recovery, single-item restore, or SSAS/SSRS/SSIS coverage.

The PodHeitor MSSQL Plugin delivers all of that and stays drop-in compatible with the Bacula Enterprise mssql-fd namespace — zero FileSet rewrites in migration.

2. Architectural model

PodHeitor pattern: FD cdylib + standalone backend, PTCOMM communication. On Windows the cdylib is a DLL (podheitor-mssql-fd.dll); on Linux it’s a .so.

v2.0.0 (May 2026): the cdylib is built as a pure-Rust cdylib from the PodHeitor Rust cdylib/crates/plugin-mssql/ workspace. No Bacula AGPLv3 source is statically linked anywhere in the build — the plugin is fully proprietary (LicenseRef-PodHeitor-Proprietary). The v1.0.0 C/C++ metaplugin shim has been archived under releases/v1.0.0/src/ for historical reference only and is no longer built.

3. Engines selectable via mode=

Mode Platform Function
auto (default) Detects platform; prefers VDI on Windows, TDS/FIFO on Linux
vdi Windows Virtual Device Interface — official Microsoft API, in-memory pipe
tds_fifo Linux/Windows BACKUP DATABASE TO DISK = ‘<FIFO>’ over TDS, mkfifo reads stream
tds_url BACKUP TO URL to Azure Blob (Azure SQL Managed Instance)
snapshot Windows VSS Snapshot
replicate_log_shipping Replication via native log shipping
replicate_ag_bootstrap Bootstrap of Always On AG secondary
replicate_fanout 1→N region replication

4. Striped parallel I/O

BACKUP DATABASE ... TO DISK = '...stripe-1', DISK = '...stripe-2', ... is the SQL Server feature for multi-target. Bacula Enterprise does not expose it; PodHeitor does, via the stripes=N parameter (1–64). On a 1 TB VLDB with stripes=8, observed throughput is ~4× single-stream. Combine with buffercount=32 and maxtransfersize=4194304 (4 MiB) to saturate storage I/O.

Plugin = "podheitor-mssql: database=warehouse stripes=8 parallel_dbs=2 
          compress=native+zstd buffercount=32 maxtransfersize=4194304"

5. Always On AG awareness

With ag_preference=readable_secondary, the plugin:

  1. Queries AG topology via sys.dm_hadr_availability_replica_states.
  2. Selects a readable secondary (offload primary).
  3. If the chosen secondary fails/rebalances during backup, retries automatically on another replica up to ag_failover_retry=3 attempts.
  4. Topology is captured in __ph_cluster__/ag_topology.json for post-restore AG reseed.

Other options: auto, primary, secondary, readable_secondary.

6. Instant Recovery + Single-Item Restore

Restore mode Function
instant DB queryable in minutes while restore continues in background
in_place Over-write restore on the original DB
new_db Restore with new name (rename via database=)
to_disk Restore to .bak file (no SQL Server import)
single_item Table/row extraction via ephemeral sandbox instance
ag_reseed AG secondary reseed from backup

single_item spawns a temporary sandbox SQL Server instance, restores the DB there, runs SELECT or BCP OUT to extract the requested rows, and discards the sandbox. Useful when “I need the Orders table from yesterday” is not worth the in-place restore downtime.

7. PITR (Point-in-Time Recovery)

Parameter Default Function
stop_at PITR datetime (e.g., 2026-04-25 15:30:00)
stop_at_mark PITR log mark
tail_log_before no Auto-capture tail-log before tearing down existing DB
file_relocation_map JSON with path mapping for cross-instance restore
tde_restore_cert TDE cert bundle for cross-server
recovery Yes WITH RECOVERY (final) vs NORECOVERY (chain)

8. BI server coverage

Server Mechanism Parameter
SSAS (Analysis Services) Native XMLA backup include_ssas=&#x3C;list&#x3E;
SSRS (Reporting Services) ReportServer DB backup + encryption keys include_ssrs=&#x3C;host:port&#x3E;
SSIS (Integration Services) SSISDB backup include_ssis=yes

9. TDE-aware cross-server restore

TDE (Transparent Data Encryption) requires the master cert + the instance’s DPAPI to open an encrypted DB. Without it, cross-server restore fails with Cannot find server certificate with thumbprint. PodHeitor with tde_capture=yes exports the cert + private key (encrypted with an operational password) during backup; on restore, tde_restore_cert=&#x3C;file&#x3E; reinstalls the cert before the DB restore. This unlocks cross-instance / cross-region restore with no manual intervention.

10. GA validation — v1.0.0

Metric Result
E2E test suite (T01–T13, 16 tests) 16 / 16 PASS (3 consecutive runs)
OL9 cargo test 311 passed, 0 failed
Win2025 cargo test 381 passed, 0 failed
SQL Server tested SQL Server 2022 on Windows Server 2025
AG configuration 2-node, CLUSTER_TYPE=NONE, SYNCHRONOUS_COMMIT
Bacula version Community 15.0.3
Packages RPM v1.0.0 (OL9) + Win64 zip v1.0.0

11. Supported platforms

OS Arch Status
Windows Server 2012 R2 – 2025 x86_64 GA
Oracle Linux 9, RHEL 8/9, Rocky/Alma 8/9 x86_64 GA
Ubuntu 20.04 / 22.04 / 24.04 x86_64 GA
Debian 11 / 12 x86_64 GA
Linux ARM64 aarch64 Roadmap v1.1
SQL Server Windows Linux Notes
2012, 2014 VDI Windows only
2016, 2017 VDI TDS/FIFO
2019, 2022 All modes TDS/FIFO
Azure SQL MI tds_url BACKUP TO URL

12. Drop-in Enterprise migration

The Bacula namespace is identical to that of Bacula Enterprise’s mssql-fd.dll:

@mssql/
├── MSSQLSERVER/
│   ├── AdventureWorks/
│   │   ├── data.bak           ← Full backup
│   │   ├── data.diff.bak      ← Differential
│   │   ├── log-&#x3C;LSN&#x3E;.trn      ← Transaction log
│   │   ├── layout.dat         ← DB layout RestoreObject
│   │   └── data.stripe-N.bak  ← When stripes &#x3E; 1
│   └── __ph_instance__/       ← PodHeitor extras (logins, jobs, config)
└── __ph_cluster__/
    └── ag_topology.json

Migrating from Enterprise to PodHeitor doesn’t require rewriting FileSets or Bacula Director jobs — just swap the binary.

13. Documented anti-patterns

  • Don’t run stripes=64 on a small DB. Coordination overhead exceeds gains; for DBs < 50 GB use stripes=4 or less.
  • Don’t combine tail_log_before=yes with absent-minded drop_existing=yes. Order matters: tail-log captures BEFORE drop, but drop_existing=only_if_match is safer in prod.
  • Don’t use compress=none over WAN. SQL Server native compression + zstd dramatically reduces bytes-on-wire; the CPU overhead is worth it.
  • Don’t run TDS/FIFO on Windows when VDI is available. VDI is the official Microsoft API with better throughput and VSS integration; TDS/FIFO exists as the Linux fallback.

14. License posture

Plugin under LicenseRef-PodHeitor-Proprietary. No Bacula AGPLv3 source is statically linked anywhere in the build in v2.0.0+. The cdylib is built from the pure-PodHeitor plugin-mssql crate.

Ready to evaluate?

30-day free trial for production SQL Server fleets (Windows + Linux + Azure SQL MI). Guaranteed at minimum 50% discount vs Bacula Enterprise, Veeam or Commvault, with more capabilities included (3 native replication modes, instant recovery, single-item restore, SSAS/SSRS/SSIS coverage).

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

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

Leave a Reply