Getting started
Add the crate, open a database on disk or in memory, write a batch, read it back and close the handle.
TessariKV needs Rust 1.89 or newer and a tokio runtime.
Add it
cargo add tessarikv
cargo add tokio --features macros,rt-multi-thread
Open, write, read
use tessarikv::{Db, DbOptions, KeyspaceId, ReadOptions, WriteBatch, WriteOptions};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// A directory on disk; it is created when it holds no database.
let db = Db::open("data/inventory", DbOptions::default()).await?;
let mut batch = WriteBatch::new();
batch.put(KeyspaceId::DEFAULT, b"sku:1001", b"12 in stock")?;
batch.put(KeyspaceId::DEFAULT, b"sku:1002", b"out of stock")?;
db.write(&batch, &WriteOptions::default()).await?;
let value = db.get(KeyspaceId::DEFAULT, b"sku:1001", &ReadOptions::default()).await?;
assert_eq!(value.as_deref(), Some(&b"12 in stock"[..]));
db.close().await?;
Ok(())
}
A WriteBatch method fails with the table format's own error type, which
tessarikv::Error does not convert from, so code that builds batches returns a
boxed error, as here.
WriteOptions::default() waits until the log record is on stable storage, so
the write survives a power loss. Writes and durability
covers the cheaper choices.
In memory only
DbOptions::in_memory() runs the same engine with every file held in process
memory. Nothing survives the process. It suits tests and caches.
use tessarikv::{Db, DbOptions};
async fn scratch() -> tessarikv::Result<Db> {
// The path only names the database; nothing is written to disk.
Db::open("scratch", DbOptions::in_memory()).await
}
Options
DbOptions::builder() starts from the defaults and validates on build().
use tessarikv::{DbOptions, WalRecovery};
fn options() -> tessarikv::Result<DbOptions> {
DbOptions::builder()
.block_cache_bytes(1 << 30) // 1 GiB of block cache
.background_threads(8)
.wal_recovery(WalRecovery::Absolute)
.build()
}
A value out of range is refused with Error::InvalidOptions, which names the
option. Every option and its default is on Options.
One handle per directory
While a database is open, its directory is locked: another process opening the
same path is refused with Error::Locked. Within one program, share one Db
between tasks: every method takes &self, so wrap it in an Arc.
Db::close lets a running flush finish, writes and syncs every acknowledged
write, then releases the lock. Dropping the handle without closing it leaves the
log writer to finish in the background, unobserved.