From 9afa195a33459ac8a852a275a12fabb7929597c0 Mon Sep 17 00:00:00 2001 From: Gary Tierney Date: Sun, 27 Aug 2017 16:25:07 +0100 Subject: [PATCH] Add support for opening a column family with options Adds a new `DB::open_cf_descriptors` method that allows passing in Options for each column family. A new `ColumnFamilyDescriptor` type was added to contain the congfiguration for each column family. This fixes an issue where a column family was created with non-default options, and then fails to re-open due to a config mismatch. --- src/db.rs | 47 ++++++++++++++++++++++++++++++++--------------- src/lib.rs | 5 +++++ 2 files changed, 37 insertions(+), 15 deletions(-) diff --git a/src/db.rs b/src/db.rs index 3067928..bfb3d45 100644 --- a/src/db.rs +++ b/src/db.rs @@ -14,7 +14,7 @@ // -use {DB, Error, Options, WriteOptions, ColumnFamily}; +use {DB, Error, Options, WriteOptions, ColumnFamily, ColumnFamilyDescriptor}; use ffi; use ffi_util::opt_bytes_to_ptr; @@ -559,6 +559,16 @@ impl<'a> Drop for Snapshot<'a> { } } +impl ColumnFamilyDescriptor { + // Create a new column family descriptor with the specified name and options. + pub fn new(name: S, options: Options) -> Self where S: Into { + ColumnFamilyDescriptor { + name: name.into(), + options + } + } +} + impl DB { /// Open a database with default options. pub fn open_default>(path: P) -> Result { @@ -572,14 +582,20 @@ impl DB { DB::open_cf(opts, path, &[]) } - /// Open a database with specified options and column family. - /// - /// A column family must be created first by calling `DB::create_cf`. + /// Open a database with the given database options and column family names. /// - /// # Panics - /// - /// * Panics if the column family doesn't exist. + /// Column families opened using this function will be created with default `Options`. pub fn open_cf>(opts: &Options, path: P, cfs: &[&str]) -> Result { + let cfs_v = cfs.to_vec().iter().map(|name| ColumnFamilyDescriptor { + name: name.to_string(), + options: Options::default(), + }).collect(); + + DB::open_cf_descriptors(opts, path, cfs_v) + } + + /// Open a database with the given database options and column family names/options. + pub fn open_cf_descriptors>(opts: &Options, path: P, cfs: Vec) -> Result { let path = path.as_ref(); let cpath = match CString::new(path.to_string_lossy().as_bytes()) { Ok(c) => c, @@ -604,16 +620,18 @@ impl DB { db = ffi_try!(ffi::rocksdb_open(opts.inner, cpath.as_ptr() as *const _)); } } else { - let mut cfs_v = cfs.to_vec(); + let mut cfs_v = cfs; // Always open the default column family. - if !cfs_v.contains(&"default") { - cfs_v.push("default"); + if !cfs_v.iter().any(|cf| cf.name == "default") { + cfs_v.push(ColumnFamilyDescriptor { + name: String::from("default"), + options: Options::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()) + .map(|cf| CString::new(cf.name.as_bytes()).unwrap()) .collect(); let cfnames: Vec<_> = c_cfs.iter().map(|cf| cf.as_ptr()).collect(); @@ -621,9 +639,8 @@ impl DB { // These handles will be populated by DB. let mut cfhandles: Vec<_> = cfs_v.iter().map(|_| ptr::null_mut()).collect(); - // TODO(tyler) allow options to be passed in. let cfopts: Vec<_> = cfs_v.iter() - .map(|_| unsafe { ffi::rocksdb_options_create() as *const _ }) + .map(|cf| cf.options.inner as *const _) .collect(); unsafe { @@ -644,7 +661,7 @@ impl DB { } for (n, h) in cfs_v.iter().zip(cfhandles) { - cf_map.insert(n.to_string(), ColumnFamily { inner: h }); + cf_map.insert(n.name.clone(), ColumnFamily { inner: h }); } } diff --git a/src/lib.rs b/src/lib.rs index ba26334..d42b1a8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -63,6 +63,11 @@ pub struct DB { path: PathBuf, } +pub struct ColumnFamilyDescriptor { + name: String, + options: Options, +} + /// A simple wrapper round a string, used for errors reported from /// ffi calls. #[derive(Debug, Clone, PartialEq)]