deltachat/
storage_usage.rs1use crate::{context::Context, message::MsgId};
3use anyhow::Result;
4use humansize::{BINARY, format_size};
5
6#[derive(Debug)]
9pub struct StorageUsage {
10 pub db_size: usize,
12 pub largest_tables: Vec<(String, usize, Option<usize>)>,
14 pub largest_webxdc_data: Vec<(MsgId, usize, usize)>,
17}
18
19impl std::fmt::Display for StorageUsage {
20 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21 writeln!(f, "Storage Usage:")?;
22 let human_db_size = format_size(self.db_size, BINARY);
23 writeln!(f, "[Database Size]: {human_db_size}")?;
24 writeln!(f, "[Largest Tables]:")?;
25 for (name, size, row_count) in &self.largest_tables {
26 let human_table_size = format_size(*size, BINARY);
27 writeln!(
28 f,
29 " {name:<20} {human_table_size:>10}, {row_count:>6} rows",
30 name = format!("{name}:"),
31 row_count = row_count.map(|c| c.to_string()).unwrap_or("?".to_owned())
32 )?;
33 }
34 writeln!(f, "[Webxdc With Biggest Status Update Space Usage]:")?;
35 for (msg_id, size, update_count) in &self.largest_webxdc_data {
36 let human_size = format_size(*size, BINARY);
37 writeln!(
38 f,
39 " {msg_id:<8} {human_size:>10} across {update_count:>5} updates",
40 msg_id = format!("{msg_id}:")
41 )?;
42 }
43 Ok(())
44 }
45}
46
47pub async fn get_storage_usage(ctx: &Context) -> Result<StorageUsage> {
49 let page_size: usize = ctx
50 .sql
51 .query_get_value("PRAGMA page_size", ())
52 .await?
53 .unwrap_or_default();
54 let page_count: usize = ctx
55 .sql
56 .query_get_value("PRAGMA page_count", ())
57 .await?
58 .unwrap_or_default();
59
60 let mut largest_tables = ctx
61 .sql
62 .query_map_vec(
63 "SELECT name,
64 SUM(pgsize) AS size
65 FROM dbstat
66 WHERE name IN (SELECT name FROM sqlite_master WHERE type='table')
67 GROUP BY name ORDER BY size DESC LIMIT 10",
68 (),
69 |row| {
70 let name: String = row.get(0)?;
71 let size: usize = row.get(1)?;
72 Ok((name, size, None))
73 },
74 )
75 .await?;
76
77 for row in &mut largest_tables {
78 let name = &row.0;
79 let row_count: Result<Option<usize>> = ctx
80 .sql
81 .query_get_value(&format!("SELECT COUNT(*) FROM {name}"), ())
83 .await;
84 row.2 = row_count.unwrap_or_default();
85 }
86
87 let largest_webxdc_data = ctx
88 .sql
89 .query_map_vec(
90 "SELECT msg_id, SUM(length(update_item)) as size, COUNT(*) as update_count
91 FROM msgs_status_updates
92 GROUP BY msg_id ORDER BY size DESC LIMIT 10",
93 (),
94 |row| {
95 let msg_id: MsgId = row.get(0)?;
96 let size: usize = row.get(1)?;
97 let count: usize = row.get(2)?;
98
99 Ok((msg_id, size, count))
100 },
101 )
102 .await?;
103
104 Ok(StorageUsage {
105 db_size: page_size * page_count,
106 largest_tables,
107 largest_webxdc_data,
108 })
109}