From 8599e4051ebe152e77795635e95b601d6e9815c2 Mon Sep 17 00:00:00 2001 From: Rick Richardson Date: Sun, 2 Dec 2018 19:04:14 -0800 Subject: [PATCH 1/3] added test for deleting values from an iter_dup db --- src/cursor.rs | 4 ++-- src/transaction.rs | 56 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/src/cursor.rs b/src/cursor.rs index f50eef4..7042524 100644 --- a/src/cursor.rs +++ b/src/cursor.rs @@ -80,7 +80,7 @@ pub trait Cursor<'txn> { /// Iterate over duplicate items in the database starting from the given /// key. Each item will be returned as an iterator of its duplicates. - fn iter_dup_from(&mut self, key: &K) -> IterDup<'txn> where K: AsRef<[u8]> { + fn iter_dup_from(&mut self, key: K) -> IterDup<'txn> where K: AsRef<[u8]> { match self.get(Some(key.as_ref()), None, ffi::MDB_SET_RANGE) { Ok(_) | Err(Error::NotFound) => (), Err(error) => panic!("mdb_cursor_get returned an unexpected error: {}", error), @@ -89,7 +89,7 @@ pub trait Cursor<'txn> { } /// Iterate over the duplicates of the item in the database with the given key. - fn iter_dup_of(&mut self, key: &K) -> Iter<'txn> where K: AsRef<[u8]> { + fn iter_dup_of(&mut self, key: K) -> Iter<'txn> where K: AsRef<[u8]> { match self.get(Some(key.as_ref()), None, ffi::MDB_SET) { Ok(_) | Err(Error::NotFound) => (), Err(error) => panic!("mdb_cursor_get returned an unexpected error: {}", error), diff --git a/src/transaction.rs b/src/transaction.rs index 590fd9f..ed7fe46 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -275,6 +275,11 @@ impl <'env> RwTransaction<'env> { mv_data: key.as_ptr() as *mut c_void }; let mut data_val: ffi::MDB_val = ffi::MDB_val { mv_size: data.len() as size_t, mv_data: data.as_ptr() as *mut c_void }; + /* + unsafe { println!("put {:?} {:?}", + std::slice::from_raw_parts(key_val.mv_data as *const u8, key_val.mv_size), + std::slice::from_raw_parts(data_val.mv_data as *const u8, data_val.mv_size)) }; + */ unsafe { lmdb_result(ffi::mdb_put(self.txn(), database.dbi(), @@ -332,6 +337,13 @@ impl <'env> RwTransaction<'env> { let data_val: Option = data.map(|data| ffi::MDB_val { mv_size: data.len() as size_t, mv_data: data.as_ptr() as *mut c_void }); + + /* + data_val.as_ref().map(|v| unsafe { + println!("del {:?} {:?}", + std::slice::from_raw_parts(key_val.mv_data as *const u8, key_val.mv_size), + std::slice::from_raw_parts(v.mv_data as *const u8, v.mv_size)) }); + */ unsafe { lmdb_result(ffi::mdb_del(self.txn(), database.dbi(), @@ -392,6 +404,7 @@ mod test { use flags::*; use super::*; use test_utils::*; + use cursor::Cursor; #[test] fn test_put_get_del() { @@ -414,6 +427,49 @@ mod test { txn.del(db, b"key1", None).unwrap(); assert_eq!(txn.get(db, b"key1"), Err(Error::NotFound)); } + + #[test] + fn test_put_get_del_multi() { + let dir = TempDir::new("test").unwrap(); + let env = Environment::new().open(dir.path()).unwrap(); + let db = env.create_db(Some("putgetdel"), 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_rw_txn().unwrap(); + { + let mut cur = txn.open_ro_cursor(db).unwrap(); + let iter = cur.iter_dup_of(b"key1"); + let vals = iter.map(|(_,x)| x).collect::>(); + assert_eq!(vals, vec![b"val1", b"val2", b"val3"]); + + } + txn.commit().unwrap(); + + let mut txn = env.begin_rw_txn().unwrap(); + txn.del(db, b"key1", Some(b"val2")).unwrap(); + txn.commit().unwrap(); + + let txn = env.begin_rw_txn().unwrap(); + { + let mut cur = txn.open_ro_cursor(db).unwrap(); + let iter = cur.iter_dup_of(b"key1"); + let vals = iter.map(|(_,x)| x).collect::>(); + assert_eq!(vals, vec![b"val1", b"val3"]); + } + txn.commit().unwrap(); + } + #[test] fn test_reserve() { From 5aa123cdbc06ba498ece32f3d3b579ae94dec173 Mon Sep 17 00:00:00 2001 From: Rick Richardson Date: Sun, 2 Dec 2018 19:28:13 -0800 Subject: [PATCH 2/3] updated Transaction::del. Fixes #17 --- src/transaction.rs | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/src/transaction.rs b/src/transaction.rs index ed7fe46..daae8e8 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -275,11 +275,6 @@ impl <'env> RwTransaction<'env> { mv_data: key.as_ptr() as *mut c_void }; let mut data_val: ffi::MDB_val = ffi::MDB_val { mv_size: data.len() as size_t, mv_data: data.as_ptr() as *mut c_void }; - /* - unsafe { println!("put {:?} {:?}", - std::slice::from_raw_parts(key_val.mv_data as *const u8, key_val.mv_size), - std::slice::from_raw_parts(data_val.mv_data as *const u8, data_val.mv_size)) }; - */ unsafe { lmdb_result(ffi::mdb_put(self.txn(), database.dbi(), @@ -338,18 +333,21 @@ impl <'env> RwTransaction<'env> { data.map(|data| ffi::MDB_val { mv_size: data.len() as size_t, mv_data: data.as_ptr() as *mut c_void }); - /* - data_val.as_ref().map(|v| unsafe { - println!("del {:?} {:?}", - std::slice::from_raw_parts(key_val.mv_data as *const u8, key_val.mv_size), - std::slice::from_raw_parts(v.mv_data as *const u8, v.mv_size)) }); - */ - unsafe { - lmdb_result(ffi::mdb_del(self.txn(), - database.dbi(), - &mut key_val, - data_val.map(|mut data_val| &mut data_val as *mut _) - .unwrap_or(ptr::null_mut()))) + if let Some(mut d) = data_val { + unsafe { + lmdb_result(ffi::mdb_del(self.txn(), + database.dbi(), + &mut key_val, + &mut d)) + + } + } else { + unsafe { + lmdb_result(ffi::mdb_del(self.txn(), + database.dbi(), + &mut key_val, + ptr::null_mut())) + } } } @@ -432,7 +430,7 @@ mod test { fn test_put_get_del_multi() { let dir = TempDir::new("test").unwrap(); let env = Environment::new().open(dir.path()).unwrap(); - let db = env.create_db(Some("putgetdel"), DatabaseFlags::DUP_SORT).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(); From 8ff1b47e26a704e90b4549a7da451afc78439c34 Mon Sep 17 00:00:00 2001 From: Rick Richardson Date: Mon, 3 Dec 2018 18:43:15 -0800 Subject: [PATCH 3/3] verifying that None passed to del in ITER_DUP dbs will delete all matching keys --- src/transaction.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/transaction.rs b/src/transaction.rs index daae8e8..8dc29b2 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -456,6 +456,7 @@ mod test { 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_rw_txn().unwrap(); @@ -464,6 +465,9 @@ mod test { let iter = cur.iter_dup_of(b"key1"); let vals = iter.map(|(_,x)| x).collect::>(); assert_eq!(vals, vec![b"val1", b"val3"]); + + let iter = cur.iter_dup_of(b"key2"); + assert_eq!(0, iter.count()); } txn.commit().unwrap(); }