Merge branch 'master' of github.com:spacejam/rust-rocksdb

master
Tyler Neely 8 years ago
commit da7590e575
  1. 107
      src/db.rs
  2. 13
      src/lib.rs
  3. 2
      test/test_column_family.rs

@ -14,7 +14,7 @@
// //
use {DB, Error, Options, WriteOptions}; use {DB, Error, Options, WriteOptions, ColumnFamily};
use ffi; use ffi;
use ffi_util::opt_bytes_to_ptr; use ffi_util::opt_bytes_to_ptr;
@ -220,12 +220,12 @@ impl DBIterator {
} }
fn new_cf(db: &DB, fn new_cf(db: &DB,
cf_handle: *mut ffi::rocksdb_column_family_handle_t, cf_handle: ColumnFamily,
readopts: &ReadOptions, readopts: &ReadOptions,
mode: IteratorMode) mode: IteratorMode)
-> Result<DBIterator, Error> { -> Result<DBIterator, Error> {
unsafe { unsafe {
let iterator = ffi::rocksdb_create_iterator_cf(db.inner, readopts.inner, cf_handle); let iterator = ffi::rocksdb_create_iterator_cf(db.inner, readopts.inner, cf_handle.inner);
let mut rv = DBIterator { let mut rv = DBIterator {
inner: iterator, inner: iterator,
@ -262,7 +262,7 @@ impl<'a> Snapshot<'a> {
} }
pub fn iterator_cf(&self, pub fn iterator_cf(&self,
cf_handle: *mut ffi::rocksdb_column_family_handle_t, cf_handle: ColumnFamily,
mode: IteratorMode) mode: IteratorMode)
-> Result<DBIterator, Error> { -> Result<DBIterator, Error> {
let mut readopts = ReadOptions::default(); let mut readopts = ReadOptions::default();
@ -277,7 +277,7 @@ impl<'a> Snapshot<'a> {
} }
pub fn get_cf(&self, pub fn get_cf(&self,
cf: *mut ffi::rocksdb_column_family_handle_t, cf: ColumnFamily,
key: &[u8]) key: &[u8])
-> Result<Option<DBVector>, Error> { -> Result<Option<DBVector>, Error> {
let mut readopts = ReadOptions::default(); let mut readopts = ReadOptions::default();
@ -379,7 +379,7 @@ impl DB {
} }
for (n, h) in cfs_v.iter().zip(cfhandles) { for (n, h) in cfs_v.iter().zip(cfhandles) {
cf_map.insert(n.to_string(), h); cf_map.insert(n.to_string(), ColumnFamily { inner: h });
} }
} }
@ -462,7 +462,7 @@ impl DB {
} }
pub fn get_cf_opt(&self, pub fn get_cf_opt(&self,
cf: *mut ffi::rocksdb_column_family_handle_t, cf: ColumnFamily,
key: &[u8], key: &[u8],
readopts: &ReadOptions) readopts: &ReadOptions)
-> Result<Option<DBVector>, Error> { -> Result<Option<DBVector>, Error> {
@ -479,7 +479,7 @@ impl DB {
let mut val_len: size_t = 0; let mut val_len: size_t = 0;
let val = ffi_try!(ffi::rocksdb_get_cf(self.inner, let val = ffi_try!(ffi::rocksdb_get_cf(self.inner,
readopts.inner, readopts.inner,
cf, cf.inner,
key.as_ptr() as *const c_char, key.as_ptr() as *const c_char,
key.len() as size_t, key.len() as size_t,
&mut val_len)) as *mut u8; &mut val_len)) as *mut u8;
@ -492,7 +492,7 @@ impl DB {
} }
pub fn get_cf(&self, pub fn get_cf(&self,
cf: *mut ffi::rocksdb_column_family_handle_t, cf: ColumnFamily,
key: &[u8]) key: &[u8])
-> Result<Option<DBVector>, Error> { -> Result<Option<DBVector>, Error> {
self.get_cf_opt(cf, key, &ReadOptions::default()) self.get_cf_opt(cf, key, &ReadOptions::default())
@ -501,7 +501,7 @@ impl DB {
pub fn create_cf(&mut self, pub fn create_cf(&mut self,
name: &str, name: &str,
opts: &Options) opts: &Options)
-> Result<*mut ffi::rocksdb_column_family_handle_t, Error> { -> Result<ColumnFamily, Error> {
let cname = match CString::new(name.as_bytes()) { let cname = match CString::new(name.as_bytes()) {
Ok(c) => c, Ok(c) => c,
Err(_) => { Err(_) => {
@ -510,13 +510,14 @@ impl DB {
.to_owned())) .to_owned()))
} }
}; };
let cf_handler = unsafe { let cf = unsafe {
let cf_handler = let cf_handler =
ffi_try!(ffi::rocksdb_create_column_family(self.inner, opts.inner, cname.as_ptr())); ffi_try!(ffi::rocksdb_create_column_family(self.inner, opts.inner, cname.as_ptr()));
self.cfs.insert(name.to_string(), cf_handler); let cf = ColumnFamily { inner: cf_handler };
cf_handler self.cfs.insert(name.to_string(), cf);
cf
}; };
Ok(cf_handler) Ok(cf)
} }
pub fn drop_cf(&mut self, name: &str) -> Result<(), Error> { pub fn drop_cf(&mut self, name: &str) -> Result<(), Error> {
@ -525,14 +526,14 @@ impl DB {
return Err(Error::new(format!("Invalid column family: {}", name).to_owned())); return Err(Error::new(format!("Invalid column family: {}", name).to_owned()));
} }
unsafe { unsafe {
ffi_try!(ffi::rocksdb_drop_column_family(self.inner, *cf.unwrap())); ffi_try!(ffi::rocksdb_drop_column_family(self.inner, cf.unwrap().inner));
} }
Ok(()) Ok(())
} }
/// Return the underlying column family handle. /// Return the underlying column family handle.
pub fn cf_handle(&self, name: &str) -> Option<&*mut ffi::rocksdb_column_family_handle_t> { pub fn cf_handle(&self, name: &str) -> Option<ColumnFamily> {
self.cfs.get(name) self.cfs.get(name).cloned()
} }
pub fn iterator(&self, mode: IteratorMode) -> DBIterator { pub fn iterator(&self, mode: IteratorMode) -> DBIterator {
@ -541,7 +542,7 @@ impl DB {
} }
pub fn iterator_cf(&self, pub fn iterator_cf(&self,
cf_handle: *mut ffi::rocksdb_column_family_handle_t, cf_handle: ColumnFamily,
mode: IteratorMode) mode: IteratorMode)
-> Result<DBIterator, Error> { -> Result<DBIterator, Error> {
let opts = ReadOptions::default(); let opts = ReadOptions::default();
@ -565,7 +566,7 @@ impl DB {
} }
pub fn put_cf_opt(&self, pub fn put_cf_opt(&self,
cf: *mut ffi::rocksdb_column_family_handle_t, cf: ColumnFamily,
key: &[u8], key: &[u8],
value: &[u8], value: &[u8],
writeopts: &WriteOptions) writeopts: &WriteOptions)
@ -573,7 +574,7 @@ impl DB {
unsafe { unsafe {
ffi_try!(ffi::rocksdb_put_cf(self.inner, ffi_try!(ffi::rocksdb_put_cf(self.inner,
writeopts.inner, writeopts.inner,
cf, cf.inner,
key.as_ptr() as *const c_char, key.as_ptr() as *const c_char,
key.len() as size_t, key.len() as size_t,
value.as_ptr() as *const c_char, value.as_ptr() as *const c_char,
@ -599,7 +600,7 @@ impl DB {
} }
pub fn merge_cf_opt(&self, pub fn merge_cf_opt(&self,
cf: *mut ffi::rocksdb_column_family_handle_t, cf: ColumnFamily,
key: &[u8], key: &[u8],
value: &[u8], value: &[u8],
writeopts: &WriteOptions) writeopts: &WriteOptions)
@ -607,7 +608,7 @@ impl DB {
unsafe { unsafe {
ffi_try!(ffi::rocksdb_merge_cf(self.inner, ffi_try!(ffi::rocksdb_merge_cf(self.inner,
writeopts.inner, writeopts.inner,
cf, cf.inner,
key.as_ptr() as *const i8, key.as_ptr() as *const i8,
key.len() as size_t, key.len() as size_t,
value.as_ptr() as *const i8, value.as_ptr() as *const i8,
@ -627,14 +628,14 @@ impl DB {
} }
pub fn delete_cf_opt(&self, pub fn delete_cf_opt(&self,
cf: *mut ffi::rocksdb_column_family_handle_t, cf: ColumnFamily,
key: &[u8], key: &[u8],
writeopts: &WriteOptions) writeopts: &WriteOptions)
-> Result<(), Error> { -> Result<(), Error> {
unsafe { unsafe {
ffi_try!(ffi::rocksdb_delete_cf(self.inner, ffi_try!(ffi::rocksdb_delete_cf(self.inner,
writeopts.inner, writeopts.inner,
cf, cf.inner,
key.as_ptr() as *const c_char, key.as_ptr() as *const c_char,
key.len() as size_t)); key.len() as size_t));
Ok(()) Ok(())
@ -646,7 +647,7 @@ impl DB {
} }
pub fn put_cf(&self, pub fn put_cf(&self,
cf: *mut ffi::rocksdb_column_family_handle_t, cf: ColumnFamily,
key: &[u8], key: &[u8],
value: &[u8]) value: &[u8])
-> Result<(), Error> { -> Result<(), Error> {
@ -658,7 +659,7 @@ impl DB {
} }
pub fn merge_cf(&self, pub fn merge_cf(&self,
cf: *mut ffi::rocksdb_column_family_handle_t, cf: ColumnFamily,
key: &[u8], key: &[u8],
value: &[u8]) value: &[u8])
-> Result<(), Error> { -> Result<(), Error> {
@ -670,7 +671,7 @@ impl DB {
} }
pub fn delete_cf(&self, pub fn delete_cf(&self,
cf: *mut ffi::rocksdb_column_family_handle_t, cf: ColumnFamily,
key: &[u8]) key: &[u8])
-> Result<(), Error> { -> Result<(), Error> {
self.delete_cf_opt(cf, key, &WriteOptions::default()) self.delete_cf_opt(cf, key, &WriteOptions::default())
@ -687,12 +688,12 @@ impl DB {
} }
pub fn compact_range_cf(&self, pub fn compact_range_cf(&self,
cf: *mut ffi::rocksdb_column_family_handle_t, cf: ColumnFamily,
start: Option<&[u8]>, start: Option<&[u8]>,
end: Option<&[u8]>) { end: Option<&[u8]>) {
unsafe { unsafe {
ffi::rocksdb_compact_range_cf(self.inner, ffi::rocksdb_compact_range_cf(self.inner,
cf, cf.inner,
opt_bytes_to_ptr(start), opt_bytes_to_ptr(start),
start.map_or(0, |s| s.len()) as size_t, start.map_or(0, |s| s.len()) as size_t,
opt_bytes_to_ptr(end), opt_bytes_to_ptr(end),
@ -723,13 +724,13 @@ impl WriteBatch {
} }
pub fn put_cf(&mut self, pub fn put_cf(&mut self,
cf: *mut ffi::rocksdb_column_family_handle_t, cf: ColumnFamily,
key: &[u8], key: &[u8],
value: &[u8]) value: &[u8])
-> Result<(), Error> { -> Result<(), Error> {
unsafe { unsafe {
ffi::rocksdb_writebatch_put_cf(self.inner, ffi::rocksdb_writebatch_put_cf(self.inner,
cf, cf.inner,
key.as_ptr() as *const i8, key.as_ptr() as *const i8,
key.len() as size_t, key.len() as size_t,
value.as_ptr() as *const i8, value.as_ptr() as *const i8,
@ -750,13 +751,13 @@ impl WriteBatch {
} }
pub fn merge_cf(&mut self, pub fn merge_cf(&mut self,
cf: *mut ffi::rocksdb_column_family_handle_t, cf: ColumnFamily,
key: &[u8], key: &[u8],
value: &[u8]) value: &[u8])
-> Result<(), Error> { -> Result<(), Error> {
unsafe { unsafe {
ffi::rocksdb_writebatch_merge_cf(self.inner, ffi::rocksdb_writebatch_merge_cf(self.inner,
cf, cf.inner,
key.as_ptr() as *const i8, key.as_ptr() as *const i8,
key.len() as size_t, key.len() as size_t,
value.as_ptr() as *const i8, value.as_ptr() as *const i8,
@ -778,12 +779,12 @@ impl WriteBatch {
} }
pub fn delete_cf(&mut self, pub fn delete_cf(&mut self,
cf: *mut ffi::rocksdb_column_family_handle_t, cf: ColumnFamily,
key: &[u8]) key: &[u8])
-> Result<(), Error> { -> Result<(), Error> {
unsafe { unsafe {
ffi::rocksdb_writebatch_delete_cf(self.inner, ffi::rocksdb_writebatch_delete_cf(self.inner,
cf, cf.inner,
key.as_ptr() as *const i8, key.as_ptr() as *const i8,
key.len() as size_t); key.len() as size_t);
Ok(()) Ok(())
@ -807,7 +808,7 @@ impl Drop for DB {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
for cf in self.cfs.values() { for cf in self.cfs.values() {
ffi::rocksdb_column_family_handle_destroy(*cf); ffi::rocksdb_column_family_handle_destroy(cf.inner);
} }
ffi::rocksdb_close(self.inner); ffi::rocksdb_close(self.inner);
} }
@ -859,6 +860,10 @@ impl Default for ReadOptions {
} }
/// Vector of bytes stored in the database. /// Vector of bytes stored in the database.
///
/// This is a `C` allocated byte array and a length value.
/// Normal usage would be to utilize the fact it implements `Deref<[u8]>` and use it as
/// a slice.
pub struct DBVector { pub struct DBVector {
base: *mut u8, base: *mut u8,
len: usize, len: usize,
@ -881,18 +886,46 @@ impl Drop for DBVector {
} }
impl DBVector { impl DBVector {
pub fn from_c(val: *mut u8, val_len: size_t) -> DBVector { /// Used internally to create a DBVector from a `C` memory block
///
/// # Unsafe
/// Requires that the ponter be allocated by a `malloc` derivative (all C libraries), and
/// `val_len` be the length of the C array to be safe (since `sizeof(u8) = 1`).
///
/// # Example
///
/// ```ignore
/// let buf_len: libc::size_t = unsafe { mem::uninitialized() };
/// // Assume the function fills buf_len with the length of the returned array
/// let buf: *mut u8 = unsafe { ffi_function_returning_byte_array(&buf_len) };
/// DBVector::from_c(buf, buf_len)
/// ```
pub unsafe fn from_c(val: *mut u8, val_len: size_t) -> DBVector {
DBVector { DBVector {
base: val, base: val,
len: val_len as usize, len: val_len as usize,
} }
} }
/// Convenience function to attempt to reinterperet value as string.
///
/// implemented as `str::from_utf8(&self[..])`
pub fn to_utf8(&self) -> Option<&str> { pub fn to_utf8(&self) -> Option<&str> {
str::from_utf8(self.deref()).ok() 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::<u8>())) };
let v = unsafe { DBVector::from_c(data, len) };
let ctrl = [0u8, 0, 0, 0];
assert_eq!(&*v, &ctrl[..]);
}
#[test] #[test]
fn external() { fn external() {
let path = "_rust_rocksdb_externaltest"; let path = "_rust_rocksdb_externaltest";

@ -55,12 +55,16 @@ use std::fmt;
use std::path::PathBuf; use std::path::PathBuf;
/// A RocksDB database. /// A RocksDB database.
///
/// See crate level documentation for a simple usage example.
pub struct DB { pub struct DB {
inner: *mut ffi::rocksdb_t, inner: *mut ffi::rocksdb_t,
cfs: BTreeMap<String, *mut ffi::rocksdb_column_family_handle_t>, cfs: BTreeMap<String, ColumnFamily>,
path: PathBuf, path: PathBuf,
} }
/// A simple wrapper round a string, used for errors reported from
/// ffi calls.
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub struct Error { pub struct Error {
message: String, message: String,
@ -162,3 +166,10 @@ pub struct Options {
pub struct WriteOptions { pub struct WriteOptions {
inner: *mut ffi::rocksdb_writeoptions_t, inner: *mut ffi::rocksdb_writeoptions_t,
} }
/// An opaque type used to represent a column family. Returned from some functions, and used
/// in others
#[derive(Copy, Clone)]
pub struct ColumnFamily {
inner: *mut ffi::rocksdb_column_family_handle_t,
}

@ -94,7 +94,7 @@ fn test_merge_operator() {
} }
Err(e) => panic!("failed to open db with column family: {}", e), Err(e) => panic!("failed to open db with column family: {}", e),
}; };
let cf1 = *db.cf_handle("cf1").unwrap(); let cf1 = db.cf_handle("cf1").unwrap();
assert!(db.put_cf(cf1, b"k1", b"v1").is_ok()); assert!(db.put_cf(cf1, b"k1", b"v1").is_ok());
assert!(db.get_cf(cf1, b"k1").unwrap().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"); let p = db.put_cf(cf1, b"k1", b"a");

Loading…
Cancel
Save