|
|
@ -3,13 +3,85 @@ use self::libc::{c_void, size_t}; |
|
|
|
use std::io::{IoError}; |
|
|
|
use std::io::{IoError}; |
|
|
|
use std::c_vec::CVec; |
|
|
|
use std::c_vec::CVec; |
|
|
|
use std::c_str::CString; |
|
|
|
use std::c_str::CString; |
|
|
|
|
|
|
|
use std::str::from_utf8; |
|
|
|
|
|
|
|
|
|
|
|
use rocksdb_ffi; |
|
|
|
use rocksdb_ffi; |
|
|
|
|
|
|
|
|
|
|
|
// TODO learn more about lifetimes and determine if it's appropriate to keep
|
|
|
|
pub struct Rocksdb { |
|
|
|
// inner on the stack, instead.
|
|
|
|
inner: rocksdb_ffi::RocksdbInstance, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl Rocksdb { |
|
|
|
|
|
|
|
pub fn put(&self, key: &[u8], value: &[u8]) -> Result<(), String> { |
|
|
|
|
|
|
|
unsafe { |
|
|
|
|
|
|
|
let writeopts = rocksdb_ffi::rocksdb_writeoptions_create(); |
|
|
|
|
|
|
|
let err = 0 as *mut i8; |
|
|
|
|
|
|
|
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() { |
|
|
|
|
|
|
|
let cs = CString::new(err as *const i8, true); |
|
|
|
|
|
|
|
match cs.as_str() { |
|
|
|
|
|
|
|
Some(error_string) => |
|
|
|
|
|
|
|
return Err(error_string.to_string()), |
|
|
|
|
|
|
|
None => { |
|
|
|
|
|
|
|
let ie = IoError::last_error(); |
|
|
|
|
|
|
|
return Err(format!( |
|
|
|
|
|
|
|
"ERROR: desc:{}, details:{}", |
|
|
|
|
|
|
|
ie.desc, |
|
|
|
|
|
|
|
ie.detail.unwrap_or_else( |
|
|
|
|
|
|
|
|| {"none provided by OS".to_string()}))) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return Ok(()) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn get<'a>(&self, key: &[u8]) -> RocksdbResult<'a, RocksdbVector, String> { |
|
|
|
|
|
|
|
unsafe { |
|
|
|
|
|
|
|
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 \ |
|
|
|
|
|
|
|
may be indicative of a mis-compiled or mis-loaded rocksdb \ |
|
|
|
|
|
|
|
library.".to_string()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let val_len: size_t = 0; |
|
|
|
|
|
|
|
let val_len_ptr = &val_len as *const size_t; |
|
|
|
|
|
|
|
let err = 0 as *mut i8; |
|
|
|
|
|
|
|
let val = rocksdb_ffi::rocksdb_get(self.inner, readopts, key.as_ptr(), |
|
|
|
|
|
|
|
key.len() as size_t, val_len_ptr, err) as *mut u8; |
|
|
|
|
|
|
|
if err.is_not_null() { |
|
|
|
|
|
|
|
let cs = CString::new(err as *const i8, true); |
|
|
|
|
|
|
|
match cs.as_str() { |
|
|
|
|
|
|
|
Some(error_string) => |
|
|
|
|
|
|
|
return RocksdbResult::Error(error_string.to_string()), |
|
|
|
|
|
|
|
None => |
|
|
|
|
|
|
|
return RocksdbResult::Error("Unable to get value from \ |
|
|
|
|
|
|
|
rocksdb. (non-utf8 error received from underlying \ |
|
|
|
|
|
|
|
library)".to_string()), |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
match val.is_null() { |
|
|
|
|
|
|
|
true => RocksdbResult::None, |
|
|
|
|
|
|
|
false => { |
|
|
|
|
|
|
|
RocksdbResult::Some(RocksdbVector::from_c(val, val_len)) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn close(&self) { |
|
|
|
|
|
|
|
unsafe { rocksdb_ffi::rocksdb_close(self.inner); } |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pub struct RocksdbVector { |
|
|
|
pub struct RocksdbVector { |
|
|
|
inner: Box<CVec<u8>>, |
|
|
|
inner: CVec<u8>, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl RocksdbVector { |
|
|
|
impl RocksdbVector { |
|
|
@ -17,50 +89,31 @@ impl RocksdbVector { |
|
|
|
unsafe { |
|
|
|
unsafe { |
|
|
|
RocksdbVector { |
|
|
|
RocksdbVector { |
|
|
|
inner: |
|
|
|
inner: |
|
|
|
box CVec::new_with_dtor(val, val_len as uint, |
|
|
|
CVec::new_with_dtor(val, val_len as uint, |
|
|
|
proc(){ |
|
|
|
proc(){ libc::free(val as *mut c_void); }) |
|
|
|
libc::free(val as *mut c_void); |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pub fn as_slice(&self) -> &[u8] { |
|
|
|
pub fn as_slice<'a>(&'a self) -> &'a [u8] { |
|
|
|
self.inner.as_slice() |
|
|
|
self.inner.as_slice() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn to_utf8<'a>(&'a self) -> Option<&'a str> { |
|
|
|
|
|
|
|
from_utf8(self.inner.as_slice()) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// RocksdbResult exists because of the inherent difference between
|
|
|
|
// RocksdbResult exists because of the inherent difference between
|
|
|
|
// an operational failure and the absence of a possible result.
|
|
|
|
// an operational failure and the absence of a possible result.
|
|
|
|
#[deriving(Clone, PartialEq, PartialOrd, Eq, Ord, Show)] |
|
|
|
#[deriving(Clone, PartialEq, PartialOrd, Eq, Ord, Show)] |
|
|
|
pub enum RocksdbResult<T, E> { |
|
|
|
pub enum RocksdbResult<'a,T,E> { |
|
|
|
Some(T), |
|
|
|
Some(T), |
|
|
|
None, |
|
|
|
None, |
|
|
|
Error(E), |
|
|
|
Error(E), |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* |
|
|
|
impl <'a,T,E> RocksdbResult<'a,T,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"] |
|
|
|
#[unstable = "waiting for unboxed closures"] |
|
|
|
pub fn map<U>(self, f: |T| -> U) -> RocksdbResult<U,E> { |
|
|
|
pub fn map<U>(self, f: |T| -> U) -> RocksdbResult<U,E> { |
|
|
|
match self { |
|
|
|
match self { |
|
|
@ -70,6 +123,14 @@ impl <T,E> RocksdbResult<T,E> { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn unwrap(self) -> T { |
|
|
|
|
|
|
|
match self { |
|
|
|
|
|
|
|
RocksdbResult::Some(x) => x, |
|
|
|
|
|
|
|
RocksdbResult::None => panic!("Attempted unwrap on RocksdbResult::None"), |
|
|
|
|
|
|
|
RocksdbResult::Error(_) => panic!("Attempted unwrap on RocksdbResult::Error"), |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#[unstable = "waiting for unboxed closures"] |
|
|
|
#[unstable = "waiting for unboxed closures"] |
|
|
|
pub fn on_error<U>(self, f: |E| -> U) -> RocksdbResult<T,U> { |
|
|
|
pub fn on_error<U>(self, f: |E| -> U) -> RocksdbResult<T,U> { |
|
|
|
match self { |
|
|
|
match self { |
|
|
@ -80,7 +141,7 @@ impl <T,E> RocksdbResult<T,E> { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#[unstable = "waiting for unboxed closures"] |
|
|
|
#[unstable = "waiting for unboxed closures"] |
|
|
|
pub fn on_absent<U>(self, f: || -> ()) -> RocksdbResult<T,E> { |
|
|
|
pub fn on_absent(self, f: || -> ()) -> RocksdbResult<T,E> { |
|
|
|
match self { |
|
|
|
match self { |
|
|
|
RocksdbResult::Some(x) => RocksdbResult::Some(x), |
|
|
|
RocksdbResult::Some(x) => RocksdbResult::Some(x), |
|
|
|
RocksdbResult::None => { |
|
|
|
RocksdbResult::None => { |
|
|
@ -114,77 +175,8 @@ impl <T,E> RocksdbResult<T,E> { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pub struct Rocksdb { |
|
|
|
pub fn create_or_open(path: String) -> Result<Rocksdb, String> { |
|
|
|
inner: rocksdb_ffi::RocksdbInstance, |
|
|
|
open(path, true) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl Rocksdb { |
|
|
|
|
|
|
|
pub fn put(&self, key: &[u8], value: &[u8]) -> Result<bool, String> { |
|
|
|
|
|
|
|
unsafe { |
|
|
|
|
|
|
|
let writeopts = rocksdb_ffi::rocksdb_writeoptions_create(); |
|
|
|
|
|
|
|
let err = 0 as *mut i8; |
|
|
|
|
|
|
|
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() { |
|
|
|
|
|
|
|
let cs = CString::new(err as *const i8, true); |
|
|
|
|
|
|
|
match cs.as_str() { |
|
|
|
|
|
|
|
Some(error_string) => |
|
|
|
|
|
|
|
return Err(error_string.to_string()), |
|
|
|
|
|
|
|
None => { |
|
|
|
|
|
|
|
let ie = IoError::last_error(); |
|
|
|
|
|
|
|
return Err(format!( |
|
|
|
|
|
|
|
"ERROR: desc:{}, details:{}", |
|
|
|
|
|
|
|
ie.desc, |
|
|
|
|
|
|
|
ie.detail.unwrap_or_else( |
|
|
|
|
|
|
|
|| {"none provided by OS".to_string()}))) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return Ok(true) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn get(&self, key: &[u8]) -> RocksdbResult<RocksdbVector, String> { |
|
|
|
|
|
|
|
unsafe { |
|
|
|
|
|
|
|
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 \ |
|
|
|
|
|
|
|
may be indicative of a mis-compiled or mis-loaded rocksdb \ |
|
|
|
|
|
|
|
library.".to_string()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let val_len: size_t = 0; |
|
|
|
|
|
|
|
let val_len_ptr = &val_len as *const size_t; |
|
|
|
|
|
|
|
let err = 0 as *mut i8; |
|
|
|
|
|
|
|
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); |
|
|
|
|
|
|
|
match cs.as_str() { |
|
|
|
|
|
|
|
Some(error_string) => |
|
|
|
|
|
|
|
return RocksdbResult::Error(error_string.to_string()), |
|
|
|
|
|
|
|
None => |
|
|
|
|
|
|
|
return RocksdbResult::Error("Unable to get value from \ |
|
|
|
|
|
|
|
rocksdb. (non-utf8 error received from underlying \ |
|
|
|
|
|
|
|
library)".to_string()), |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
match val.is_null() { |
|
|
|
|
|
|
|
true => RocksdbResult::None, |
|
|
|
|
|
|
|
false => { |
|
|
|
|
|
|
|
RocksdbResult::Some(RocksdbVector::from_c(val, val_len)) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn close(&self) { |
|
|
|
|
|
|
|
unsafe { rocksdb_ffi::rocksdb_close(self.inner); } |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pub fn open(path: String, create_if_missing: bool) -> Result<Rocksdb, String> { |
|
|
|
pub fn open(path: String, create_if_missing: bool) -> Result<Rocksdb, String> { |
|
|
@ -206,6 +198,9 @@ pub fn open(path: String, create_if_missing: bool) -> Result<Rocksdb, String> { |
|
|
|
let cpath = path.to_c_str(); |
|
|
|
let cpath = path.to_c_str(); |
|
|
|
let cpath_ptr = cpath.as_ptr(); |
|
|
|
let cpath_ptr = cpath.as_ptr(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//TODO test path here, as if rocksdb fails it will just crash the
|
|
|
|
|
|
|
|
// process currently
|
|
|
|
|
|
|
|
|
|
|
|
let err = 0 as *mut i8; |
|
|
|
let err = 0 as *mut i8; |
|
|
|
let db = rocksdb_ffi::rocksdb_open(opts, cpath_ptr, err); |
|
|
|
let db = rocksdb_ffi::rocksdb_open(opts, cpath_ptr, err); |
|
|
|
let rocksdb_ffi::RocksdbInstance(db_ptr) = db; |
|
|
|
let rocksdb_ffi::RocksdbInstance(db_ptr) = db; |
|
|
|