diff --git a/.gitignore b/.gitignore index 8a4f43d..4fc9764 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ *.swp target Cargo.lock +*.orig diff --git a/Cargo.toml b/Cargo.toml index 894a6f7..bed6a80 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "rocksdb" description = "A Rust wrapper for Facebook's RocksDB embeddable database." -version = "0.1.1" +version = "0.2.0" authors = ["Tyler Neely ", "David Greenberg "] license = "Apache-2.0" keywords = ["database", "embedded", "LSM-tree", "persistence"] diff --git a/README.md b/README.md index baa2f63..4d4bd49 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ rust-rocksdb [![Build Status](https://travis-ci.org/spacejam/rust-rocksdb.svg?branch=master)](https://travis-ci.org/spacejam/rust-rocksdb) [![crates.io](http://meritbadge.herokuapp.com/rocksdb)](https://crates.io/crates/rocksdb) -This library has been tested against RocksDB 3.13.1 on linux and OSX. The 0.1.1 crate should work with the Rust 1.2 stable and nightly releases as of 9/7/15. +This library has been tested against RocksDB 3.13.1 on linux and OSX. The 0.2.0 crate should work with the Rust 1.4 stable and nightly releases as of 11/7/15. ### status - [x] basic open/put/get/delete/close @@ -16,6 +16,7 @@ This library has been tested against RocksDB 3.13.1 on linux and OSX. The 0.1.1 - [x] comparator - [x] snapshot - [x] column family operations + - [ ] prefix seek - [ ] slicetransform - [ ] windows support @@ -35,7 +36,7 @@ sudo make install ###### Cargo.toml ```rust [dependencies] -rocksdb = "~0.1.1" +rocksdb = "~0.2.0" ``` ###### Code ```rust @@ -45,12 +46,11 @@ use rocksdb::{DB, Writable}; fn main() { let mut db = DB::open_default("/path/for/rocksdb/storage").unwrap(); db.put(b"my key", b"my value"); - db.get(b"my key") - .map( |value| { - println!("retrieved value {}", value.to_utf8().unwrap()) - }) - .on_absent( || { println!("value not found") }) - .on_error( |e| { println!("operational problem encountered: {}", e) }); + match db.get(b"my key") { + Ok(Some(value)) => println!("retrieved value {}", value.to_utf8().unwrap()), + Ok(None) => println!("value not found"), + Err(e) => println!("operational problem encountered: {}", e), + } db.delete(b"my key"); } @@ -141,7 +141,7 @@ fn main() { db.merge(b"k1", b"d"); db.merge(b"k1", b"efg"); let r = db.get(b"k1"); - assert!(r.unwrap().to_utf8().unwrap() == "abcdefg"); + assert!(r.unwrap().unwrap().to_utf8().unwrap() == "abcdefg"); } ``` diff --git a/src/lib.rs b/src/lib.rs index e43636d..bdbb56f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,7 +15,7 @@ */ pub use ffi as rocksdb_ffi; pub use ffi::{new_bloom_filter, DBCompactionStyle, DBComparator}; -pub use rocksdb::{DB, DBResult, DBVector, WriteBatch, Writable, Direction}; +pub use rocksdb::{DB, DBVector, WriteBatch, Writable, Direction}; pub use rocksdb_options::{Options, BlockBasedOptions}; pub use merge_operator::MergeOperands; pub mod rocksdb; diff --git a/src/main.rs b/src/main.rs index 939fb45..0de0e57 100644 --- a/src/main.rs +++ b/src/main.rs @@ -48,16 +48,18 @@ fn main() { let path = "/tmp/rust-rocksdb"; let db = DB::open_default(path).unwrap(); assert!(db.put(b"my key", b"my value").is_ok()); - db.get(b"my key").map( |value| { + match db.get(b"my key") { + Ok(Some(value)) => { match value.to_utf8() { - Some(v) => - println!("retrieved utf8 value: {}", v), - None => - println!("did not read valid utf-8 out of the db"), + Some(v) => + println!("retrieved utf8 value: {}", v), + None => + println!("did not read valid utf-8 out of the db"), } - }) - .on_absent( || { println!("value not found") }) - .on_error( |e| { println!("error retrieving value: {}", e) }); + }, + Err(e) => println!("error retrieving value: {}", e), + _ => panic!("value not present!"), + } assert!(db.delete(b"my key").is_ok()); @@ -94,17 +96,18 @@ fn custom_merge() { db.merge(b"k1", b"d").unwrap(); db.merge(b"k1", b"efg").unwrap(); db.merge(b"k1", b"h").unwrap(); - db.get(b"k1").map( |value| { + match db.get(b"k1") { + Ok(Some(value)) => { match value.to_utf8() { - Some(v) => - println!("retrieved utf8 value: {}", v), - None => - println!("did not read valid utf-8 out of the db"), + Some(v) => + println!("retrieved utf8 value: {}", v), + None => + println!("did not read valid utf-8 out of the db"), } - }) - .on_absent( || { println!("value not found") }) - .on_error( |e| { println!("error retrieving value: {}", e) }); - + } + Err(e) => println!("error retrieving value: {}", e), + _ => panic!("value not present!"), + } } DB::destroy(&opts, path).is_ok(); } @@ -129,8 +132,7 @@ fn main() { None => panic!("value corrupted"), } }) - .on_absent( || { panic!("value not found") }) - .on_error( |e| { panic!("error retrieving value: {}", e) }); + .or_else( |e| { panic!("error retrieving value: {}", e) }); db.delete(b"k1"); } } diff --git a/src/merge_operator.rs b/src/merge_operator.rs index 4495380..4b863aa 100644 --- a/src/merge_operator.rs +++ b/src/merge_operator.rs @@ -21,7 +21,7 @@ use std::ptr; use std::slice; use rocksdb_options::Options; -use rocksdb::{DB, DBResult, DBVector, Writable}; +use rocksdb::{DB, DBVector, Writable}; pub struct MergeOperatorCallback { pub name: CString, @@ -196,21 +196,24 @@ fn mergetest() { db.merge(b"k1", b"efg"); let m = db.merge(b"k1", b"h"); assert!(m.is_ok()); - db.get(b"k1").map( |value| { + match db.get(b"k1") { + Ok(Some(value)) => { match value.to_utf8() { - Some(v) => - println!("retrieved utf8 value: {}", v), - None => - println!("did not read valid utf-8 out of the db"), + Some(v) => + println!("retrieved utf8 value: {}", v), + None => + println!("did not read valid utf-8 out of the db"), } - }).on_absent( || { println!("value not present!") }) - .on_error( |e| { println!("error reading value")}); //: {", e) }); + }, + Err(e) => { println!("error reading value")}, + _ => panic!("value not present"), + } assert!(m.is_ok()); - let r: DBResult = db.get(b"k1"); - assert!(r.unwrap().to_utf8().unwrap() == "abcdefgh"); + let r: Result, String> = db.get(b"k1"); + assert!(r.unwrap().unwrap().to_utf8().unwrap() == "abcdefgh"); assert!(db.delete(b"k1").is_ok()); - assert!(db.get(b"k1").is_none()); + assert!(db.get(b"k1").unwrap().is_none()); } assert!(DB::destroy(&opts, path).is_ok()); } diff --git a/src/rocksdb.rs b/src/rocksdb.rs index 4150c31..0a06fc1 100644 --- a/src/rocksdb.rs +++ b/src/rocksdb.rs @@ -327,11 +327,11 @@ impl DB { return Ok(()) } - pub fn get(&self, key: &[u8]) -> DBResult { + pub fn get(&self, key: &[u8]) -> Result, String> { unsafe { let readopts = rocksdb_ffi::rocksdb_readoptions_create(); if readopts.0.is_null() { - return DBResult::Error("Unable to create rocksdb read \ + return Err("Unable to create rocksdb read \ options. This is a fairly trivial call, and its failure \ may be indicative of a mis-compiled or mis-loaded rocksdb \ library.".to_string()); @@ -345,22 +345,22 @@ impl DB { key.as_ptr(), key.len() as size_t, val_len_ptr, err_ptr) as *mut u8; rocksdb_ffi::rocksdb_readoptions_destroy(readopts); if !err.is_null() { - return DBResult::Error(error_message(err)); + return Err(error_message(err)); } match val.is_null() { - true => DBResult::None, + true => Ok(None), false => { - DBResult::Some(DBVector::from_c(val, val_len)) + Ok(Some(DBVector::from_c(val, val_len))) } } } } - pub fn get_cf(&self, cf: DBCFHandle, key: &[u8]) -> DBResult { + pub fn get_cf(&self, cf: DBCFHandle, key: &[u8]) -> Result, String> { unsafe { let readopts = rocksdb_ffi::rocksdb_readoptions_create(); if readopts.0.is_null() { - return DBResult::Error("Unable to create rocksdb read \ + return Err("Unable to create rocksdb read \ options. This is a fairly trivial call, and its failure \ may be indicative of a mis-compiled or mis-loaded rocksdb \ library.".to_string()); @@ -375,12 +375,12 @@ impl DB { err_ptr) as *mut u8; rocksdb_ffi::rocksdb_readoptions_destroy(readopts); if !err.is_null() { - return DBResult::Error(error_message(err)); + return Err(error_message(err)); } match val.is_null() { - true => DBResult::None, + true => Ok(None), false => { - DBResult::Some(DBVector::from_c(val, val_len)) + Ok(Some(DBVector::from_c(val, val_len))) } } } @@ -691,76 +691,6 @@ impl DBVector { } } -// DBResult exists because of the inherent difference between -// an operational failure and the absence of a possible result. -#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Debug)] -pub enum DBResult { - Some(T), - None, - Error(E), -} - -impl DBResult { - pub fn map U>(self, f: F) -> DBResult { - match self { - DBResult::Some(x) => DBResult::Some(f(x)), - DBResult::None => DBResult::None, - DBResult::Error(e) => DBResult::Error(e), - } - } - - pub fn unwrap(self) -> T { - match self { - DBResult::Some(x) => x, - DBResult::None => - panic!("Attempted unwrap on DBResult::None"), - DBResult::Error(_) => - panic!("Attempted unwrap on DBResult::Error"), - } - } - - pub fn on_error U>(self, f: F) -> DBResult { - match self { - DBResult::Some(x) => DBResult::Some(x), - DBResult::None => DBResult::None, - DBResult::Error(e) => DBResult::Error(f(e)), - } - } - - pub fn on_absent ()>(self, f: F) -> DBResult { - match self { - DBResult::Some(x) => DBResult::Some(x), - DBResult::None => { - f(); - DBResult::None - }, - DBResult::Error(e) => DBResult::Error(e), - } - } - - pub fn is_some(self) -> bool { - match self { - DBResult::Some(_) => true, - DBResult::None => false, - DBResult::Error(_) => false, - } - } - pub fn is_none(self) -> bool { - match self { - DBResult::Some(_) => false, - DBResult::None => true, - DBResult::Error(_) => false, - } - } - pub fn is_error(self) -> bool { - match self { - DBResult::Some(_) => false, - DBResult::None => false, - DBResult::Error(_) => true, - } - } -} - #[test] fn external() { let path = "_rust_rocksdb_externaltest"; @@ -768,10 +698,10 @@ fn external() { let mut db = DB::open_default(path).unwrap(); let p = db.put(b"k1", b"v1111"); assert!(p.is_ok()); - let r: DBResult = db.get(b"k1"); - assert!(r.unwrap().to_utf8().unwrap() == "v1111"); + let r: Result, String> = db.get(b"k1"); + assert!(r.unwrap().unwrap().to_utf8().unwrap() == "v1111"); assert!(db.delete(b"k1").is_ok()); - assert!(db.get(b"k1").is_none()); + assert!(db.get(b"k1").unwrap().is_none()); } let opts = Options::new(); let result = DB::destroy(&opts, path); @@ -797,20 +727,20 @@ fn writebatch_works() { let mut db = DB::open_default(path).unwrap(); { // test put let mut batch = WriteBatch::new(); - assert!(db.get(b"k1").is_none()); + assert!(db.get(b"k1").unwrap().is_none()); batch.put(b"k1", b"v1111"); - assert!(db.get(b"k1").is_none()); + assert!(db.get(b"k1").unwrap().is_none()); let p = db.write(batch); assert!(p.is_ok()); - let r: DBResult = db.get(b"k1"); - assert!(r.unwrap().to_utf8().unwrap() == "v1111"); + let r: Result, String> = db.get(b"k1"); + assert!(r.unwrap().unwrap().to_utf8().unwrap() == "v1111"); } { // test delete let mut batch = WriteBatch::new(); batch.delete(b"k1"); let p = db.write(batch); assert!(p.is_ok()); - assert!(db.get(b"k1").is_none()); + assert!(db.get(b"k1").unwrap().is_none()); } } let opts = Options::new(); diff --git a/test/test_column_family.rs b/test/test_column_family.rs index cfa346c..d509e77 100644 --- a/test/test_column_family.rs +++ b/test/test_column_family.rs @@ -67,7 +67,7 @@ pub fn test_column_family() { }; let cf1 = *db.cf_handle("cf1").unwrap(); assert!(db.put_cf(cf1, b"k1", b"v1").is_ok()); - assert!(db.get_cf(cf1, b"k1").unwrap().to_utf8().unwrap() == "v1"); + assert!(db.get_cf(cf1, b"k1").unwrap().unwrap().to_utf8().unwrap() == "v1"); let p = db.put_cf(cf1, b"k1", b"a"); assert!(p.is_ok()); db.merge_cf(cf1, b"k1", b"b").unwrap(); @@ -77,20 +77,23 @@ pub fn test_column_family() { let m = db.merge_cf(cf1, b"k1", b"h"); println!("m is {:?}", m); // TODO assert!(m.is_ok()); - db.get(b"k1").map( |value| { + match db.get(b"k1") { + Ok(Some(value)) => { match value.to_utf8() { - Some(v) => - println!("retrieved utf8 value: {}", v), - None => - println!("did not read valid utf-8 out of the db"), + Some(v) => + println!("retrieved utf8 value: {}", v), + None => + println!("did not read valid utf-8 out of the db"), } - }).on_absent( || { println!("value not present!") }) - .on_error( |_| { println!("error reading value")}); //: {", e) }); + }, + Err(e) => println!("error reading value"), + _ => panic!("value not present!"), + } let _ = db.get_cf(cf1, b"k1"); // TODO assert!(r.unwrap().to_utf8().unwrap() == "abcdefgh"); assert!(db.delete(b"k1").is_ok()); - assert!(db.get(b"k1").is_none()); + assert!(db.get(b"k1").unwrap().is_none()); } // TODO should be able to use writebatch ops with a cf { diff --git a/test/test_multithreaded.rs b/test/test_multithreaded.rs index 76f25e2..dfec8b3 100644 --- a/test/test_multithreaded.rs +++ b/test/test_multithreaded.rs @@ -1,4 +1,4 @@ -use rocksdb::{Options, DB, Writable, DBResult}; +use rocksdb::{Options, DB, Writable}; use std::thread; use std::sync::Arc; @@ -31,7 +31,7 @@ pub fn test_multithreaded() { let j3 = thread::spawn(move|| { for _ in 1..N { match db3.get(b"key") { - DBResult::Some(v) => { + Ok(Some(v)) => { if &v[..] != b"value1" && &v[..] != b"value2" { assert!(false); }