ugnos: Concurrent Time-Series Database Core in Rust
ugnos is a concurrent, embeddable time-series storage + query engine designed for durability and high-throughput ingest in Rust services.
For project goals and long-term architecture, see the whitepaper.
Features (today)
- Concurrent ingest: sharded write buffering + background flush thread.
- Durable persistence:
- WAL with explicit format versioning and per-record CRC32 checksums.
- Snapshots with explicit format versioning, payload CRC32, and atomic install (temp + rename + fsync).
- On-disk segment engine (SST-like):
- Immutable segment files with per-series columnar blocks + CRC.
- Atomic manifest (
MANIFEST.bin) tracking active segments and retention watermark. - Background compaction (L0 → L1 merge) with safe concurrent reads.
- Retention/TTL:
- Immediate logical deletion via tombstone watermark.
- Physical removal via compaction guarantees.
- Observability hooks:
- No stdout logging in core hot paths.
- Structured
DbEventstream viaDbConfig.event_listener.
Data layout on disk
All persistence lives under DbConfig.data_dir:
wal/wal.log(current WAL)wal_*.log(rotated WAL segments; may exist briefly)
snapshots/snapshot_<timestamp>.bin(atomic, checksummed snapshots)
engine/segments/MANIFEST.bin(atomic + checksummed)seg_<id>_l0.seg,seg_<id>_l1.seg, ...
Core API notes
DbCore::flush()blocks until the flush is complete.DbCore::snapshot()blocks until the snapshot is written (when enabled).- With segments enabled,
DbCore::recover():- Uses segment max-seq to replay only the WAL tail.
- Truncates
wal.logback to just the header (bounded restart cost).
- Query results are not guaranteed to be globally sorted across multiple segments; sort by timestamp if you need ordering.
Configuration
DbConfig is intended to be explicit and production-friendly:
use PathBuf;
use Duration;
use ;
let mut cfg = default;
cfg.data_dir = from;
// Durability toggles
cfg.enable_wal = true;
cfg.enable_snapshots = true;
cfg.enable_segments = true; // segment engine + compaction + retention
// Tuning
cfg.wal_buffer_size = 1_000;
cfg.flush_interval = from_millis;
cfg.snapshot_interval = from_secs;
// Retention (optional): makes data older than now - ttl invisible, and compaction reclaims disk.
cfg.retention_ttl = Some;
cfg.retention_check_interval = from_secs;
let mut db = with_config.unwrap;
db.recover.unwrap;
Observability (event hook)
Core emits structured events via DbConfig.event_listener:
use ;
use ;
;
Basic usage
use PathBuf;
use ;
use Duration;
use ;
;
How to build and test (this workspace)
This repo is a Rust workspace. From the workspace root (the papers/ folder):
Benchmarks
NOWAL=1
Benchmark results are saved in target/criterion/. Benchmarks default to the in-memory engine (segments disabled) to keep IO minimal.
License
This project is licensed under either of
- MIT License (LICENSE-MIT or http://opensource.org/licenses/MIT)
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option.