Skip to content

pjtatlow/jammdb

Repository files navigation

jammdb

Just Another Memory Mapped Database

crates.io docs.rs Build status Coverage Status License Dependency Status

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 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.

Supported platforms

jammdb is continuously cross-compiled and tested on the following platforms:

  • x86_64-unknown-linux-gnu (Linux)
  • i686-unknown-linux-gnu
  • x86_64-unknown-linux-musl (Linux MUSL)
  • x86_64-apple-darwin (OSX)
  • x86_64-pc-windows-msvc (Windows)
  • i686-pc-windows-msvc
  • x86_64-pc-windows-gnu
  • i686-pc-windows-gnu

Examples

Here are a couple of simple examples to get you started, but you should check out the docs for more details.

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 tx = db.tx(true)?;

    // create a bucket to store a map of first names to last names
    let names_bucket = tx.create_bucket("names")?;
    names_bucket.put("Kanan", "Jarrus")?;
    names_bucket.put("Ezra", "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 tx = db.tx(false)?;
    // 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("Kanan") {
        assert!(data.is_kv());
        assert_eq!(data.kv().value(), b"Jarrus");
    }
}
    Ok(())
}

Storing structs

use jammdb::{DB, Data, Error};
use serde::{Deserialize, Serialize};

#[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 tx = db.tx(true)?;

    // create a bucket to store users
    let 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("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 tx = db.tx(false)?;
    // 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("user1") {
        if data.is_kv() {
            let kv = data.kv();
            // deserialize into a user struct
            let db_user: User = rmp_serde::from_slice(kv.value()).unwrap();
            assert_eq!(db_user, user);
        }
    }
}
    Ok(())
}

MSRV

Currently 1.63

License

Available under both the Apache License or the MIT license.