ckb_rocksdb/ops/
property.rs

1use crate::{handle::Handle, ColumnFamily, Error};
2use libc::{c_char, c_void};
3use std::ffi::{CStr, CString};
4
5pub trait GetProperty {
6    /// Retrieves a RocksDB property by name.
7    ///
8    /// For a full list of properties, see
9    /// https://github.com/facebook/rocksdb/blob/08809f5e6cd9cc4bc3958dd4d59457ae78c76660/include/rocksdb/db.h#L428-L634
10    fn property_value(&self, name: &str) -> Result<Option<String>, Error>;
11
12    /// Retrieves a RocksDB property and casts it to an integer.
13    ///
14    /// For a full list of properties that return int values, see
15    /// https://github.com/facebook/rocksdb/blob/08809f5e6cd9cc4bc3958dd4d59457ae78c76660/include/rocksdb/db.h#L654-L689
16    fn property_int_value(&self, name: &str) -> Result<Option<u64>, Error>;
17}
18
19pub trait GetPropertyCF {
20    /// Retrieves a RocksDB property by name, for a specific column family.
21    ///
22    /// For a full list of properties, see
23    /// https://github.com/facebook/rocksdb/blob/08809f5e6cd9cc4bc3958dd4d59457ae78c76660/include/rocksdb/db.h#L428-L634
24    fn property_value_cf(&self, cf: &ColumnFamily, name: &str) -> Result<Option<String>, Error>;
25
26    /// Retrieves a RocksDB property for a specific column family and casts it to an integer.
27    ///
28    /// For a full list of properties that return int values, see
29    /// https://github.com/facebook/rocksdb/blob/08809f5e6cd9cc4bc3958dd4d59457ae78c76660/include/rocksdb/db.h#L654-L689
30    fn property_int_value_cf(&self, cf: &ColumnFamily, name: &str) -> Result<Option<u64>, Error>;
31}
32
33impl<T> GetProperty for T
34where
35    T: Handle<ffi::rocksdb_t>,
36{
37    fn property_value(&self, name: &str) -> Result<Option<String>, Error> {
38        property_value_impl(
39            name,
40            |prop_name| unsafe { ffi::rocksdb_property_value(self.handle(), prop_name) },
41            |str_value| Ok(str_value.to_owned()),
42        )
43    }
44
45    fn property_int_value(&self, name: &str) -> Result<Option<u64>, Error> {
46        property_value_impl(
47            name,
48            |prop_name| unsafe { ffi::rocksdb_property_value(self.handle(), prop_name) },
49            parse_property_int_value,
50        )
51    }
52}
53
54impl<T> GetPropertyCF for T
55where
56    T: Handle<ffi::rocksdb_t>,
57{
58    fn property_value_cf(&self, cf: &ColumnFamily, name: &str) -> Result<Option<String>, Error> {
59        property_value_impl(
60            name,
61            |prop_name| unsafe {
62                ffi::rocksdb_property_value_cf(self.handle(), cf.inner, prop_name)
63            },
64            |str_value| Ok(str_value.to_owned()),
65        )
66    }
67
68    fn property_int_value_cf(&self, cf: &ColumnFamily, name: &str) -> Result<Option<u64>, Error> {
69        property_value_impl(
70            name,
71            |prop_name| unsafe {
72                ffi::rocksdb_property_value_cf(self.handle(), cf.inner, prop_name)
73            },
74            parse_property_int_value,
75        )
76    }
77}
78
79fn parse_property_int_value(value: &str) -> Result<u64, Error> {
80    value.parse::<u64>().map_err(|err| {
81        Error::new(format!(
82            "Failed to convert property value {} to int: {}",
83            value, err
84        ))
85    })
86}
87
88/// Implementation for property_value et al methods.
89///
90/// `name` is the name of the property.  It will be converted into a CString
91/// and passed to `get_property` as argument.  `get_property` reads the
92/// specified property and either returns NULL or a pointer to a C allocated
93/// string; this method takes ownership of that string and will free it at
94/// the end.  That string is parsed using `parse` callback which produces
95/// the returned result.
96fn property_value_impl<R>(
97    name: &str,
98    get_property: impl FnOnce(*const c_char) -> *mut c_char,
99    parse: impl FnOnce(&str) -> Result<R, Error>,
100) -> Result<Option<R>, Error> {
101    let value = match CString::new(name) {
102        Ok(prop_name) => get_property(prop_name.as_ptr()),
103        Err(e) => {
104            return Err(Error::new(format!(
105                "Failed to convert property name to CString: {}",
106                e
107            )));
108        }
109    };
110    if value.is_null() {
111        return Ok(None);
112    }
113    let result = match unsafe { CStr::from_ptr(value) }.to_str() {
114        Ok(s) => parse(s).map(Some),
115        Err(e) => Err(Error::new(format!(
116            "Failed to convert property value to string: {}",
117            e
118        ))),
119    };
120    unsafe {
121        ffi::rocksdb_free(value as *mut c_void);
122    }
123    result
124}