diff --git a/Cargo.lock b/Cargo.lock index c66d1928..20c7d1d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -877,6 +877,19 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "crossbeam-epoch" +version = "0.9.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + [[package]] name = "crossbeam-queue" version = "0.3.8" @@ -1158,6 +1171,16 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "futures" version = "0.3.26" @@ -1258,6 +1281,15 @@ dependencies = [ "slab", ] +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + [[package]] name = "generic-array" version = "0.14.6" @@ -1692,6 +1724,15 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "memoffset" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +dependencies = [ + "autocfg", +] + [[package]] name = "mime" version = "0.3.16" @@ -2204,6 +2245,14 @@ dependencies = [ "winreg", ] +[[package]] +name = "revdb" +version = "0.1.0" +dependencies = [ + "sled", + "thiserror", +] + [[package]] name = "ring" version = "0.16.20" @@ -2451,6 +2500,22 @@ dependencies = [ "autocfg", ] +[[package]] +name = "sled" +version = "0.34.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f96b4737c2ce5987354855aed3797279def4ebf734436c6aa4552cf8e169935" +dependencies = [ + "crc32fast", + "crossbeam-epoch", + "crossbeam-utils", + "fs2", + "fxhash", + "libc", + "log", + "parking_lot 0.11.2", +] + [[package]] name = "smallvec" version = "1.10.0" diff --git a/crates/revdb/Cargo.toml b/crates/revdb/Cargo.toml index 4cb30ad7..172fae99 100644 --- a/crates/revdb/Cargo.toml +++ b/crates/revdb/Cargo.toml @@ -6,3 +6,5 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +sled = "0.34.7" +thiserror = "1.0.30" diff --git a/crates/revdb/src/db.rs b/crates/revdb/src/db.rs new file mode 100644 index 00000000..cfbdd213 --- /dev/null +++ b/crates/revdb/src/db.rs @@ -0,0 +1,65 @@ +use crate::error::RevDBError; +use sled::Db; +use std::path::Path; + +pub struct RevDB { + pub(crate) db: Db, +} + +impl RevDB { + pub fn open(path: impl AsRef) -> Result { + let db = sled::open(path)?; + Ok(Self { db }) + } + + pub fn insert(&self, uid: i64, rev_id: i64, data: &[u8]) -> Result<(), RevDBError> { + let key = make_seq_key(uid, rev_id); + let _ = self.db.insert(key, data)?; + Ok(()) + } + + pub fn get(&self, uid: i64, rev_id: i64) -> Result>, RevDBError> { + let key = make_seq_key(uid, rev_id); + let value = self.db.get(key)?; + Ok(value.map(|value| value.to_vec())) + } +} +// Optimize your data layout: Sled's B-Tree implementation works best when the keys are sequential, +// so try to organize the data in a way that maximizes sequential access. +fn make_seq_key(uid: i64, rev_id: i64) -> [u8; 16] { + let mut key = [0; 16]; + key[0..8].copy_from_slice(&uid.to_be_bytes()); + key[8..16].copy_from_slice(&rev_id.to_be_bytes()); + key +} + +#[cfg(test)] +mod tests { + use crate::db::RevDB; + use std::path::Path; + use std::time::Instant; + + #[test] + fn insert_speed() { + let path = Path::new("."); + let db = RevDB::open(path).unwrap(); + let start_time = Instant::now(); + + for i in 0..=100000 { + db.insert(1, i, b"hello world").unwrap(); + } + + for i in 0..=100000 { + db.get(1, i).unwrap(); + } + + let end_time = Instant::now(); + let elapsed_time = end_time - start_time; + // Print the elapsed time in seconds and milliseconds + println!( + "Elapsed time: {}s, {}ms", + elapsed_time.as_secs(), + elapsed_time.subsec_millis() + ); + } +} diff --git a/crates/revdb/src/error.rs b/crates/revdb/src/error.rs new file mode 100644 index 00000000..2a48e59b --- /dev/null +++ b/crates/revdb/src/error.rs @@ -0,0 +1,8 @@ +#[derive(Debug, thiserror::Error)] +pub enum RevDBError { + #[error(transparent)] + Db(#[from] sled::Error), + + #[error("invalid data")] + InvalidData, +} diff --git a/crates/revdb/src/lib.rs b/crates/revdb/src/lib.rs index 7d12d9af..7f097aa1 100644 --- a/crates/revdb/src/lib.rs +++ b/crates/revdb/src/lib.rs @@ -1,14 +1,2 @@ -pub fn add(left: usize, right: usize) -> usize { - left + right -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); - } -} +mod db; +pub mod error;