From b4f5f53e9df146b7ee05eb6808ca9d2d59a419fa Mon Sep 17 00:00:00 2001 From: Nan Jiang Date: Thu, 28 Feb 2019 17:18:23 -0500 Subject: [PATCH 1/2] Implement clear for stores --- examples/simple-store.rs | 14 +++++++++ src/env.rs | 62 +++++++++++++++++++++++++++++++++++++++ src/lib.rs | 24 +++++++++++++++ src/readwrite.rs | 4 +++ src/store/integer.rs | 31 ++++++++++++++++++++ src/store/integermulti.rs | 30 +++++++++++++++++++ src/store/multi.rs | 4 +++ src/store/single.rs | 4 +++ 8 files changed, 173 insertions(+) diff --git a/examples/simple-store.rs b/examples/simple-store.rs index bd0b342e..292cfa30 100644 --- a/examples/simple-store.rs +++ b/examples/simple-store.rs @@ -153,6 +153,20 @@ fn main() { // store.put(&mut writer, "baz", &Value::Str("buz")).unwrap(); } + println!("Clearing store..."); + { + // Clearing a store deletes all the entries in that store + let mut writer = k.write().unwrap(); + store.put(&mut writer, "foo", &Value::Str("bar")).unwrap(); + store.put(&mut writer, "bar", &Value::Str("baz")).unwrap(); + store.clear(&mut writer).unwrap(); + writer.commit().unwrap(); + + let reader = k.read().expect("reader"); + println!("It should be None! ({:?})", store.get(&reader, "foo").unwrap()); + println!("It should be None! ({:?})", store.get(&reader, "bar").unwrap()); + } + println!("Write and read on multiple stores..."); { let another_store = k.open_single("another_store", StoreOptions::create()).unwrap(); diff --git a/src/env.rs b/src/env.rs index 377649ef..2bfe8228 100644 --- a/src/env.rs +++ b/src/env.rs @@ -454,6 +454,35 @@ mod tests { } } + #[test] + fn test_single_store_clear() { + let root = Builder::new().prefix("test_single_store_clear").tempdir().expect("tempdir"); + fs::create_dir_all(root.path()).expect("dir created"); + let k = Rkv::new(root.path()).expect("new succeeded"); + + let sk: SingleStore = k.open_single("sk", StoreOptions::create()).expect("opened"); + + { + let mut writer = k.write().expect("writer"); + sk.put(&mut writer, "foo", &Value::I64(1234)).expect("wrote"); + sk.put(&mut writer, "bar", &Value::Bool(true)).expect("wrote"); + sk.put(&mut writer, "baz", &Value::Str("héllo, yöu")).expect("wrote"); + writer.commit().expect("committed"); + } + + { + let mut writer = k.write().expect("writer"); + sk.clear(&mut writer).expect("cleared"); + writer.commit().expect("committed"); + } + + { + let r = k.read().unwrap(); + let iter = sk.iter_start(&r).expect("iter"); + assert_eq!(iter.count(), 0); + } + } + #[test] fn test_multi_put_get_del() { let root = Builder::new().prefix("test_multi_put_get_del").tempdir().expect("tempdir"); @@ -490,6 +519,39 @@ mod tests { writer.commit().unwrap(); } + #[test] + fn test_multiple_store_clear() { + let root = Builder::new().prefix("test_multiple_store_clear").tempdir().expect("tempdir"); + fs::create_dir_all(root.path()).expect("dir created"); + let k = Rkv::new(root.path()).expect("new succeeded"); + + let multistore = k.open_multi("multistore", StoreOptions::create()).expect("opened"); + + { + let mut writer = k.write().expect("writer"); + multistore.put(&mut writer, "str1", &Value::Str("str1 foo")).unwrap(); + multistore.put(&mut writer, "str1", &Value::Str("str1 bar")).unwrap(); + multistore.put(&mut writer, "str2", &Value::Str("str2 foo")).unwrap(); + multistore.put(&mut writer, "str2", &Value::Str("str2 bar")).unwrap(); + multistore.put(&mut writer, "str3", &Value::Str("str3 foo")).unwrap(); + multistore.put(&mut writer, "str3", &Value::Str("str3 bar")).unwrap(); + writer.commit().expect("committed"); + } + + { + let mut writer = k.write().expect("writer"); + multistore.clear(&mut writer).expect("cleared"); + writer.commit().expect("committed"); + } + + { + let r = k.read().unwrap(); + assert_eq!(multistore.get_first(&r, "str1").expect("read"), None); + assert_eq!(multistore.get_first(&r, "str2").expect("read"), None); + assert_eq!(multistore.get_first(&r, "str3").expect("read"), None); + } + } + #[test] fn test_open_store_for_read() { let root = Builder::new().prefix("test_open_store_for_read").tempdir().expect("tempdir"); diff --git a/src/lib.rs b/src/lib.rs index 35a4bfd3..7a675442 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -171,6 +171,30 @@ //! // This line would report error[E0382]: borrow of moved value: `writer`. //! // store.put(&mut writer, "baz", &Value::Str("buz")).unwrap(); //! } +//! +//! { +//! // Clearing all the entries in the store with a write transaction. +//! { +//! let mut writer = env.write().unwrap(); +//! store.put(&mut writer, "foo", &Value::Str("bar")).unwrap(); +//! store.put(&mut writer, "bar", &Value::Str("baz")).unwrap(); +//! writer.commit().unwrap(); +//! } +//! +//! { +//! let mut writer = env.write().unwrap(); +//! store.clear(&mut writer).unwrap(); +//! writer.commit().unwrap(); +//! } +//! +//! { +//! let reader = env.read().expect("reader"); +//! println!("It should be None! ({:?})", store.get(&reader, "foo").unwrap()); +//! println!("It should be None! ({:?})", store.get(&reader, "bar").unwrap()); +//! } +//! +//! } +//! //! ``` #![allow(dead_code)] diff --git a/src/readwrite.rs b/src/readwrite.rs index 8bdc9674..f78c0284 100644 --- a/src/readwrite.rs +++ b/src/readwrite.rs @@ -88,4 +88,8 @@ impl<'env> Writer<'env> { pub(crate) fn delete>(&mut self, db: Database, k: &K, v: Option<&[u8]>) -> Result<(), StoreError> { self.0.del(db, &k, v).map_err(StoreError::LmdbError) } + + pub(crate) fn clear(&mut self, db: Database) -> Result<(), StoreError> { + self.0.clear_db(db).map_err(StoreError::LmdbError) + } } diff --git a/src/store/integer.rs b/src/store/integer.rs index ab3bd99c..bcf97ba7 100644 --- a/src/store/integer.rs +++ b/src/store/integer.rs @@ -105,6 +105,10 @@ where pub fn delete(&self, writer: &mut Writer, k: K) -> Result<(), StoreError> { self.inner.delete(writer, Key::new(&k)?) } + + pub fn clear(&self, writer: &mut Writer) -> Result<(), StoreError> { + self.inner.clear(writer) + } } #[cfg(test)] @@ -138,4 +142,31 @@ mod tests { test_integer_keys!(u32, std::u32::MIN); test_integer_keys!(u32, std::u32::MAX); } + + #[test] + fn test_clear() { + let root = Builder::new().prefix("test_integer_clear").tempdir().expect("tempdir"); + fs::create_dir_all(root.path()).expect("dir created"); + let k = Rkv::new(root.path()).expect("new succeeded"); + let s = k.open_integer("s", StoreOptions::create()).expect("open"); + + { + let mut writer = k.write().expect("writer"); + s.put(&mut writer, 1, &Value::Str("hello!")).expect("write"); + s.put(&mut writer, 2, &Value::Str("hello!")).expect("write"); + s.put(&mut writer, 3, &Value::Str("hello!")).expect("write"); + writer.commit().expect("committed"); + } + + { + let mut writer = k.write().expect("writer"); + s.clear(&mut writer).expect("cleared"); + writer.commit().expect("committed"); + + let reader = k.read().expect("reader"); + assert_eq!(s.get(&reader, 1).expect("read"), None); + assert_eq!(s.get(&reader, 2).expect("read"), None); + assert_eq!(s.get(&reader, 3).expect("read"), None); + } + } } diff --git a/src/store/integermulti.rs b/src/store/integermulti.rs index 16c568be..9ce1cd45 100644 --- a/src/store/integermulti.rs +++ b/src/store/integermulti.rs @@ -76,6 +76,10 @@ where pub fn delete(&self, writer: &mut Writer, k: K, v: &Value) -> Result<(), StoreError> { self.inner.delete(writer, Key::new(&k)?, v) } + + pub fn clear(&self, writer: &mut Writer) -> Result<(), StoreError> { + self.inner.clear(writer) + } } #[cfg(test)] @@ -111,4 +115,30 @@ mod tests { test_integer_keys!(u32, std::u32::MIN); test_integer_keys!(u32, std::u32::MAX); } + + #[test] + fn test_clear() { + let root = Builder::new().prefix("test_multi_integer_clear").tempdir().expect("tempdir"); + fs::create_dir_all(root.path()).expect("dir created"); + let k = Rkv::new(root.path()).expect("new succeeded"); + let s = k.open_multi_integer("s", StoreOptions::create()).expect("open"); + + { + let mut writer = k.write().expect("writer"); + s.put(&mut writer, 1, &Value::Str("hello!")).expect("write"); + s.put(&mut writer, 1, &Value::Str("hello1!")).expect("write"); + s.put(&mut writer, 2, &Value::Str("hello!")).expect("write"); + writer.commit().expect("committed"); + } + + { + let mut writer = k.write().expect("writer"); + s.clear(&mut writer).expect("cleared"); + writer.commit().expect("committed"); + + let reader = k.read().expect("reader"); + assert_eq!(s.get_first(&reader, 1).expect("read"), None); + assert_eq!(s.get_first(&reader, 2).expect("read"), None); + } + } } diff --git a/src/store/multi.rs b/src/store/multi.rs index 4c77e708..6ee5eba8 100644 --- a/src/store/multi.rs +++ b/src/store/multi.rs @@ -105,6 +105,10 @@ impl MultiStore { }) } */ + + pub fn clear(self, writer: &mut Writer) -> Result<(), StoreError> { + writer.clear(self.db) + } } /* diff --git a/src/store/single.rs b/src/store/single.rs index ef004f9b..f5fe42b0 100644 --- a/src/store/single.rs +++ b/src/store/single.rs @@ -82,6 +82,10 @@ impl SingleStore { cursor, }) } + + pub fn clear(self, writer: &mut Writer) -> Result<(), StoreError> { + writer.clear(self.db) + } } impl<'env> Iterator for Iter<'env> { From 798b13e74d40f97cca2c4f263f5532ba6069882f Mon Sep 17 00:00:00 2001 From: Nan Jiang Date: Fri, 1 Mar 2019 18:43:29 -0500 Subject: [PATCH 2/2] Clippy fixes --- src/env.rs | 6 +++--- src/store/integer.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/env.rs b/src/env.rs index 2bfe8228..defa6d4d 100644 --- a/src/env.rs +++ b/src/env.rs @@ -194,12 +194,12 @@ impl Rkv { /// Otherwise if the environment has the `NO_SYNC` flag set the flushes will be omitted, /// and with `MAP_ASYNC` they will be asynchronous. pub fn sync(&self, force: bool) -> Result<(), StoreError> { - self.env.sync(force).map_err(|e| e.into()) + self.env.sync(force).map_err(Into::into) } /// Retrieves statistics about this environment. pub fn stat(&self) -> Result { - self.env.stat().map_err(|e| e.into()) + self.env.stat().map_err(Into::into) } } @@ -592,7 +592,7 @@ mod tests { // Open the same store for read while the reader is in progress will panic let store: Result = k.open_single("sk", StoreOptions::default()); match store { - Err(StoreError::OpenAttemptedDuringTransaction(_thread_id)) => assert!(true), + Err(StoreError::OpenAttemptedDuringTransaction(_thread_id)) => (), _ => panic!("should panic"), } } diff --git a/src/store/integer.rs b/src/store/integer.rs index bcf97ba7..32f1e685 100644 --- a/src/store/integer.rs +++ b/src/store/integer.rs @@ -44,7 +44,7 @@ where { fn to_bytes(&self) -> Result, DataError> { serialize(self) // TODO: limited key length. - .map_err(|e| e.into()) + .map_err(Into::into) } }