Skip to content

Commit

Permalink
feat: Properties for TransactionDB rust-rocksdb#899 (rust-rocksdb#902)
Browse files Browse the repository at this point in the history
  • Loading branch information
4TT1L4 authored Jul 26, 2024
1 parent 9e86b32 commit ed35bde
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 0 deletions.
71 changes: 71 additions & 0 deletions src/transactions/transaction_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ use std::{
sync::{Arc, Mutex},
};

use crate::CStrLike;
use std::ffi::CStr;

use crate::{
column_family::UnboundColumnFamily,
db::{convert_values, DBAccess},
Expand Down Expand Up @@ -1002,6 +1005,74 @@ impl TransactionDB<MultiThreaded> {
Err(Error::new(format!("Invalid column family: {name}")))
}
}

/// Implementation for property_value et al methods.
///
/// `name` is the name of the property. It will be converted into a CString
/// and passed to `get_property` as argument. `get_property` reads the
/// specified property and either returns NULL or a pointer to a C allocated
/// string; this method takes ownership of that string and will free it at
/// the end. That string is parsed using `parse` callback which produces
/// the returned result.
fn property_value_impl<R>(
name: impl CStrLike,
get_property: impl FnOnce(*const c_char) -> *mut c_char,
parse: impl FnOnce(&str) -> Result<R, Error>,
) -> Result<Option<R>, Error> {
let value = match name.bake() {
Ok(prop_name) => get_property(prop_name.as_ptr()),
Err(e) => {
return Err(Error::new(format!(
"Failed to convert property name to CString: {e}"
)));
}
};
if value.is_null() {
return Ok(None);
}
let result = match unsafe { CStr::from_ptr(value) }.to_str() {
Ok(s) => parse(s).map(|value| Some(value)),
Err(e) => Err(Error::new(format!(
"Failed to convert property value to string: {e}"
))),
};
unsafe {
ffi::rocksdb_free(value as *mut c_void);
}
result
}

/// Retrieves a RocksDB property by name.
///
/// Full list of properties could be find
/// [here](https://github.com/facebook/rocksdb/blob/08809f5e6cd9cc4bc3958dd4d59457ae78c76660/include/rocksdb/db.h#L428-L634).
pub fn property_value(&self, name: impl CStrLike) -> Result<Option<String>, Error> {
Self::property_value_impl(
name,
|prop_name| unsafe { ffi::rocksdb_transactiondb_property_value(self.inner, prop_name) },
|str_value| Ok(str_value.to_owned()),
)
}

fn parse_property_int_value(value: &str) -> Result<u64, Error> {
value.parse::<u64>().map_err(|err| {
Error::new(format!(
"Failed to convert property value {value} to int: {err}"
))
})
}

/// Retrieves a RocksDB property and casts it to an integer.
///
/// Full list of properties that return int values could be find
/// [here](https://github.com/facebook/rocksdb/blob/08809f5e6cd9cc4bc3958dd4d59457ae78c76660/include/rocksdb/db.h#L654-L689).
pub fn property_int_value(&self, name: impl CStrLike) -> Result<Option<u64>, Error> {
Self::property_value_impl(
name,
|prop_name| unsafe { ffi::rocksdb_transactiondb_property_value(self.inner, prop_name) },
Self::parse_property_int_value,
)
}
}

impl<T: ThreadMode> Drop for TransactionDB<T> {
Expand Down
62 changes: 62 additions & 0 deletions tests/test_transaction_db_property.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright 2020 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.

mod util;

use pretty_assertions::assert_eq;

use rocksdb::{properties, Options, TransactionDB, TransactionDBOptions};
use util::DBPath;

#[test]
fn transaction_db_property_test() {
let path = DBPath::new("_rust_rocksdb_transaction_db_property_test");
{
let mut options = Options::default();
options.create_if_missing(true);
options.enable_statistics();
let tx_db_options = TransactionDBOptions::default();
let db = TransactionDB::open(&options, &tx_db_options, &path).unwrap();

db.put("key1", "value1").unwrap();
db.put("key2", "value2").unwrap();
db.put("key3", "value3").unwrap();

let prop_name: &std::ffi::CStr = properties::STATS;
let value = db.property_value(prop_name).unwrap().unwrap();

assert!(value.contains("Compaction Stats"));
assert!(value.contains("Cumulative writes: 3 writes"));
}
}

#[test]
fn transaction_db_int_property_test() {
let path = DBPath::new("_rust_rocksdb_transaction_db_int_property_test");
{
let mut options = Options::default();
options.create_if_missing(true);
options.enable_statistics();
let tx_db_options = TransactionDBOptions::default();
let db = TransactionDB::open(&options, &tx_db_options, &path).unwrap();

db.put("key1", "value1").unwrap();
db.put("key2", "value2").unwrap();

let prop_name: properties::PropertyName = properties::ESTIMATE_NUM_KEYS.to_owned();
let value = db.property_int_value(&prop_name).unwrap().unwrap();

assert_eq!(value, 2);
}
}

0 comments on commit ed35bde

Please sign in to comment.