A minimal key-value store implemented in Rust using an append-only log for persistence.
Designed to explore durability, log replay, and trade-offs between simplicity and performance without external dependencies.
- SET / GET / DELETE operations
- Append-only log (AOF)
- Full state reconstruction via replay
- Log compaction
- Buffered file reads
- Read log file sequentially
- Replay all operations into an in-memory HashMap
- Append operation to log file
- Sync to disk
- Update in-memory state
- Serve directly from HashMap (O(1))
- Enables fast O(1) reads
- Trade-off: entire dataset must fit in memory
- Simplifies persistence model
- Avoids in-place file mutation
- Trade-off: file grows indefinitely without compaction
- Ensures recoverability after crash
- In-memory state is always reconstructible
- Guarantees OS-level persistence
- Trade-off: slower writes due to disk I/O
- Reads: O(1)
- Writes: O(1) append + disk sync
- Startup: O(n) log replay
Example:
- ~10k operations replayed in ~30ms
(Measured on local machine, SSD, release build)
Primary bottleneck:
- Disk I/O during sync_all
- Replay time grows linearly with log size
- Log file grows without bounds until compaction
- No concurrency support (single-process only)
- Entire dataset loaded into memory
- No crash recovery during partial writes
- No indexing or partial replay
- Incremental or background compaction
- Async I/O for better throughput
- File locking for multi-process safety
- Snapshotting to reduce replay cost
- Checksums to detect log corruption
cargo run set key value
cargo run get key
cargo run delete key
cargo run compact