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 typedFuseWriter::add/FuseReader::getAPI, 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§
Constants§
- CRATE_
VERSION - Version of this crate, as published on crates.io.