diff --git a/Cargo.toml b/Cargo.toml index 33aa224..3137ad5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,9 +3,20 @@ name = "rocksdb" description = "A Rust wrapper for Facebook's RocksDB embeddable database." version = "0.0.7" -authors = ["Tyler Neely "] +authors = ["Tyler Neely ", "David Greenberg "] license = "Apache-2.0" +exclude = [ + ".gitignore", + ".travis.yml", + "deploy.sh", + "test/**/*", +] [features] default=[] valgrind=[] + +[[test]] + +name = "test" +path = "test/test.rs" diff --git a/src/main.rs b/src/main.rs index bb084cf..14f0d51 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,85 +20,35 @@ extern crate test; use rocksdb::{Options, RocksDB, MergeOperands, new_bloom_filter, Writable, }; use rocksdb::RocksDBCompactionStyle::RocksDBUniversalCompaction; -fn snapshot_test() { - let path = "_rust_rocksdb_iteratortest"; - { - let mut db = RocksDB::open_default(path).unwrap(); - let p = db.put(b"k1", b"v1111"); - assert!(p.is_ok()); - let p = db.put(b"k2", b"v2222"); - assert!(p.is_ok()); - let p = db.put(b"k3", b"v3333"); - assert!(p.is_ok()); - let mut snap = db.snapshot(); - let mut view1 = snap.iterator(); - println!("See the output of the first iter"); - for (k,v) in view1.from_start() { - println!("Hello {}: {}", std::str::from_utf8(k).unwrap(), std::str::from_utf8(v).unwrap()); - }; - for (k,v) in view1.from_start() { - println!("Hello {}: {}", std::str::from_utf8(k).unwrap(), std::str::from_utf8(v).unwrap()); - }; - for (k,v) in view1.from_end() { - println!("Hello {}: {}", std::str::from_utf8(k).unwrap(), std::str::from_utf8(v).unwrap()); - }; - } - let opts = Options::new(); - assert!(RocksDB::destroy(&opts, path).is_ok()); -} - -fn iterator_test() { - let path = "_rust_rocksdb_iteratortest"; - { - let mut db = RocksDB::open_default(path).unwrap(); - let p = db.put(b"k1", b"v1111"); - assert!(p.is_ok()); - let p = db.put(b"k2", b"v2222"); - assert!(p.is_ok()); - let p = db.put(b"k3", b"v3333"); - assert!(p.is_ok()); - { - let mut view1 = db.iterator(); - println!("See the output of the first iter"); - for (k,v) in view1.from_start() { - println!("Hello {}: {}", std::str::from_utf8(k).unwrap(), std::str::from_utf8(v).unwrap()); - }; - for (k,v) in view1.from_start() { - println!("Hello {}: {}", std::str::from_utf8(k).unwrap(), std::str::from_utf8(v).unwrap()); - }; - for (k,v) in view1.from_end() { - println!("Hello {}: {}", std::str::from_utf8(k).unwrap(), std::str::from_utf8(v).unwrap()); - }; - } - let mut view2 = db.iterator(); - let p = db.put(b"k4", b"v4444"); - assert!(p.is_ok()); - let mut view3 = db.iterator(); - println!("See the output of the second iter"); - for (k,v) in view2.from_start() { - println!("Hello {}: {}", std::str::from_utf8(k).unwrap(), std::str::from_utf8(v).unwrap()); - } - println!("See the output of the third iter"); - for (k,v) in view3.from_start() { - println!("Hello {}: {}", std::str::from_utf8(k).unwrap(), std::str::from_utf8(v).unwrap()); - } - println!("now the 3rd iter from k2 fwd"); - for (k,v) in view3.from(b"k2", rocksdb::Direction::forward) { - println!("Hello {}: {}", std::str::from_utf8(k).unwrap(), std::str::from_utf8(v).unwrap()); - } - println!("now the 3rd iter from k2 and back"); - for (k,v) in view3.from(b"k2", rocksdb::Direction::reverse) { - println!("Hello {}: {}", std::str::from_utf8(k).unwrap(), std::str::from_utf8(v).unwrap()); - } - } - let opts = Options::new(); - assert!(RocksDB::destroy(&opts, path).is_ok()); -} +//fn snapshot_test() { +// let path = "_rust_rocksdb_iteratortest"; +// { +// let mut db = RocksDB::open_default(path).unwrap(); +// let p = db.put(b"k1", b"v1111"); +// assert!(p.is_ok()); +// let p = db.put(b"k2", b"v2222"); +// assert!(p.is_ok()); +// let p = db.put(b"k3", b"v3333"); +// assert!(p.is_ok()); +// let mut snap = db.snapshot(); +// let mut view1 = snap.iterator(); +// println!("See the output of the first iter"); +// for (k,v) in view1.from_start() { +// println!("Hello {}: {}", std::str::from_utf8(k).unwrap(), std::str::from_utf8(v).unwrap()); +// }; +// for (k,v) in view1.from_start() { +// println!("Hello {}: {}", std::str::from_utf8(k).unwrap(), std::str::from_utf8(v).unwrap()); +// }; +// for (k,v) in view1.from_end() { +// println!("Hello {}: {}", std::str::from_utf8(k).unwrap(), std::str::from_utf8(v).unwrap()); +// }; +// } +// let opts = Options::new(); +// assert!(RocksDB::destroy(&opts, path).is_ok()); +//} #[cfg(not(feature = "valgrind"))] fn main() { - snapshot_test(); - iterator_test(); let path = "/tmp/rust-rocksdb"; let mut db = RocksDB::open_default(path).unwrap(); assert!(db.put(b"my key", b"my value").is_ok()); diff --git a/src/rocksdb.rs b/src/rocksdb.rs index 815dfe7..dba957a 100644 --- a/src/rocksdb.rs +++ b/src/rocksdb.rs @@ -64,9 +64,9 @@ pub struct SubDBIterator<'a> { } impl <'a> Iterator for SubDBIterator<'a> { - type Item = (&'a [u8], &'a [u8]); + type Item = (Box<[u8]>, Box<[u8]>); - fn next(&mut self) -> Option<(&'a [u8], &'a [u8])> { + fn next(&mut self) -> Option<(Box<[u8]>, Box<[u8]>)> { let native_iter = self.iter.inner; if !self.iter.just_seeked { match self.direction { @@ -85,7 +85,8 @@ impl <'a> Iterator for SubDBIterator<'a> { let key = unsafe { slice::from_raw_parts(key_ptr, key_len as usize) }; let val_ptr = unsafe { rocksdb_ffi::rocksdb_iter_value(native_iter, val_len_ptr) }; let val = unsafe { slice::from_raw_parts(val_ptr, val_len as usize) }; - Some((key,val)) + + Some((key.to_vec().into_boxed_slice(),val.to_vec().into_boxed_slice())) } else { None } @@ -612,7 +613,7 @@ fn iterator_test() { assert!(p.is_ok()); let mut iter = db.iterator(); for (k,v) in iter.from_start() { - println!("Hello {}: {}", from_utf8(k).unwrap(), from_utf8(v).unwrap()); + println!("Hello {}: {}", from_utf8(&*k).unwrap(), from_utf8(&*v).unwrap()); } } let opts = Options::new(); diff --git a/test/test.rs b/test/test.rs new file mode 100644 index 0000000..d10d9ae --- /dev/null +++ b/test/test.rs @@ -0,0 +1,3 @@ +extern crate rocksdb; + +mod test_iterator; diff --git a/test/test_iterator.rs b/test/test_iterator.rs new file mode 100644 index 0000000..f5cb0c0 --- /dev/null +++ b/test/test_iterator.rs @@ -0,0 +1,114 @@ +use rocksdb::{Options, RocksDB, Writable, Direction}; +use std; + +fn cba(input: &Box<[u8]>) -> Box<[u8]> { + input.iter().cloned().collect::>().into_boxed_slice() +} + +#[test] +pub fn test_iterator() { + let path = "_rust_rocksdb_iteratortest"; + { + let k1:Box<[u8]> = b"k1".to_vec().into_boxed_slice(); + let k2:Box<[u8]> = b"k2".to_vec().into_boxed_slice(); + let k3:Box<[u8]> = b"k3".to_vec().into_boxed_slice(); + let k4:Box<[u8]> = b"k4".to_vec().into_boxed_slice(); + let v1:Box<[u8]> = b"v1111".to_vec().into_boxed_slice(); + let v2:Box<[u8]> = b"v2222".to_vec().into_boxed_slice(); + let v3:Box<[u8]> = b"v3333".to_vec().into_boxed_slice(); + let v4:Box<[u8]> = b"v4444".to_vec().into_boxed_slice(); + let mut db = RocksDB::open_default(path).unwrap(); + let p = db.put(&*k1, &*v1); + assert!(p.is_ok()); + let p = db.put(&*k2, &*v2); + assert!(p.is_ok()); + let p = db.put(&*k3, &*v3); + assert!(p.is_ok()); + let mut view1 = db.iterator(); + let expected = vec![(cba(&k1), cba(&v1)), (cba(&k2), cba(&v2)), (cba(&k3), cba(&v3))]; + { + let mut iterator1 = view1.from_start(); + assert_eq!(iterator1.collect::>(), expected); + } + // Test that it's reusable a few times + { + let mut iterator1 = view1.from_start(); + assert_eq!(iterator1.collect::>(), expected); + } + { + let mut iterator1 = view1.from_start(); + assert_eq!(iterator1.collect::>(), expected); + } + { + let mut iterator1 = view1.from_start(); + assert_eq!(iterator1.collect::>(), expected); + } + // Test it in reverse a few times + { + let mut iterator1 = view1.from_end(); + let mut tmp_vec = iterator1.collect::>(); + tmp_vec.reverse(); + assert_eq!(tmp_vec, expected); + } + { + let mut iterator1 = view1.from_end(); + let mut tmp_vec = iterator1.collect::>(); + tmp_vec.reverse(); + assert_eq!(tmp_vec, expected); + } + { + let mut iterator1 = view1.from_end(); + let mut tmp_vec = iterator1.collect::>(); + tmp_vec.reverse(); + assert_eq!(tmp_vec, expected); + } + { + let mut iterator1 = view1.from_end(); + let mut tmp_vec = iterator1.collect::>(); + tmp_vec.reverse(); + assert_eq!(tmp_vec, expected); + } + { + let mut iterator1 = view1.from_end(); + let mut tmp_vec = iterator1.collect::>(); + tmp_vec.reverse(); + assert_eq!(tmp_vec, expected); + } + // Try it forward again + { + let mut iterator1 = view1.from_start(); + assert_eq!(iterator1.collect::>(), expected); + } + { + let mut iterator1 = view1.from_start(); + assert_eq!(iterator1.collect::>(), expected); + } + + let mut view2 = db.iterator(); + let p = db.put(&*k4, &*v4); + assert!(p.is_ok()); + let mut view3 = db.iterator(); + let expected2 = vec![(cba(&k1), cba(&v1)), (cba(&k2), cba(&v2)), (cba(&k3), cba(&v3)), (cba(&k4), cba(&v4))]; + { + let mut iterator1 = view1.from_start(); + assert_eq!(iterator1.collect::>(), expected); + } + { + let mut iterator1 = view3.from_start(); + assert_eq!(iterator1.collect::>(), expected2); + } + { + let mut iterator1 = view3.from(b"k2", Direction::forward); + let expected = vec![(cba(&k2), cba(&v2)), (cba(&k3), cba(&v3)), (cba(&k4), cba(&v4))]; + assert_eq!(iterator1.collect::>(), expected); + } + { + let mut iterator1 = view3.from(b"k2", Direction::reverse); + let expected = vec![(cba(&k2), cba(&v2)), (cba(&k1), cba(&v1))]; + assert_eq!(iterator1.collect::>(), expected); + } + } + let opts = Options::new(); + assert!(RocksDB::destroy(&opts, path).is_ok()); +} +