Crate jammdb[−][src]
Just Another Memory Mapped Database
jammdb is an embedded, single-file database that allows you to store key / value pairs as bytes.
It started life as a Rust port of Ben Johnson's awesome BoltDB, which was inspired by Howard Chu's LMDB, so please check out both of these awesome projects!
jammdb offers ACID compliance, serializable and isolated transactions, with multiple lock-free readers and a single concurrent writer. The data is organized in a single level B+ tree so random and sequential reads are very fast. The underlying file is memory mapped, so reads require no additional memory allocation.
jammdb is meant to be very simple, and has only a few exported types. It will allow you to store data in collections (called Buckets
),
and each bucket can contain any number of unique keys which map to either an arbitrary value (a &[u8]
) or a nested bucket. Examples on how to use jammdb are below.
There are also more examples in the docs, be sure to check out
- Using a
Cursor
to iterate over the data in a bucket - How to create and use multiple
Transaction
s - Nested
Buckets
OpenOptions
to provide parameters for opening aDB
Examples
Simple put and get
use jammdb::{DB, Data, Error}; fn main() -> Result<(), Error> { { // open a new database file let db = DB::open("my-database.db")?; // open a writable transaction so we can make changes let mut tx = db.tx(true)?; // create a bucket to store a map of first names to last names let mut names_bucket = tx.create_bucket("names")?; names_bucket.put(b"Kanan", b"Jarrus")?; names_bucket.put(b"Ezra", b"Bridger")?; // commit the changes so they are saved to disk tx.commit()?; } { // open the existing database file let db = DB::open("my-database.db")?; // open a read-only transaction to get the data let mut tx = db.tx(true)?; // get the bucket we created in the last transaction let names_bucket = tx.get_bucket("names")?; // get the key / value pair we inserted into the bucket if let Some(data) = names_bucket.get(b"Kanan") { assert_eq!(data.kv().value(), b"Jarrus"); } } Ok(()) }
Storing structs
use jammdb::{DB, Data, Error}; use serde::{Deserialize, Serialize}; // use rmps crate to serialize structs using the MessagePack format use rmp_serde::{Deserializer, Serializer}; #[derive(Debug, PartialEq, Deserialize, Serialize)] struct User { username: String, password: String, } fn main() -> Result<(), Error> { let user = User{ username: "my-user".to_string(), password: "my-password".to_string(), }; { // open a new database file and start a writable transaction let db = DB::open("my-database.db")?; let mut tx = db.tx(true)?; // create a bucket to store users let mut users_bucket = tx.create_bucket("users")?; // serialize struct to bytes and store in bucket let user_bytes = rmp_serde::to_vec(&user).unwrap(); users_bucket.put(b"user1", user_bytes)?; // commit the changes so they are saved to disk tx.commit()?; } { // open the existing database file let db = DB::open("my-database.db")?; // open a read-only transaction to get the data let mut tx = db.tx(true)?; // get the bucket we created in the last transaction let users_bucket = tx.get_bucket("users")?; // get the key / value pair we inserted into the bucket if let Some(data) = users_bucket.get(b"user1") { // deserialize into a user struct let db_user: User = rmp_serde::from_slice(data.kv().value()).unwrap(); assert_eq!(db_user, user); } } Ok(()) }
Structs
Bucket | A collection of data |
BucketData | Nested bucket placeholder |
Cursor | An iterator over a bucket |
DB | A database |
KVPair | Key / Value Pair |
OpenOptions | Options to configure how a |
Ref | A wrapper around data to ensure it is used before a bucket goes out of scope |
Transaction | An isolated view of the database |
Enums
Data | Key / Value or Bucket Data |
Error | Possible database errors |