BenoStreamDB Recovery Runbook¶
This document outlines the formal recovery procedures for BenoStreamDB, detailing RPO/RTO expectations and step-by-step resolution paths for catastrophic failures.
BenoStreamDB is designed around a strict separation of authoritative state (Iceberg snapshots, Parquet data files) and derived state (HNSW/BM25 indexes). This architecture ensures that most “database corruption” events are merely cache-invalidation events that can be resolved without data loss.
Recovery Objectives¶
RPO (Recovery Point Objective)¶
BenoStreamDB’s RPO depends entirely on your configured WalDurability setting (BSDB_WAL_DURABILITY / TableBuilder::with_durability):
WalDurability::Sync("sync", Default): RPO = 0. Every acknowledged write waits forfdatasync(File::sync_data, falling back toFile::sync_all) on the WAL segment before the caller receivesOk. Failed syncs return an error to the caller. Note: fors3://,gs://, oraz://tables, configure a persistent local volume viaBSDB_WAL_DIRorTableBuilder::with_wal_dir(); otherwise the WAL defaults to temporary local storage (/tmp/benostream_wal/...) and logs a startup warning.WalDurability::Async("async"): RPO <= sync window. Batches are handed to the WAL worker channel without blocking forfdatasync; the worker syncs everyBSDB_WAL_SYNC_BATCH_SIZE(10batches) orBSDB_WAL_SYNC_INTERVAL_MS(100ms). Writes buffered inside the un-synced window are lost on hard termination.
RTO (Recovery Time Objective)¶
Data Availability: Seconds. On startup, BenoStreamDB reads the latest manifest (
_manifest/v{N}.json), replays uncommitted records from the segmented WAL while skipping anybenostream:tx_idalready present in the manifest propertybenostream.committed_wal_tx, and immediately resumes queries (falling back to Parquet scans while secondary indexes rebuild).Performance Recovery (Index Rebuild): Minutes to Hours. If an index is lost or corrupted, queries degrade deterministically to Parquet/exact scans. Rebuilding the index executes asynchronously without blocking ingestion.
1. Restore-from-Object-Store Procedure¶
Because Iceberg/Parquet in the object store is the authoritative source of truth, BenoStreamDB compute nodes are essentially stateless cache engines.
Scenario: The physical server hosting BenoStreamDB is destroyed. Action:
Provision a new compute node.
Ensure the node has IAM/network access to the backing object store (S3/GCS/Azure).
Start the BenoStreamDB process pointing to the existing URI (with
BSDB_WAL_DIRpointing to persistent local WAL storage if present):let table = Table::new_async("s3://my-bucket/my-table").await?;
Result: The system loads the latest atomic manifest (
_manifest/v{N}.jsonviaload_latest_direct) and Iceberg metadata pointer, replays any uncommitted WAL segments, and resumes reads and writes.
2. WAL Recovery Procedure¶
The Write-Ahead Log (_wal/ by default for local tables, or BSDB_WAL_DIR for remote URIs) stores durable writes in rotated Arrow IPC stream segments named log_<timestamp>_<pid>_<seq>.arrow until the transaction commits to a manifest and watermark pruning removes the sealed file (prune_committed_segments).
Automatic Startup Recovery (Standard Crashes & Torn Tails)¶
In most crash scenarios (SIGKILL, power loss mid-append, or crash between manifest commit and WAL cleanup), no manual action is required:
Torn Trailing Frame / Interrupted Header: On startup,
open_wal_segmentandSafeIpcSegmentIterautomatically recover from 0-byte segments, zeroed preallocation headers (<= 8bytes), truncated Arrow IPC continuation/schema headers at EOF (Empty), and anUnexpectedEofmid-way through a trailing uncommitted batch frame (logging awarnand preserving every complete synced prefix batch).Idempotent Crash Replay: If the process exited after committing
_manifest/v{N}.json(CommitPhase::ManifestCommitted) but before watermark pruning deleted the sealed.arrowsegment, startup filters out every batch whosebenostream:tx_idalready appears inbenostream.committed_wal_txand registers the segment for pruning on the next commit.
Manual Quarantine Procedure (Mid-Stream Byte Corruption)¶
Scenario: Storage hardware corruption damages bytes inside a WAL header (non-zero wrong magic bytes, invalid metadata length) or mid-stream FlatBuffers payload, causing startup to refuse initialization with a WAL Recovery Error.
Action: BenoStreamDB refuses silent data truncation when mid-stream corruption is detected inside a non-EOF record. To restore table availability by quarantining only the damaged segment:
Inspect startup logs for the failing segment path (under
[table_uri]/_wal/or$BSDB_WAL_DIR).Inspect the directory (
ls -lasorted chronologically; filenames encode nanosecond timestamps and sequence numbers). Keep all undamaged segments in place.Quarantine only the failing segment outside the WAL directory:
mkdir -p /var/backups/bsdb-wal-quarantine mv /path/to/table/_wal/log_0001762780000000000_004210_00000003.arrow /var/backups/bsdb-wal-quarantine/
Restart the process.
Result: Startup replays all valid WAL segments, skips already-committed transactions idempotently, and resumes serving traffic. Only uncommitted batches contained after the corruption point in the quarantined segment are absent.
3. Index Rebuild Procedure¶
Indexes (HNSW, BM25, Bloom filters) are non-authoritative. If they become corrupted, out-of-sync, or are accidentally deleted, they can be regenerated directly from the Parquet data files.
Scenario: Vector search latency spikes because the HNSW index was partially deleted, or logs report IndexChecksumMismatch.
Action:
Drop the corrupted index. This removes the metadata pointer and deletes the corrupted
.binfiles:table.drop_index("embedding").await?;
Re-create the index. The database will launch a background task to rebuild it from the authoritative Iceberg data:
table.add_index("embedding".to_string(), IndexAlgorithm::HNSW).await?;
Result: The system serves vector similarity queries using exact nearest-neighbor scans until the background HNSW build attaches to the manifest, then switches queries onto the rebuilt HNSW index automatically.
4. Catalog Recovery Procedure¶
If you are using a decoupled catalog (e.g., Nessie, REST, or Hive Metastore) to track table states instead of the built-in file-based commit.lock:
Scenario: The external catalog database (e.g., PostgreSQL backing Nessie) is irrecoverably corrupted.
Action:
Because BenoStreamDB writes valid Iceberg metadata files (v1.metadata.json, v2.metadata.json) into the metadata/ directory of the object store, the table can be recovered even if the catalog is lost.
Inspect the
metadata/directory in your object store.Identify the highest numbered metadata file (e.g.,
v42.metadata.json).Manually register this table in your new/restored catalog using the Iceberg REST API or catalog-specific CLI:
POST /v1/namespaces/default/register HTTP/1.1 Content-Type: application/json { "name": "my-table", "metadata-location": "s3://my-bucket/my-table/metadata/v42.metadata.json" }
Result: The new catalog will point to the exact transaction state of
v42, and BenoStreamDB will resume operations normally.