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