durability
Durability primitives for local persistence.
durability is the I/O floor for the storage crates: filesystem and in-memory
directories, atomic writes, WALs, record logs, checkpoint files, CRC validation,
and sync helpers. It does not own indexing, segment selection, compaction, or
reader visibility; those live one layer up.
Quick start
[]
= "0.7"
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).
Feature flags
postcard is enabled by default. It provides typed serde/postcard helpers:
WalWriter::append, WalReader::replay, CheckpointFile::write_postcard,
recover, and publish.
serde is enabled by postcard. In no-default builds, enable serde directly
if you only need WalEntry serialization derives without postcard helpers.
With default-features = false, durability still provides Directory,
RecordLogWriter::append_bytes, RecordLogReader::read_all,
CheckpointFile::{write_bytes, read_bytes}, raw WAL append/replay, WAL
maintenance, and sync helpers.
Backends
FsDirectory is the stable-storage backend. It exposes filesystem paths for
fsync, parent-directory sync, and mmap helpers. MemoryDirectory is useful for
tests and process-local stores; it does not provide power-loss durability and
cannot support mmap.
The optional mmap feature provides MappedFile for read-only memory maps with
advisory access hints. Higher-level crates decide which files are safe and useful
to map.
Thread-safe writer
SyncWalWriter wraps a WalWriter in a Mutex for concurrent access.
append_durable appends one entry and syncs it to stable storage while holding
that mutex:
use FsDirectory;
use SyncWalWriter;
use Arc;
#
let dir = arc.unwrap;
let sw = new;
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.7", = ["async"] }
use ;
use FsDirectory;
# async
Modules
| Module | Purpose |
|---|---|
storage |
Directory trait, FsDirectory, MemoryDirectory, sync helpers |
walog |
Generic WAL: raw bytes always, typed serde/postcard helpers with feature postcard |
recordlog |
Append-only single-file log with CRC framing |
checkpoint |
CRC-validated snapshot files |
recover |
Generic recover_with_wal() + segment-specific RecoveryManager (feature postcard) |
publish |
Crash-safe checkpoint publish + WAL truncation (feature postcard) |
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.
- Per-write fsync 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/)