From 32d6553598a0337c98460cd0f137e04562978abf Mon Sep 17 00:00:00 2001 From: Simon Laux Date: Sat, 22 Nov 2025 00:29:13 +0100 Subject: [PATCH 01/16] feat: add api to get information about diskspace usage of database. new jsonrpc api: `get_space_usage_report_string` --- deltachat-jsonrpc/src/api.rs | 7 ++ src/context.rs | 5 ++ src/lib.rs | 1 + src/space_usage.rs | 124 +++++++++++++++++++++++++++++++++++ 4 files changed, 137 insertions(+) create mode 100644 src/space_usage.rs diff --git a/deltachat-jsonrpc/src/api.rs b/deltachat-jsonrpc/src/api.rs index 1603f341ab..3949a7b1b3 100644 --- a/deltachat-jsonrpc/src/api.rs +++ b/deltachat-jsonrpc/src/api.rs @@ -366,6 +366,13 @@ impl CommandApi { ctx.get_info().await } + /// Get space usage report as formatted string + async fn get_space_usage_report_string(&self, account_id: u32) -> Result { + let ctx = self.get_context(account_id).await?; + let space_usage = ctx.get_space_usage().await?; + Ok(space_usage.to_string()) + } + /// Get the blob dir. async fn get_blob_dir(&self, account_id: u32) -> Result> { let ctx = self.get_context(account_id).await?; diff --git a/src/context.rs b/src/context.rs index 7ccaf64a43..4536db7a2c 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1085,6 +1085,11 @@ impl Context { .unwrap_or_default(), ); + res.insert( + "storage_usage", + format!("{:#?}", self.get_space_usage().await), + ); + let elapsed = time_elapsed(&self.creation_time); res.insert("uptime", duration_to_str(elapsed)); diff --git a/src/lib.rs b/src/lib.rs index 27edc28091..1971c419fb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -88,6 +88,7 @@ mod scheduler; pub mod securejoin; mod simplify; mod smtp; +pub mod space_usage; pub mod stock_str; mod sync; mod timesmearing; diff --git a/src/space_usage.rs b/src/space_usage.rs new file mode 100644 index 0000000000..312257549a --- /dev/null +++ b/src/space_usage.rs @@ -0,0 +1,124 @@ +//! Module to collect and display Disk Space Usage of a Profile. +use crate::context::Context; +use anyhow::Result; +use humansize::{BINARY, format_size}; + +/// Space Usage Report +/// Useful for debugging space usage problems in the deltachat database. +#[derive(Debug)] +pub struct SpaceUsage { + /// Total database size, subtract this from the backup size to estimate size of all blobs + pub db_size: usize, + /// size and row count of the 10 biggest tables + pub largest_tables: Vec<(String, usize, Option)>, + /// count and total size of status updates + /// for the 10 webxdc apps with the most size usage in status updates + pub largest_webxdc_data: Vec<(String, usize, usize)>, +} + +impl std::fmt::Display for SpaceUsage { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut report = String::from("SpaceUsage:\n"); + let human_db_size = format_size(self.db_size, BINARY); + report += &format!("[Database Size]: {human_db_size}\n"); + report += "[Largest Tables]:\n"; + for (name, size, row_count) in &self.largest_tables { + let human_table_size = format_size(*size, BINARY); + report += &format!( + " {name:<20} {human_table_size:>10}, {row_count:>6} rows\n", + name = format!("{name}:"), + row_count = row_count.map(|c| c.to_string()).unwrap_or("?".to_owned()) + ); + } + report += "[Webxdc With Biggest Status Update Space Usage]:\n"; + for (msg_id, size, update_count) in &self.largest_webxdc_data { + let human_size = format_size(*size, BINARY); + report += &format!( + " {msg_id:<5} {human_size} across {update_count} updates\n", + msg_id = format!("{msg_id}:") + ); + } + write!(f, "{report}") + } +} + +impl Context { + /// Get space usage information for the Context's database + /// used in Context.get_info() + pub async fn get_space_usage(&self) -> Result { + // currently this is shown in system info, so needs to be fast, + // that's why we donot count size of all blobs for now + let page_size: usize = self + .sql + .query_get_value("PRAGMA page_size", ()) + .await? + .unwrap_or_default(); + let page_count: usize = self + .sql + .query_get_value("PRAGMA page_count", ()) + .await? + .unwrap_or_default(); + + let mut largest_tables = Vec::new(); + + // check if https://sqlite.org/dbstat.html is enabled + if self + .sql + .query_map("SELECT * FROM dbstat LIMIT 1", (), |_| Ok(()), |_| Ok(())) + .await + .is_ok() + { + let biggest_tables = self + .sql + .query_map_vec( + "SELECT name, + SUM(pgsize) AS size + FROM dbstat + WHERE name IN (SELECT name FROM sqlite_master WHERE type='table') + GROUP BY name ORDER BY size DESC LIMIT 10", + (), + |row| { + let name: String = row.get(0)?; + let size: usize = row.get(1)?; + Ok((name, size)) + }, + ) + .await?; + + for (name, size) in biggest_tables { + let row_count: Result> = self + .sql + // SAFETY: the table name comes from the db, not from the user + .query_get_value(&format!("SELECT COUNT(*) FROM {name}"), ()) + .await; + largest_tables.push((name, size, row_count.unwrap_or_default())); + } + } else { + error!(self, "used sqlite version does not support dbstat"); + } + + let largest_webxdc_data = Default::default(); + + self.sql + .query_map_vec( + "SELECT msg_id, SUM(length(update_item)) as size, COUNT(*) as update_count + FROM msgs_status_updates + GROUP BY msg_id ORDER BY size DESC LIMIT 10", + (), + |row| { + let msg_id: usize = row.get(0)?; + let size: usize = row.get(1)?; + let count: usize = row.get(2)?; + + Ok((msg_id, size, count)) + }, + ) + .await?; + + Ok(SpaceUsage { + db_size: page_size * page_count, + largest_tables, + largest_webxdc_data, + }) + } +} From 56cd7719a3f6ebd42d38d555680fb4a8388575f8 Mon Sep 17 00:00:00 2001 From: Simon Laux Date: Sat, 22 Nov 2025 00:36:30 +0100 Subject: [PATCH 02/16] fix that `largest_webxdc_data` result was ignored --- src/space_usage.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/space_usage.rs b/src/space_usage.rs index 312257549a..9ef723f19a 100644 --- a/src/space_usage.rs +++ b/src/space_usage.rs @@ -13,7 +13,7 @@ pub struct SpaceUsage { pub largest_tables: Vec<(String, usize, Option)>, /// count and total size of status updates /// for the 10 webxdc apps with the most size usage in status updates - pub largest_webxdc_data: Vec<(String, usize, usize)>, + pub largest_webxdc_data: Vec<(usize, usize, usize)>, } impl std::fmt::Display for SpaceUsage { @@ -97,9 +97,8 @@ impl Context { error!(self, "used sqlite version does not support dbstat"); } - let largest_webxdc_data = Default::default(); - - self.sql + let largest_webxdc_data = self + .sql .query_map_vec( "SELECT msg_id, SUM(length(update_item)) as size, COUNT(*) as update_count FROM msgs_status_updates From 6fb3b9a674c0106b35e5525a496e3ef7de93ab53 Mon Sep 17 00:00:00 2001 From: Simon Laux Date: Sat, 22 Nov 2025 00:57:22 +0100 Subject: [PATCH 03/16] fix allignment in the string report --- src/space_usage.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/space_usage.rs b/src/space_usage.rs index 9ef723f19a..d610775b28 100644 --- a/src/space_usage.rs +++ b/src/space_usage.rs @@ -34,7 +34,7 @@ impl std::fmt::Display for SpaceUsage { for (msg_id, size, update_count) in &self.largest_webxdc_data { let human_size = format_size(*size, BINARY); report += &format!( - " {msg_id:<5} {human_size} across {update_count} updates\n", + " {msg_id:<8} {human_size:>10} across {update_count:>5} updates\n", msg_id = format!("{msg_id}:") ); } From 2562354dd859f7effe263f45aa98967a737e17a5 Mon Sep 17 00:00:00 2001 From: Simon Laux Date: Sat, 22 Nov 2025 21:04:13 +0100 Subject: [PATCH 04/16] use write! macro instead of building result string --- src/space_usage.rs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/space_usage.rs b/src/space_usage.rs index d610775b28..a32941e5d5 100644 --- a/src/space_usage.rs +++ b/src/space_usage.rs @@ -18,27 +18,29 @@ pub struct SpaceUsage { impl std::fmt::Display for SpaceUsage { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let mut report = String::from("SpaceUsage:\n"); + writeln!(f, "SpaceUsage:")?; let human_db_size = format_size(self.db_size, BINARY); - report += &format!("[Database Size]: {human_db_size}\n"); - report += "[Largest Tables]:\n"; + writeln!(f, "[Database Size]: {human_db_size}")?; + writeln!(f, "[Largest Tables]:")?; for (name, size, row_count) in &self.largest_tables { let human_table_size = format_size(*size, BINARY); - report += &format!( - " {name:<20} {human_table_size:>10}, {row_count:>6} rows\n", + writeln!( + f, + " {name:<20} {human_table_size:>10}, {row_count:>6} rows", name = format!("{name}:"), row_count = row_count.map(|c| c.to_string()).unwrap_or("?".to_owned()) - ); + )?; } - report += "[Webxdc With Biggest Status Update Space Usage]:\n"; + writeln!(f, "[Webxdc With Biggest Status Update Space Usage]:")?; for (msg_id, size, update_count) in &self.largest_webxdc_data { let human_size = format_size(*size, BINARY); - report += &format!( - " {msg_id:<8} {human_size:>10} across {update_count:>5} updates\n", + writeln!( + f, + " {msg_id:<8} {human_size:>10} across {update_count:>5} updates", msg_id = format!("{msg_id}:") - ); + )?; } - write!(f, "{report}") + Ok(()) } } From 6fe3e1899b0f66ff2fdc370e18b7208e4b1300d0 Mon Sep 17 00:00:00 2001 From: Simon Laux Date: Sat, 22 Nov 2025 21:10:13 +0100 Subject: [PATCH 05/16] add hint that rust api users shouldn't rely on the content format of SpaceUsage struct and should use output of to_string instead. --- src/space_usage.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/space_usage.rs b/src/space_usage.rs index a32941e5d5..1ca84b4879 100644 --- a/src/space_usage.rs +++ b/src/space_usage.rs @@ -5,6 +5,10 @@ use humansize::{BINARY, format_size}; /// Space Usage Report /// Useful for debugging space usage problems in the deltachat database. +/// +/// Warning: Attention Rust-API users: This API is Experimental! +/// - The contents of this struct may change in future core versions. +/// - For now it is better to just show the to_string() output to users. #[derive(Debug)] pub struct SpaceUsage { /// Total database size, subtract this from the backup size to estimate size of all blobs From d7aba0adba4bb48f986a5e190bf6c029cd8a42ec Mon Sep 17 00:00:00 2001 From: Simon Laux Date: Sat, 22 Nov 2025 21:12:20 +0100 Subject: [PATCH 06/16] remove storage usage from Context.get_info --- src/context.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/context.rs b/src/context.rs index 4536db7a2c..7ccaf64a43 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1085,11 +1085,6 @@ impl Context { .unwrap_or_default(), ); - res.insert( - "storage_usage", - format!("{:#?}", self.get_space_usage().await), - ); - let elapsed = time_elapsed(&self.creation_time); res.insert("uptime", duration_to_str(elapsed)); From d55a5e4e6f3b4ee6fc020598a75938f4bfc56062 Mon Sep 17 00:00:00 2001 From: Simon Laux Date: Sat, 22 Nov 2025 21:14:51 +0100 Subject: [PATCH 07/16] dedicated method, not part of context --- src/space_usage.rs | 123 ++++++++++++++++++++++----------------------- 1 file changed, 60 insertions(+), 63 deletions(-) diff --git a/src/space_usage.rs b/src/space_usage.rs index 1ca84b4879..cdd0cccd1c 100644 --- a/src/space_usage.rs +++ b/src/space_usage.rs @@ -48,82 +48,79 @@ impl std::fmt::Display for SpaceUsage { } } -impl Context { - /// Get space usage information for the Context's database - /// used in Context.get_info() - pub async fn get_space_usage(&self) -> Result { - // currently this is shown in system info, so needs to be fast, - // that's why we donot count size of all blobs for now - let page_size: usize = self - .sql - .query_get_value("PRAGMA page_size", ()) - .await? - .unwrap_or_default(); - let page_count: usize = self - .sql - .query_get_value("PRAGMA page_count", ()) - .await? - .unwrap_or_default(); +/// Get space usage information for the Context's database +pub async fn get_space_usage(ctx: &Context) -> Result { + // currently this is shown in system info, so needs to be fast, + // that's why we donot count size of all blobs for now + let page_size: usize = ctx + .sql + .query_get_value("PRAGMA page_size", ()) + .await? + .unwrap_or_default(); + let page_count: usize = ctx + .sql + .query_get_value("PRAGMA page_count", ()) + .await? + .unwrap_or_default(); - let mut largest_tables = Vec::new(); + let mut largest_tables = Vec::new(); - // check if https://sqlite.org/dbstat.html is enabled - if self + // check if https://sqlite.org/dbstat.html is enabled + if ctx + .sql + .query_map("SELECT * FROM dbstat LIMIT 1", (), |_| Ok(()), |_| Ok(())) + .await + .is_ok() + { + let biggest_tables = ctx .sql - .query_map("SELECT * FROM dbstat LIMIT 1", (), |_| Ok(()), |_| Ok(())) - .await - .is_ok() - { - let biggest_tables = self - .sql - .query_map_vec( - "SELECT name, + .query_map_vec( + "SELECT name, SUM(pgsize) AS size FROM dbstat WHERE name IN (SELECT name FROM sqlite_master WHERE type='table') GROUP BY name ORDER BY size DESC LIMIT 10", - (), - |row| { - let name: String = row.get(0)?; - let size: usize = row.get(1)?; - Ok((name, size)) - }, - ) - .await?; - - for (name, size) in biggest_tables { - let row_count: Result> = self - .sql - // SAFETY: the table name comes from the db, not from the user - .query_get_value(&format!("SELECT COUNT(*) FROM {name}"), ()) - .await; - largest_tables.push((name, size, row_count.unwrap_or_default())); - } - } else { - error!(self, "used sqlite version does not support dbstat"); - } - - let largest_webxdc_data = self - .sql - .query_map_vec( - "SELECT msg_id, SUM(length(update_item)) as size, COUNT(*) as update_count - FROM msgs_status_updates - GROUP BY msg_id ORDER BY size DESC LIMIT 10", (), |row| { - let msg_id: usize = row.get(0)?; + let name: String = row.get(0)?; let size: usize = row.get(1)?; - let count: usize = row.get(2)?; - - Ok((msg_id, size, count)) + Ok((name, size)) }, ) .await?; - Ok(SpaceUsage { - db_size: page_size * page_count, - largest_tables, - largest_webxdc_data, - }) + for (name, size) in biggest_tables { + let row_count: Result> = ctx + .sql + // SAFETY: the table name comes from the db, not from the user + .query_get_value(&format!("SELECT COUNT(*) FROM {name}"), ()) + .await; + largest_tables.push((name, size, row_count.unwrap_or_default())); + } + } else { + error!(ctx, "used sqlite version does not support dbstat"); } + + let largest_webxdc_data = ctx + .sql + .query_map_vec( + "SELECT msg_id, SUM(length(update_item)) as size, COUNT(*) as update_count + FROM msgs_status_updates + GROUP BY msg_id ORDER BY size DESC LIMIT 10", + (), + |row| { + let msg_id: usize = row.get(0)?; + let size: usize = row.get(1)?; + let count: usize = row.get(2)?; + + Ok((msg_id, size, count)) + }, + ) + .await?; + + Ok(SpaceUsage { + db_size: page_size * page_count, + largest_tables, + largest_webxdc_data, + }) } From 503ef274b28fa61b8baac94eb47772264c017030 Mon Sep 17 00:00:00 2001 From: Simon Laux Date: Sat, 22 Nov 2025 21:15:18 +0100 Subject: [PATCH 08/16] remove another outdated comment --- src/space_usage.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/space_usage.rs b/src/space_usage.rs index cdd0cccd1c..b1f052a34d 100644 --- a/src/space_usage.rs +++ b/src/space_usage.rs @@ -50,8 +50,6 @@ impl std::fmt::Display for SpaceUsage { /// Get space usage information for the Context's database pub async fn get_space_usage(ctx: &Context) -> Result { - // currently this is shown in system info, so needs to be fast, - // that's why we donot count size of all blobs for now let page_size: usize = ctx .sql .query_get_value("PRAGMA page_size", ()) From cccab2b4b3de77656647c9d0bbd703e3612cae9c Mon Sep 17 00:00:00 2001 From: Simon Laux Date: Sat, 22 Nov 2025 21:16:32 +0100 Subject: [PATCH 09/16] remove check for dbstat --- src/space_usage.rs | 46 ++++++++++++++++++---------------------------- 1 file changed, 18 insertions(+), 28 deletions(-) diff --git a/src/space_usage.rs b/src/space_usage.rs index b1f052a34d..01b4f370ff 100644 --- a/src/space_usage.rs +++ b/src/space_usage.rs @@ -63,40 +63,30 @@ pub async fn get_space_usage(ctx: &Context) -> Result { let mut largest_tables = Vec::new(); - // check if https://sqlite.org/dbstat.html is enabled - if ctx + let biggest_tables = ctx .sql - .query_map("SELECT * FROM dbstat LIMIT 1", (), |_| Ok(()), |_| Ok(())) - .await - .is_ok() - { - let biggest_tables = ctx - .sql - .query_map_vec( - "SELECT name, + .query_map_vec( + "SELECT name, SUM(pgsize) AS size FROM dbstat WHERE name IN (SELECT name FROM sqlite_master WHERE type='table') GROUP BY name ORDER BY size DESC LIMIT 10", - (), - |row| { - let name: String = row.get(0)?; - let size: usize = row.get(1)?; - Ok((name, size)) - }, - ) - .await?; + (), + |row| { + let name: String = row.get(0)?; + let size: usize = row.get(1)?; + Ok((name, size)) + }, + ) + .await?; - for (name, size) in biggest_tables { - let row_count: Result> = ctx - .sql - // SAFETY: the table name comes from the db, not from the user - .query_get_value(&format!("SELECT COUNT(*) FROM {name}"), ()) - .await; - largest_tables.push((name, size, row_count.unwrap_or_default())); - } - } else { - error!(ctx, "used sqlite version does not support dbstat"); + for (name, size) in biggest_tables { + let row_count: Result> = ctx + .sql + // SAFETY: the table name comes from the db, not from the user + .query_get_value(&format!("SELECT COUNT(*) FROM {name}"), ()) + .await; + largest_tables.push((name, size, row_count.unwrap_or_default())); } let largest_webxdc_data = ctx From 1677561d0235ffb2dc443f1a37ba347d592b1da8 Mon Sep 17 00:00:00 2001 From: Simon Laux Date: Sat, 22 Nov 2025 21:17:08 +0100 Subject: [PATCH 10/16] comment: safety -> security --- src/space_usage.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/space_usage.rs b/src/space_usage.rs index 01b4f370ff..e5953559bb 100644 --- a/src/space_usage.rs +++ b/src/space_usage.rs @@ -83,7 +83,7 @@ pub async fn get_space_usage(ctx: &Context) -> Result { for (name, size) in biggest_tables { let row_count: Result> = ctx .sql - // SAFETY: the table name comes from the db, not from the user + // SECURITY: the table name comes from the db, not from the user .query_get_value(&format!("SELECT COUNT(*) FROM {name}"), ()) .await; largest_tables.push((name, size, row_count.unwrap_or_default())); From d466c6ea3eea4b4333b6c31a216407ca9636ffd0 Mon Sep 17 00:00:00 2001 From: Simon Laux Date: Sat, 22 Nov 2025 21:23:16 +0100 Subject: [PATCH 11/16] fix jsonrpc api --- deltachat-jsonrpc/src/api.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/deltachat-jsonrpc/src/api.rs b/deltachat-jsonrpc/src/api.rs index 3949a7b1b3..ac32510ebe 100644 --- a/deltachat-jsonrpc/src/api.rs +++ b/deltachat-jsonrpc/src/api.rs @@ -33,6 +33,7 @@ use deltachat::qr::{self, Qr}; use deltachat::qr_code_generator::{generate_backup_qr, get_securejoin_qr_svg}; use deltachat::reaction::{get_msg_reactions, send_reaction}; use deltachat::securejoin; +use deltachat::space_usage::get_space_usage; use deltachat::stock_str::StockMessage; use deltachat::webxdc::StatusUpdateSerial; use deltachat::EventEmitter; @@ -369,7 +370,7 @@ impl CommandApi { /// Get space usage report as formatted string async fn get_space_usage_report_string(&self, account_id: u32) -> Result { let ctx = self.get_context(account_id).await?; - let space_usage = ctx.get_space_usage().await?; + let space_usage = get_space_usage(&ctx).await?; Ok(space_usage.to_string()) } From 8f817c00b4caa35801964ccb8d4d1d995be2c89f Mon Sep 17 00:00:00 2001 From: Simon Laux Date: Sat, 22 Nov 2025 23:43:07 +0100 Subject: [PATCH 12/16] remove experimental warning --- src/space_usage.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/space_usage.rs b/src/space_usage.rs index e5953559bb..0d316e9500 100644 --- a/src/space_usage.rs +++ b/src/space_usage.rs @@ -5,10 +5,6 @@ use humansize::{BINARY, format_size}; /// Space Usage Report /// Useful for debugging space usage problems in the deltachat database. -/// -/// Warning: Attention Rust-API users: This API is Experimental! -/// - The contents of this struct may change in future core versions. -/// - For now it is better to just show the to_string() output to users. #[derive(Debug)] pub struct SpaceUsage { /// Total database size, subtract this from the backup size to estimate size of all blobs From ff45f584757df6cc1b9efa2f63aa052b395fd7bc Mon Sep 17 00:00:00 2001 From: Simon Laux Date: Sun, 23 Nov 2025 15:57:24 +0100 Subject: [PATCH 13/16] rename api to storage --- deltachat-jsonrpc/src/api.rs | 6 +++--- src/space_usage.rs | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/deltachat-jsonrpc/src/api.rs b/deltachat-jsonrpc/src/api.rs index ac32510ebe..8402e74d8e 100644 --- a/deltachat-jsonrpc/src/api.rs +++ b/deltachat-jsonrpc/src/api.rs @@ -33,7 +33,7 @@ use deltachat::qr::{self, Qr}; use deltachat::qr_code_generator::{generate_backup_qr, get_securejoin_qr_svg}; use deltachat::reaction::{get_msg_reactions, send_reaction}; use deltachat::securejoin; -use deltachat::space_usage::get_space_usage; +use deltachat::space_usage::get_storage_usage; use deltachat::stock_str::StockMessage; use deltachat::webxdc::StatusUpdateSerial; use deltachat::EventEmitter; @@ -368,9 +368,9 @@ impl CommandApi { } /// Get space usage report as formatted string - async fn get_space_usage_report_string(&self, account_id: u32) -> Result { + async fn get_storage_usage_report_string(&self, account_id: u32) -> Result { let ctx = self.get_context(account_id).await?; - let space_usage = get_space_usage(&ctx).await?; + let space_usage = get_storage_usage(&ctx).await?; Ok(space_usage.to_string()) } diff --git a/src/space_usage.rs b/src/space_usage.rs index 0d316e9500..2c7188b4d7 100644 --- a/src/space_usage.rs +++ b/src/space_usage.rs @@ -3,10 +3,10 @@ use crate::context::Context; use anyhow::Result; use humansize::{BINARY, format_size}; -/// Space Usage Report +/// Storage Usage Report /// Useful for debugging space usage problems in the deltachat database. #[derive(Debug)] -pub struct SpaceUsage { +pub struct StorageUsage { /// Total database size, subtract this from the backup size to estimate size of all blobs pub db_size: usize, /// size and row count of the 10 biggest tables @@ -16,9 +16,9 @@ pub struct SpaceUsage { pub largest_webxdc_data: Vec<(usize, usize, usize)>, } -impl std::fmt::Display for SpaceUsage { +impl std::fmt::Display for StorageUsage { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - writeln!(f, "SpaceUsage:")?; + writeln!(f, "Storage Usage:")?; let human_db_size = format_size(self.db_size, BINARY); writeln!(f, "[Database Size]: {human_db_size}")?; writeln!(f, "[Largest Tables]:")?; @@ -44,8 +44,8 @@ impl std::fmt::Display for SpaceUsage { } } -/// Get space usage information for the Context's database -pub async fn get_space_usage(ctx: &Context) -> Result { +/// Get storage usage information for the Context's database +pub async fn get_storage_usage(ctx: &Context) -> Result { let page_size: usize = ctx .sql .query_get_value("PRAGMA page_size", ()) @@ -102,7 +102,7 @@ pub async fn get_space_usage(ctx: &Context) -> Result { ) .await?; - Ok(SpaceUsage { + Ok(StorageUsage { db_size: page_size * page_count, largest_tables, largest_webxdc_data, From 38c7d6140d498c53c063e125711569050ada69e2 Mon Sep 17 00:00:00 2001 From: Simon Laux Date: Sun, 23 Nov 2025 16:03:44 +0100 Subject: [PATCH 14/16] fill largest_tables in place --- src/space_usage.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/space_usage.rs b/src/space_usage.rs index 2c7188b4d7..32b82d23af 100644 --- a/src/space_usage.rs +++ b/src/space_usage.rs @@ -57,9 +57,7 @@ pub async fn get_storage_usage(ctx: &Context) -> Result { .await? .unwrap_or_default(); - let mut largest_tables = Vec::new(); - - let biggest_tables = ctx + let mut largest_tables = ctx .sql .query_map_vec( "SELECT name, @@ -71,18 +69,19 @@ pub async fn get_storage_usage(ctx: &Context) -> Result { |row| { let name: String = row.get(0)?; let size: usize = row.get(1)?; - Ok((name, size)) + Ok((name, size, None)) }, ) .await?; - for (name, size) in biggest_tables { + for row in &mut largest_tables { + let name = &row.0; let row_count: Result> = ctx .sql // SECURITY: the table name comes from the db, not from the user .query_get_value(&format!("SELECT COUNT(*) FROM {name}"), ()) .await; - largest_tables.push((name, size, row_count.unwrap_or_default())); + row.2 = row_count.unwrap_or_default(); } let largest_webxdc_data = ctx From ac6f12a5c02317edd129440f13b1b31b8f57069e Mon Sep 17 00:00:00 2001 From: Simon Laux Date: Sun, 23 Nov 2025 16:04:50 +0100 Subject: [PATCH 15/16] more space to storage renaming --- deltachat-jsonrpc/src/api.rs | 8 ++++---- src/lib.rs | 2 +- src/{space_usage.rs => storage_usage.rs} | 0 3 files changed, 5 insertions(+), 5 deletions(-) rename src/{space_usage.rs => storage_usage.rs} (100%) diff --git a/deltachat-jsonrpc/src/api.rs b/deltachat-jsonrpc/src/api.rs index 8402e74d8e..5fc27adb83 100644 --- a/deltachat-jsonrpc/src/api.rs +++ b/deltachat-jsonrpc/src/api.rs @@ -33,8 +33,8 @@ use deltachat::qr::{self, Qr}; use deltachat::qr_code_generator::{generate_backup_qr, get_securejoin_qr_svg}; use deltachat::reaction::{get_msg_reactions, send_reaction}; use deltachat::securejoin; -use deltachat::space_usage::get_storage_usage; use deltachat::stock_str::StockMessage; +use deltachat::storage_usage::get_storage_usage; use deltachat::webxdc::StatusUpdateSerial; use deltachat::EventEmitter; use sanitize_filename::is_sanitized; @@ -367,11 +367,11 @@ impl CommandApi { ctx.get_info().await } - /// Get space usage report as formatted string + /// Get storage usage report as formatted string async fn get_storage_usage_report_string(&self, account_id: u32) -> Result { let ctx = self.get_context(account_id).await?; - let space_usage = get_storage_usage(&ctx).await?; - Ok(space_usage.to_string()) + let storage_usage = get_storage_usage(&ctx).await?; + Ok(storage_usage.to_string()) } /// Get the blob dir. diff --git a/src/lib.rs b/src/lib.rs index 1971c419fb..382e4de96e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -88,8 +88,8 @@ mod scheduler; pub mod securejoin; mod simplify; mod smtp; -pub mod space_usage; pub mod stock_str; +pub mod storage_usage; mod sync; mod timesmearing; mod token; diff --git a/src/space_usage.rs b/src/storage_usage.rs similarity index 100% rename from src/space_usage.rs rename to src/storage_usage.rs From 6ec173334644cde3cd61b4c8c51ea207fe92f3ae Mon Sep 17 00:00:00 2001 From: Simon Laux Date: Sun, 23 Nov 2025 16:05:47 +0100 Subject: [PATCH 16/16] use MsgId type for webxdc instance ids instead of usize --- src/storage_usage.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/storage_usage.rs b/src/storage_usage.rs index 32b82d23af..c58efddf7b 100644 --- a/src/storage_usage.rs +++ b/src/storage_usage.rs @@ -1,5 +1,5 @@ //! Module to collect and display Disk Space Usage of a Profile. -use crate::context::Context; +use crate::{context::Context, message::MsgId}; use anyhow::Result; use humansize::{BINARY, format_size}; @@ -13,7 +13,7 @@ pub struct StorageUsage { pub largest_tables: Vec<(String, usize, Option)>, /// count and total size of status updates /// for the 10 webxdc apps with the most size usage in status updates - pub largest_webxdc_data: Vec<(usize, usize, usize)>, + pub largest_webxdc_data: Vec<(MsgId, usize, usize)>, } impl std::fmt::Display for StorageUsage { @@ -92,7 +92,7 @@ pub async fn get_storage_usage(ctx: &Context) -> Result { GROUP BY msg_id ORDER BY size DESC LIMIT 10", (), |row| { - let msg_id: usize = row.get(0)?; + let msg_id: MsgId = row.get(0)?; let size: usize = row.get(1)?; let count: usize = row.get(2)?;