diff --git a/src/environment.rs b/src/environment.rs index dc0f96a..e31d9f1 100644 --- a/src/environment.rs +++ b/src/environment.rs @@ -161,8 +161,8 @@ impl Environment { /// Retrieves statistics about this environment. pub fn stat(&self) -> Result { unsafe { - let mut stat = Stat(mem::zeroed()); - lmdb_try!(ffi::mdb_env_stat(self.env(), &mut stat.0)); + let mut stat = Stat::new(); + lmdb_try!(ffi::mdb_env_stat(self.env(), stat.mdb_stat())); Ok(stat) } } @@ -247,9 +247,23 @@ impl Environment { /// Environment statistics. /// -/// Contains information about the size and layout of an LMDB environment. +/// Contains information about the size and layout of an LMDB environment or database. pub struct Stat(ffi::MDB_stat); +impl Stat { + /// Create a new Stat with zero'd inner struct `ffi::MDB_stat`. + pub(crate) fn new() -> Stat { + unsafe { + Stat(mem::zeroed()) + } + } + + /// Returns a mut pointer to `ffi::MDB_stat`. + pub(crate) fn mdb_stat(&mut self) -> *mut ffi::MDB_stat { + &mut self.0 + } +} + impl Stat { /// Size of a database page. This is the same for all databases in the environment. #[inline] diff --git a/src/transaction.rs b/src/transaction.rs index 16804d3..78175b1 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -5,7 +5,7 @@ use std::marker::PhantomData ; use ffi; use cursor::{RoCursor, RwCursor}; -use environment::Environment; +use environment::{Environment, Stat}; use database::Database; use error::{Error, Result, lmdb_result}; use flags::{DatabaseFlags, EnvironmentFlags, WriteFlags}; @@ -102,6 +102,15 @@ pub trait Transaction : Sized { } Ok(DatabaseFlags::from_bits_truncate(flags)) } + + /// Retrieves database statistics. + fn stat(&self, db: Database) -> Result { + unsafe { + let mut stat = Stat::new(); + lmdb_try!(ffi::mdb_stat(self.txn(), db.dbi(), stat.mdb_stat())); + Ok(stat) + } + } } /// An LMDB read-only transaction. @@ -654,6 +663,96 @@ mod test { } } + #[test] + fn test_stat() { + let dir = TempDir::new("test").unwrap(); + let env = Environment::new().open(dir.path()).unwrap(); + let db = env.create_db(None, DatabaseFlags::empty()).unwrap(); + + let mut txn = env.begin_rw_txn().unwrap(); + txn.put(db, b"key1", b"val1", WriteFlags::empty()).unwrap(); + txn.put(db, b"key2", b"val2", WriteFlags::empty()).unwrap(); + txn.put(db, b"key3", b"val3", WriteFlags::empty()).unwrap(); + txn.commit().unwrap(); + + { + let txn = env.begin_ro_txn().unwrap(); + let stat = txn.stat(db).unwrap(); + assert_eq!(stat.entries(), 3); + } + + let mut txn = env.begin_rw_txn().unwrap(); + txn.del(db, b"key1", None).unwrap(); + txn.del(db, b"key2", None).unwrap(); + txn.commit().unwrap(); + + { + let txn = env.begin_ro_txn().unwrap(); + let stat = txn.stat(db).unwrap(); + assert_eq!(stat.entries(), 1); + } + + let mut txn = env.begin_rw_txn().unwrap(); + txn.put(db, b"key4", b"val4", WriteFlags::empty()).unwrap(); + txn.put(db, b"key5", b"val5", WriteFlags::empty()).unwrap(); + txn.put(db, b"key6", b"val6", WriteFlags::empty()).unwrap(); + txn.commit().unwrap(); + + { + let txn = env.begin_ro_txn().unwrap(); + let stat = txn.stat(db).unwrap(); + assert_eq!(stat.entries(), 4); + } + } + + #[test] + fn test_stat_dupsort() { + let dir = TempDir::new("test").unwrap(); + let env = Environment::new().open(dir.path()).unwrap(); + let db = env.create_db(None, DatabaseFlags::DUP_SORT).unwrap(); + + let mut txn = env.begin_rw_txn().unwrap(); + txn.put(db, b"key1", b"val1", WriteFlags::empty()).unwrap(); + txn.put(db, b"key1", b"val2", WriteFlags::empty()).unwrap(); + txn.put(db, b"key1", b"val3", WriteFlags::empty()).unwrap(); + txn.put(db, b"key2", b"val1", WriteFlags::empty()).unwrap(); + txn.put(db, b"key2", b"val2", WriteFlags::empty()).unwrap(); + txn.put(db, b"key2", b"val3", WriteFlags::empty()).unwrap(); + txn.put(db, b"key3", b"val1", WriteFlags::empty()).unwrap(); + txn.put(db, b"key3", b"val2", WriteFlags::empty()).unwrap(); + txn.put(db, b"key3", b"val3", WriteFlags::empty()).unwrap(); + txn.commit().unwrap(); + + { + let txn = env.begin_ro_txn().unwrap(); + let stat = txn.stat(db).unwrap(); + assert_eq!(stat.entries(), 9); + } + + let mut txn = env.begin_rw_txn().unwrap(); + txn.del(db, b"key1", Some(b"val2")).unwrap(); + txn.del(db, b"key2", None).unwrap(); + txn.commit().unwrap(); + + { + let txn = env.begin_ro_txn().unwrap(); + let stat = txn.stat(db).unwrap(); + assert_eq!(stat.entries(), 5); + } + + let mut txn = env.begin_rw_txn().unwrap(); + txn.put(db, b"key4", b"val1", WriteFlags::empty()).unwrap(); + txn.put(db, b"key4", b"val2", WriteFlags::empty()).unwrap(); + txn.put(db, b"key4", b"val3", WriteFlags::empty()).unwrap(); + txn.commit().unwrap(); + + { + let txn = env.begin_ro_txn().unwrap(); + let stat = txn.stat(db).unwrap(); + assert_eq!(stat.entries(), 8); + } + } + #[bench] fn bench_get_rand(b: &mut Bencher) { let n = 100u32;