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