some cleanups and interface smoothing

master
Tyler Neely 10 years ago
parent 59af66101c
commit e1142f4f2f
  1. 34
      README.md
  2. 8
      rocksdb-sys/lib.rs
  3. 1
      src/lib.rs
  4. 22
      src/main.rs
  5. 201
      src/rocksdb.rs

@ -4,22 +4,32 @@ rust-rocksdb
### running ### running
- Cargo.toml - Cargo.toml
```rust ```rust
[dependencies.rocksdb] [dependencies.rocksdb]
git = "https://github.com/spacejam/rust-rocksdb" git = "https://github.com/spacejam/rust-rocksdb"
``` ```
- Code - Code
```rust ```rust
extern crate rocksdb; extern crate rocksdb;
fn main() { fn main() {
let db = rocksdb::open("/path/to/db".to_string(), true).unwrap(); match rocksdb::create_or_open("/path/for/rocksdb/storage".to_string()) {
assert!(db.put(b"hey", b"v1111").is_ok()); Ok(db) => {
db.get(b"hey").map( |raw| { db.put(b"my key", b"my value");
std::str::from_utf8(raw.as_slice()).map( |v| {
println!("value: {}", v); db.get(b"my key").map( |value| {
}) match value.to_utf8() {
}); Some(v) =>
db.close() println!("retrieved utf8 value {}", v),
None =>
println!("did not read valid utf-8 out of the db"),
}});
db.get(b"NOT my key").on_absent(|| { println!("value not found") });
db.close();
},
Err(e) => panic!(e),
}
} }
``` ```

@ -105,7 +105,7 @@ extern {
pub fn rocksdb_readoptions_create() -> RocksdbReadOptions; pub fn rocksdb_readoptions_create() -> RocksdbReadOptions;
pub fn rocksdb_get(db: RocksdbInstance, readopts: RocksdbReadOptions, pub fn rocksdb_get(db: RocksdbInstance, readopts: RocksdbReadOptions,
k: *const u8, kLen: size_t, k: *const u8, kLen: size_t,
valLen: *const size_t, err: *mut i8) -> *mut u8; valLen: *const size_t, err: *mut i8) -> *mut c_void;
pub fn rocksdb_close(db: RocksdbInstance); pub fn rocksdb_close(db: RocksdbInstance);
pub fn rocksdb_destroy_db( pub fn rocksdb_destroy_db(
options: RocksdbOptions, path: *const i8, err: *mut i8); options: RocksdbOptions, path: *const i8, err: *mut i8);
@ -122,7 +122,7 @@ fn internal() {
let opts = rocksdb_options_create(); let opts = rocksdb_options_create();
let RocksdbOptions(opt_ptr) = opts; let RocksdbOptions(opt_ptr) = opts;
assert!(opt_ptr.is_not_null()); assert!(opt_ptr.is_not_null());
rocksdb_options_increase_parallelism(opts, 0); rocksdb_options_increase_parallelism(opts, 0);
rocksdb_options_optimize_level_style_compaction(opts, 0); rocksdb_options_optimize_level_style_compaction(opts, 0);
rocksdb_options_set_create_if_missing(opts, 1); rocksdb_options_set_create_if_missing(opts, 1);
@ -130,9 +130,9 @@ fn internal() {
let rustpath = "internaltest"; let rustpath = "internaltest";
let cpath = rustpath.to_c_str(); let cpath = rustpath.to_c_str();
let cpath_ptr = cpath.as_ptr(); let cpath_ptr = cpath.as_ptr();
let err = 0 as *mut i8; let err = 0 as *mut i8;
let db = rocksdb_open(opts, cpath_ptr, err); let db = rocksdb_open(opts, cpath_ptr, err);
assert!(err.is_null()); assert!(err.is_null());
libc::free(err as *mut c_void); libc::free(err as *mut c_void);

@ -5,6 +5,7 @@
extern crate "rocksdb-sys" as rocksdb_ffi; extern crate "rocksdb-sys" as rocksdb_ffi;
pub use rocksdb::{ pub use rocksdb::{
create_or_open,
open, open,
Rocksdb, Rocksdb,
RocksdbResult, RocksdbResult,

@ -5,10 +5,24 @@ use test::Bencher;
#[allow(dead_code)] #[allow(dead_code)]
fn main() { fn main() {
let db = open("testdb".to_string(), true).unwrap(); match rocksdb::create_or_open("/tmp/rust-rocksdb".to_string()) {
assert!(db.put(b"hey", b"v1111").is_ok()); Ok(db) => {
db.get(b"hey").map(|raw| { std::str::from_utf8(raw.as_slice()).map(|v| {println!("value: {}", v); })}); db.put(b"my key", b"my value");
db.close();
db.get(b"my key").map( |value| {
match value.to_utf8() {
Some(v) =>
println!("retrieved utf8 value {}", v),
None =>
println!("did not read valid utf-8 out of the db"),
}});
db.get(b"NOT my key").on_absent(|| { println!("value not found") });
db.close();
},
Err(e) => panic!(e),
}
} }
#[allow(dead_code)] #[allow(dead_code)]

@ -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;

Loading…
Cancel
Save