|
|
|
@ -1,10 +1,10 @@ |
|
|
|
|
extern crate libc; |
|
|
|
|
use self::libc::{c_int, c_void, size_t}; |
|
|
|
|
use std::io::{IoResult, IoError}; |
|
|
|
|
use self::libc::{c_void, size_t}; |
|
|
|
|
use std::io::{IoError}; |
|
|
|
|
use std::c_vec::CVec; |
|
|
|
|
use std::c_str::CString; |
|
|
|
|
|
|
|
|
|
use ffi; |
|
|
|
|
use rocksdb_ffi; |
|
|
|
|
|
|
|
|
|
// TODO learn more about lifetimes and determine if it's appropriate to keep
|
|
|
|
|
// inner on the stack, instead.
|
|
|
|
@ -15,12 +15,13 @@ pub struct RocksdbVector { |
|
|
|
|
impl RocksdbVector { |
|
|
|
|
pub fn from_c(val: *mut u8, val_len: size_t) -> RocksdbVector { |
|
|
|
|
unsafe { |
|
|
|
|
RocksdbVector{ |
|
|
|
|
RocksdbVector { |
|
|
|
|
inner: |
|
|
|
|
box CVec::new_with_dtor(val, val_len as uint, |
|
|
|
|
proc(){ |
|
|
|
|
libc::free(val as *mut c_void); |
|
|
|
|
})} |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -29,7 +30,8 @@ impl RocksdbVector { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// RocksdbResult exists because of the inherent difference between
|
|
|
|
|
// an operational failure and the absence of a possible result.
|
|
|
|
|
#[deriving(Clone, PartialEq, PartialOrd, Eq, Ord, Show)] |
|
|
|
|
pub enum RocksdbResult<T, E> { |
|
|
|
|
Some(T), |
|
|
|
@ -37,6 +39,27 @@ pub enum RocksdbResult<T, E> { |
|
|
|
|
Error(E), |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
impl <E> RocksdbResult<Box<CVec<u8>>, E> { |
|
|
|
|
pub fn from_c(val: *mut u8, val_len: size_t) -> RocksdbResult<Box<CVec<u8>>, E> { |
|
|
|
|
unsafe { |
|
|
|
|
RocksdbResult::Some( |
|
|
|
|
box CVec::new_with_dtor(val, val_len as uint, |
|
|
|
|
proc(){ |
|
|
|
|
libc::free(val as *mut c_void); |
|
|
|
|
})) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn as_slice<'a>(self) -> Option<&'a [u8]> { |
|
|
|
|
match self { |
|
|
|
|
RocksdbResult::Some(x) => Some(x.as_slice()), |
|
|
|
|
RocksdbResult::None => None, |
|
|
|
|
RocksdbResult::Error(e) => None, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
*/ |
|
|
|
|
impl <T,E> RocksdbResult<T,E> { |
|
|
|
|
#[unstable = "waiting for unboxed closures"] |
|
|
|
|
pub fn map<U>(self, f: |T| -> U) -> RocksdbResult<U,E> { |
|
|
|
@ -70,38 +93,37 @@ impl <T,E> RocksdbResult<T,E> { |
|
|
|
|
|
|
|
|
|
pub fn is_some(self) -> bool { |
|
|
|
|
match self { |
|
|
|
|
RocksdbResult::Some(T) => true, |
|
|
|
|
RocksdbResult::Some(_) => true, |
|
|
|
|
RocksdbResult::None => false, |
|
|
|
|
RocksdbResult::Error(E) => false, |
|
|
|
|
RocksdbResult::Error(_) => false, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
pub fn is_none(self) -> bool { |
|
|
|
|
match self { |
|
|
|
|
RocksdbResult::Some(T) => false, |
|
|
|
|
RocksdbResult::Some(_) => false, |
|
|
|
|
RocksdbResult::None => true, |
|
|
|
|
RocksdbResult::Error(E) => false, |
|
|
|
|
RocksdbResult::Error(_) => false, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
pub fn is_error(self) -> bool { |
|
|
|
|
match self { |
|
|
|
|
RocksdbResult::Some(T) => false, |
|
|
|
|
RocksdbResult::Some(_) => false, |
|
|
|
|
RocksdbResult::None => false, |
|
|
|
|
RocksdbResult::Error(E) => true, |
|
|
|
|
RocksdbResult::Error(_) => true, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub struct Rocksdb { |
|
|
|
|
inner: ffi::RocksdbInstance, |
|
|
|
|
path: String, |
|
|
|
|
inner: rocksdb_ffi::RocksdbInstance, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl Rocksdb { |
|
|
|
|
pub fn put(&self, key: &[u8], value: &[u8]) -> Result<bool, String> { |
|
|
|
|
unsafe {
|
|
|
|
|
let writeopts = ffi::rocksdb_writeoptions_create(); |
|
|
|
|
unsafe { |
|
|
|
|
let writeopts = rocksdb_ffi::rocksdb_writeoptions_create(); |
|
|
|
|
let err = 0 as *mut i8; |
|
|
|
|
ffi::rocksdb_put(self.inner, writeopts, key.as_ptr(), |
|
|
|
|
rocksdb_ffi::rocksdb_put(self.inner, writeopts, key.as_ptr(), |
|
|
|
|
key.len() as size_t, value.as_ptr(), |
|
|
|
|
value.len() as size_t, err); |
|
|
|
|
if err.is_not_null() { |
|
|
|
@ -112,7 +134,7 @@ impl Rocksdb { |
|
|
|
|
None => { |
|
|
|
|
let ie = IoError::last_error(); |
|
|
|
|
return Err(format!( |
|
|
|
|
"ERROR: desc:{}, details:{}",
|
|
|
|
|
"ERROR: desc:{}, details:{}", |
|
|
|
|
ie.desc, |
|
|
|
|
ie.detail.unwrap_or_else( |
|
|
|
|
|| {"none provided by OS".to_string()}))) |
|
|
|
@ -125,8 +147,8 @@ impl Rocksdb { |
|
|
|
|
|
|
|
|
|
pub fn get(&self, key: &[u8]) -> RocksdbResult<RocksdbVector, String> { |
|
|
|
|
unsafe { |
|
|
|
|
let readopts = ffi::rocksdb_readoptions_create(); |
|
|
|
|
let ffi::RocksdbReadOptions(read_opts_ptr) = readopts; |
|
|
|
|
let readopts = rocksdb_ffi::rocksdb_readoptions_create(); |
|
|
|
|
let rocksdb_ffi::RocksdbReadOptions(read_opts_ptr) = readopts; |
|
|
|
|
if read_opts_ptr.is_null() { |
|
|
|
|
return RocksdbResult::Error("Unable to create rocksdb read \ |
|
|
|
|
options. This is a fairly trivial call, and its failure \ |
|
|
|
@ -137,7 +159,7 @@ impl Rocksdb { |
|
|
|
|
let val_len: size_t = 0; |
|
|
|
|
let val_len_ptr = &val_len as *const size_t; |
|
|
|
|
let err = 0 as *mut i8; |
|
|
|
|
let val = ffi::rocksdb_get(self.inner, readopts, key.as_ptr(), |
|
|
|
|
let val = rocksdb_ffi::rocksdb_get(self.inner, readopts, key.as_ptr(), |
|
|
|
|
key.len() as size_t, val_len_ptr, err); |
|
|
|
|
if err.is_not_null() { |
|
|
|
|
let cs = CString::new(err as *const i8, true); |
|
|
|
@ -160,33 +182,33 @@ impl Rocksdb { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn close(&self) { |
|
|
|
|
unsafe { ffi::rocksdb_close(self.inner); } |
|
|
|
|
unsafe { rocksdb_ffi::rocksdb_close(self.inner); } |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn open(path: String, create_if_missing: bool) -> Result<Rocksdb, String> { |
|
|
|
|
unsafe { |
|
|
|
|
let opts = ffi::rocksdb_options_create(); |
|
|
|
|
let ffi::RocksdbOptions(opt_ptr) = opts; |
|
|
|
|
let opts = rocksdb_ffi::rocksdb_options_create(); |
|
|
|
|
let rocksdb_ffi::RocksdbOptions(opt_ptr) = opts; |
|
|
|
|
if opt_ptr.is_null() { |
|
|
|
|
return Err("Could not create options".to_string()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ffi::rocksdb_options_increase_parallelism(opts, 2); |
|
|
|
|
//ffi::rocksdb_options_optimize_level_style_compaction(opts, 0);
|
|
|
|
|
|
|
|
|
|
//rocksdb_ffi::rocksdb_options_increase_parallelism(opts, 2);
|
|
|
|
|
//rocksdb_ffi::rocksdb_options_optimize_level_style_compaction(opts, 0);
|
|
|
|
|
|
|
|
|
|
match create_if_missing { |
|
|
|
|
true => ffi::rocksdb_options_set_create_if_missing(opts, 1), |
|
|
|
|
false => ffi::rocksdb_options_set_create_if_missing(opts, 0), |
|
|
|
|
true => rocksdb_ffi::rocksdb_options_set_create_if_missing(opts, 1), |
|
|
|
|
false => rocksdb_ffi::rocksdb_options_set_create_if_missing(opts, 0), |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
let cpath = path.to_c_str(); |
|
|
|
|
let cpath_ptr = cpath.as_ptr(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let err = 0 as *mut i8; |
|
|
|
|
let db = ffi::rocksdb_open(opts, cpath_ptr, err);
|
|
|
|
|
let ffi::RocksdbInstance(db_ptr) = db; |
|
|
|
|
let db = rocksdb_ffi::rocksdb_open(opts, cpath_ptr, err); |
|
|
|
|
let rocksdb_ffi::RocksdbInstance(db_ptr) = db; |
|
|
|
|
if err.is_not_null() { |
|
|
|
|
let cs = CString::new(err as *const i8, true); |
|
|
|
|
match cs.as_str() { |
|
|
|
@ -199,14 +221,16 @@ pub fn open(path: String, create_if_missing: bool) -> Result<Rocksdb, String> { |
|
|
|
|
if db_ptr.is_null() { |
|
|
|
|
return Err("Could not initialize database.".to_string()); |
|
|
|
|
} |
|
|
|
|
Ok(Rocksdb{inner: db, path: path}) |
|
|
|
|
Ok(Rocksdb{inner: db}) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[allow(dead_code)] |
|
|
|
|
#[test] |
|
|
|
|
fn external() { |
|
|
|
|
let db = open("testdb".to_string(), true).unwrap(); |
|
|
|
|
db.put(b"k1", b"v1111"); |
|
|
|
|
let db = open("externaltest".to_string(), true).unwrap(); |
|
|
|
|
let p = db.put(b"k1", b"v1111"); |
|
|
|
|
assert!(p.is_ok()); |
|
|
|
|
let r: RocksdbResult<RocksdbVector, String> = db.get(b"k1"); |
|
|
|
|
//assert!(r.is_some());
|
|
|
|
|
r.map(|v| { assert!(v.as_slice().len() == 5); } ); |
|
|
|
|