From 520d9cef43e6fc65e9bbfeec9e2891748461fe60 Mon Sep 17 00:00:00 2001 From: Tyler Neely Date: Sun, 19 Jul 2015 19:14:46 -0700 Subject: [PATCH] Initial column family (broken) stubs. --- src/ffi.rs | 21 +++++++++++- src/lib.rs | 2 ++ src/rocksdb.rs | 66 ++++++++++++++++++++++++++++++++++---- test/test.rs | 1 + test/test_column_family.rs | 57 ++++++++++++++++++++++++++++++++ test/test_multithreaded.rs | 63 +++++++++++++++++++----------------- 6 files changed, 172 insertions(+), 38 deletions(-) create mode 100644 test/test_column_family.rs diff --git a/src/ffi.rs b/src/ffi.rs index 10c8cc9..706a5b2 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -353,9 +353,28 @@ extern { name_fn: extern fn(*mut c_void) -> *const c_char ) -> RocksDBComparator; pub fn rocksdb_comparator_destroy(cmp: RocksDBComparator); + + // Column Family + pub fn rocksdb_open_column_families(options: RocksDBOptions, + path: *const i8, + num_column_families: c_int, + column_family_names: *const *const i8, + column_family_options: *const [RocksDBOptions], + column_family_handles: *mut *const RocksDBCFHandle, + err: *mut *const i8 + ) -> RocksDBInstance; + pub fn rocksdb_create_column_family(db: RocksDBInstance, + column_family_options: RocksDBOptions, + column_family_name: *const i8, + err: *mut *const i8 + ) -> RocksDBCFHandle; + pub fn rocksdb_drop_column_family(db: RocksDBInstance, + column_family_handle: *const RocksDBCFHandle, + err: *mut *const i8); + pub fn rocksdb_column_family_handle_destroy(column_family_handle: *mut *const RocksDBCFHandle); + } -#[allow(dead_code)] #[test] fn internal() { unsafe { diff --git a/src/lib.rs b/src/lib.rs index 621add8..43cbe98 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,7 +18,9 @@ #![feature(libc)] #![feature(unique)] #![feature(path_ext)] +#![feature(convert)] #![feature(raw)] +#![allow(dead_code)] pub use ffi as rocksdb_ffi; pub use ffi::{new_bloom_filter, RocksDBCompactionStyle, RocksDBComparator}; diff --git a/src/rocksdb.rs b/src/rocksdb.rs index f0f1e78..683ca9d 100644 --- a/src/rocksdb.rs +++ b/src/rocksdb.rs @@ -23,13 +23,13 @@ use std::path::Path; use std::ptr::Unique; use std::slice; use std::str::from_utf8; -use std::marker::PhantomData; use rocksdb_ffi; use rocksdb_options::Options; pub struct RocksDB { inner: rocksdb_ffi::RocksDBInstance, + cfs: Vec, } unsafe impl Send for RocksDB {} @@ -184,6 +184,10 @@ impl RocksDB { } pub fn open(opts: &Options, path: &str) -> Result { + RocksDB::open_cf(opts, path, vec![]) + } + + pub fn open_cf(opts: &Options, path: &str, mut cfs: Vec<&str>) -> Result { let cpath = match CString::new(path.as_bytes()) { Ok(c) => c, Err(_) => @@ -203,18 +207,49 @@ impl RocksDB { let err_ptr: *mut *const i8 = &mut err; let db: rocksdb_ffi::RocksDBInstance; - unsafe { - db = rocksdb_ffi::rocksdb_open(opts.inner, cpath_ptr, err_ptr); + if cfs.len() == 0 { + unsafe { + db = rocksdb_ffi::rocksdb_open(opts.inner, cpath_ptr, err_ptr); + } + } else { + let nfam = cfs.len(); + let mut cfnames: Vec<*const i8> = vec![]; + let mut cfhandles: Vec = vec![]; + let mut cfopts: Vec = vec![]; + + cfs.push("default"); + for name in cfs { + match CString::new(name.as_bytes()) { + Ok(c) => { + cfnames.push(c.as_ptr()); + cfhandles.push(rocksdb_ffi::RocksDBCFHandle(0 as *mut c_void)); + cfopts.push(Options::new().inner); + }, + Err(_) => + return Err("Failed to convert path to CString when opening rocksdb".to_string()), + } + }; + unsafe { + println!("1!"); + println!("nfam: {}", nfam); + db = rocksdb_ffi::rocksdb_open_column_families(opts.inner, cpath_ptr, + nfam as libc::c_int, + cfnames.as_slice().as_ptr(), + cfopts.as_slice(), + cfhandles.as_ptr() as *mut *const rocksdb_ffi::RocksDBCFHandle, + err_ptr); + println!("2!"); + } } if !err.is_null() { return Err(error_message(err)); } - let rocksdb_ffi::RocksDBInstance(db_ptr) = db; - if db_ptr.is_null() { + if db.0.is_null() { return Err("Could not initialize database.".to_string()); } - Ok(RocksDB { inner: db }) + + Ok(RocksDB { inner: db, cfs: vec![] }) } pub fn destroy(opts: &Options, path: &str) -> Result<(), String> { @@ -300,6 +335,24 @@ impl RocksDB { } } + pub fn create_cf(&mut self, name: &str, opts: &Options) -> Result<(), String> { + let cname = match CString::new(name.as_bytes()) { + Ok(c) => c, + Err(_) => + return Err("Failed to convert path to CString when opening rocksdb".to_string()), + }; + let cname_ptr = cname.as_ptr(); + let mut err: *const i8 = 0 as *const i8; + let err_ptr: *mut *const i8 = &mut err; + unsafe { + rocksdb_ffi::rocksdb_create_column_family(self.inner, opts.inner, cname_ptr, err_ptr); + } + if !err.is_null() { + return Err(error_message(err)); + } + Ok(()) + } + pub fn iterator(&self) -> DBIterator { let opts = ReadOptions::new(); DBIterator::new(&self, &opts) @@ -546,7 +599,6 @@ impl RocksDBResult { } } -#[allow(dead_code)] #[test] fn external() { let path = "_rust_rocksdb_externaltest"; diff --git a/test/test.rs b/test/test.rs index 5a6aca5..20a1b69 100644 --- a/test/test.rs +++ b/test/test.rs @@ -2,3 +2,4 @@ extern crate rocksdb; mod test_iterator; mod test_multithreaded; +mod test_column_family; diff --git a/test/test_column_family.rs b/test/test_column_family.rs new file mode 100644 index 0000000..9f2e81b --- /dev/null +++ b/test/test_column_family.rs @@ -0,0 +1,57 @@ +/* + Copyright 2014 Tyler Neely + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +use rocksdb::{Options, RocksDB, Writable, Direction}; + +#[test] +pub fn test_column_family() { + let path = "_rust_rocksdb_cftest"; + + // should be able to create column families + { + let mut db = RocksDB::open_default(path).unwrap(); + let opts = Options::new(); + match db.create_cf("cf1", &opts) { + Ok(_) => println!("cf1 created successfully"), + Err(e) => { + panic!("could not create column family: {}", e); + }, + } + } + + // should fail to open db without specifying same column families + { + match RocksDB::open_default(path) { + Ok(_) => panic!("should not have opened DB successfully without specifying column + families"), + Err(e) => assert!(e.starts_with("Invalid argument: You have to open all column families.")), + } + } + + // should properly open db when specyfing all column families + { + match RocksDB::open_cf(&Options::new(), path, vec!["cf1"]) { + Ok(_) => println!("successfully opened db with column family"), + Err(e) => panic!("failed to open db with column family"), + } + + } + // should be able to write, read, merge, batch, and iterate over a cf + { + + } + + assert!(RocksDB::destroy(&Options::new(), path).is_ok()); +} diff --git a/test/test_multithreaded.rs b/test/test_multithreaded.rs index 0d240e0..4cb13bb 100644 --- a/test/test_multithreaded.rs +++ b/test/test_multithreaded.rs @@ -2,47 +2,50 @@ use rocksdb::{Options, RocksDB, Writable, Direction, RocksDBResult}; use std::thread::{self, Builder}; use std::sync::Arc; -const N: usize = 1000_000; +const N: usize = 100_000; #[test] pub fn test_multithreaded() { let path = "_rust_rocksdb_multithreadtest"; - let db = RocksDB::open_default(path).unwrap(); - let db = Arc::new(db); + { + let db = RocksDB::open_default(path).unwrap(); + let db = Arc::new(db); - db.put(b"key", b"value1"); + db.put(b"key", b"value1"); - let db1 = db.clone(); - let j1 = thread::spawn(move|| { - for i in 1..N { - db1.put(b"key", b"value1"); - } - }); + let db1 = db.clone(); + let j1 = thread::spawn(move|| { + for i in 1..N { + db1.put(b"key", b"value1"); + } + }); - let db2 = db.clone(); - let j2 = thread::spawn(move|| { - for i in 1..N { - db2.put(b"key", b"value2"); - } - }); + let db2 = db.clone(); + let j2 = thread::spawn(move|| { + for i in 1..N { + db2.put(b"key", b"value2"); + } + }); - let db3 = db.clone(); - let j3 = thread::spawn(move|| { - for i in 1..N { - match db3.get(b"key") { - RocksDBResult::Some(v) => { - if &v[..] != b"value1" && &v[..] != b"value2" { + let db3 = db.clone(); + let j3 = thread::spawn(move|| { + for i in 1..N { + match db3.get(b"key") { + RocksDBResult::Some(v) => { + if &v[..] != b"value1" && &v[..] != b"value2" { + assert!(false); + } + } + _ => { assert!(false); } } - _ => { - assert!(false); - } } - } - }); + }); - j1.join(); - j2.join(); - j3.join(); + j1.join(); + j2.join(); + j3.join(); + } + assert!(RocksDB::destroy(&Options::new(), path).is_ok()); }