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

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 DB is opened.

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