More idiomatic iterators

master
Pete Hunt 9 years ago
parent f5d4d834b7
commit 09250315e8
  1. 2
      src/lib.rs
  2. 137
      src/rocksdb.rs
  3. 38
      test/test_iterator.rs

@ -15,7 +15,7 @@
// //
pub use ffi as rocksdb_ffi; pub use ffi as rocksdb_ffi;
pub use ffi::{DBCompactionStyle, DBComparator, new_bloom_filter}; pub use ffi::{DBCompactionStyle, DBComparator, new_bloom_filter};
pub use rocksdb::{DB, DBIterator, DBVector, Direction, SubDBIterator, Writable, WriteBatch}; pub use rocksdb::{DB, DBIterator, DBVector, Direction, Writable, WriteBatch, IteratorMode};
pub use rocksdb_options::{BlockBasedOptions, Options}; pub use rocksdb_options::{BlockBasedOptions, Options};
pub use merge_operator::MergeOperands; pub use merge_operator::MergeOperands;
pub mod rocksdb; pub mod rocksdb;

@ -51,9 +51,8 @@ pub struct Snapshot<'a> {
inner: rocksdb_ffi::DBSnapshot, inner: rocksdb_ffi::DBSnapshot,
} }
pub struct DBIterator { pub struct DBIterator<'a> {
// TODO: should have a reference to DB to enforce scope, but it's trickier than I db: &'a DB,
// thought to add
inner: rocksdb_ffi::DBIterator, inner: rocksdb_ffi::DBIterator,
direction: Direction, direction: Direction,
just_seeked: bool, just_seeked: bool,
@ -64,23 +63,18 @@ pub enum Direction {
reverse, reverse,
} }
pub struct SubDBIterator<'a> { impl<'a> Iterator for DBIterator<'a> {
iter: &'a mut DBIterator,
direction: Direction,
}
impl <'a> Iterator for SubDBIterator<'a> {
type Item = (Box<[u8]>, Box<[u8]>); type Item = (Box<[u8]>, Box<[u8]>);
fn next(&mut self) -> Option<(Box<[u8]>, Box<[u8]>)> { fn next(&mut self) -> Option<(Box<[u8]>, Box<[u8]>)> {
let native_iter = self.iter.inner; let native_iter = self.inner;
if !self.iter.just_seeked { if !self.just_seeked {
match self.direction { match self.direction {
Direction::forward => unsafe { rocksdb_ffi::rocksdb_iter_next(native_iter) }, Direction::forward => unsafe { rocksdb_ffi::rocksdb_iter_next(native_iter) },
Direction::reverse => unsafe { rocksdb_ffi::rocksdb_iter_prev(native_iter) }, Direction::reverse => unsafe { rocksdb_ffi::rocksdb_iter_prev(native_iter) },
} }
} else { } else {
self.iter.just_seeked = false; self.just_seeked = false;
} }
if unsafe { rocksdb_ffi::rocksdb_iter_valid(native_iter) } { if unsafe { rocksdb_ffi::rocksdb_iter_valid(native_iter) } {
let mut key_len: size_t = 0; let mut key_len: size_t = 0;
@ -108,77 +102,80 @@ impl <'a> Iterator for SubDBIterator<'a> {
} }
} }
impl DBIterator { pub enum IteratorMode<'a> {
// TODO alias db & opts to different lifetimes, and DBIterator to the db's Start,
// lifetime End,
fn new(db: &DB, readopts: &ReadOptions) -> DBIterator { From(&'a [u8], Direction),
}
impl<'a> DBIterator<'a> {
fn new<'b>(db: &'a DB, readopts: &'b ReadOptions, mode: IteratorMode) -> DBIterator<'a> {
unsafe { unsafe {
let iterator = rocksdb_ffi::rocksdb_create_iterator(db.inner, let iterator = rocksdb_ffi::rocksdb_create_iterator(db.inner,
readopts.inner); readopts.inner);
rocksdb_ffi::rocksdb_iter_seek_to_first(iterator);
DBIterator { let mut rv = DBIterator {
db: db,
inner: iterator, inner: iterator,
direction: Direction::forward, direction: Direction::forward, // blown away by set_mode()
just_seeked: true, just_seeked: false,
};
rv.set_mode(mode);
rv
} }
} }
pub fn set_mode(&mut self, mode: IteratorMode) {
unsafe {
match mode {
IteratorMode::Start => {
rocksdb_ffi::rocksdb_iter_seek_to_first(self.inner);
self.direction = Direction::forward;
},
IteratorMode::End => {
rocksdb_ffi::rocksdb_iter_seek_to_last(self.inner);
self.direction = Direction::reverse;
},
IteratorMode::From(key, dir) => {
rocksdb_ffi::rocksdb_iter_seek(self.inner,
key.as_ptr(),
key.len() as size_t);
self.direction = dir;
}
};
self.just_seeked = true;
}
} }
fn new_cf(db: &DB, fn new_cf(db: &'a DB,
cf_handle: DBCFHandle, cf_handle: DBCFHandle,
readopts: &ReadOptions) readopts: &ReadOptions,
-> Result<DBIterator, String> { mode: IteratorMode)
-> Result<DBIterator<'a>, String> {
unsafe { unsafe {
let iterator = let iterator =
rocksdb_ffi::rocksdb_create_iterator_cf(db.inner, rocksdb_ffi::rocksdb_create_iterator_cf(db.inner,
readopts.inner, readopts.inner,
cf_handle); cf_handle);
rocksdb_ffi::rocksdb_iter_seek_to_first(iterator);
Ok(DBIterator {
inner: iterator,
direction: Direction::forward,
just_seeked: true,
})
}
}
pub fn from_start(&mut self) -> SubDBIterator { let mut rv = DBIterator {
self.just_seeked = true; db: db,
unsafe { inner: iterator,
rocksdb_ffi::rocksdb_iter_seek_to_first(self.inner); direction: Direction::forward, // blown away by set_mode()
} just_seeked: false,
SubDBIterator { };
iter: self,
direction: Direction::forward,
}
}
pub fn from_end(&mut self) -> SubDBIterator { rv.set_mode(mode);
self.just_seeked = true;
unsafe {
rocksdb_ffi::rocksdb_iter_seek_to_last(self.inner);
}
SubDBIterator {
iter: self,
direction: Direction::reverse,
}
}
pub fn from(&mut self, key: &[u8], dir: Direction) -> SubDBIterator { Ok(rv)
self.just_seeked = true;
unsafe {
rocksdb_ffi::rocksdb_iter_seek(self.inner,
key.as_ptr(),
key.len() as size_t);
}
SubDBIterator {
iter: self,
direction: dir,
} }
} }
} }
impl Drop for DBIterator { impl<'a> Drop for DBIterator<'a> {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
rocksdb_ffi::rocksdb_iter_destroy(self.inner); rocksdb_ffi::rocksdb_iter_destroy(self.inner);
@ -197,10 +194,10 @@ impl <'a> Snapshot<'a> {
} }
} }
pub fn iterator(&self) -> DBIterator { pub fn iterator(&self, mode: IteratorMode) -> DBIterator {
let mut readopts = ReadOptions::new(); let mut readopts = ReadOptions::new();
readopts.set_snapshot(self); readopts.set_snapshot(self);
DBIterator::new(self.db, &readopts) DBIterator::new(self.db, &readopts, mode)
} }
} }
@ -512,14 +509,14 @@ impl DB {
self.cfs.get(name) self.cfs.get(name)
} }
pub fn iterator(&self) -> DBIterator { pub fn iterator(&self, mode: IteratorMode) -> DBIterator {
let opts = ReadOptions::new(); let opts = ReadOptions::new();
DBIterator::new(&self, &opts) DBIterator::new(&self, &opts, mode)
} }
pub fn iterator_cf(&self, cf_handle: DBCFHandle) -> Result<DBIterator, String> { pub fn iterator_cf(&self, cf_handle: DBCFHandle, mode: IteratorMode) -> Result<DBIterator, String> {
let opts = ReadOptions::new(); let opts = ReadOptions::new();
DBIterator::new_cf(&self, cf_handle, &opts) DBIterator::new_cf(&self, cf_handle, &opts, mode)
} }
pub fn snapshot(&self) -> Snapshot { pub fn snapshot(&self) -> Snapshot {
@ -891,8 +888,8 @@ fn iterator_test() {
assert!(p.is_ok()); assert!(p.is_ok());
let p = db.put(b"k3", b"v3333"); let p = db.put(b"k3", b"v3333");
assert!(p.is_ok()); assert!(p.is_ok());
let mut iter = db.iterator(); let mut iter = db.iterator(IteratorMode::Start);
for (k, v) in iter.from_start() { for (k, v) in iter {
println!("Hello {}: {}", println!("Hello {}: {}",
from_utf8(&*k).unwrap(), from_utf8(&*k).unwrap(),
from_utf8(&*v).unwrap()); from_utf8(&*v).unwrap());

@ -1,4 +1,4 @@
use rocksdb::{DB, Direction, Options, Writable}; use rocksdb::{DB, Direction, Options, Writable, IteratorMode};
fn cba(input: &Box<[u8]>) -> Box<[u8]> { fn cba(input: &Box<[u8]>) -> Box<[u8]> {
input.iter().cloned().collect::<Vec<_>>().into_boxed_slice() input.iter().cloned().collect::<Vec<_>>().into_boxed_slice()
@ -23,92 +23,90 @@ pub fn test_iterator() {
assert!(p.is_ok()); assert!(p.is_ok());
let p = db.put(&*k3, &*v3); let p = db.put(&*k3, &*v3);
assert!(p.is_ok()); assert!(p.is_ok());
let mut view1 = db.iterator();
let expected = vec![(cba(&k1), cba(&v1)), let expected = vec![(cba(&k1), cba(&v1)),
(cba(&k2), cba(&v2)), (cba(&k2), cba(&v2)),
(cba(&k3), cba(&v3))]; (cba(&k3), cba(&v3))];
{ {
let iterator1 = view1.from_start(); let iterator1 = db.iterator(IteratorMode::Start);
assert_eq!(iterator1.collect::<Vec<_>>(), expected); assert_eq!(iterator1.collect::<Vec<_>>(), expected);
} }
// Test that it's reusable a few times // Test that it's idempotent
{ {
let iterator1 = view1.from_start(); let iterator1 = db.iterator(IteratorMode::Start);
assert_eq!(iterator1.collect::<Vec<_>>(), expected); assert_eq!(iterator1.collect::<Vec<_>>(), expected);
} }
{ {
let iterator1 = view1.from_start(); let iterator1 = db.iterator(IteratorMode::Start);
assert_eq!(iterator1.collect::<Vec<_>>(), expected); assert_eq!(iterator1.collect::<Vec<_>>(), expected);
} }
{ {
let iterator1 = view1.from_start(); let iterator1 = db.iterator(IteratorMode::Start);
assert_eq!(iterator1.collect::<Vec<_>>(), expected); assert_eq!(iterator1.collect::<Vec<_>>(), expected);
} }
// Test it in reverse a few times // Test it in reverse a few times
{ {
let iterator1 = view1.from_end(); let iterator1 = db.iterator(IteratorMode::End);
let mut tmp_vec = iterator1.collect::<Vec<_>>(); let mut tmp_vec = iterator1.collect::<Vec<_>>();
tmp_vec.reverse(); tmp_vec.reverse();
assert_eq!(tmp_vec, expected); assert_eq!(tmp_vec, expected);
} }
{ {
let iterator1 = view1.from_end(); let iterator1 = db.iterator(IteratorMode::End);
let mut tmp_vec = iterator1.collect::<Vec<_>>(); let mut tmp_vec = iterator1.collect::<Vec<_>>();
tmp_vec.reverse(); tmp_vec.reverse();
assert_eq!(tmp_vec, expected); assert_eq!(tmp_vec, expected);
} }
{ {
let iterator1 = view1.from_end(); let iterator1 = db.iterator(IteratorMode::End);
let mut tmp_vec = iterator1.collect::<Vec<_>>(); let mut tmp_vec = iterator1.collect::<Vec<_>>();
tmp_vec.reverse(); tmp_vec.reverse();
assert_eq!(tmp_vec, expected); assert_eq!(tmp_vec, expected);
} }
{ {
let iterator1 = view1.from_end(); let iterator1 = db.iterator(IteratorMode::End);
let mut tmp_vec = iterator1.collect::<Vec<_>>(); let mut tmp_vec = iterator1.collect::<Vec<_>>();
tmp_vec.reverse(); tmp_vec.reverse();
assert_eq!(tmp_vec, expected); assert_eq!(tmp_vec, expected);
} }
{ {
let iterator1 = view1.from_end(); let iterator1 = db.iterator(IteratorMode::End);
let mut tmp_vec = iterator1.collect::<Vec<_>>(); let mut tmp_vec = iterator1.collect::<Vec<_>>();
tmp_vec.reverse(); tmp_vec.reverse();
assert_eq!(tmp_vec, expected); assert_eq!(tmp_vec, expected);
} }
// Try it forward again // Try it forward again
{ {
let iterator1 = view1.from_start(); let iterator1 = db.iterator(IteratorMode::Start);
assert_eq!(iterator1.collect::<Vec<_>>(), expected); assert_eq!(iterator1.collect::<Vec<_>>(), expected);
} }
{ {
let iterator1 = view1.from_start(); let iterator1 = db.iterator(IteratorMode::Start);
assert_eq!(iterator1.collect::<Vec<_>>(), expected); assert_eq!(iterator1.collect::<Vec<_>>(), expected);
} }
let old_iterator = db.iterator(IteratorMode::Start);
let p = db.put(&*k4, &*v4); let p = db.put(&*k4, &*v4);
assert!(p.is_ok()); assert!(p.is_ok());
let mut view3 = db.iterator();
let expected2 = vec![(cba(&k1), cba(&v1)), let expected2 = vec![(cba(&k1), cba(&v1)),
(cba(&k2), cba(&v2)), (cba(&k2), cba(&v2)),
(cba(&k3), cba(&v3)), (cba(&k3), cba(&v3)),
(cba(&k4), cba(&v4))]; (cba(&k4), cba(&v4))];
{ {
let iterator1 = view1.from_start(); assert_eq!(old_iterator.collect::<Vec<_>>(), expected);
assert_eq!(iterator1.collect::<Vec<_>>(), expected);
} }
{ {
let iterator1 = view3.from_start(); let iterator1 = db.iterator(IteratorMode::Start);
assert_eq!(iterator1.collect::<Vec<_>>(), expected2); assert_eq!(iterator1.collect::<Vec<_>>(), expected2);
} }
{ {
let iterator1 = view3.from(b"k2", Direction::forward); let iterator1 = db.iterator(IteratorMode::From(b"k2", Direction::forward));
let expected = vec![(cba(&k2), cba(&v2)), let expected = vec![(cba(&k2), cba(&v2)),
(cba(&k3), cba(&v3)), (cba(&k3), cba(&v3)),
(cba(&k4), cba(&v4))]; (cba(&k4), cba(&v4))];
assert_eq!(iterator1.collect::<Vec<_>>(), expected); assert_eq!(iterator1.collect::<Vec<_>>(), expected);
} }
{ {
let iterator1 = view3.from(b"k2", Direction::reverse); let iterator1 = db.iterator(IteratorMode::From(b"k2", Direction::reverse));
let expected = vec![(cba(&k2), cba(&v2)), (cba(&k1), cba(&v1))]; let expected = vec![(cba(&k2), cba(&v2)), (cba(&k1), cba(&v1))];
assert_eq!(iterator1.collect::<Vec<_>>(), expected); assert_eq!(iterator1.collect::<Vec<_>>(), expected);
} }

Loading…
Cancel
Save