pub struct Lsm { /* private fields */ }std only.Expand description
A log-structured merge-tree key-value store backed by a directory on disk.
Lsm is the Tier-1 entry point: open, put,
get, delete, and scan cover the
whole common case. Keys and values are arbitrary byte strings; keys are
ordered lexicographically.
The handle is cheap to share: every method takes &self, and the type is
Send + Sync, so one engine can be wrapped in an
Arc and used from many threads.
A background thread compacts runs as they accumulate. Dropping the Lsm
signals that thread to stop and joins it, so no work outlives the handle.
§Durability
Flushed runs are fsynced and recorded in a manifest, so flushed data
survives reopening and a crash mid-flush or mid-compaction recovers to a
consistent run set. Writes still buffered in the memtable when the process
exits without a flush are not yet crash-safe; write-ahead logging arrives
under the durability feature in a later release. Call flush
to force the buffer to disk on demand.
§Examples
let dir = tempfile::tempdir()?;
let db = lsm_db::Lsm::open(dir.path())?;
db.put(b"hello", b"world")?;
assert_eq!(db.get(b"hello")?, Some(b"world".to_vec()));
db.delete(b"hello")?;
assert_eq!(db.get(b"hello")?, None);Implementations§
Source§impl Lsm
impl Lsm
Sourcepub fn open(dir: impl AsRef<Path>) -> Result<Self>
pub fn open(dir: impl AsRef<Path>) -> Result<Self>
Open the database in dir, creating the directory if it does not exist,
using the default LsmConfig.
The run set recorded in the manifest is reopened, so flushed data is visible immediately. Temporary files and run files orphaned by a crash mid-flush or mid-compaction are reclaimed.
§Examples
let dir = tempfile::tempdir()?;
let db = lsm_db::Lsm::open(dir.path())?;
db.put(b"k", b"v")?;Sourcepub fn put(&self, key: impl AsRef<[u8]>, value: impl AsRef<[u8]>) -> Result<()>
pub fn put(&self, key: impl AsRef<[u8]>, value: impl AsRef<[u8]>) -> Result<()>
Set key to value, overwriting any previous value.
§Examples
let dir = tempfile::tempdir()?;
let db = lsm_db::Lsm::open(dir.path())?;
db.put(b"key", b"value")?;
assert_eq!(db.get(b"key")?, Some(b"value".to_vec()));Sourcepub fn delete(&self, key: impl AsRef<[u8]>) -> Result<()>
pub fn delete(&self, key: impl AsRef<[u8]>) -> Result<()>
Delete key. A subsequent get returns None.
Deleting a key that is not present is not an error.
§Examples
let dir = tempfile::tempdir()?;
let db = lsm_db::Lsm::open(dir.path())?;
db.put(b"key", b"value")?;
db.delete(b"key")?;
assert_eq!(db.get(b"key")?, None);
db.delete(b"never-existed")?; // not an errorSourcepub fn write(&self, batch: Batch) -> Result<()>
pub fn write(&self, batch: Batch) -> Result<()>
Apply a Batch of writes as one group.
The whole batch is applied under a single lock acquisition, so concurrent readers observe either none or all of it.
§Examples
use lsm_db::Batch;
let dir = tempfile::tempdir()?;
let db = lsm_db::Lsm::open(dir.path())?;
let mut batch = Batch::new();
batch.put(b"a", b"1");
batch.put(b"b", b"2");
batch.delete(b"c");
db.write(batch)?;
assert_eq!(db.get(b"a")?, Some(b"1".to_vec()));Sourcepub fn get(&self, key: impl AsRef<[u8]>) -> Result<Option<Vec<u8>>>
pub fn get(&self, key: impl AsRef<[u8]>) -> Result<Option<Vec<u8>>>
Look up key, returning its value, or None if it is absent or deleted.
§Examples
let dir = tempfile::tempdir()?;
let db = lsm_db::Lsm::open(dir.path())?;
assert_eq!(db.get(b"missing")?, None);
db.put(b"present", b"1")?;
assert_eq!(db.get(b"present")?, Some(b"1".to_vec()));Sourcepub fn scan<R>(&self, range: R) -> Result<Scan>
pub fn scan<R>(&self, range: R) -> Result<Scan>
Iterate the live (key, value) pairs whose key falls in range, in
ascending key order.
The range is taken over Vec<u8> bounds, so the usual syntaxes all work:
.., a..b, a..=b, a.., ..b. The returned Scan is a consistent
snapshot taken when scan is called; later writes do not affect it.
§Examples
let dir = tempfile::tempdir()?;
let db = lsm_db::Lsm::open(dir.path())?;
db.put(b"a", b"1")?;
db.put(b"b", b"2")?;
db.put(b"c", b"3")?;
let mid: Vec<_> = db.scan(b"a".to_vec()..b"c".to_vec())?.collect();
assert_eq!(mid, vec![(b"a".to_vec(), b"1".to_vec()), (b"b".to_vec(), b"2".to_vec())]);
assert_eq!(db.scan(..)?.count(), 3);Sourcepub fn flush(&self) -> Result<()>
pub fn flush(&self) -> Result<()>
Force the in-memory buffer to disk as a new run.
Flushing an empty buffer is a no-op. After a successful flush every previously written key is durable and will be read back on reopen.
§Examples
let dir = tempfile::tempdir()?;
let db = lsm_db::Lsm::open(dir.path())?;
db.put(b"k", b"v")?;
db.flush()?;
drop(db);
let db = lsm_db::Lsm::open(dir.path())?;
assert_eq!(db.get(b"k")?, Some(b"v".to_vec()));