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