diff --git a/src/db.rs b/src/db.rs index d56e459..b871d87 100644 --- a/src/db.rs +++ b/src/db.rs @@ -1392,6 +1392,118 @@ impl DB { )) }) } + + /// Retrieves a RocksDB property by name. + /// + /// For a full list of properties, see + /// https://github.com/facebook/rocksdb/blob/08809f5e6cd9cc4bc3958dd4d59457ae78c76660/include/rocksdb/db.h#L428-L634 + pub fn property_value(&self, name: &str) -> Result, Error> { + let prop_name = match CString::new(name) { + Ok(c) => c, + Err(e) => { + return Err(Error::new(format!( + "Failed to convert property name to CString: {}", + e + ))); + } + }; + + unsafe { + let value = ffi::rocksdb_property_value(self.inner, prop_name.as_ptr()); + if value.is_null() { + return Ok(None); + } + + let str_value = match CStr::from_ptr(value).to_str() { + Ok(s) => s.to_owned(), + Err(e) => { + return Err(Error::new(format!( + "Failed to convert property value to string: {}", + e + ))); + } + }; + + libc::free(value as *mut c_void); + Ok(Some(str_value)) + } + } + + /// Retrieves a RocksDB property by name, for a specific column family. + /// + /// For a full list of properties, see + /// https://github.com/facebook/rocksdb/blob/08809f5e6cd9cc4bc3958dd4d59457ae78c76660/include/rocksdb/db.h#L428-L634 + pub fn property_value_cf(&self, cf: ColumnFamily, name: &str) -> Result, Error> { + let prop_name = match CString::new(name) { + Ok(c) => c, + Err(e) => { + return Err(Error::new(format!( + "Failed to convert property name to CString: {}", + e + ))); + } + }; + + unsafe { + let value = ffi::rocksdb_property_value_cf(self.inner, cf.inner, prop_name.as_ptr()); + if value.is_null() { + return Ok(None); + } + + let str_value = match CStr::from_ptr(value).to_str() { + Ok(s) => s.to_owned(), + Err(e) => { + return Err(Error::new(format!( + "Failed to convert property value to string: {}", + e + ))); + } + }; + + libc::free(value as *mut c_void); + Ok(Some(str_value)) + } + } + + /// Retrieves a RocksDB property and casts it to an integer. + /// + /// For a full list of properties that return int values, see + /// https://github.com/facebook/rocksdb/blob/08809f5e6cd9cc4bc3958dd4d59457ae78c76660/include/rocksdb/db.h#L654-L689 + pub fn property_int_value(&self, name: &str) -> Result, Error> { + match self.property_value(name) { + Ok(Some(value)) => match value.parse::() { + Ok(int_value) => Ok(Some(int_value)), + Err(e) => Err(Error::new(format!( + "Failed to convert property value to int: {}", + e + ))), + }, + Ok(None) => Ok(None), + Err(e) => Err(e), + } + } + + /// Retrieves a RocksDB property for a specific column family and casts it to an integer. + /// + /// For a full list of properties that return int values, see + /// https://github.com/facebook/rocksdb/blob/08809f5e6cd9cc4bc3958dd4d59457ae78c76660/include/rocksdb/db.h#L654-L689 + pub fn property_int_value_cf( + &self, + cf: ColumnFamily, + name: &str, + ) -> Result, Error> { + match self.property_value_cf(cf, name) { + Ok(Some(value)) => match value.parse::() { + Ok(int_value) => Ok(Some(int_value)), + Err(e) => Err(Error::new(format!( + "Failed to convert property value to int: {}", + e + ))), + }, + Ok(None) => Ok(None), + Err(e) => Err(e), + } + } } impl WriteBatch { diff --git a/tests/test_property.rs b/tests/test_property.rs new file mode 100644 index 0000000..6b30e59 --- /dev/null +++ b/tests/test_property.rs @@ -0,0 +1,71 @@ +// Copyright 2019 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. +// +extern crate rocksdb; +mod util; + +use rocksdb::{Options, DB}; +use util::DBPath; + +#[test] +fn property_test() { + let n = DBPath::new("_rust_rocksdb_property_test"); + { + let db = DB::open_default(&n).unwrap(); + let value = db.property_value("rocksdb.stats").unwrap().unwrap(); + + assert!(value.contains("Stats")); + } +} + +#[test] +fn property_cf_test() { + let n = DBPath::new("_rust_rocksdb_property_cf_test"); + { + let opts = Options::default(); + let db = DB::open_default(&n).unwrap(); + let cf = db.create_cf("cf1", &opts).unwrap(); + let value = db.property_value_cf(cf, "rocksdb.stats").unwrap().unwrap(); + + assert!(value.contains("Stats")); + } +} + +#[test] +fn property_int_test() { + let n = DBPath::new("_rust_rocksdb_property_int_test"); + { + let db = DB::open_default(&n).unwrap(); + let value = db + .property_int_value("rocksdb.estimate-live-data-size") + .unwrap(); + + assert!(value == Some(0)); + } +} + +#[test] +fn property_int_cf_test() { + let n = DBPath::new("_rust_rocksdb_property_int_cf_test"); + { + let opts = Options::default(); + let db = DB::open_default(&n).unwrap(); + let cf = db.create_cf("cf1", &opts).unwrap(); + let total_keys = db + .property_int_value_cf(cf, "rocksdb.estimate-num-keys") + .unwrap(); + + assert!(total_keys == Some(0)); + } +}