A high-performance, zero-copy event logging library for Rust. Built for trading systems and other latency-critical applications.
| Test | Throughput | Events |
|---|---|---|
| SPSC + Mmap Persistence | 29.96M events/sec | 149.7M in 5s |
- Lock-free SPSC Ring Buffer - Single producer, single consumer with atomic operations
- Mmap Persistence - Memory-mapped files for crash recovery and replay
- Zero-copy Reads - Direct memory access without allocation
- Consumer Dispatcher - Pluggable event consumers with stats tracking
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Producer │────▶│ SPSC Ring Buffer │────▶│ Mmap Log File │
│ (hot path) │ │ (lock-free) │ │ (persistence) │
└─────────────────┘ └──────────────────┘ └─────────────────┘
use ringlog::ring::RingBuffer;
use ringlog::event::EventHeader;
// Create buffer - returns Result for validation
let mut ring = RingBuffer::new(64 * 1024)?;
let header = EventHeader::new(timestamp, event_type, payload.len() as u16);
ring.write_event(&header, &payload)?;
while let Some((header, payload)) = ring.read_event() {
// process event
}use ringlog::ring::SpscRingBuffer;
// Create buffer - returns Result for validation
let ring = SpscRingBuffer::new(64 * 1024 * 1024)?;
let (mut producer, mut consumer) = ring.split();
// Producer thread
producer.write_event(&header, &payload);
// Consumer thread
while let Some((header, payload)) = consumer.read_event() {
// process event
}use ringlog::storage::{MmapWriter, MmapReader};
// Write
let mut writer = MmapWriter::create("/tmp/events.log", 1024 * 1024 * 1024)?;
writer.write_event(&header, &payload);
writer.sync()?;
// Read (zero-copy replay)
let reader = MmapReader::open("/tmp/events.log")?;
reader.replay(|event| {
// event.header, event.payload available without copy
});use ringlog::consumer::{EventDispatcher, EventConsumer};
struct MyConsumer;
impl EventConsumer for MyConsumer {
fn consume(&mut self, header: &EventHeader, payload: &[u8]) -> bool {
// handle event
true
}
fn name(&self) -> &str { "my-consumer" }
}
let mut dispatcher = EventDispatcher::new();
dispatcher.add_consumer(MyConsumer);
dispatcher.drain(&mut ring);# Run service
cargo run --release
# Run stress test
cargo run --release --bin stress
# Run tests
cargo test --releaseringlog has comprehensive test coverage across all critical components. All tests use optimized unwrap() calls for fast failure detection.
Tests for the core lock-free ring buffer implementation:
new_creates_empty_buffer- Verifies buffer initializationwrite_single_event- Tests basic write operationread_single_event- Tests basic read operation and data integritywrite_multiple_events- Validates sequential writes and FIFO orderingbuffer_full_returns_error- Tests buffer capacity limits and error handlingwrap_around_works- Verifies circular buffer behavior across boundarycapacity_must_be_power_of_two- Validates power-of-2 capacity requirement
What they verify:
- Zero-copy operations work correctly
- FIFO ordering is maintained
- Circular buffer wrapping is correct
- Error handling for capacity issues
Tests for the event header structure:
size_is_16_bytes- Ensures fixed 16-byte header sizetotal_size_includes_payload- Validates size calculationsnew_sets_fields_correctly- Tests header field initialization
What they verify:
- Memory layout is correct and aligned
- Size calculations are accurate
- Fields are properly initialized
Tests for the consumer dispatch system:
drain_empty_buffer- Tests dispatch with no eventsdrain_delivers_to_consumer- Validates event delivery to consumersdrain_tracks_failures- Tests failure tracking when consumers faildrain_batch_respects_limit- Verifies batch size limitingmultiple_consumers- Tests fanout to multiple consumerssuccess_rate_calculation- Tests statistics calculationsuccess_rate_empty- Edge case for empty stats
What they verify:
- Events are correctly delivered to all consumers
- Failure tracking is accurate
- Batch processing works as expected
- Statistics are calculated correctly
Tests for memory-mapped file persistence:
create_and_write- Tests file creation and writingwrite_and_read_back- Validates write → read round-tripiterator_works- Tests zero-copy iteration over eventsreopen_existing_file- Tests file reopening and appendingbuffer_full_returns_false- Tests capacity limitsinvalid_file_returns_error- Tests error handling for corrupt files
What they verify:
- Data is correctly persisted to disk
- Memory-mapped I/O works reliably
- File format is correct and readable
- Error handling for I/O failures
- Zero-copy replay works
# Run all tests
cargo test
# Run tests with output
cargo test -- --nocapture
# Run specific test
cargo test ring_buffer::write_single_event
# Run tests in release mode (faster)
cargo test --release
# Run with all features
cargo test --all-features- Fast failures: Tests use
unwrap()for immediate panic on errors - Comprehensive coverage: All critical paths are tested
- Isolation: Each test is independent and can run in parallel
- Real scenarios: Tests simulate actual usage patterns
- Error paths: Both success and failure cases are tested
# Watch mode (requires cargo-watch)
cargo watch -x test
# Run tests on every save
cargo watch -x 'test -- --nocapture'All production code uses Result types with detailed error messages. See ERROR_HANDLING.md for details.
Error types:
RingError::NotEnoughSpace { required, available }- Buffer capacity exceededRingError::InvalidCapacity { capacity, reason }- Invalid buffer sizeio::Errorwith context - File and mmap operation failures
EventHeader (16 bytes):
┌──────────────┬────────────┬───────┬─────────────┬───────────┐
│ timestamp │ event_type │ flags │ payload_len │ _reserved │
│ (8 bytes) │ (1 byte) │ (1) │ (2 bytes) │ (4 bytes) │
└──────────────┴────────────┴───────┴─────────────┴───────────┘
File Format:
┌────────────────────────────────────────┐
│ FileHeader (64 bytes) │
│ magic: "EVTL" │
│ version: 1 │
│ event_count, write_offset, etc. │
├────────────────────────────────────────┤
│ Event 0: [Header][Payload] │
│ Event 1: [Header][Payload] │
│ ... │
└────────────────────────────────────────┘