Skip to main content

Crate fusedb

Crate fusedb 

Source
Expand description

A read-optimised binary database where many keys share one object — with zero duplication on disk.

FuseDB stores each payload once and lets any number of keys point at it. Reads are memory-mapped: opening a database is a mmap plus an index parse, and a lookup is a hash probe followed by a single page read.

§Quick start

use fusedb::{FuseReader, FuseWriter};
use std::collections::BTreeMap;

let mut w = FuseWriter::new();

let mut google = BTreeMap::new();
google.insert("company", "Google");

let oid = w.add_object(&google)?;   // stored once…
w.add_key("google.com", oid)?;      // …reached by three keys
w.add_key("8.8.8.8", oid)?;
w.add_key("8.8.4.4", oid)?;
w.build("db.fsdb")?;

let db = FuseReader::open("db.fsdb")?;
let hit: Option<BTreeMap<String, String>> = db.get("8.8.8.8")?;
assert_eq!(hit.unwrap()["company"], "Google");

§One format, two languages

There is no “Rust format” and no “Python format” — only the FuseDB format. A file written by this crate opens in the fusedb Python package and vice versa, with no conversion step: same magic and version, same big-endian header, same CRC32 placement, same sorted index layout, and — with the default msgpack feature — the same MessagePack value encoding.

// reads a file `FuseWriter().build("db.fsdb")` produced in Python
let db = FuseReader::open("db.fsdb")?;

§Live updates

.fsdb files are immutable once built; you update one by rebuilding it and swapping. ReloadableReader does the swap on demand, FuseWatcher does it from a background thread. Either way you read them exactly like a FuseReader — every call resolves the current file, so there is no swap bookkeeping and no way to keep reading a replaced database.

use std::time::Duration;
use fusedb::FuseWatcher;

let watcher = FuseWatcher::builder("live.fsdb")
    .interval(Duration::from_secs(30))
    .on_reload(|db| eprintln!("reloaded: {} keys", db.len()))
    .spawn()?;

println!("{:?}", watcher.get_raw("8.8.8.8")?);   // always the newest build

// For a batch, resolve the reader once with load() and reuse it.
let db = watcher.load();
for key in ["8.8.8.8", "8.8.4.4"] {
    println!("{:?}", db.get_raw(key)?);
}

§Features

  • msgpack (default) — the typed FuseWriter::add / FuseReader::get API, encoding values exactly the way the Python package does. Disable it (default-features = false) for a dependency-light build that speaks only raw bytes.
  • python — PyO3 bindings. Enabled by maturin when building the Python wheel; Rust consumers never need it.

Re-exports§

pub use api::decode;
pub use api::encode;
pub use api::merge;
pub use api::merge;
pub use api::merge_into;
pub use api::FuseReader;
pub use api::FuseWatcher;
pub use api::FuseWriter;
pub use api::PrefixIter;
pub use api::ReloadableReader;
pub use api::Stats;
pub use api::WatcherBuilder;
pub use core::format::MAGIC;
pub use core::format::MAX_KEY_LEN;
pub use core::format::MAX_OBJECT_LEN;
pub use core::format::VERSION;
pub use core::BuildReport;
pub use core::FuseError;
pub use core::FuseResult;

Modules§

api
core

Constants§

CRATE_VERSION
Version of this crate, as published on crates.io.