nano-wal

A simple, lightweight Write-Ahead Log (WAL) implementation in Rust designed for append-only operations with configurable retention and segment management.
Features
- Append-only operations: Efficient write operations with optional durability guarantees
- Segment rotation: Automatic segment file rotation based on configurable size limits
- Key-based indexing: Fast lookups and enumeration of records by key
- Configurable retention: Automatic cleanup of old entries based on time-based retention policies
- Compaction: Remove expired segments to reclaim disk space
- Thread-safe design: Safe for concurrent access patterns
Installation
Add this to your Cargo.toml:
[]
= "0.1.0"
Quick Start
use ;
use Bytes;
use Duration;
// Create a new WAL with default options
let mut wal = new?;
// Append an entry
let content = from;
wal.append_entry?;
// Log an entry with durability (forced sync to disk)
let durable_content = from;
wal.log_entry?;
// Retrieve records for a key
let records: = wal.enumerate_records?.collect;
// Enumerate all keys
let keys: = wal.enumerate_keys?.collect;
// Compact the WAL (remove expired segments)
wal.compact?;
// Clean shutdown
wal.shutdown?;
Configuration
Customize WAL behavior with WalOptions:
use ;
use Duration;
let options = WalOptions ;
let mut wal = new?;
Configuration Options
entry_retention: Duration for which entries are retained before being eligible for compaction (default: 1 week)segments: Number of segments to use per retention period (default: 10 segments, creating time-based rotation)
API Reference
Core Methods
new(filepath: &str, options: WalOptions)- Create a new WAL instanceappend_entry<K>(key: K, content: Bytes, durable: bool)- Append an entry to the WALlog_entry<K>(key: K, content: Bytes)- Append an entry with durability enabledenumerate_records<K>(key: K)- Get all records for a specific keyenumerate_keys<K>()- Get all unique keys in the WALcompact()- Remove expired segments based on retention policyshutdown()- Clean shutdown and remove all WAL files
Key Types
Keys must implement Hash + AsRef<[u8]> for append operations and Hash + Eq + From<Vec<u8>> for enumeration operations. Common types like &[u8], Vec<u8>, and String work out of the box.
File Format
The WAL stores data in binary format across multiple segment files:
- Each segment is named
{segment_id}.wal - Entries contain: timestamp (8 bytes) + key_length (8 bytes) + key + content_length (8 bytes) + content
- Segments rotate based on time intervals (retention_period / segments)
Use Cases
- Event Sourcing: Store events in append-only fashion with key-based retrieval
- Database WAL: Write-ahead logging for database systems
- Message Queues: Persistent message storage with compaction
- Audit Logs: Tamper-evident logging with time-based retention
- Cache Persistence: Persistent storage for cache warming
Performance Characteristics
- Write throughput: Optimized for sequential writes
- Read performance: O(1) key lookups via in-memory index
- Storage efficiency: Time-based segment rotation and automatic compaction
- Memory usage: Minimal memory footprint with lazy loading
Thread Safety
While the WAL struct itself is not Sync, it can be safely used in single-threaded contexts or wrapped in appropriate synchronization primitives (Arc<Mutex<Wal>>) for multi-threaded scenarios.
Examples
Basic Usage
use ;
use Bytes;
Event Sourcing Pattern
use ;
use Bytes;
use json;
License
This project is licensed under the MIT License - see the LICENSE file for details.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.