jammdb 0.4.0

An embedded single-file database for Rust
Documentation

jammdb

Just Another Memory Mapped Database

Crates.io Crates.io MacOS Build Windows Build Linux Build Coverage Status License

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.

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
  • arm-linux-androideabi (Android)
  • aarch64-unknown-linux-gnu (ARM)
  • arm-unknown-linux-gnueabihf
  • mips-unknown-linux-gnu (MIPS)
  • x86_64-apple-ios (iOS)

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 mut 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(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!(data.is_kv());
        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 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") {
        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(())
}

License

Available under both the Apache License or the MIT license.