rust_rocksdb/
statistics.rs

1use crate::ffi;
2
3#[derive(Debug, Clone)]
4pub struct NameParseError;
5impl core::fmt::Display for NameParseError {
6    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
7        write!(f, "unrecognized name")
8    }
9}
10
11impl std::error::Error for NameParseError {}
12
13// Helper macro to generate iterable nums that translate into static strings mapped from the cpp
14// land.
15macro_rules! iterable_named_enum {
16    (
17    $(#[$m:meta])*
18    $type_vis:vis enum $typename:ident {
19        $(
20            $(#[$variant_meta:meta])*
21            $variant:ident($variant_str:literal) $(= $value:expr)?,
22        )+
23    }
24    ) => {
25        // Main Type
26        #[allow(clippy::all)]
27        $(#[$m])*
28        $type_vis enum $typename {
29            $(
30            $(#[$variant_meta])*
31            $variant$( = $value)?,
32            )+
33        }
34
35        impl $typename {
36            #[doc = "The corresponding rocksdb string identifier for this variant"]
37            pub const fn name(&self) -> &'static str {
38                match self {
39                    $(
40                        $typename::$variant => $variant_str,
41                    )+
42                }
43            }
44            pub fn iter() -> ::core::slice::Iter<'static, $typename> {
45                static VARIANTS: &'static [$typename] = &[
46                    $(
47                        $typename::$variant,
48                    )+
49                ];
50                VARIANTS.iter()
51            }
52        }
53
54
55        #[automatically_derived]
56        impl ::core::str::FromStr for $typename {
57            type Err = NameParseError;
58            fn from_str(s: &str) -> Result<Self, Self::Err> {
59                match s {
60                    $(
61                        $variant_str => Ok($typename::$variant),
62                    )+
63                    _ => Err(NameParseError),
64                }
65            }
66        }
67
68        #[automatically_derived]
69        impl ::core::fmt::Display for $typename {
70            fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
71                self.name().fmt(f)
72            }
73        }
74    };
75}
76
77/// StatsLevel can be used to reduce statistics overhead by skipping certain
78/// types of stats in the stats collection process.
79#[derive(Debug, Copy, Clone, PartialEq, Eq)]
80#[repr(u8)]
81pub enum StatsLevel {
82    /// Disable all metrics
83    DisableAll = 0,
84    /// Disable timer stats, and skip histogram stats
85    ExceptHistogramOrTimers = 2,
86    /// Skip timer stats
87    ExceptTimers,
88    /// Collect all stats except time inside mutex lock AND time spent on
89    /// compression.
90    ExceptDetailedTimers,
91    /// Collect all stats except the counters requiring to get time inside the
92    /// mutex lock.
93    ExceptTimeForMutex,
94    /// Collect all stats, including measuring duration of mutex operations.
95    /// If getting time is expensive on the platform to run, it can
96    /// reduce scalability to more threads, especially for writes.
97    All,
98}
99
100include!("statistics_enum_ticker.rs");
101include!("statistics_enum_histogram.rs");
102
103pub struct HistogramData {
104    pub(crate) inner: *mut ffi::rocksdb_statistics_histogram_data_t,
105}
106
107impl HistogramData {
108    pub fn new() -> HistogramData {
109        HistogramData::default()
110    }
111    pub fn median(&self) -> f64 {
112        unsafe { ffi::rocksdb_statistics_histogram_data_get_median(self.inner) }
113    }
114    pub fn average(&self) -> f64 {
115        unsafe { ffi::rocksdb_statistics_histogram_data_get_average(self.inner) }
116    }
117    pub fn p95(&self) -> f64 {
118        unsafe { ffi::rocksdb_statistics_histogram_data_get_p95(self.inner) }
119    }
120    pub fn p99(&self) -> f64 {
121        unsafe { ffi::rocksdb_statistics_histogram_data_get_p99(self.inner) }
122    }
123    pub fn max(&self) -> f64 {
124        unsafe { ffi::rocksdb_statistics_histogram_data_get_max(self.inner) }
125    }
126    pub fn min(&self) -> f64 {
127        unsafe { ffi::rocksdb_statistics_histogram_data_get_min(self.inner) }
128    }
129    pub fn sum(&self) -> u64 {
130        unsafe { ffi::rocksdb_statistics_histogram_data_get_sum(self.inner) }
131    }
132    pub fn count(&self) -> u64 {
133        unsafe { ffi::rocksdb_statistics_histogram_data_get_count(self.inner) }
134    }
135    pub fn std_dev(&self) -> f64 {
136        unsafe { ffi::rocksdb_statistics_histogram_data_get_std_dev(self.inner) }
137    }
138}
139
140impl Default for HistogramData {
141    fn default() -> Self {
142        let histogram_data_inner = unsafe { ffi::rocksdb_statistics_histogram_data_create() };
143        assert!(
144            !histogram_data_inner.is_null(),
145            "Could not create RocksDB histogram data"
146        );
147
148        Self {
149            inner: histogram_data_inner,
150        }
151    }
152}
153
154impl Drop for HistogramData {
155    fn drop(&mut self) {
156        unsafe {
157            ffi::rocksdb_statistics_histogram_data_destroy(self.inner);
158        }
159    }
160}
161
162#[test]
163fn sanity_checks() {
164    let want = "rocksdb.async.read.bytes";
165    assert_eq!(want, Histogram::AsyncReadBytes.name());
166
167    let want = "rocksdb.block.cache.index.miss";
168    assert_eq!(want, Ticker::BlockCacheIndexMiss.to_string());
169
170    // assert enum lengths
171    assert_eq!(Ticker::iter().count(), 221 /* TICKER_ENUM_MAX */);
172    assert_eq!(Histogram::iter().count(), 64 /* HISTOGRAM_ENUM_MAX */);
173}