diff --git a/src/cursor.rs b/src/cursor.rs index 20715c2..ea70af7 100644 --- a/src/cursor.rs +++ b/src/cursor.rs @@ -228,6 +228,7 @@ mod test { use ffi::*; use super::*; use transaction::*; + use test_utils::setup_bench_db; #[test] fn test_iter() { @@ -371,28 +372,9 @@ mod test { cursor.get(None, None, MDB_LAST).unwrap()); } - fn setup_bench_db<'a>(num_rows: u32) -> (io::TempDir, Environment) { - let dir = io::TempDir::new("test").unwrap(); - let env = Environment::new().open(dir.path(), io::USER_RWX).unwrap(); - - { - let db = env.open_db(None).unwrap(); - let mut txn = env.begin_write_txn().unwrap(); - for i in range(0, num_rows) { - txn.put(db, - format!("key{}", i).as_bytes(), - format!("val{}", i).as_bytes(), - WriteFlags::empty()) - .unwrap(); - } - txn.commit().unwrap(); - } - (dir, env) - } - /// Benchmark of iterator sequential read performance. #[bench] - fn bench_seq_iter(b: &mut Bencher) { + fn bench_get_seq_iter(b: &mut Bencher) { let n = 100; let (_dir, env) = setup_bench_db(n); let db = env.open_db(None).unwrap(); @@ -415,7 +397,7 @@ mod test { /// Benchmark of cursor sequential read performance. #[bench] - fn bench_seq_cursor(b: &mut Bencher) { + fn bench_get_seq_cursor(b: &mut Bencher) { let n = 100; let (_dir, env) = setup_bench_db(n); let db = env.open_db(None).unwrap(); @@ -438,7 +420,7 @@ mod test { /// Benchmark of raw LMDB sequential read performance (control). #[bench] - fn bench_seq_raw(b: &mut Bencher) { + fn bench_get_seq_raw(b: &mut Bencher) { let n = 100; let (_dir, env) = setup_bench_db(n); let db = env.open_db(None).unwrap(); diff --git a/src/lib.rs b/src/lib.rs index d4aea2d..6b0e852 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,7 +17,15 @@ pub use cursor::Cursor; pub use database::Database; pub use environment::{Environment, EnvironmentBuilder}; pub use error::{LmdbResult, LmdbError}; -pub use transaction::{ReadTransaction, WriteTransaction, RoTransaction, RwTransaction}; +pub use transaction::{ + ReadTransaction, + RoTransaction, + RwTransaction, + Transaction, + TransactionExt, + WriteTransaction, +}; +pub use ffi::{DatabaseFlags, EnvironmentFlags, WriteFlags}; macro_rules! lmdb_try { ($expr:expr) => ({ @@ -45,3 +53,38 @@ mod database; mod environment; mod error; mod transaction; + +#[cfg(test)] +mod test_utils { + + use std::io; + + use super::*; + + pub fn get_key(n: u32) -> String { + format!("key{}", n) + } + + pub fn get_data(n: u32) -> String { + format!("data{}", n) + } + + pub fn setup_bench_db<'a>(num_rows: u32) -> (io::TempDir, Environment) { + let dir = io::TempDir::new("test").unwrap(); + let env = Environment::new().open(dir.path(), io::USER_RWX).unwrap(); + + { + let db = env.open_db(None).unwrap(); + let mut txn = env.begin_write_txn().unwrap(); + for i in range(0, num_rows) { + txn.put(db, + get_key(i).as_bytes(), + get_data(i).as_bytes(), + WriteFlags::empty()) + .unwrap(); + } + txn.commit().unwrap(); + } + (dir, env) + } +} diff --git a/src/transaction.rs b/src/transaction.rs index ad996b0..5b28694 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -71,7 +71,6 @@ pub trait ReadTransaction<'env> : Transaction<'env> { len: data_val.mv_size as uint }); Ok(Some(slice)) - } else if err_code == ffi::MDB_NOTFOUND { Ok(None) } else { @@ -91,7 +90,6 @@ pub trait ReadTransaction<'env> : Transaction<'env> { unsafe { try!(lmdb_result(ffi::mdb_dbi_flags(self.txn(), db.dbi(), &mut flags))); } - Ok(DatabaseFlags::from_bits_truncate(flags)) } } @@ -153,7 +151,6 @@ pub trait WriteTransaction<'env> : ReadTransaction<'env> { data: data_val.mv_data as *const u8, len: data_val.mv_size as uint }); - Ok(BufWriter::new(slice)) } } @@ -282,13 +279,17 @@ impl <'env> WriteTransaction<'env> for RwTransaction<'env> { } #[cfg(test)] mod test { + use libc::{c_uint, c_void, size_t}; use std::io; + use std::ptr; + use std::rand::{Rng, XorShiftRng}; use std::sync::{Arc, Barrier, Future}; + use test::{Bencher, black_box}; use environment::*; use ffi::*; use super::*; - + use test_utils::*; #[test] fn test_put_get_del() { @@ -442,4 +443,112 @@ mod test { txn.get(db, format!("{}{}", key, i).as_bytes()).unwrap().unwrap()); } } + + #[bench] + fn bench_get_rand(b: &mut Bencher) { + let n = 100u32; + let (_dir, env) = setup_bench_db(n); + let db = env.open_db(None).unwrap(); + let txn = env.begin_read_txn().unwrap(); + + let mut keys: Vec = range(0, n).map(|n| get_key(n)) + .collect::>(); + XorShiftRng::new_unseeded().shuffle(keys.as_mut_slice()); + + b.iter(|| { + let mut i = 0u; + for key in keys.iter() { + i = i + txn.get(db, key.as_bytes()).unwrap().unwrap().len(); + } + black_box(i); + }); + } + + #[bench] + fn bench_get_rand_raw(b: &mut Bencher) { + let n = 100u32; + let (_dir, env) = setup_bench_db(n); + let db = env.open_db(None).unwrap(); + let _txn = env.begin_read_txn().unwrap(); + + let mut keys: Vec = range(0, n).map(|n| get_key(n)) + .collect::>(); + XorShiftRng::new_unseeded().shuffle(keys.as_mut_slice()); + + let dbi = db.dbi(); + let txn = _txn.txn(); + + let mut key_val: MDB_val = MDB_val { mv_size: 0, mv_data: ptr::null_mut() }; + let mut data_val: MDB_val = MDB_val { mv_size: 0, mv_data: ptr::null_mut() }; + + b.iter(|| unsafe { + let mut i = 0u64; + for key in keys.iter() { + key_val.mv_size = key.len() as u64; + key_val.mv_data = key.as_bytes().as_ptr() as *mut _; + + mdb_get(txn, dbi, &mut key_val, &mut data_val); + + i = i + key_val.mv_size; + } + black_box(i); + }); + } + + #[bench] + fn bench_put_rand(b: &mut Bencher) { + let n = 100u32; + let (_dir, env) = setup_bench_db(0); + let db = env.open_db(None).unwrap(); + + let mut items: Vec<(String, String)> = range(0, n).map(|n| (get_key(n), get_data(n))) + .collect::>(); + XorShiftRng::new_unseeded().shuffle(items.as_mut_slice()); + + b.iter(|| { + // TODO: change this to just a transaction renew, instead of a new transaction + let mut txn = env.begin_write_txn().unwrap(); + let mut i = 0u; + for &(ref key, ref data) in items.iter() { + txn.put(db, key.as_bytes(), data.as_bytes(), WriteFlags::empty()).unwrap(); + } + txn.abort(); + }); + } + + #[bench] + fn bench_put_rand_raw(b: &mut Bencher) { + let n = 100u32; + let (_dir, _env) = setup_bench_db(0); + let db = _env.open_db(None).unwrap(); + + let mut items: Vec<(String, String)> = range(0, n).map(|n| (get_key(n), get_data(n))) + .collect::>(); + XorShiftRng::new_unseeded().shuffle(items.as_mut_slice()); + + let dbi = db.dbi(); + let env = _env.env(); + + let mut key_val: MDB_val = MDB_val { mv_size: 0, mv_data: ptr::null_mut() }; + let mut data_val: MDB_val = MDB_val { mv_size: 0, mv_data: ptr::null_mut() }; + + b.iter(|| unsafe { + // TODO: change this to just a transaction renew, instead of a new transaction + let mut txn: *mut MDB_txn = ptr::null_mut(); + mdb_txn_begin(env, ptr::null_mut(), 0, &mut txn); + + let mut i = 0i32; + for &(ref key, ref data) in items.iter() { + + key_val.mv_size = key.len() as u64; + key_val.mv_data = key.as_bytes().as_ptr() as *mut _; + data_val.mv_size = data.len() as u64; + data_val.mv_data = data.as_bytes().as_ptr() as *mut _; + + i += mdb_put(txn, dbi, &mut key_val, &mut data_val, 0); + } + assert_eq!(0, i); + mdb_txn_abort(txn); + }); + } }