use std::env::current_dir; use tempfile::{NamedTempFile, TempDir}; mod common; use common::*; use rand::Rng; use std::time::{Duration, Instant}; const ELEMENTS: usize = 1_000_000; /// Returns pairs of key, value fn gen_data(count: usize, key_size: usize, value_size: usize) -> Vec<(Vec, Vec)> { let mut pairs = vec![]; for _ in 0..count { let key: Vec = (0..key_size).map(|_| rand::thread_rng().gen()).collect(); let value: Vec = (0..value_size).map(|_| rand::thread_rng().gen()).collect(); pairs.push((key, value)); } pairs } fn benchmark(db: T) -> Vec<(&'static str, Duration)> { let mut results = Vec::new(); let mut pairs = gen_data(1_000_000, 24, 150); let mut written = 0; let mut bigpairs = gen_data(100, 24, 2_000_000); let bigelements = 4000; let start = Instant::now(); let mut txn = db.write_transaction(); let mut inserter = txn.get_inserter(); { for _ in 0..bigelements { let len = bigpairs.len(); let (key, value) = &mut bigpairs[written % len]; key[16..].copy_from_slice(&(written as u64).to_le_bytes()); inserter.insert(key, value).unwrap(); written += 1; } for _ in 0..ELEMENTS { let len = pairs.len(); let (key, value) = &mut pairs[written % len]; key[16..].copy_from_slice(&(written as u64).to_le_bytes()); inserter.insert(key, value).unwrap(); written += 1; } } drop(inserter); txn.commit().unwrap(); let end = Instant::now(); let duration = end - start; println!( "{}: Bulk loaded {} 2MB items and {} small items in {}ms", T::db_type_name(), bigelements, ELEMENTS, duration.as_millis() ); results.push(("bulk load (2MB values)", duration)); results } fn main() { let redb_latency_results = { let tmpfile: NamedTempFile = NamedTempFile::new_in(current_dir().unwrap()).unwrap(); let db = redb::Database::builder().create(tmpfile.path()).unwrap(); let table = RedbBenchDatabase::new(&db); benchmark(table) }; let lmdb_results = { let tmpfile: TempDir = tempfile::tempdir_in(current_dir().unwrap()).unwrap(); let env = unsafe { heed::EnvOpenOptions::new() .map_size(10 * 4096 * 1024 * 1024) .open(tmpfile.path()) .unwrap() }; let table = HeedBenchDatabase::new(&env); benchmark(table) }; let rocksdb_results = { let tmpfile: TempDir = tempfile::tempdir_in(current_dir().unwrap()).unwrap(); let db = rocksdb::TransactionDB::open_default(tmpfile.path()).unwrap(); let table = RocksdbBenchDatabase::new(&db); benchmark(table) }; let sled_results = { let tmpfile: TempDir = tempfile::tempdir_in(current_dir().unwrap()).unwrap(); let db = sled::Config::new().path(tmpfile.path()).open().unwrap(); let table = SledBenchDatabase::new(&db, tmpfile.path()); benchmark(table) }; let mut rows = Vec::new(); for (benchmark, _duration) in &redb_latency_results { rows.push(vec![benchmark.to_string()]); } for results in [ redb_latency_results, lmdb_results, rocksdb_results, sled_results, ] { for (i, (_benchmark, duration)) in results.iter().enumerate() { rows[i].push(format!("{}ms", duration.as_millis())); } } let mut table = comfy_table::Table::new(); table.set_width(100); table.set_header(["", "redb", "lmdb", "rocksdb", "sled"]); for row in rows { table.add_row(row); } println!(); println!("{table}"); }