tuwunel_database/engine/
memory_usage.rs1use std::{ffi::CStr, fmt::Write};
2
3use rocksdb::perf::get_memory_usage_stats;
4use tuwunel_core::{Result, implement};
5
6use super::{
7 Engine,
8 context::{ColCache, SHARED_POOL},
9};
10use crate::or_else;
11
12const CACHE_CAPACITY_PROPERTY: &CStr = c"rocksdb.block-cache-capacity";
15
16fn mib(input: u64) -> f64 { f64::from(u32::try_from(input / 1024).unwrap_or(0)) / 1024.0 }
17
18#[implement(Engine)]
24pub fn memory_usage(&self) -> Result<String> {
25 let mut res = String::new();
26 let row_cache = self.ctx.row_cache.lock()?;
27 let row_usage = u64::try_from(row_cache.get_usage())?;
28 let row_capacity = u64::try_from(self.ctx.row_cache_capacity)?;
29 let stats =
30 get_memory_usage_stats(Some(&[&self.db]), Some(&[&*row_cache])).or_else(or_else)?;
31
32 writeln!(res, "- Memory buffers: {:.2} MiB", mib(stats.mem_table_total))?;
33 writeln!(res, "- Pending write: {:.2} MiB", mib(stats.mem_table_unflushed))?;
34 writeln!(res, "- Table readers: {:.2} MiB", mib(stats.mem_table_readers_total))?;
35 writeln!(
36 res,
37 "- Row cache: {:.2} / {:.2} MiB ({:.1}%)",
38 mib(row_usage),
39 mib(row_capacity),
40 utilization_percent(row_usage, row_capacity),
41 )?;
42
43 drop(row_cache);
44
45 let pools = self.ctx.col_cache.lock()?;
46 if pools.is_empty() {
47 return Ok(res);
48 }
49
50 writeln!(res, "\n```")?;
51 writeln!(
52 res,
53 "{:<34} {:>11} {:>14} {:>8} {:>12} {:>3}",
54 "POOL", "USAGE (MiB)", "CAPACITY (MiB)", "UTIL (%)", "PINNED (MiB)", "CFS",
55 )?;
56
57 for (name, pool) in &*pools {
58 self.write_pool(&mut res, name, pool)?;
59 }
60 writeln!(res, "```")?;
61
62 Ok(res)
63}
64
65#[implement(Engine)]
66fn write_pool(&self, out: &mut String, name: &str, pool: &ColCache) -> Result {
67 let label = if name == SHARED_POOL { "Shared" } else { name };
68 let pinned = u64::try_from(pool.cache.get_pinned_usage())?;
69 let usage = u64::try_from(pool.cache.get_usage())?;
70 let capacity = pool
71 .participants
72 .first()
73 .copied()
74 .map(|cf_name| self.cf(cf_name))
75 .and_then(|cf| {
76 self.property_integer(&cf, CACHE_CAPACITY_PROPERTY)
77 .ok()
78 })
79 .unwrap_or(0);
80
81 writeln!(
82 out,
83 "{label:<34} {:>11.2} {:>14.2} {:>8.1} {:>12.2} {:>3}",
84 mib(usage),
85 mib(capacity),
86 utilization_percent(usage, capacity),
87 mib(pinned),
88 pool.participants.len(),
89 )?;
90
91 Ok(())
92}
93
94#[expect(clippy::as_conversions, clippy::cast_precision_loss)]
95fn utilization_percent(usage: u64, capacity: u64) -> f64 {
96 if capacity == 0 {
97 return 0.0;
98 }
99
100 (usage as f64 / capacity as f64) * 100.0
101}