kiban · 基盤 · n. foundation
a storage engine, built from scratch.
kiban is an embedded LSM-tree key-value store for Linux, written in Rust: a write-ahead log, memtables, SSTs, leveled compaction, snapshots and crash recovery.
open, put, sync().
Open a directory, write, sync, read. Byte keys and byte values, kept in order, inside your process.
use kiban::db::Kiban;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut db = Kiban::open("example-db")?;
db.put(b"hello", b"world")?;
db.sync()?; // put alone is not crash-durable
assert_eq!(db.get(b"hello")?, Some(b"world".to_vec()));
drop(db);
let reopened = Kiban::open("example-db")?;
assert_eq!(reopened.get(b"hello")?, Some(b"world".to_vec()));
Ok(())
}
Rust 2024 · no runtime dependencies by default · Linux · MIT
what Ok means.
Ok means accepted. sync() means durable.
- promised
sync()every write accepted before it survives a crashwrite(batch)all or nothing, one WAL recordsnapshot()unmoved by later writes and compactionsa failed syncthe engine refuses writes until reopenedWAL, SST, MANIFESTCRC-32 checksummedafter a crasha real past state, every synced write in itsynced WAL damagereported when a later sync mark proves itWAL rotationold log synced before the next opens
- not promised
put() before sync()lost if the machine goes downdropnot a synctwo processes, one directorynot validatedmachine power losssimulated, not tested on hardwareAPI, on-disk formatmay change before 1.0not built yetcompression, range deletes, reverse iteration, transactions
we tried to break it.
Simulated crashes, injected filesystem faults and real SIGKILLs. After each one, the reopened database is checked for a prefix of accepted writes that includes every synced write.
- Crash seeds on every PR
- 128
- Power losses per seed
- 4
- Bugs found and fixed
- 4
- SIGKILL / reopen cycles
- 1,000
- Acknowledged writes verified
- 530,100
- Library tests
- 422
Every guarantee names the test that checks it. Tested cases, not a proof, and not a claim of production readiness.
Read the repair reportagainst the field.
One agent-memory workload on four engines at kiban commit 3935977: warm cache, one worker, every result checked. kiban leads warm reads, keeps pace on durable writes, and gives up disk and memory to do it.
- Faster point reads than tuned RocksDB
- 2.6×
- Faster latest-ten reads than tuned RocksDB
- 4.2×
- Faster latest-ten reads than SQLite with mmap
- 4.9×
- Faster point reads than LMDB
- 1.3×
- More durable writes with group commit, at 16 writers
- 7.7×
- The syncs for the same durable writes, at 16 writers
- 1/8
every workload
Median latency, p99 beneath. Pick an opponent. A gap that changes sign between trials reads as even.
| workload | kiban | RocksDB | ← RocksDB faster1×kiban faster → |
|---|---|---|---|
| reads | |||
| point read1M records | 1.09 µsp99 1.57 µs | 2.75 µsp99 4.61 µs | |
| latest ten1M records, one agent | 1.95 µsp99 2.62 µs | 8.19 µsp99 12 µs | |
| point read, small cache32 MiB cache, mmap on | 1.25 µsp99 2.24 µs | 6.53 µsp99 12 µs | |
| latest ten, small cache32 MiB cache, mmap on | 3.39 µsp99 5.25 µs | 8.45 µsp99 13 µs | |
| durable writes | |||
| new recordsynced before return | 492 µsp99 2.0 ms | 500 µsp99 1.7 ms | |
| updatesynced before return | 500 µsp99 1.7 ms | 483 µsp99 1.5 ms | |
| 16 concurrent writersgroup commit, every write verified | 14.1Kwrites/s · p99 3.0 ms | 12.8Kwrites/s · p99 2.7 ms | |
double the writers
Group commit shares one sync across waiting writers. Press play, or drag across the plot.
writes per second, every one synced
writes per secondready
┊ RocksDB finished the same run at 35 s
queued above level targets0 MiB
one write run
Four levels of a real tree, stacked. Scroll to open them.
replay the long runs
The scale runs, second by second from each engine's median trial. Press play, or drag across the plot.
kiban finished 6 min 10 s ahead. The default point index costs this small-cache run half its speed: with it off, kiban reached 3.8M ops/s.
the other column
What these wins cost, and what this campaign cannot tell you.
- where it loses
memory450 MiB peak RSS, RocksDB 356, SQLite 349disk352 MiB for 1M records, RocksDB 304, SQLite 315latest ten, small cacheLMDB is 1.4× faster at 32 MiBpoint read, no mmapbehind LMDB at 32 MiB unless mmap is onsustained writesRocksDB finishes the long write runs about 3× soonerpoint index, tiny cachehalves 100M reads at 33 MiB: 1.7M ops/s, 3.8M with it offflush and compaction1.36× and 1.26× slower with the point index
- not measured
larger than memorybeyond the 32 MiB cache rowscold readsevery read here starts warmmany readersone reader, one pinned coreshared hostnot an exclusive core
One shared laptop on mains power: Intel Core Ultra 9 185H, NVMe behind LUKS, Linux 7.2. A memory record is a JSON value with 200 bytes of text, across 64 agents. Reads ran on one pinned core, five rotated trials per engine. kiban ran with its agent_memory settings, RocksDB with the winner of its published screen, and SQLite with its fastest read row. These runs use the engine code released as v0.2.0, and say nothing about larger-than-memory or cold-storage performance.
Methodology and raw results The v0.1.0 throughput comparisonfollow a write.
One put(), from the log to memory to a sorted file on disk.
what happens after put()?
The work that follows a write: compaction, snapshots, file cleanup, and recovery after a crash.
inside the engine.
An ordered byte-key, byte-value store that runs inside your process. The MANIFEST decides which log and table files belong to the database.
get() and scan() read the memtables, then the SSTs, newest first; the newest visible version wins.- block cache
- Holds checksum-verified SST blocks for reads. Compaction streams through its own reader and leaves the cache alone.
- MANIFEST
- Records which WAL and SST files are live, and at which level, before any reader sees the change.
- compaction
- Merges overlapping files downward. From L1 on, files in a level never overlap in key range.
- snapshots
- Pin a sequence number and the files behind it. Later writes and compactions don't change what a snapshot reads.
what's here.
Shipped features and the work ahead.
- capabilities
RustshippedPython (ctypes)shippedMCP servershippedC ABIshippedGroup commitshippedPerfect-hash point indexshippedagent_memory profileshipped
- roadmap
doneCrash-simulation suitedoneWrite path: group commitdoneBindings: Python/MCPdonePublished benchmarksnextStorage API: reverse/prefix scans, namespaces, range deletes, TTLplannedTransactions
everything we measured.
How kiban is built, how it was tested, and what it lost along the way.
how it is built.
Ownership, durable state, reads, snapshots and maintenance.
against the field.
Four engines at one commit: the campaign behind this site's numbers.
the perfect hash.
The experiment that showed immutable tables could beat a B+tree.
The reports worth reading, set for the screen.
Open the library