From 15ad3666f57618a04f84fc1c86325cf0ad5b455d Mon Sep 17 00:00:00 2001 From: Griffin Smith Date: Sun, 19 Nov 2017 13:40:20 -0500 Subject: [PATCH] Allow creating iterators over prefixes Allow creating both db and column family iterators that are specific to a key prefix, by setting the `prefix_same_as_start` read option when creating the iterator. Currently this only supports `Direction::Forward`, but it'd likely be trivial to support `Backward` as well, by incrementing the given prefix by one and seeking to the key before that key. --- src/db.rs | 22 ++++++++++++++++++++++ tests/test_iterator.rs | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/src/db.rs b/src/db.rs index 256f12f..e92bb2f 100644 --- a/src/db.rs +++ b/src/db.rs @@ -872,6 +872,12 @@ impl DB { DBIterator::new(self, &opts, mode) } + pub fn prefix_iterator<'a>(&self, prefix: &'a [u8]) -> DBIterator { + let mut opts = ReadOptions::default(); + opts.set_prefix_same_as_start(true); + DBIterator::new(self, &opts, IteratorMode::From(prefix, Direction::Forward)) + } + pub fn iterator_cf( &self, cf_handle: ColumnFamily, @@ -881,6 +887,16 @@ impl DB { DBIterator::new_cf(self, cf_handle, &opts, mode) } + pub fn prefix_iterator_cf<'a>( + &self, + cf_handle: ColumnFamily, + prefix: &'a [u8] + ) -> Result { + let mut opts = ReadOptions::default(); + opts.set_prefix_same_as_start(true); + DBIterator::new_cf(self, cf_handle, &opts, IteratorMode::From(prefix, Direction::Forward)) + } + pub fn raw_iterator(&self) -> DBRawIterator { let opts = ReadOptions::default(); DBRawIterator::new(self, &opts) @@ -1202,6 +1218,12 @@ impl ReadOptions { ); } } + + pub fn set_prefix_same_as_start(&mut self, v: bool) { + unsafe { + ffi::rocksdb_readoptions_set_prefix_same_as_start(self.inner, v as c_uchar) + } + } } impl Default for ReadOptions { diff --git a/tests/test_iterator.rs b/tests/test_iterator.rs index 4b8a5b2..d80b8ee 100644 --- a/tests/test_iterator.rs +++ b/tests/test_iterator.rs @@ -151,3 +151,35 @@ pub fn test_iterator() { let opts = Options::default(); assert!(DB::destroy(&opts, path).is_ok()); } + +fn key(k: &[u8]) -> Box<[u8]> { k.to_vec().into_boxed_slice() } + +#[test] +pub fn test_prefix_iterator() { + let path = "_rust_rocksdb_prefixiteratortest"; + { + let a1: Box<[u8]> = key(b"aaa1"); + let a2: Box<[u8]> = key(b"aaa2"); + let b1: Box<[u8]> = key(b"bbb1"); + let b2: Box<[u8]> = key(b"bbb2"); + + let db = DB::open_default(path).unwrap(); + + assert!(db.put(&*a1, &*a1).is_ok()); + assert!(db.put(&*a2, &*a2).is_ok()); + assert!(db.put(&*b1, &*b1).is_ok()); + assert!(db.put(&*b2, &*b2).is_ok()); + + { + let expected = vec![(cba(&a1), cba(&a1)), (cba(&a2), cba(&a2))]; + let a_iterator = db.prefix_iterator(b"aaa"); + assert_eq!(a_iterator.collect::>(), expected) + } + + { + let expected = vec![(cba(&b1), cba(&b1)), (cba(&b2), cba(&b2))]; + let b_iterator = db.prefix_iterator(b"bbb"); + assert_eq!(b_iterator.collect::>(), expected) + } + } +}