durability
Crash-consistent persistence primitives: directory abstraction, generic WAL, checkpoints, and recovery.
Quick start
[]
= "0.6"
use MemoryDirectory;
use ;
let dir = arc;
// open() creates a fresh WAL or resumes an existing one.
let mut w = open.unwrap;
w.append.unwrap;
w.append.unwrap;
w.flush.unwrap;
assert_eq!;
drop;
// Recover
let records = new.replay.unwrap;
assert_eq!;
assert_eq!;
WalWriter<E> and WalReader<E> are generic -- define your own entry type with
#[derive(Serialize, Deserialize)] and use WalWriter::<YourType>::open(dir).
Thread-safe writer
SyncWalWriter wraps a WalWriter in a Mutex for concurrent access.
append_durable provides group commit semantics -- concurrent callers share
a single fsync:
use FsDirectory;
use SyncWalWriter;
use Arc;
#
let dir = arc.unwrap;
let sw = new;
// Each thread calls append_durable; fsync is batched across callers.
let sw2 = sw.clone;
spawn;
sw.append_durable.unwrap;
Generic recovery
recover_with_wal coordinates checkpoint loading and WAL replay for any
entry type and checkpoint schema:
use ;
use WalWriter;
use MemoryDirectory;
let dir = arc;
let mut w = new;
w.append.unwrap;
w.append.unwrap;
w.append.unwrap;
w.flush.unwrap;
drop;
let result = .unwrap;
assert_eq!; // 0 + 1 + 1 - 1
Tuning
use ;
use WalWriter;
#
let dir = arc.unwrap;
let mut w = with_options;
w.set_segment_size_limit_bytes; // 64 MiB segments
w.set_segment_max_age; // rotate after 5 min
w.set_preallocate_bytes; // 4 MiB preallocation
w.set_recycle_capacity; // reuse up to 4 truncated segments
Async support
The async feature provides AsyncDirectory and BlockingBridge for tokio:
[]
= { = "0.6", = ["async"] }
use ;
use FsDirectory;
# async
Modules
| Module | Purpose |
|---|---|
storage |
Directory trait, FsDirectory, MemoryDirectory, sync helpers |
walog |
Generic WAL: WalWriter<E>, WalReader<E>, SyncWalWriter<E>, WalObserver |
recordlog |
Append-only single-file log with CRC framing |
checkpoint |
CRC-validated snapshot files (postcard payloads) |
recover |
Generic recover_with_wal() + segment-specific RecoveryManager |
publish |
Crash-safe checkpoint publish + WAL truncation |
async_dir |
AsyncDirectory trait + BlockingBridge (feature async) |
Not provided
- Multi-process locking: single-writer-per-directory assumed. Advisory lockfile catches in-process double-instantiation only.
- Strong consistency by default: writes are buffered. Use
flush_and_sync()for a durability barrier. - fsync failure recovery: a failed fsync poisons the writer. Callers should treat this as unrecoverable and restart from WAL.
Contract
- Prefix property: best-effort replay returns a prefix of the valid stream.
- Narrow best-effort: tolerance applies only to the final segment's torn tail. Corruption in non-final segments is an error.
- Deterministic checkpoints: payloads are written with stable ordering.
Running
- Tests:
cargo test - Property tests:
PROPTEST_CASES=512 cargo test --test prop_wal_resume - Benches:
cargo bench - Fuzzing:
cargo fuzz run fuzz_wal_entry_decode(seefuzz/)