Skip to main content

lsm_db/
lib.rs

1//! # lsm-db
2//!
3//! A log-structured merge-tree storage engine for Rust.
4//!
5//! An LSM engine is the write path that powers RocksDB, LevelDB, Cassandra, and
6//! ScyllaDB: writes accumulate in a sorted in-memory buffer (the *memtable*);
7//! when the buffer fills it is flushed to an immutable, sorted file on disk (an
8//! *SSTable*); reads consult the buffer first and fall through to the file. The
9//! design turns random writes into sequential disk writes, which is why it
10//! underpins so many write-heavy stores.
11//!
12//! `lsm-db` packages that write path as a small, audited library so the storage
13//! engines in the portfolio — `txn-db`, Hive DB — share one implementation
14//! rather than each re-deriving it.
15//!
16//! ## The Tier-1 API
17//!
18//! The common case is five calls: open, put, get, delete, scan.
19//!
20//! ```
21//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
22//! use lsm_db::Lsm;
23//!
24//! // Open (or create) a database backed by a directory.
25//! let dir = tempfile::tempdir()?;
26//! let db = Lsm::open(dir.path())?;
27//!
28//! // Write and read arbitrary byte keys and values.
29//! db.put(b"user:1", b"alice")?;
30//! db.put(b"user:2", b"bob")?;
31//! assert_eq!(db.get(b"user:1")?, Some(b"alice".to_vec()));
32//!
33//! // Delete masks the key.
34//! db.delete(b"user:1")?;
35//! assert_eq!(db.get(b"user:1")?, None);
36//!
37//! // Range scans walk keys in sorted order.
38//! db.put(b"user:1", b"alice")?;
39//! let users: Vec<_> = db.scan(b"user:".to_vec()..b"user;".to_vec())?.collect();
40//! assert_eq!(users.len(), 2);
41//! # Ok(())
42//! # }
43//! ```
44//!
45//! ## Tuning
46//!
47//! [`LsmConfig`] is the Tier-2 surface for tuning the write-buffer size. Pass it
48//! to [`Lsm::open_with`]; [`Lsm::open`] uses the defaults.
49//!
50//! ```
51//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
52//! use lsm_db::{Lsm, LsmConfig};
53//! let dir = tempfile::tempdir()?;
54//! let db = Lsm::open_with(dir.path(), LsmConfig::new().memtable_capacity(1 << 20))?;
55//! db.put(b"k", b"v")?;
56//! # Ok(())
57//! # }
58//! ```
59//!
60//! ## Grouped writes
61//!
62//! [`Batch`] applies several writes as one atomic group; see [`Lsm::write`].
63//!
64//! ## Durability
65//!
66//! Flushed runs are `fsync`ed and recorded in a manifest, so flushed data
67//! survives reopening, and the on-disk format is frozen for the 1.x series.
68//! Writes still buffered in the memtable when a process exits without
69//! [`flush`](Lsm::flush)ing are durable only with the `durability` feature: it
70//! logs every write to a `wal-db` write-ahead log before acknowledging it and
71//! replays the log on open, so no acknowledged write is lost across a crash.
72//!
73//! ## Feature flags
74//!
75//! | Feature | Default | Description |
76//! |---------|---------|-------------|
77//! | `std` | yes | Standard library. The engine requires it. |
78//! | `durability` | no | Crash-safe writes via a `wal-db` write-ahead log. |
79//! | `bloom` | no | Bloom-filtered point lookups via `bloom-lib`. |
80
81#![cfg_attr(not(feature = "std"), no_std)]
82#![cfg_attr(docsrs, feature(doc_cfg))]
83#![deny(warnings)]
84#![deny(missing_docs)]
85#![forbid(unsafe_code)]
86#![deny(unused_must_use)]
87#![deny(unused_results)]
88#![deny(clippy::unwrap_used)]
89#![deny(clippy::expect_used)]
90#![deny(clippy::todo)]
91#![deny(clippy::unimplemented)]
92#![deny(clippy::print_stdout)]
93#![deny(clippy::print_stderr)]
94#![deny(clippy::dbg_macro)]
95#![deny(clippy::unreachable)]
96
97#[cfg(feature = "std")]
98mod batch;
99#[cfg(feature = "std")]
100mod bloom;
101#[cfg(feature = "std")]
102mod cache;
103#[cfg(feature = "std")]
104mod config;
105#[cfg(feature = "std")]
106mod db;
107#[cfg(feature = "std")]
108mod durability;
109#[cfg(feature = "std")]
110mod error;
111#[cfg(feature = "std")]
112mod manifest;
113#[cfg(feature = "std")]
114mod memtable;
115#[cfg(feature = "std")]
116mod merge;
117#[cfg(feature = "std")]
118mod record;
119#[cfg(feature = "std")]
120mod scan;
121#[cfg(feature = "std")]
122mod sstable;
123
124#[cfg(feature = "std")]
125pub use crate::batch::Batch;
126#[cfg(feature = "std")]
127pub use crate::config::{
128    DEFAULT_BLOCK_CACHE_CAPACITY, DEFAULT_COMPACTION_TRIGGER, DEFAULT_MEMTABLE_CAPACITY, LsmConfig,
129};
130#[cfg(feature = "std")]
131pub use crate::db::Lsm;
132#[cfg(feature = "std")]
133pub use crate::error::{Error, Result};
134#[cfg(feature = "std")]
135pub use crate::scan::Scan;
136
137/// The crate's common imports in one `use`.
138///
139/// ```
140/// use lsm_db::prelude::*;
141/// # fn main() -> Result<()> {
142/// let dir = tempfile::tempdir().map_err(Error::from)?;
143/// let db = Lsm::open(dir.path())?;
144/// db.put(b"k", b"v")?;
145/// # Ok(())
146/// # }
147/// ```
148#[cfg(feature = "std")]
149pub mod prelude {
150    pub use crate::{Batch, Error, Lsm, LsmConfig, Result, Scan};
151}