1.0 release!

redb is stable!

redb is an embedded key-value database written in pure Rust. It provides a similar interface to other embedded key-value stores such as rocksdb and lmdb, and it has comparable performance while still being memory-safe. Besides the table stakes features such as zero-copy reads and MVCC to allow multiple concurrent readers, redb provides a few other notable features:

  • ACID transaction semantics with configurable durability per transaction: transactions may be configured to be non-durable which improves commit performance without sacrificing atomicity, consistency, or isolation.
  • Savepoints. redb implements savepoints which allow the state of the database to be captured and rolled back at any point in the future. This can be used to implement sub-transactions, or more complex rollback strategies such as distributed commit protocols.

redb’s interface is designed to be similar to BtreeMap with persistence and thread-safety, and is completely type safe. A simple example application might use it as follows:

use redb::*;

const TABLE: TableDefinition<u64, &str> = TableDefinition::new("messages");

fn main() -> Result<(), Error> {
  let db = Database::create("messages.redb")?;
  let write_txn = db.begin_write()?;
  {
    let mut table = write_txn.open_table(TABLE)?;
    table.insert(0, "the first message ever sent!")?;
  }
  write_txn.commit()?;

  let read_txn = db.begin_read()?;
  let table = read_txn.open_table(TABLE)?;
  assert_eq!(table.get(0)?.unwrap().value(), "the first message ever sent!");
  assert_eq!(table.len()?.unwrap(), 1);

  Ok(())
}

Design and architecture

redb’s design is inspired by lmdb and uses a collection of copy-on-write btrees. This provides very good read performance, non-blocking readers and writer, and supports features like savepoints.

Logically, a redb database file consists of some metadata, and several B-trees:

  • pending free tree: mapping from transaction ids to the list of pages they freed. This is used by the MVCC system to ensure that pages are only freed once all transactions that could reference them have completed.
  • table tree: name -> table definition mapping of table names to their definitions
  • data tree(s) (per one table): key -> value mapping for table

Except for the database metadata, all other data structures are copy-on-write.

The database file begins with the database header, and is followed by one or more regions. Each region contains a header, and a data section which is split into many pages. These regions allow for efficient, dynamic, growth of the database file.

For more details see the design doc

Benchmarks

Below are some benchmarks comparing redb with other popular embedded key-value databases

+---------------------------+--------+--------+---------+--------+-----------+
|                           | redb   | lmdb   | rocksdb | sled   | sanakirja |
+============================================================================+
| bulk load                 | 2594ms | 1114ms | 5814ms  | 5337ms | 1193ms    |
|---------------------------+--------+--------+---------+--------+-----------|
| individual writes         | 395ms  | 723ms  | 1129ms  | 1200ms | 655ms     |
|---------------------------+--------+--------+---------+--------+-----------|
| batch writes              | 2610ms | 2098ms | 1227ms  | 1815ms | 2537ms    |
|---------------------------+--------+--------+---------+--------+-----------|
| random reads              | 975ms  | 567ms  | 3197ms  | 1512ms | 673ms     |
|---------------------------+--------+--------+---------+--------+-----------|
| random reads              | 886ms  | 565ms  | 3402ms  | 1349ms | 674ms     |
|---------------------------+--------+--------+---------+--------+-----------|
| random range reads        | 2518ms | 1011ms | 5939ms  | 4618ms | 1080ms    |
|---------------------------+--------+--------+---------+--------+-----------|
| random range reads        | 2519ms | 1014ms | 5791ms  | 4755ms | 1165ms    |
|---------------------------+--------+--------+---------+--------+-----------|
| random reads (4 threads)  | 332ms  | 158ms  | 1166ms  | 436ms  | 260ms     |
|---------------------------+--------+--------+---------+--------+-----------|
| random reads (8 threads)  | 173ms  | 89ms   | 648ms   | 228ms  | 705ms     |
|---------------------------+--------+--------+---------+--------+-----------|
| random reads (16 threads) | 104ms  | 47ms   | 451ms   | 143ms  | 3417ms    |
|---------------------------+--------+--------+---------+--------+-----------|
| random reads (32 threads) | 92ms   | 46ms   | 390ms   | 120ms  | 4538ms    |
|---------------------------+--------+--------+---------+--------+-----------|
| removals                  | 2055ms | 778ms  | 2433ms  | 2052ms | 1218ms    |
+---------------------------+--------+--------+---------+--------+-----------+