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