From 895c3f0c325e8c609710001ccc833d1a4d8ad332 Mon Sep 17 00:00:00 2001 From: Jordan Terrell Date: Sat, 26 Jan 2019 14:46:06 -0600 Subject: [PATCH 01/11] Fixing spelling typos... --- tests/test_column_family.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_column_family.rs b/tests/test_column_family.rs index d36fec2..bdd4eec 100644 --- a/tests/test_column_family.rs +++ b/tests/test_column_family.rs @@ -185,7 +185,7 @@ pub fn test_column_family_with_options() { let cfs = vec![cf_descriptor]; match DB::open_cf_descriptors(&opts, &n, cfs) { - Ok(_db) => println!("created db with column family descriptors succesfully"), + Ok(_db) => println!("created db with column family descriptors successfully"), Err(e) => { panic!( "could not create new database with column family descriptors: {}", @@ -204,7 +204,7 @@ pub fn test_column_family_with_options() { let cfs = vec![cf_descriptor]; match DB::open_cf_descriptors(&opts, &n, cfs) { - Ok(_db) => println!("succesfully re-opened database with column family descriptors"), + Ok(_db) => println!("successfully re-opened database with column family descriptors"), Err(e) => { panic!( "unable to re-open database with column family descriptors: {}", From e2949d094c121cab68422fb514ee3e02d5873729 Mon Sep 17 00:00:00 2001 From: Jordan Terrell Date: Sat, 26 Jan 2019 15:25:49 -0600 Subject: [PATCH 02/11] Removed new_bloom_filter function... --- src/db.rs | 4 ---- src/lib.rs | 4 ++-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/db.rs b/src/db.rs index ed18a12..2a620cd 100644 --- a/src/db.rs +++ b/src/db.rs @@ -29,10 +29,6 @@ use std::slice; use std::str; use std::sync::{Arc, RwLock}; -pub fn new_bloom_filter(bits: c_int) -> *mut ffi::rocksdb_filterpolicy_t { - unsafe { ffi::rocksdb_filterpolicy_create_bloom(bits) } -} - unsafe impl Send for DB {} unsafe impl Sync for DB {} diff --git a/src/lib.rs b/src/lib.rs index cb46114..a0c1672 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -63,8 +63,8 @@ mod slice_transform; pub use compaction_filter::Decision as CompactionDecision; pub use db::{ - new_bloom_filter, DBCompactionStyle, DBCompressionType, DBIterator, DBRawIterator, - DBRecoveryMode, DBVector, Direction, IteratorMode, ReadOptions, Snapshot, WriteBatch, + DBCompactionStyle, DBCompressionType, DBIterator, DBRawIterator, DBRecoveryMode, + DBVector, Direction, IteratorMode, ReadOptions, Snapshot, WriteBatch, }; pub use slice_transform::SliceTransform; From 248b40b4659c4f300b46a0948b3fc175d321c397 Mon Sep 17 00:00:00 2001 From: Jordan Terrell Date: Sun, 27 Jan 2019 20:28:30 -0600 Subject: [PATCH 03/11] Adding lifetime to ColumnFamily... --- src/db.rs | 28 ++++++++++++++++++++-------- src/lib.rs | 8 +++++--- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/db.rs b/src/db.rs index 2a620cd..44701fb 100644 --- a/src/db.rs +++ b/src/db.rs @@ -22,6 +22,7 @@ use std::collections::BTreeMap; use std::ffi::{CStr, CString}; use std::fmt; use std::fs; +use std::marker::PhantomData; use std::ops::Deref; use std::path::Path; use std::ptr; @@ -699,7 +700,7 @@ impl DB { for (n, h) in cfs_v.iter().zip(cfhandles) { cf_map.write() .map_err(|e| Error::new(e.to_string()))? - .insert(n.name.clone(), ColumnFamily { inner: h }); + .insert(n.name.clone(), h); } } @@ -866,15 +867,19 @@ impl DB { } }; let cf = unsafe { - let cf_handler = ffi_try!(ffi::rocksdb_create_column_family( + let cf_handle = ffi_try!(ffi::rocksdb_create_column_family( self.inner, opts.inner, cname.as_ptr(), )); - let cf = ColumnFamily { inner: cf_handler }; + self.cfs.write().map_err(|e| Error::new(e.to_string()))? - .insert(name.to_string(), cf); - cf + .insert(name.to_string(), cf_handle); + + ColumnFamily { + inner: cf_handle, + db: PhantomData, + } }; Ok(cf) } @@ -883,7 +888,7 @@ impl DB { if let Some(cf) = self.cfs.write().map_err(|e| Error::new(e.to_string()))? .remove(name) { unsafe { - ffi_try!(ffi::rocksdb_drop_column_family(self.inner, cf.inner,)); + ffi_try!(ffi::rocksdb_drop_column_family(self.inner, cf,)); } Ok(()) } else { @@ -895,7 +900,14 @@ impl DB { /// Return the underlying column family handle. pub fn cf_handle(&self, name: &str) -> Option { - self.cfs.read().ok()?.get(name).cloned() + self.cfs + .read() + .ok()? + .get(name) + .map(|h| ColumnFamily { + inner: *h, + db: PhantomData + }) } pub fn iterator(&self, mode: IteratorMode) -> DBIterator { @@ -1269,7 +1281,7 @@ impl Drop for DB { unsafe { if let Ok(cfs) = self.cfs.read() { for cf in cfs.values() { - ffi::rocksdb_column_family_handle_destroy(cf.inner); + ffi::rocksdb_column_family_handle_destroy(*cf); } } ffi::rocksdb_close(self.inner); diff --git a/src/lib.rs b/src/lib.rs index a0c1672..666be5b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -73,6 +73,7 @@ pub use merge_operator::MergeOperands; use std::collections::BTreeMap; use std::error; use std::fmt; +use std::marker::PhantomData; use std::path::PathBuf; use std::sync::{Arc, RwLock}; @@ -81,7 +82,7 @@ use std::sync::{Arc, RwLock}; /// See crate level documentation for a simple usage example. pub struct DB { inner: *mut ffi::rocksdb_t, - cfs: Arc>>, + cfs: Arc>>, path: PathBuf, } @@ -233,8 +234,9 @@ pub struct WriteOptions { /// An opaque type used to represent a column family. Returned from some functions, and used /// in others #[derive(Copy, Clone)] -pub struct ColumnFamily { +pub struct ColumnFamily<'a> { inner: *mut ffi::rocksdb_column_family_handle_t, + db: PhantomData<&'a DB>, } -unsafe impl Send for ColumnFamily {} +unsafe impl<'a> Send for ColumnFamily<'a> {} From 857efff67071be943f3a578e3940b48d50465a0a Mon Sep 17 00:00:00 2001 From: Jordan Terrell Date: Sun, 27 Jan 2019 20:42:34 -0600 Subject: [PATCH 04/11] Adding lifetime to DBIterator and DBRawIterator... --- src/db.rs | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/db.rs b/src/db.rs index 44701fb..d3eaec6 100644 --- a/src/db.rs +++ b/src/db.rs @@ -142,8 +142,9 @@ pub struct Snapshot<'a> { /// iter.prev(); /// } /// ``` -pub struct DBRawIterator { +pub struct DBRawIterator<'a> { inner: *mut ffi::rocksdb_iterator_t, + db: PhantomData<&'a DB> } /// An iterator over a database or column family, with specifiable @@ -173,13 +174,13 @@ pub struct DBRawIterator { /// println!("Saw {:?} {:?}", key, value); /// } /// ``` -pub struct DBIterator { - raw: DBRawIterator, +pub struct DBIterator<'a> { + raw: DBRawIterator<'a>, direction: Direction, just_seeked: bool, } -unsafe impl Send for DBIterator {} +unsafe impl<'a> Send for DBIterator<'a> {} pub enum Direction { Forward, @@ -194,11 +195,12 @@ pub enum IteratorMode<'a> { From(&'a [u8], Direction), } -impl DBRawIterator { - fn new(db: &DB, readopts: &ReadOptions) -> DBRawIterator { +impl<'a> DBRawIterator<'a> { + fn new(db: &DB, readopts: &ReadOptions) -> DBRawIterator<'a> { unsafe { DBRawIterator { inner: ffi::rocksdb_create_iterator(db.inner, readopts.inner), + db: PhantomData } } } @@ -207,10 +209,11 @@ impl DBRawIterator { db: &DB, cf_handle: ColumnFamily, readopts: &ReadOptions, - ) -> Result { + ) -> Result, Error> { unsafe { Ok(DBRawIterator { inner: ffi::rocksdb_create_iterator_cf(db.inner, readopts.inner, cf_handle.inner), + db: PhantomData }) } } @@ -425,7 +428,7 @@ impl DBRawIterator { } } -impl Drop for DBRawIterator { +impl<'a> Drop for DBRawIterator<'a> { fn drop(&mut self) { unsafe { ffi::rocksdb_iter_destroy(self.inner); @@ -433,8 +436,8 @@ impl Drop for DBRawIterator { } } -impl DBIterator { - fn new(db: &DB, readopts: &ReadOptions, mode: IteratorMode) -> DBIterator { +impl<'a> DBIterator<'a> { + fn new(db: &DB, readopts: &ReadOptions, mode: IteratorMode) -> DBIterator<'a> { let mut rv = DBIterator { raw: DBRawIterator::new(db, readopts), direction: Direction::Forward, // blown away by set_mode() @@ -449,7 +452,7 @@ impl DBIterator { cf_handle: ColumnFamily, readopts: &ReadOptions, mode: IteratorMode, - ) -> Result { + ) -> Result, Error> { let mut rv = DBIterator { raw: DBRawIterator::new_cf(db, cf_handle, readopts)?, direction: Direction::Forward, // blown away by set_mode() @@ -487,7 +490,7 @@ impl DBIterator { } } -impl Iterator for DBIterator { +impl<'a> Iterator for DBIterator<'a> { type Item = KVBytes; fn next(&mut self) -> Option { @@ -514,8 +517,8 @@ impl Iterator for DBIterator { } } -impl Into for DBIterator { - fn into(self) -> DBRawIterator { +impl<'a> Into> for DBIterator<'a> { + fn into(self) -> DBRawIterator<'a> { self.raw } } From 1a2c2682746f103cc73b7aaad0057e7ce3853c87 Mon Sep 17 00:00:00 2001 From: Jordan Terrell Date: Sun, 27 Jan 2019 22:09:10 -0600 Subject: [PATCH 05/11] Moving tests to take advantage of DBPath (ensuring cleanup)... --- src/compaction_filter.rs | 33 +----- src/db.rs | 171 +------------------------------ tests/test_checkpoint.rs | 27 ++--- tests/test_compationfilter.rs | 51 ++++++++++ tests/test_db.rs | 183 ++++++++++++++++++++++++++++++++++ tests/util/mod.rs | 2 +- 6 files changed, 244 insertions(+), 223 deletions(-) create mode 100644 tests/test_compationfilter.rs create mode 100644 tests/test_db.rs diff --git a/src/compaction_filter.rs b/src/compaction_filter.rs index 0c63b2a..a6cc9ea 100644 --- a/src/compaction_filter.rs +++ b/src/compaction_filter.rs @@ -100,35 +100,4 @@ where 0 } } -} - -#[cfg(test)] -#[allow(unused_variables)] -fn test_filter(level: u32, key: &[u8], value: &[u8]) -> Decision { - use self::Decision::*; - match key.first() { - Some(&b'_') => Remove, - Some(&b'%') => Change(b"secret"), - _ => Keep, - } -} - -#[test] -fn compaction_filter_test() { - use {Options, DB}; - - let path = "_rust_rocksdb_filtertest"; - let mut opts = Options::default(); - opts.create_if_missing(true); - opts.set_compaction_filter("test", test_filter); - { - let db = DB::open(&opts, path).unwrap(); - let _ = db.put(b"k1", b"a"); - let _ = db.put(b"_k", b"b"); - let _ = db.put(b"%k", b"c"); - db.compact_range(None, None); - assert_eq!(&*db.get(b"k1").unwrap().unwrap(), b"a"); - assert!(db.get(b"_k").unwrap().is_none()); - assert_eq!(&*db.get(b"%k").unwrap().unwrap(), b"secret"); - } -} +} \ No newline at end of file diff --git a/src/db.rs b/src/db.rs index d3eaec6..c07863d 100644 --- a/src/db.rs +++ b/src/db.rs @@ -1404,173 +1404,4 @@ impl DBVector { pub fn to_utf8(&self) -> Option<&str> { str::from_utf8(self.deref()).ok() } -} - -#[test] -fn test_db_vector() { - use std::mem; - let len: size_t = 4; - let data: *mut u8 = unsafe { mem::transmute(libc::calloc(len, mem::size_of::())) }; - let v = unsafe { DBVector::from_c(data, len) }; - let ctrl = [0u8, 0, 0, 0]; - assert_eq!(&*v, &ctrl[..]); -} - -#[test] -fn external() { - let path = "_rust_rocksdb_externaltest"; - { - let db = DB::open_default(path).unwrap(); - let p = db.put(b"k1", b"v1111"); - assert!(p.is_ok()); - let r: Result, Error> = db.get(b"k1"); - assert!(r.unwrap().unwrap().to_utf8().unwrap() == "v1111"); - assert!(db.delete(b"k1").is_ok()); - assert!(db.get(b"k1").unwrap().is_none()); - } - let opts = Options::default(); - let result = DB::destroy(&opts, path); - assert!(result.is_ok()); -} - -#[test] -fn errors_do_stuff() { - let path = "_rust_rocksdb_error"; - let _db = DB::open_default(path).unwrap(); - let opts = Options::default(); - // The DB will still be open when we try to destroy it and the lock should fail. - match DB::destroy(&opts, path) { - Err(s) => { - let message = s.to_string(); - assert!(message.find("IO error:").is_some()); - assert!(message.find("_rust_rocksdb_error/LOCK:").is_some()); - } - Ok(_) => panic!("should fail"), - } -} - -#[test] -fn writebatch_works() { - let path = "_rust_rocksdb_writebacktest"; - { - let db = DB::open_default(path).unwrap(); - { - // test put - let mut batch = WriteBatch::default(); - assert!(db.get(b"k1").unwrap().is_none()); - assert_eq!(batch.len(), 0); - assert!(batch.is_empty()); - let _ = batch.put(b"k1", b"v1111"); - assert_eq!(batch.len(), 1); - assert!(!batch.is_empty()); - assert!(db.get(b"k1").unwrap().is_none()); - let p = db.write(batch); - assert!(p.is_ok()); - let r: Result, Error> = db.get(b"k1"); - assert!(r.unwrap().unwrap().to_utf8().unwrap() == "v1111"); - } - { - // test delete - let mut batch = WriteBatch::default(); - let _ = batch.delete(b"k1"); - assert_eq!(batch.len(), 1); - assert!(!batch.is_empty()); - let p = db.write(batch); - assert!(p.is_ok()); - assert!(db.get(b"k1").unwrap().is_none()); - } - { - // test size_in_bytes - let mut batch = WriteBatch::default(); - let before = batch.size_in_bytes(); - let _ = batch.put(b"k1", b"v1234567890"); - let after = batch.size_in_bytes(); - assert!(before + 10 <= after); - } - } - let opts = Options::default(); - assert!(DB::destroy(&opts, path).is_ok()); -} - -#[test] -fn iterator_test() { - let path = "_rust_rocksdb_iteratortest"; - { - let db = DB::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 iter = db.iterator(IteratorMode::Start); - for (k, v) in iter { - println!( - "Hello {}: {}", - str::from_utf8(&*k).unwrap(), - str::from_utf8(&*v).unwrap() - ); - } - } - let opts = Options::default(); - assert!(DB::destroy(&opts, path).is_ok()); -} - -#[test] -fn snapshot_test() { - let path = "_rust_rocksdb_snapshottest"; - { - let db = DB::open_default(path).unwrap(); - let p = db.put(b"k1", b"v1111"); - assert!(p.is_ok()); - - let snap = db.snapshot(); - let r: Result, Error> = snap.get(b"k1"); - assert!(r.unwrap().unwrap().to_utf8().unwrap() == "v1111"); - - let p = db.put(b"k2", b"v2222"); - assert!(p.is_ok()); - - assert!(db.get(b"k2").unwrap().is_some()); - assert!(snap.get(b"k2").unwrap().is_none()); - } - let opts = Options::default(); - assert!(DB::destroy(&opts, path).is_ok()); -} - -#[test] -fn set_option_test() { - let path = "_rust_rocksdb_set_optionstest"; - { - let db = DB::open_default(path).unwrap(); - // set an option to valid values - assert!(db - .set_options(&[("disable_auto_compactions", "true")]) - .is_ok()); - assert!(db - .set_options(&[("disable_auto_compactions", "false")]) - .is_ok()); - // invalid names/values should result in an error - assert!(db - .set_options(&[("disable_auto_compactions", "INVALID_VALUE")]) - .is_err()); - assert!(db - .set_options(&[("INVALID_NAME", "INVALID_VALUE")]) - .is_err()); - // option names/values must not contain NULLs - assert!(db - .set_options(&[("disable_auto_compactions", "true\0")]) - .is_err()); - assert!(db - .set_options(&[("disable_auto_compactions\0", "true")]) - .is_err()); - // empty options are not allowed - assert!(db.set_options(&[]).is_err()); - // multiple options can be set in a single API call - let multiple_options = [ - ("paranoid_file_checks", "true"), - ("report_bg_io_stats", "true"), - ]; - db.set_options(&multiple_options).unwrap(); - } -} +} \ No newline at end of file diff --git a/tests/test_checkpoint.rs b/tests/test_checkpoint.rs index 854a1d1..998f256 100644 --- a/tests/test_checkpoint.rs +++ b/tests/test_checkpoint.rs @@ -13,18 +13,17 @@ // limitations under the License. // extern crate rocksdb; +mod util; use rocksdb::{checkpoint::Checkpoint, Options, DB}; -use std::fs::remove_dir_all; +use util::DBPath; #[test] pub fn test_single_checkpoint() { const PATH_PREFIX: &str = "_rust_rocksdb_cp_single_"; // Create DB with some data - let db_path = format!("{}db1", PATH_PREFIX); - - let _ = remove_dir_all(&db_path); + let db_path = DBPath::new(&format!("{}db1", PATH_PREFIX)); let mut opts = Options::default(); opts.create_if_missing(true); @@ -37,8 +36,7 @@ pub fn test_single_checkpoint() { // Create checkpoint let cp1 = Checkpoint::new(&db).unwrap(); - let cp1_path = format!("{}cp1", PATH_PREFIX); - let _ = remove_dir_all(&cp1_path); + let cp1_path = DBPath::new(&format!("{}cp1", PATH_PREFIX)); cp1.create_checkpoint(&cp1_path).unwrap(); // Verify checkpoint @@ -48,9 +46,6 @@ pub fn test_single_checkpoint() { assert_eq!(*cp.get(b"k2").unwrap().unwrap(), *b"v2"); assert_eq!(*cp.get(b"k3").unwrap().unwrap(), *b"v3"); assert_eq!(*cp.get(b"k4").unwrap().unwrap(), *b"v4"); - - let _ = remove_dir_all(&db_path); - let _ = remove_dir_all(&cp1_path); } #[test] @@ -58,8 +53,7 @@ pub fn test_multi_checkpoints() { const PATH_PREFIX: &str = "_rust_rocksdb_cp_multi_"; // Create DB with some data - let db_path = format!("{}db1", PATH_PREFIX); - let _ = remove_dir_all(&db_path); + let db_path = DBPath::new(&format!("{}db1", PATH_PREFIX)); let mut opts = Options::default(); opts.create_if_missing(true); @@ -72,8 +66,7 @@ pub fn test_multi_checkpoints() { // Create first checkpoint let cp1 = Checkpoint::new(&db).unwrap(); - let cp1_path = format!("{}cp1", PATH_PREFIX); - let _ = remove_dir_all(&cp1_path); + let cp1_path = DBPath::new(&format!("{}cp1", PATH_PREFIX)); cp1.create_checkpoint(&cp1_path).unwrap(); // Verify checkpoint @@ -84,8 +77,6 @@ pub fn test_multi_checkpoints() { assert_eq!(*cp.get(b"k3").unwrap().unwrap(), *b"v3"); assert_eq!(*cp.get(b"k4").unwrap().unwrap(), *b"v4"); - let _ = remove_dir_all(&cp1_path); - // Change some existing keys db.put(b"k1", b"modified").unwrap(); db.put(b"k2", b"changed").unwrap(); @@ -96,8 +87,7 @@ pub fn test_multi_checkpoints() { // Create another checkpoint let cp2 = Checkpoint::new(&db).unwrap(); - let cp2_path = format!("{}cp2", PATH_PREFIX); - let _ = remove_dir_all(&cp2_path); + let cp2_path = DBPath::new(&format!("{}cp2", PATH_PREFIX)); cp2.create_checkpoint(&cp2_path).unwrap(); // Verify second checkpoint @@ -107,7 +97,4 @@ pub fn test_multi_checkpoints() { assert_eq!(*cp.get(b"k2").unwrap().unwrap(), *b"changed"); assert_eq!(*cp.get(b"k5").unwrap().unwrap(), *b"v5"); assert_eq!(*cp.get(b"k6").unwrap().unwrap(), *b"v6"); - - let _ = remove_dir_all(&db_path); - let _ = remove_dir_all(&cp2_path); } diff --git a/tests/test_compationfilter.rs b/tests/test_compationfilter.rs new file mode 100644 index 0000000..5cd4dc0 --- /dev/null +++ b/tests/test_compationfilter.rs @@ -0,0 +1,51 @@ +// Copyright 2014 Tyler Neely +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +extern crate rocksdb; + +mod util; + +use rocksdb::{CompactionDecision, DB, Options}; +use util::DBPath; + +#[cfg(test)] +#[allow(unused_variables)] +fn test_filter(level: u32, key: &[u8], value: &[u8]) -> CompactionDecision { + use self::CompactionDecision::*; + match key.first() { + Some(&b'_') => Remove, + Some(&b'%') => Change(b"secret"), + _ => Keep, + } +} + +#[test] +fn compaction_filter_test() { + use {Options, DB}; + + let path = DBPath::new("_rust_rocksdb_filtertest"); + let mut opts = Options::default(); + opts.create_if_missing(true); + opts.set_compaction_filter("test", test_filter); + { + let db = DB::open(&opts, &path).unwrap(); + let _ = db.put(b"k1", b"a"); + let _ = db.put(b"_k", b"b"); + let _ = db.put(b"%k", b"c"); + db.compact_range(None, None); + assert_eq!(&*db.get(b"k1").unwrap().unwrap(), b"a"); + assert!(db.get(b"_k").unwrap().is_none()); + assert_eq!(&*db.get(b"%k").unwrap().unwrap(), b"secret"); + } +} \ No newline at end of file diff --git a/tests/test_db.rs b/tests/test_db.rs new file mode 100644 index 0000000..01f5b92 --- /dev/null +++ b/tests/test_db.rs @@ -0,0 +1,183 @@ +// Copyright 2014 Tyler Neely +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +extern crate rocksdb; +extern crate libc; + +mod util; + +use libc::{size_t}; + +use rocksdb::{DB, DBVector, Error, IteratorMode, Options, WriteBatch}; +use std::str; +use util::DBPath; + +#[test] +fn test_db_vector() { + use std::mem; + let len: size_t = 4; + let data: *mut u8 = unsafe { mem::transmute(libc::calloc(len, mem::size_of::())) }; + let v = unsafe { DBVector::from_c(data, len) }; + let ctrl = [0u8, 0, 0, 0]; + assert_eq!(&*v, &ctrl[..]); +} + +#[test] +fn external() { + let path = DBPath::new("_rust_rocksdb_externaltest"); + let db = DB::open_default(&path).unwrap(); + let p = db.put(b"k1", b"v1111"); + assert!(p.is_ok()); + let r: Result, Error> = db.get(b"k1"); + assert!(r.unwrap().unwrap().to_utf8().unwrap() == "v1111"); + assert!(db.delete(b"k1").is_ok()); + assert!(db.get(b"k1").unwrap().is_none()); +} + +#[test] +fn errors_do_stuff() { + let path = DBPath::new("_rust_rocksdb_error"); + let _db = DB::open_default(&path).unwrap(); + let opts = Options::default(); + // The DB will still be open when we try to destroy it and the lock should fail. + match DB::destroy(&opts, &path) { + Err(s) => { + let message = s.to_string(); + assert!(message.find("IO error:").is_some()); + assert!(message.find("_rust_rocksdb_error").is_some()); + assert!(message.find("/LOCK:").is_some()); + } + Ok(_) => panic!("should fail"), + } +} + +#[test] +fn writebatch_works() { + let path = DBPath::new("_rust_rocksdb_writebacktest"); + { + let db = DB::open_default(&path).unwrap(); + { + // test put + let mut batch = WriteBatch::default(); + assert!(db.get(b"k1").unwrap().is_none()); + assert_eq!(batch.len(), 0); + assert!(batch.is_empty()); + let _ = batch.put(b"k1", b"v1111"); + assert_eq!(batch.len(), 1); + assert!(!batch.is_empty()); + assert!(db.get(b"k1").unwrap().is_none()); + let p = db.write(batch); + assert!(p.is_ok()); + let r: Result, Error> = db.get(b"k1"); + assert!(r.unwrap().unwrap().to_utf8().unwrap() == "v1111"); + } + { + // test delete + let mut batch = WriteBatch::default(); + let _ = batch.delete(b"k1"); + assert_eq!(batch.len(), 1); + assert!(!batch.is_empty()); + let p = db.write(batch); + assert!(p.is_ok()); + assert!(db.get(b"k1").unwrap().is_none()); + } + { + // test size_in_bytes + let mut batch = WriteBatch::default(); + let before = batch.size_in_bytes(); + let _ = batch.put(b"k1", b"v1234567890"); + let after = batch.size_in_bytes(); + assert!(before + 10 <= after); + } + } +} + +#[test] +fn iterator_test() { + let path = DBPath::new("_rust_rocksdb_iteratortest"); + { + let db = DB::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 iter = db.iterator(IteratorMode::Start); + for (k, v) in iter { + println!( + "Hello {}: {}", + str::from_utf8(&*k).unwrap(), + str::from_utf8(&*v).unwrap() + ); + } + } +} + +#[test] +fn snapshot_test() { + let path = DBPath::new("_rust_rocksdb_snapshottest"); + { + let db = DB::open_default(&path).unwrap(); + let p = db.put(b"k1", b"v1111"); + assert!(p.is_ok()); + + let snap = db.snapshot(); + let r: Result, Error> = snap.get(b"k1"); + assert!(r.unwrap().unwrap().to_utf8().unwrap() == "v1111"); + + let p = db.put(b"k2", b"v2222"); + assert!(p.is_ok()); + + assert!(db.get(b"k2").unwrap().is_some()); + assert!(snap.get(b"k2").unwrap().is_none()); + } +} + +#[test] +fn set_option_test() { + let path = DBPath::new("_rust_rocksdb_set_optionstest"); + { + let db = DB::open_default(&path).unwrap(); + // set an option to valid values + assert!(db + .set_options(&[("disable_auto_compactions", "true")]) + .is_ok()); + assert!(db + .set_options(&[("disable_auto_compactions", "false")]) + .is_ok()); + // invalid names/values should result in an error + assert!(db + .set_options(&[("disable_auto_compactions", "INVALID_VALUE")]) + .is_err()); + assert!(db + .set_options(&[("INVALID_NAME", "INVALID_VALUE")]) + .is_err()); + // option names/values must not contain NULLs + assert!(db + .set_options(&[("disable_auto_compactions", "true\0")]) + .is_err()); + assert!(db + .set_options(&[("disable_auto_compactions\0", "true")]) + .is_err()); + // empty options are not allowed + assert!(db.set_options(&[]).is_err()); + // multiple options can be set in a single API call + let multiple_options = [ + ("paranoid_file_checks", "true"), + ("report_bg_io_stats", "true"), + ]; + db.set_options(&multiple_options).unwrap(); + } +} \ No newline at end of file diff --git a/tests/util/mod.rs b/tests/util/mod.rs index 1e028ba..5987bbe 100644 --- a/tests/util/mod.rs +++ b/tests/util/mod.rs @@ -39,4 +39,4 @@ impl AsRef for DBPath { fn as_ref(&self) -> &Path { &self.path } -} +} \ No newline at end of file From 4f61f96727ecdb64bec475e2cabc9ae5b66b7766 Mon Sep 17 00:00:00 2001 From: Jordan Terrell Date: Fri, 1 Feb 2019 19:29:04 -0600 Subject: [PATCH 06/11] Adding iterator construction methods that accept ReadOptions... --- src/db.rs | 55 ++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/src/db.rs b/src/db.rs index c07863d..84395fb 100644 --- a/src/db.rs +++ b/src/db.rs @@ -533,41 +533,70 @@ impl<'a> Snapshot<'a> { } pub fn iterator(&self, mode: IteratorMode) -> DBIterator { - let mut readopts = ReadOptions::default(); + let readopts = ReadOptions::default(); + self.iterator_opt(mode, readopts) + } + + pub fn iterator_cf( + &self, + cf_handle: ColumnFamily, + mode: IteratorMode, + ) -> Result { + let readopts = ReadOptions::default(); + self.iterator_cf_opt(cf_handle, readopts, mode) + } + + pub fn iterator_opt(&self, mode: IteratorMode, mut readopts: ReadOptions) -> DBIterator { readopts.set_snapshot(self); DBIterator::new(self.db, &readopts, mode) } - pub fn iterator_cf( + pub fn iterator_cf_opt( &self, cf_handle: ColumnFamily, + mut readopts: ReadOptions, mode: IteratorMode, ) -> Result { - let mut readopts = ReadOptions::default(); readopts.set_snapshot(self); DBIterator::new_cf(self.db, cf_handle, &readopts, mode) } pub fn raw_iterator(&self) -> DBRawIterator { - let mut readopts = ReadOptions::default(); + let readopts = ReadOptions::default(); + self.raw_iterator_opt(readopts) + } + + pub fn raw_iterator_cf(&self, cf_handle: ColumnFamily) -> Result { + let readopts = ReadOptions::default(); + self.raw_iterator_cf_opt(cf_handle, readopts) + } + + pub fn raw_iterator_opt(&self, mut readopts: ReadOptions) -> DBRawIterator { readopts.set_snapshot(self); DBRawIterator::new(self.db, &readopts) } - pub fn raw_iterator_cf(&self, cf_handle: ColumnFamily) -> Result { - let mut readopts = ReadOptions::default(); + pub fn raw_iterator_cf_opt(&self, cf_handle: ColumnFamily, mut readopts: ReadOptions) -> Result { readopts.set_snapshot(self); DBRawIterator::new_cf(self.db, cf_handle, &readopts) } pub fn get(&self, key: &[u8]) -> Result, Error> { - let mut readopts = ReadOptions::default(); + let readopts = ReadOptions::default(); + self.get_opt(key, readopts) + } + + pub fn get_cf(&self, cf: ColumnFamily, key: &[u8]) -> Result, Error> { + let readopts = ReadOptions::default(); + self.get_cf_opt(cf, key, readopts) + } + + pub fn get_opt(&self, key: &[u8], mut readopts: ReadOptions) -> Result, Error> { readopts.set_snapshot(self); self.db.get_opt(key, &readopts) } - pub fn get_cf(&self, cf: ColumnFamily, key: &[u8]) -> Result, Error> { - let mut readopts = ReadOptions::default(); + pub fn get_cf_opt(&self, cf: ColumnFamily, key: &[u8], mut readopts: ReadOptions) -> Result, Error> { readopts.set_snapshot(self); self.db.get_cf_opt(cf, key, &readopts) } @@ -914,8 +943,12 @@ impl DB { } pub fn iterator(&self, mode: IteratorMode) -> DBIterator { - let opts = ReadOptions::default(); - DBIterator::new(self, &opts, mode) + let readopts = ReadOptions::default(); + self.iterator_opt(mode, &readopts) + } + + pub fn iterator_opt(&self, mode: IteratorMode, readopts: &ReadOptions) -> DBIterator { + DBIterator::new(self, &readopts, mode) } /// Opens an interator with `set_total_order_seek` enabled. From 21b9a9e98aa5f2d6d3a04cab2cc2dedfa3011fb6 Mon Sep 17 00:00:00 2001 From: Jordan Terrell Date: Fri, 1 Feb 2019 20:38:07 -0600 Subject: [PATCH 07/11] Key/value arguments are now generic types that impl AsRef<[u8]>... --- src/db.rs | 199 ++++++++++++++++++++++++---------- src/ffi_util.rs | 4 +- src/merge_operator.rs | 4 +- tests/test_compationfilter.rs | 2 +- 4 files changed, 147 insertions(+), 62 deletions(-) diff --git a/src/db.rs b/src/db.rs index 84395fb..347788d 100644 --- a/src/db.rs +++ b/src/db.rs @@ -318,7 +318,9 @@ impl<'a> DBRawIterator<'a> { /// // There are no keys in the database /// } /// ``` - pub fn seek(&mut self, key: &[u8]) { + pub fn seek>(&mut self, key: K) { + let key = key.as_ref(); + unsafe { ffi::rocksdb_iter_seek( self.inner, @@ -351,7 +353,9 @@ impl<'a> DBRawIterator<'a> { /// } else { /// // There are no keys in the database /// } - pub fn seek_for_prev(&mut self, key: &[u8]) { + pub fn seek_for_prev>(&mut self, key: K) { + let key = key.as_ref(); + unsafe { ffi::rocksdb_iter_seek_for_prev( self.inner, @@ -581,24 +585,24 @@ impl<'a> Snapshot<'a> { DBRawIterator::new_cf(self.db, cf_handle, &readopts) } - pub fn get(&self, key: &[u8]) -> Result, Error> { + pub fn get>(&self, key: K) -> Result, Error> { let readopts = ReadOptions::default(); self.get_opt(key, readopts) } - pub fn get_cf(&self, cf: ColumnFamily, key: &[u8]) -> Result, Error> { + pub fn get_cf>(&self, cf: ColumnFamily, key: K) -> Result, Error> { let readopts = ReadOptions::default(); - self.get_cf_opt(cf, key, readopts) + self.get_cf_opt(cf, key.as_ref(), readopts) } - pub fn get_opt(&self, key: &[u8], mut readopts: ReadOptions) -> Result, Error> { + pub fn get_opt>(&self, key: K, mut readopts: ReadOptions) -> Result, Error> { readopts.set_snapshot(self); - self.db.get_opt(key, &readopts) + self.db.get_opt(key.as_ref(), &readopts) } - pub fn get_cf_opt(&self, cf: ColumnFamily, key: &[u8], mut readopts: ReadOptions) -> Result, Error> { + pub fn get_cf_opt>(&self, cf: ColumnFamily, key: K, mut readopts: ReadOptions) -> Result, Error> { readopts.set_snapshot(self); - self.db.get_cf_opt(cf, key, &readopts) + self.db.get_cf_opt(cf, key.as_ref(), &readopts) } } @@ -814,7 +818,7 @@ impl DB { self.write_opt(batch, &wo) } - pub fn get_opt(&self, key: &[u8], readopts: &ReadOptions) -> Result, Error> { + pub fn get_opt>(&self, key: K, readopts: &ReadOptions) -> Result, Error> { if readopts.inner.is_null() { return Err(Error::new( "Unable to create RocksDB read options. \ @@ -826,6 +830,8 @@ impl DB { )); } + let key = key.as_ref(); + unsafe { let mut val_len: size_t = 0; let val = ffi_try!(ffi::rocksdb_get( @@ -844,14 +850,14 @@ impl DB { } /// Return the bytes associated with a key value - pub fn get(&self, key: &[u8]) -> Result, Error> { - self.get_opt(key, &ReadOptions::default()) + pub fn get>(&self, key: K) -> Result, Error> { + self.get_opt(key.as_ref(), &ReadOptions::default()) } - pub fn get_cf_opt( + pub fn get_cf_opt>( &self, cf: ColumnFamily, - key: &[u8], + key: K, readopts: &ReadOptions, ) -> Result, Error> { if readopts.inner.is_null() { @@ -865,6 +871,8 @@ impl DB { )); } + let key = key.as_ref(); + unsafe { let mut val_len: size_t = 0; let val = ffi_try!(ffi::rocksdb_get_cf( @@ -883,8 +891,8 @@ impl DB { } } - pub fn get_cf(&self, cf: ColumnFamily, key: &[u8]) -> Result, Error> { - self.get_cf_opt(cf, key, &ReadOptions::default()) + pub fn get_cf>(&self, cf: ColumnFamily, key: K) -> Result, Error> { + self.get_cf_opt(cf, key.as_ref(), &ReadOptions::default()) } pub fn create_cf(&self, name: &str, opts: &Options) -> Result { @@ -960,10 +968,10 @@ impl DB { DBIterator::new(self, &opts, mode) } - pub fn prefix_iterator(&self, prefix: &[u8]) -> DBIterator { + pub fn prefix_iterator>(&self, prefix: P) -> DBIterator { let mut opts = ReadOptions::default(); opts.set_prefix_same_as_start(true); - DBIterator::new(self, &opts, IteratorMode::From(prefix, Direction::Forward)) + DBIterator::new(self, &opts, IteratorMode::From(prefix.as_ref(), Direction::Forward)) } pub fn iterator_cf( @@ -985,10 +993,10 @@ impl DB { DBIterator::new_cf(self, cf_handle, &opts, mode) } - pub fn prefix_iterator_cf( + pub fn prefix_iterator_cf>( &self, cf_handle: ColumnFamily, - prefix: &[u8] + prefix: P ) -> Result { let mut opts = ReadOptions::default(); opts.set_prefix_same_as_start(true); @@ -996,7 +1004,7 @@ impl DB { self, cf_handle, &opts, - IteratorMode::From(prefix, Direction::Forward), + IteratorMode::From(prefix.as_ref(), Direction::Forward), ) } @@ -1014,8 +1022,15 @@ impl DB { Snapshot::new(self) } - pub fn put_opt(&self, key: &[u8], value: &[u8], writeopts: &WriteOptions) -> Result<(), Error> { + pub fn put_opt(&self, key: K, value: V, writeopts: &WriteOptions) -> Result<(), Error> + where K: AsRef<[u8]>, + V: AsRef<[u8]> { + + let key = key.as_ref(); + let value = value.as_ref(); + unsafe { + ffi_try!(ffi::rocksdb_put( self.inner, writeopts.inner, @@ -1028,14 +1043,21 @@ impl DB { } } - pub fn put_cf_opt( + pub fn put_cf_opt( &self, cf: ColumnFamily, - key: &[u8], - value: &[u8], + key: K, + value: V, writeopts: &WriteOptions, - ) -> Result<(), Error> { + ) -> Result<(), Error> + where K: AsRef<[u8]>, + V: AsRef<[u8]> { + + let key = key.as_ref(); + let value = value.as_ref(); + unsafe { + ffi_try!(ffi::rocksdb_put_cf( self.inner, writeopts.inner, @@ -1049,12 +1071,18 @@ impl DB { } } - pub fn merge_opt( + pub fn merge_opt( &self, - key: &[u8], - value: &[u8], + key: K, + value: V, writeopts: &WriteOptions, - ) -> Result<(), Error> { + ) -> Result<(), Error> + where K: AsRef<[u8]>, + V: AsRef<[u8]> { + + let key = key.as_ref(); + let value = value.as_ref(); + unsafe { ffi_try!(ffi::rocksdb_merge( self.inner, @@ -1068,14 +1096,21 @@ impl DB { } } - pub fn merge_cf_opt( + pub fn merge_cf_opt( &self, cf: ColumnFamily, - key: &[u8], - value: &[u8], + key: K, + value: V, writeopts: &WriteOptions, - ) -> Result<(), Error> { + ) -> Result<(), Error> + where K: AsRef<[u8]>, + V: AsRef<[u8]> { + + let key = key.as_ref(); + let value = value.as_ref(); + unsafe { + ffi_try!(ffi::rocksdb_merge_cf( self.inner, writeopts.inner, @@ -1089,7 +1124,9 @@ impl DB { } } - pub fn delete_opt(&self, key: &[u8], writeopts: &WriteOptions) -> Result<(), Error> { + pub fn delete_opt>(&self, key: K, writeopts: &WriteOptions) -> Result<(), Error> { + let key = key.as_ref(); + unsafe { ffi_try!(ffi::rocksdb_delete( self.inner, @@ -1101,12 +1138,15 @@ impl DB { } } - pub fn delete_cf_opt( + pub fn delete_cf_opt>( &self, cf: ColumnFamily, - key: &[u8], + key: K, writeopts: &WriteOptions, ) -> Result<(), Error> { + + let key = key.as_ref(); + unsafe { ffi_try!(ffi::rocksdb_delete_cf( self.inner, @@ -1119,32 +1159,47 @@ impl DB { } } - pub fn put(&self, key: &[u8], value: &[u8]) -> Result<(), Error> { - self.put_opt(key, value, &WriteOptions::default()) + pub fn put(&self, key: K, value: V) -> Result<(), Error> + where K: AsRef<[u8]>, + V: AsRef<[u8]> { + + self.put_opt(key.as_ref(), value.as_ref(), &WriteOptions::default()) } - pub fn put_cf(&self, cf: ColumnFamily, key: &[u8], value: &[u8]) -> Result<(), Error> { - self.put_cf_opt(cf, key, value, &WriteOptions::default()) + pub fn put_cf(&self, cf: ColumnFamily, key: K, value: V) -> Result<(), Error> + where K: AsRef<[u8]>, + V: AsRef<[u8]> { + + self.put_cf_opt(cf, key.as_ref(), value.as_ref(), &WriteOptions::default()) } - pub fn merge(&self, key: &[u8], value: &[u8]) -> Result<(), Error> { - self.merge_opt(key, value, &WriteOptions::default()) + pub fn merge(&self, key: K, value: V) -> Result<(), Error> + where K: AsRef<[u8]>, + V: AsRef<[u8]> { + + self.merge_opt(key.as_ref(), value.as_ref(), &WriteOptions::default()) } - pub fn merge_cf(&self, cf: ColumnFamily, key: &[u8], value: &[u8]) -> Result<(), Error> { - self.merge_cf_opt(cf, key, value, &WriteOptions::default()) + pub fn merge_cf(&self, cf: ColumnFamily, key: K, value: V) -> Result<(), Error> + where K: AsRef<[u8]>, + V: AsRef<[u8]> { + + self.merge_cf_opt(cf, key.as_ref(), value.as_ref(), &WriteOptions::default()) } - pub fn delete(&self, key: &[u8]) -> Result<(), Error> { - self.delete_opt(key, &WriteOptions::default()) + pub fn delete>(&self, key: K) -> Result<(), Error> { + self.delete_opt(key.as_ref(), &WriteOptions::default()) } - pub fn delete_cf(&self, cf: ColumnFamily, key: &[u8]) -> Result<(), Error> { - self.delete_cf_opt(cf, key, &WriteOptions::default()) + pub fn delete_cf>(&self, cf: ColumnFamily, key: K) -> Result<(), Error> { + self.delete_cf_opt(cf, key.as_ref(), &WriteOptions::default()) } - pub fn compact_range(&self, start: Option<&[u8]>, end: Option<&[u8]>) { + pub fn compact_range, E: AsRef<[u8]>>(&self, start: Option, end: Option) { unsafe { + let start = start.as_ref().map(|s| s.as_ref()); + let end = end.as_ref().map(|e| e.as_ref()); + ffi::rocksdb_compact_range( self.inner, opt_bytes_to_ptr(start), @@ -1217,7 +1272,13 @@ impl WriteBatch { } /// Insert a value into the database under the given key. - pub fn put(&mut self, key: &[u8], value: &[u8]) -> Result<(), Error> { + pub fn put(&mut self, key: K, value: V) -> Result<(), Error> + where K: AsRef<[u8]>, + V: AsRef<[u8]> { + + let key = key.as_ref(); + let value = value.as_ref(); + unsafe { ffi::rocksdb_writebatch_put( self.inner, @@ -1230,7 +1291,13 @@ impl WriteBatch { } } - pub fn put_cf(&mut self, cf: ColumnFamily, key: &[u8], value: &[u8]) -> Result<(), Error> { + pub fn put_cf(&mut self, cf: ColumnFamily, key: K, value: V) -> Result<(), Error> + where K: AsRef<[u8]>, + V: AsRef<[u8]> { + + let key = key.as_ref(); + let value = value.as_ref(); + unsafe { ffi::rocksdb_writebatch_put_cf( self.inner, @@ -1244,7 +1311,13 @@ impl WriteBatch { } } - pub fn merge(&mut self, key: &[u8], value: &[u8]) -> Result<(), Error> { + pub fn merge(&mut self, key: K, value: V) -> Result<(), Error> + where K: AsRef<[u8]>, + V: AsRef<[u8]> { + + let key = key.as_ref(); + let value = value.as_ref(); + unsafe { ffi::rocksdb_writebatch_merge( self.inner, @@ -1257,7 +1330,13 @@ impl WriteBatch { } } - pub fn merge_cf(&mut self, cf: ColumnFamily, key: &[u8], value: &[u8]) -> Result<(), Error> { + pub fn merge_cf(&mut self, cf: ColumnFamily, key: K, value: V) -> Result<(), Error> + where K: AsRef<[u8]>, + V: AsRef<[u8]> { + + let key = key.as_ref(); + let value = value.as_ref(); + unsafe { ffi::rocksdb_writebatch_merge_cf( self.inner, @@ -1274,7 +1353,9 @@ impl WriteBatch { /// Remove the database entry for key. /// /// Returns an error if the key was not found. - pub fn delete(&mut self, key: &[u8]) -> Result<(), Error> { + pub fn delete>(&mut self, key: K) -> Result<(), Error> { + let key = key.as_ref(); + unsafe { ffi::rocksdb_writebatch_delete( self.inner, @@ -1285,7 +1366,9 @@ impl WriteBatch { } } - pub fn delete_cf(&mut self, cf: ColumnFamily, key: &[u8]) -> Result<(), Error> { + pub fn delete_cf>(&mut self, cf: ColumnFamily, key: K) -> Result<(), Error> { + let key = key.as_ref(); + unsafe { ffi::rocksdb_writebatch_delete_cf( self.inner, @@ -1354,7 +1437,9 @@ impl ReadOptions { } } - pub fn set_iterate_upper_bound(&mut self, key: &[u8]) { + pub fn set_iterate_upper_bound>(&mut self, key: K) { + let key = key.as_ref(); + unsafe { ffi::rocksdb_readoptions_set_iterate_upper_bound( self.inner, diff --git a/src/ffi_util.rs b/src/ffi_util.rs index 49c298e..cce3b83 100644 --- a/src/ffi_util.rs +++ b/src/ffi_util.rs @@ -26,9 +26,9 @@ pub fn error_message(ptr: *const c_char) -> String { s } -pub fn opt_bytes_to_ptr(opt: Option<&[u8]>) -> *const c_char { +pub fn opt_bytes_to_ptr>(opt: Option) -> *const c_char { match opt { - Some(v) => v.as_ptr() as *const c_char, + Some(v) => v.as_ref().as_ptr() as *const c_char, None => ptr::null(), } } diff --git a/src/merge_operator.rs b/src/merge_operator.rs index 69551d8..fb3d1c7 100644 --- a/src/merge_operator.rs +++ b/src/merge_operator.rs @@ -368,7 +368,7 @@ mod test { let _ = db.get(b"k2"); } } - db.compact_range(None, None); + db.compact_range(None::<&[u8]>, None::<&[u8]>); let d1 = db.clone(); let d2 = db.clone(); let d3 = db.clone(); @@ -399,7 +399,7 @@ mod test { let _ = d2.get(b"k2"); } } - d2.compact_range(None, None); + d2.compact_range(None::<&[u8]>, None::<&[u8]>); }); h2.join().unwrap(); let h3 = thread::spawn(move || { diff --git a/tests/test_compationfilter.rs b/tests/test_compationfilter.rs index 5cd4dc0..c5fc8a2 100644 --- a/tests/test_compationfilter.rs +++ b/tests/test_compationfilter.rs @@ -43,7 +43,7 @@ fn compaction_filter_test() { let _ = db.put(b"k1", b"a"); let _ = db.put(b"_k", b"b"); let _ = db.put(b"%k", b"c"); - db.compact_range(None, None); + db.compact_range(None::<&[u8]>, None::<&[u8]>); assert_eq!(&*db.get(b"k1").unwrap().unwrap(), b"a"); assert!(db.get(b"_k").unwrap().is_none()); assert_eq!(&*db.get(b"%k").unwrap().unwrap(), b"secret"); From 8f843a8eb78f5c0236b779c94a50c74303032487 Mon Sep 17 00:00:00 2001 From: Jordan Terrell Date: Sun, 3 Feb 2019 04:33:04 -0600 Subject: [PATCH 08/11] Adding missing end-of-file newlines... --- tests/test_compationfilter.rs | 2 +- tests/test_db.rs | 2 +- tests/util/mod.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_compationfilter.rs b/tests/test_compationfilter.rs index c5fc8a2..feccc46 100644 --- a/tests/test_compationfilter.rs +++ b/tests/test_compationfilter.rs @@ -48,4 +48,4 @@ fn compaction_filter_test() { assert!(db.get(b"_k").unwrap().is_none()); assert_eq!(&*db.get(b"%k").unwrap().unwrap(), b"secret"); } -} \ No newline at end of file +} diff --git a/tests/test_db.rs b/tests/test_db.rs index 01f5b92..51a276e 100644 --- a/tests/test_db.rs +++ b/tests/test_db.rs @@ -180,4 +180,4 @@ fn set_option_test() { ]; db.set_options(&multiple_options).unwrap(); } -} \ No newline at end of file +} diff --git a/tests/util/mod.rs b/tests/util/mod.rs index 5987bbe..1e028ba 100644 --- a/tests/util/mod.rs +++ b/tests/util/mod.rs @@ -39,4 +39,4 @@ impl AsRef for DBPath { fn as_ref(&self) -> &Path { &self.path } -} \ No newline at end of file +} From 4a974054b2248813e4de76449895b83647caa5c2 Mon Sep 17 00:00:00 2001 From: Jordan Terrell Date: Sun, 3 Feb 2019 05:04:56 -0600 Subject: [PATCH 09/11] Fixing incorrect copyright year... --- tests/test_compationfilter.rs | 2 +- tests/test_db.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_compationfilter.rs b/tests/test_compationfilter.rs index feccc46..26529be 100644 --- a/tests/test_compationfilter.rs +++ b/tests/test_compationfilter.rs @@ -1,4 +1,4 @@ -// Copyright 2014 Tyler Neely +// Copyright 2019 Tyler Neely // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/tests/test_db.rs b/tests/test_db.rs index 51a276e..da71633 100644 --- a/tests/test_db.rs +++ b/tests/test_db.rs @@ -1,4 +1,4 @@ -// Copyright 2014 Tyler Neely +// Copyright 2019 Tyler Neely // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. From cf4679d8e8347ef54fa65a7594ba5194a88d34ff Mon Sep 17 00:00:00 2001 From: Jordan Terrell Date: Sun, 3 Feb 2019 06:00:34 -0600 Subject: [PATCH 10/11] Some test cleanup... --- tests/test_db.rs | 54 +++++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/tests/test_db.rs b/tests/test_db.rs index da71633..03344bc 100644 --- a/tests/test_db.rs +++ b/tests/test_db.rs @@ -20,7 +20,6 @@ mod util; use libc::{size_t}; use rocksdb::{DB, DBVector, Error, IteratorMode, Options, WriteBatch}; -use std::str; use util::DBPath; #[test] @@ -35,14 +34,20 @@ fn test_db_vector() { #[test] fn external() { - let path = DBPath::new("_rust_rocksdb_externaltest"); - let db = DB::open_default(&path).unwrap(); - let p = db.put(b"k1", b"v1111"); - assert!(p.is_ok()); - let r: Result, Error> = db.get(b"k1"); - assert!(r.unwrap().unwrap().to_utf8().unwrap() == "v1111"); - assert!(db.delete(b"k1").is_ok()); - assert!(db.get(b"k1").unwrap().is_none()); + let path = DBPath::new("_rust_rocksdb_externaltest"); + + { + let db = DB::open_default(&path).unwrap(); + + let p = db.put(b"k1", b"v1111"); + assert!(p.is_ok()); + + let r: Result, Error> = db.get(b"k1"); + + assert!(r.unwrap().unwrap().to_utf8().unwrap() == "v1111"); + assert!(db.delete(b"k1").is_ok()); + assert!(db.get(b"k1").unwrap().is_none()); + } } #[test] @@ -107,20 +112,18 @@ fn writebatch_works() { fn iterator_test() { let path = DBPath::new("_rust_rocksdb_iteratortest"); { + let data = [(b"k1", b"v1111"), (b"k2", b"v2222"), (b"k3", b"v3333")]; let db = DB::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()); + + for (key, value) in &data { + assert!(db.put(key, value).is_ok()); + } + let iter = db.iterator(IteratorMode::Start); - for (k, v) in iter { - println!( - "Hello {}: {}", - str::from_utf8(&*k).unwrap(), - str::from_utf8(&*v).unwrap() - ); + + for (idx, (db_key, db_value)) in iter.enumerate() { + let (key, value) = data[idx]; + assert_eq!((&key[..], &value[..]), (db_key.as_ref(), db_value.as_ref())); } } } @@ -130,16 +133,15 @@ fn snapshot_test() { let path = DBPath::new("_rust_rocksdb_snapshottest"); { let db = DB::open_default(&path).unwrap(); - let p = db.put(b"k1", b"v1111"); - assert!(p.is_ok()); + + assert!(db.put(b"k1", b"v1111").is_ok()); let snap = db.snapshot(); let r: Result, Error> = snap.get(b"k1"); assert!(r.unwrap().unwrap().to_utf8().unwrap() == "v1111"); - let p = db.put(b"k2", b"v2222"); - assert!(p.is_ok()); - + assert!(db.put(b"k2", b"v2222").is_ok()); + assert!(db.get(b"k2").unwrap().is_some()); assert!(snap.get(b"k2").unwrap().is_none()); } From 4dfedd9dfd7dca0f69213260ce2f328e02bd6cd1 Mon Sep 17 00:00:00 2001 From: Jordan Terrell Date: Sun, 3 Feb 2019 07:14:37 -0600 Subject: [PATCH 11/11] Removing unnecessary let bindings in tests... --- tests/test_db.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/tests/test_db.rs b/tests/test_db.rs index 03344bc..ecb0bb5 100644 --- a/tests/test_db.rs +++ b/tests/test_db.rs @@ -39,8 +39,7 @@ fn external() { { let db = DB::open_default(&path).unwrap(); - let p = db.put(b"k1", b"v1111"); - assert!(p.is_ok()); + assert!(db.put(b"k1", b"v1111").is_ok()); let r: Result, Error> = db.get(b"k1"); @@ -82,8 +81,7 @@ fn writebatch_works() { assert_eq!(batch.len(), 1); assert!(!batch.is_empty()); assert!(db.get(b"k1").unwrap().is_none()); - let p = db.write(batch); - assert!(p.is_ok()); + assert!(db.write(batch).is_ok()); let r: Result, Error> = db.get(b"k1"); assert!(r.unwrap().unwrap().to_utf8().unwrap() == "v1111"); } @@ -93,8 +91,7 @@ fn writebatch_works() { let _ = batch.delete(b"k1"); assert_eq!(batch.len(), 1); assert!(!batch.is_empty()); - let p = db.write(batch); - assert!(p.is_ok()); + assert!(db.write(batch).is_ok()); assert!(db.get(b"k1").unwrap().is_none()); } { @@ -137,8 +134,7 @@ fn snapshot_test() { assert!(db.put(b"k1", b"v1111").is_ok()); let snap = db.snapshot(); - let r: Result, Error> = snap.get(b"k1"); - assert!(r.unwrap().unwrap().to_utf8().unwrap() == "v1111"); + assert!(snap.get(b"k1").unwrap().unwrap().to_utf8().unwrap() == "v1111"); assert!(db.put(b"k2", b"v2222").is_ok());