From 4db1723001d0cfe4060268d2a1da94744897ef43 Mon Sep 17 00:00:00 2001 From: Tyler Neely Date: Tue, 21 Jul 2015 11:52:41 -0700 Subject: [PATCH] Fix pointer use for opening column families. --- src/ffi.rs | 4 +- src/rocksdb.rs | 78 +++++++++++++++++++++++++------------- test/test_column_family.rs | 4 +- 3 files changed, 55 insertions(+), 31 deletions(-) diff --git a/src/ffi.rs b/src/ffi.rs index 706a5b2..4b56e61 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -359,8 +359,8 @@ extern { 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, + column_family_options: *const RocksDBOptions, + column_family_handles: *const RocksDBCFHandle, err: *mut *const i8 ) -> RocksDBInstance; pub fn rocksdb_create_column_family(db: RocksDBInstance, diff --git a/src/rocksdb.rs b/src/rocksdb.rs index 683ca9d..6d12fe2 100644 --- a/src/rocksdb.rs +++ b/src/rocksdb.rs @@ -16,6 +16,7 @@ extern crate libc; use self::libc::{c_void, size_t}; +use std::collections::BTreeMap; use std::ffi::{CString, CStr}; use std::fs::{self, PathExt}; use std::ops::Deref; @@ -29,7 +30,7 @@ use rocksdb_options::Options; pub struct RocksDB { inner: rocksdb_ffi::RocksDBInstance, - cfs: Vec, + cfs: BTreeMap, } unsafe impl Send for RocksDB {} @@ -184,10 +185,10 @@ impl RocksDB { } pub fn open(opts: &Options, path: &str) -> Result { - RocksDB::open_cf(opts, path, vec![]) + RocksDB::open_cf(opts, path, &[]) } - pub fn open_cf(opts: &Options, path: &str, mut cfs: Vec<&str>) -> Result { + pub fn open_cf(opts: &Options, path: &str, cfs: &[&str]) -> Result { let cpath = match CString::new(path.as_bytes()) { Ok(c) => c, Err(_) => @@ -206,39 +207,62 @@ impl RocksDB { let mut err: *const i8 = 0 as *const i8; let err_ptr: *mut *const i8 = &mut err; let db: rocksdb_ffi::RocksDBInstance; + let mut cfMap = BTreeMap::new(); 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()), - } - }; + let mut cfs_v = cfs.to_vec(); + // Always open the default column family + if !cfs_v.contains(&"default") { + cfs_v.push("default"); + } + + // We need to store our CStrings in an intermediate vector + // so that their pointers remain valid. + let c_cfs: Vec = cfs_v.iter().map( |cf| { + CString::new(cf.as_bytes()).unwrap() + }).collect(); + + let cfnames: Vec<*const i8> = c_cfs.iter().map( |cf| { + cf.as_ptr() + }).collect(); + + // These handles will be populated by RocksDB. + let mut cfhandles: Vec = + cfs_v.iter().map( |_| { + rocksdb_ffi::RocksDBCFHandle(0 as *mut c_void) + }).collect(); + + // TODO(tyler) allow options to be passed in. + let cfopts: Vec = cfs_v.iter().map( |_| { + unsafe { rocksdb_ffi::rocksdb_options_create() } + }).collect(); + + // Prepare to ship to C. + let names = cfnames.as_slice(); + let copts: *const rocksdb_ffi::RocksDBOptions = cfopts.as_ptr(); + let handles: *const rocksdb_ffi::RocksDBCFHandle = cfhandles.as_ptr(); + let nfam = cfs_v.len(); 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, + names.as_ptr(), + copts, + handles, err_ptr); - println!("2!"); + } + + for handle in cfhandles.iter() { + if handle.0.is_null() { + return Err("Received null column family handle from RocksDB.".to_string()); + } + } + + for (n, h) in cfs_v.iter().zip(cfhandles) { + cfMap.insert(n.to_string(), h); } } @@ -249,7 +273,7 @@ impl RocksDB { return Err("Could not initialize database.".to_string()); } - Ok(RocksDB { inner: db, cfs: vec![] }) + Ok(RocksDB { inner: db, cfs: cfMap }) } pub fn destroy(opts: &Options, path: &str) -> Result<(), String> { diff --git a/test/test_column_family.rs b/test/test_column_family.rs index 9f2e81b..034d1a1 100644 --- a/test/test_column_family.rs +++ b/test/test_column_family.rs @@ -42,9 +42,9 @@ pub fn test_column_family() { // should properly open db when specyfing all column families { - match RocksDB::open_cf(&Options::new(), path, vec!["cf1"]) { + match RocksDB::open_cf(&Options::new(), path, &["cf1"]) { Ok(_) => println!("successfully opened db with column family"), - Err(e) => panic!("failed to open db with column family"), + Err(e) => panic!("failed to open db with column family: {}", e), } }