1use libc::{c_int, c_uchar, c_void};
16
17use crate::{db::DBInner, ffi, ffi_util::from_cstr, Cache, Error, DB};
18
19#[derive(Debug, Copy, Clone, PartialEq, Eq)]
20#[repr(i32)]
21pub enum PerfStatsLevel {
22 Uninitialized = 0,
24 Disable,
26 EnableCount,
28 EnableTimeExceptForMutex,
30 EnableTimeAndCPUTimeExceptForMutex,
33 EnableTime,
35 OutOfBound,
37}
38
39#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
40#[non_exhaustive]
41#[repr(i32)]
42pub enum PerfMetric {
43 UserKeyComparisonCount = 0,
44 BlockCacheHitCount = 1,
45 BlockReadCount = 2,
46 BlockReadByte = 3,
47 BlockReadTime = 4,
48 BlockChecksumTime = 5,
49 BlockDecompressTime = 6,
50 GetReadBytes = 7,
51 MultigetReadBytes = 8,
52 IterReadBytes = 9,
53 InternalKeySkippedCount = 10,
54 InternalDeleteSkippedCount = 11,
55 InternalRecentSkippedCount = 12,
56 InternalMergeCount = 13,
57 GetSnapshotTime = 14,
58 GetFromMemtableTime = 15,
59 GetFromMemtableCount = 16,
60 GetPostProcessTime = 17,
61 GetFromOutputFilesTime = 18,
62 SeekOnMemtableTime = 19,
63 SeekOnMemtableCount = 20,
64 NextOnMemtableCount = 21,
65 PrevOnMemtableCount = 22,
66 SeekChildSeekTime = 23,
67 SeekChildSeekCount = 24,
68 SeekMinHeapTime = 25,
69 SeekMaxHeapTime = 26,
70 SeekInternalSeekTime = 27,
71 FindNextUserEntryTime = 28,
72 WriteWalTime = 29,
73 WriteMemtableTime = 30,
74 WriteDelayTime = 31,
75 WritePreAndPostProcessTime = 32,
76 DbMutexLockNanos = 33,
77 DbConditionWaitNanos = 34,
78 MergeOperatorTimeNanos = 35,
79 ReadIndexBlockNanos = 36,
80 ReadFilterBlockNanos = 37,
81 NewTableBlockIterNanos = 38,
82 NewTableIteratorNanos = 39,
83 BlockSeekNanos = 40,
84 FindTableNanos = 41,
85 BloomMemtableHitCount = 42,
86 BloomMemtableMissCount = 43,
87 BloomSstHitCount = 44,
88 BloomSstMissCount = 45,
89 KeyLockWaitTime = 46,
90 KeyLockWaitCount = 47,
91 EnvNewSequentialFileNanos = 48,
92 EnvNewRandomAccessFileNanos = 49,
93 EnvNewWritableFileNanos = 50,
94 EnvReuseWritableFileNanos = 51,
95 EnvNewRandomRwFileNanos = 52,
96 EnvNewDirectoryNanos = 53,
97 EnvFileExistsNanos = 54,
98 EnvGetChildrenNanos = 55,
99 EnvGetChildrenFileAttributesNanos = 56,
100 EnvDeleteFileNanos = 57,
101 EnvCreateDirNanos = 58,
102 EnvCreateDirIfMissingNanos = 59,
103 EnvDeleteDirNanos = 60,
104 EnvGetFileSizeNanos = 61,
105 EnvGetFileModificationTimeNanos = 62,
106 EnvRenameFileNanos = 63,
107 EnvLinkFileNanos = 64,
108 EnvLockFileNanos = 65,
109 EnvUnlockFileNanos = 66,
110 EnvNewLoggerNanos = 67,
111 TotalMetricCount = 68,
112}
113
114pub fn set_perf_stats(lvl: PerfStatsLevel) {
116 unsafe {
117 ffi::rocksdb_set_perf_level(lvl as c_int);
118 }
119}
120
121pub struct PerfContext {
124 pub(crate) inner: *mut ffi::rocksdb_perfcontext_t,
125}
126
127impl Default for PerfContext {
128 fn default() -> Self {
129 let ctx = unsafe { ffi::rocksdb_perfcontext_create() };
130 assert!(!ctx.is_null(), "Could not create Perf Context");
131
132 Self { inner: ctx }
133 }
134}
135
136impl Drop for PerfContext {
137 fn drop(&mut self) {
138 unsafe {
139 ffi::rocksdb_perfcontext_destroy(self.inner);
140 }
141 }
142}
143
144impl PerfContext {
145 pub fn reset(&mut self) {
147 unsafe {
148 ffi::rocksdb_perfcontext_reset(self.inner);
149 }
150 }
151
152 pub fn report(&self, exclude_zero_counters: bool) -> String {
154 unsafe {
155 let ptr =
156 ffi::rocksdb_perfcontext_report(self.inner, c_uchar::from(exclude_zero_counters));
157 let report = from_cstr(ptr);
158 libc::free(ptr as *mut c_void);
159 report
160 }
161 }
162
163 pub fn metric(&self, id: PerfMetric) -> u64 {
165 unsafe { ffi::rocksdb_perfcontext_metric(self.inner, id as c_int) }
166 }
167}
168
169pub struct MemoryUsageStats {
171 pub mem_table_total: u64,
173 pub mem_table_unflushed: u64,
175 pub mem_table_readers_total: u64,
177 pub cache_total: u64,
179}
180
181struct MemoryUsage {
183 inner: *mut ffi::rocksdb_memory_usage_t,
184}
185
186impl Drop for MemoryUsage {
187 fn drop(&mut self) {
188 unsafe {
189 ffi::rocksdb_approximate_memory_usage_destroy(self.inner);
190 }
191 }
192}
193
194impl MemoryUsage {
195 fn approximate_mem_table_total(&self) -> u64 {
197 unsafe { ffi::rocksdb_approximate_memory_usage_get_mem_table_total(self.inner) }
198 }
199
200 fn approximate_mem_table_unflushed(&self) -> u64 {
202 unsafe { ffi::rocksdb_approximate_memory_usage_get_mem_table_unflushed(self.inner) }
203 }
204
205 fn approximate_mem_table_readers_total(&self) -> u64 {
207 unsafe { ffi::rocksdb_approximate_memory_usage_get_mem_table_readers_total(self.inner) }
208 }
209
210 fn approximate_cache_total(&self) -> u64 {
212 unsafe { ffi::rocksdb_approximate_memory_usage_get_cache_total(self.inner) }
213 }
214}
215
216struct MemoryUsageBuilder {
218 inner: *mut ffi::rocksdb_memory_consumers_t,
219}
220
221impl Drop for MemoryUsageBuilder {
222 fn drop(&mut self) {
223 unsafe {
224 ffi::rocksdb_memory_consumers_destroy(self.inner);
225 }
226 }
227}
228
229impl MemoryUsageBuilder {
230 fn new() -> Result<Self, Error> {
232 let mc = unsafe { ffi::rocksdb_memory_consumers_create() };
233 if mc.is_null() {
234 Err(Error::new(
235 "Could not create MemoryUsage builder".to_owned(),
236 ))
237 } else {
238 Ok(Self { inner: mc })
239 }
240 }
241
242 fn add_db(&mut self, db: &DB) {
244 unsafe {
245 ffi::rocksdb_memory_consumers_add_db(self.inner, db.inner.inner());
246 }
247 }
248
249 fn add_cache(&mut self, cache: &Cache) {
251 unsafe {
252 ffi::rocksdb_memory_consumers_add_cache(self.inner, cache.0.inner.as_ptr());
253 }
254 }
255
256 fn build(&self) -> Result<MemoryUsage, Error> {
258 unsafe {
259 let mu = ffi_try!(ffi::rocksdb_approximate_memory_usage_create(self.inner));
260 Ok(MemoryUsage { inner: mu })
261 }
262 }
263}
264
265pub fn get_memory_usage_stats(
267 dbs: Option<&[&DB]>,
268 caches: Option<&[&Cache]>,
269) -> Result<MemoryUsageStats, Error> {
270 let mut builder = MemoryUsageBuilder::new()?;
271 if let Some(dbs_) = dbs {
272 dbs_.iter().for_each(|db| builder.add_db(db));
273 }
274 if let Some(caches_) = caches {
275 caches_.iter().for_each(|cache| builder.add_cache(cache));
276 }
277
278 let mu = builder.build()?;
279 Ok(MemoryUsageStats {
280 mem_table_total: mu.approximate_mem_table_total(),
281 mem_table_unflushed: mu.approximate_mem_table_unflushed(),
282 mem_table_readers_total: mu.approximate_mem_table_readers_total(),
283 cache_total: mu.approximate_cache_total(),
284 })
285}