TurboKV: Insanely fast Rust key-value store

Aug 29, 2026 09:23 AM - 2 hours ago 3

TurboKV Logo

A fast, embedded key-value shop successful Rust

GitHub License Rust

TurboKV is an async embedded key-value database pinch atomic batches, ordered range scans, configurable durability, compression, and inheritance compaction.

cargo adhd turbokv cargo adhd tokio --features full

Or adhd the limitations directly:

[dependencies] turbokv = "0.6" tokio = { version = "1", features = ["full"] }

TurboKV's persisted Bloom-filter format uses hardware AES. Build x86/x86_64 targets pinch RUSTFLAGS="-C target-feature=+aes,+sse2", and ARM/AArch64 targets pinch RUSTFLAGS="-C target-feature=+aes,+neon". You whitethorn alternatively use -C target-cpu=native erstwhile the binary will tally only connected the aforesaid CPU exemplary aliases a feature superset.

use turbokv::{Db, DbOptions, WriteBatch}; #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> { let db = Db::open_with_options("./my-database", DbOptions::durable()).await?; db.insert(b"user:1", b"Ada").await?; assert_eq!(db.get(b"user:1").await?, Some(b"Ada".to_vec())); let mut batch = WriteBatch::new(); batch.put(b"user:2", b"Grace"); batch.put(b"user:3", b"Linus"); batch.delete(b"user:1"); db.write_batch(&batch).await?; for (key, value) in db.scan_prefix(b"user:").await? { println!( "{} = {}", String::from_utf8_lossy(&key), String::from_utf8_lossy(&value) ); } db.close().await?; Ok(()) }

Runnable examples:

  • basic: insert, get, update, and remove
  • batch_writes: atomic puts and deletes
  • range_queries: ordered scope and prefix scans
  • concurrent: shared entree from Tokio tasks
  • persistence: paranoid WAL recovery
  • configuration: cache, memtable, and compression options
Preset Acknowledgement boundary Use case
DbOptions::fast() In-memory visibility; nary WAL Caches and reproducible data
DbOptions::durable() Appended to the WAL without a per-write sync Process-crash recovery; recommended default
DbOptions::paranoid() WAL group completed sync_all earlier return Strongest mode, taxable to filesystem/device guarantees

One unfastened Db aliases Engine exclusively owns its information directory. Use close() or close_with_status() for a cleanable shutdown; dropping a grip is not a clean shutdown contract.

Keys and values are arbitrary byte sequences supplied done AsRef<[u8]>; strings request to beryllium encoded by the caller. Mutation APIs transcript their inputs before returning. Point and collecting sounds return owned Vec<u8> values. An empty value is valid information and is chopped from a deleted key.

Opening and configuration

API Parameters Result and behavior
Db::open(path) path: AsRef<Path> Opens aliases creates the directory pinch DbOptions::durable(). The unfastened grip exclusively owns the directory.
Db::open_with_options(path, options) Database way and a DbOptions value Opens pinch definitive durability, memory, cache, and compression settings. Rejects contradictory settings specified arsenic sync_writes = existent pinch the WAL disabled.
DbOptions::fast() None Returns the no-WAL preset.
DbOptions::durable() None Returns the process-crash-recoverable WAL preset.
DbOptions::paranoid() None Returns the sync-before-acknowledgement preset.
options.with_compression(compression) A Compression variant Builder-style update that returns the modified options.

All presets commencement pinch a 64 MiB memtable, a 64 MiB artifact cache, and LZ4 compression. Their nationalist fields tin beryllium adjusted earlier opening:

DbOptions field Meaning
wal_enabled: bool Append mutations to the WAL. Disabling it permits process-crash information nonaccomplishment until a successful flush aliases close.
sync_writes: bool Await a WAL sync obstruction earlier acknowledging each mutation group. Requires wal_enabled.
memtable_size: usize Approximate in-memory byte period that triggers a memtable rotation and inheritance flush.
block_cache_size: usize Decompressed SSTable block-cache fund successful bytes. Set to 0 to disable the cache.
compression: Compression SSTable compression for recently written data: Lz4, Snappy, Zstd, aliases None. Existing tables clasp their encoded format.

Point, bulk, and batch operations

API Parameters Returns and semantics
insert(key, value) Byte-like cardinal and value Result<()>. Inserts aliases replaces the key. The selected durability bound is reached earlier success.
insert_many(entries) Any iterator of (key, value) pairs Result<()>. Copies the afloat iterator and applies entries successful order; the past copy cardinal wins. This is simply a bulk API, not 1 atomic visibility transition.
get(key) Byte-like key Result<Option<Vec<u8>>>. Returns None for missing aliases deleted keys and Some(Vec::new()) for a stored quiet value.
remove(key) Byte-like key Result<()>. Writes a tombstone; deleting a missing cardinal is allowed.
contains_key(key) Byte-like key Result<bool>. Resolves the aforesaid authorities arsenic get and presently incurs its worth allocation.
write_batch(batch) &WriteBatch Result<()>. Publishes each operations atomically; readers spot either the authorities earlier the batch aliases the complete batch. The past cognition for a copy cardinal wins.

With the WAL enabled, 1 grounds aliases complete batch must fresh successful the WAL's u32 payload length. A grounded aliases cancelled mutation whitethorn already person reached the WAL; inspect the cardinal aliases reopen earlier retrying a non-idempotent operation.

WriteBatch owns copies of each cardinal and value:

API Parameters Effect
WriteBatch::new() None Creates an quiet batch.
WriteBatch::with_capacity(capacity) Expected cognition count Preallocates cognition slots, but not cardinal aliases worth bytes.
batch.put(key, value) Byte-like cardinal and value Appends an owned put operation.
batch.delete(key) Byte-like key Appends an owned delete operation.
batch.ops() None Borrows the ordered &[BatchOp] cognition list.
batch.len() / batch.is_empty() None Reports the existent cognition count.
batch.clear() None Removes each operations while retaining the batch allocation for reuse.

Keys are ordered lexicographically by earthy bytes. Every scan captures a coherent point-in-time view. Creating 1 tin frost a nonempty progressive memtable, so frequent mini scans whitethorn summation later flush work.

API Parameters Returns and allocation
range(start, end) Inclusive commencement cardinal and exclusive extremity key Result<Vec<(Vec<u8>, Vec<u8>)>>; eagerly allocates each returned cardinal and value.
scan_prefix(prefix) Byte prefix; an quiet prefix matches everything Eagerly collects each matching key/value pairs successful order.
range_iter(start, end) The aforesaid [start, end) bounds Creates a RangeIter. Iterator items are Result<EntryGuard, ScanError> because corruption tin beryllium discovered while advancing.
scan_prefix_iter(prefix) Byte prefix Creates a PrefixIter, an othername of the aforesaid streaming implementation.

Advancing a streaming iterator is synchronous and whitethorn execute mmap reads, checksum validation, decompression, and cache locking. Drop it promptly: the iterator pins its snapshot readers and database-directory ownership.

Iterator aliases defender API Parameters Result
iter.count() None Consumes the iterator and returns Result<usize, ScanError>.
iter.keys() None Consumes the iterator and collects owned keys without materializing memtable values.
iter.collect_pairs() None Consumes the iterator and collects owned key/value pairs.
iter.paginate(offset, limit) Number of entries to skip and maximum entries to yield Returns a lazy iterator; skipped entries are traversed but their memtable values are not copied.
guard.key() None Borrows the cardinal without loading the value.
guard.value() / guard.value_len() None Borrows the value, aliases reports its length; a memtable worth is copied only erstwhile value() is first requested.
guard.into_pair() / into_key() / into_value() None Consumes the defender and returns the requested owned bytes.

Persistence, maintenance, and statistics

API Parameters Returns and cost
flush() None Result<()>. Drains pending writes, installs SSTables and the manifest, syncs the WAL, and reclaims eligible WAL segments. Writes that commencement concurrently whitethorn request a later flush.
compact() None Result<CompactionResult>. Drains the captured compaction scope and reports existent files, bytes, duration, reclaimed tombstones, and whether activity remains.
status() None Cheap DatabaseStatus snapshot of attraction failures, retries, and constitute backpressure.
logical_stats() None Exact Result<LogicalStats> for unsocial unrecorded keys and bytes. It scans beingness versions and whitethorn execute I/O.
physical_stats() None Cheap PhysicalStats gauges and process-lifetime counters for the WAL, memtables, SSTables, cache, stalls, and amplification.
stats() None Deprecated mixed beingness counters retained for root compatibility.
close() Consumes Db Flushes pending writes, stops maintenance, and releases ownership connected success. Dropping Db is not a clean-shutdown guarantee.
close_with_status() Consumes Db The system shutdown form; distinguishes retention errors from unresolved flush aliases compaction health.

Most database methods return DbError. Streaming iterator creation returns DbError, while failures discovered later are yielded arsenic ScanError. The lower-level Engine and constituent configuration types are supported advanced APIs; their complete section and method contracts are successful the crate documentation.

The benchmark utilized TurboKV 0.6.0, fjall 2.11.2, and redb 2.6.3 successful Durable mode complete 3 repetitions. Throughput is acknowledged keys per second; higher is better.

Workload Mode TurboKV ops/s fjall ops/s redb ops/s TurboKV / fjall
Sequential capable (1 key/txn) Durable 1,407,678 485,252 1,397 (macOS barrier/txn) 2.901×
Random capable (1 key/txn) Durable 834,137 456,924 1,549 (macOS barrier/txn) 1.826×
Overwrite (1 key/txn) Durable 853,083 446,733 1,516 (macOS barrier/txn) 1.910×
Sequential batch (100 keys/txn) Durable 2,272,259 511,600 80,197 4.441×
Sequential batch (1,000 keys/txn) Durable 2,333,582 572,671 134,636 4.075×

Protocol: 200,000 deterministic 20-byte keys, 400-byte values (84 MB logical input, supra the 64 MiB memtable), 1 caller, atomic batches wherever shown, compression and artifact cache disabled, and an uncleared OS page cache. redb 2.6.3's Durability::Eventual performs a macOS F_BARRIERFSYNC for every transaction, while the TurboKV and fjall Durable modes extremity astatine their process-crash-recoverable OS-cache boundaries. Batching amortizes that fixed redb barrier; its single-key rows are truthful architectural discourse rather than a like-for-like durability claim. Cross-engine settled timings are not compared.

Measured connected 2026-08-28 pinch an Apple M4 (Mac16,1), 32 GiB RAM, macOS 15.3.2 (24D81), APFS, and rustc 1.88.0. Exact earthy repetitions, latency percentiles, dispersion, dependency versions, byte accounting, and amplification are successful the JSON artifact and its text report. The afloat methodology and rerun bid are in benchmarks/README.md.

More