| Crates.io | lsmlite-rs |
| lib.rs | lsmlite-rs |
| version | 0.2.2 |
| created_at | 2023-07-17 12:03:40.541081+00 |
| updated_at | 2025-04-16 16:37:17.791512+00 |
| description | Helsing's Rust bindings for sqlite3's lsm1 extension in stand-alone fashion. |
| homepage | |
| repository | https://github.com/helsing-ai/lsmlite-rs |
| max_upload_size | |
| id | 918424 |
| size | 952,490 |
Helsing's Rust bindings for sqlite3's lsm1 extension.
lsmlite-rs exposes sqlite3's lsm1 extension in stand-alone fashion (without the whole sqlite3 stack). This extension is an excellent implementation of Log-structured Merge Trees and is in principle similar in spirit to RocksDB and WiredTiger (the storage engine of MongoDB). Unlike RocksDB, for example, lsm1 structures data on stable storage as a collection of read-only B-trees (called "segments" in lsm1's terminology) that increase in size as the database grows. Thus, lsm1 follows the fundamental design principles of bLSM rather than those of a traditional LSM-Tree - in which data is stored in immutable sorted arrays. This comes with the advantage of offering excellent I/O for reads out-of-the-box; while also being efficient at writing data.
Other appealing characteristics of lsm1 are:
src/lsm1/lsm.c.WORM) workloads. A database becomes essentially a single densely-packed B-tree. Improving the space required by the database on disk, as well as providing optimal I/O for reads.lsm1's default durability setting.Relevant work in our roadmap currently includes:
lsmlite-js).lsmlite-py) using PyO3. We are aware of existing python bindings for lsm1 like python-lsm-db, so this has low priority at the moment.lsm1 versionslsmlite-rs version 0.1.0 is based on lsm1 contained in sqlite3-3.41.2 released on 22nd of March 2023. Amalgamated lsm1 file can be found under src/lsm1/lsm1-ae2e7fc.c along a short explanation about how this file was produced and how can it be locally updated from the official SQLite3's source code.The following is a short example on how to declare and open a database, then insert data and traverse the whole database extracting all keys and values currently contained therein. Additional examples on particular topics (e.g., transactions, or compression) can be found under the examples directory.
use lsmlite_rs::*;
// Make sure that `/tmp/my_db.lsm` does not exist yet.
let db_conf = DbConf::new("/tmp/", "my_db".to_string());
// Let's declare an empty handle.
let mut db: LsmDb = Default::default();
// Let's initialize the handle with our configuration.
let rc = db.initialize(db_conf);
// Let's connect to the database. It is at this point that the file is produced.
let rc = db.connect();
// Insert data into the database, so that something gets traversed.
// Let's persist numbers 1 to 100 with 1 KB zeroed payload.
let value = vec![0; 1024];
let max_n: usize = 100;
for n in 1..=max_n {
let key_serial = n.to_be_bytes();
let rc = db.persist(&key_serial, &value).unwrap();
}
// Let's open the cursor once we have written data (snapshot isolation).
let mut cursor = db.cursor_open().unwrap();
// Let's move the cursor to the very first record on the database.
let rc = cursor.first();
assert!(rc.is_ok());
// Now let's traverse the database extracting the data we just added.
let mut num_records = 0;
while cursor.valid().is_ok() {
num_records += 1;
// Extract the key.
let current_key = Cursor::get_key(&cursor).unwrap();
// Parse it to an integer.
assert!(current_key.len() == 8);
let key = usize::from_be_bytes(current_key.try_into().unwrap());
// Extract the value.
let current_value = Cursor::get_value(&cursor).unwrap();
// Everything should match.
assert!(key == num_records);
assert!(current_value.len() == 1024);
// Move onto the next record.
cursor.next().unwrap();
}
// We did find what we wanted.
assert_eq!(num_records, max_n);
// EOF
assert!(cursor.valid().is_err());
We would be happy to hear your thoughts, feedback and pull requests are welcome.