diff --git a/crates/matrix-sdk-sqlite/CHANGELOG.md b/crates/matrix-sdk-sqlite/CHANGELOG.md index ad69cf2bb..152459bd9 100644 --- a/crates/matrix-sdk-sqlite/CHANGELOG.md +++ b/crates/matrix-sdk-sqlite/CHANGELOG.md @@ -10,6 +10,8 @@ All notable changes to this project will be documented in this file. - Implement the new method of `EventCacheStoreMedia` for `SqliteEventCacheStore`. ([#4603](https://github.com/matrix-org/matrix-rust-sdk/pull/4603)) +- Defragment an sqlite state store after removing a room. + ([#4651](https://github.com/matrix-org/matrix-rust-sdk/pull/4651)) ## [0.10.0] - 2025-02-04 diff --git a/crates/matrix-sdk-sqlite/src/event_cache_store.rs b/crates/matrix-sdk-sqlite/src/event_cache_store.rs index e477a4922..e0aeefa86 100644 --- a/crates/matrix-sdk-sqlite/src/event_cache_store.rs +++ b/crates/matrix-sdk-sqlite/src/event_cache_store.rs @@ -36,8 +36,6 @@ use matrix_sdk_store_encryption::StoreCipher; use ruma::{time::SystemTime, MilliSecondsSinceUnixEpoch, MxcUri, RoomId}; use rusqlite::{params_from_iter, OptionalExtension, Transaction, TransactionBehavior}; use tokio::fs; -#[cfg(not(test))] -use tracing::warn; use tracing::{debug, trace}; use crate::{ @@ -959,19 +957,10 @@ impl EventCacheStoreMedia for SqliteEventCacheStore { }) .await?; - // If we removed media, use the VACUUM command to defragment the - // database and free space on the filesystem. + // If we removed media, defragment the database and free space on the + // filesystem. if removed { - if let Err(error) = conn.execute("VACUUM", ()).await { - // Since this is an optimisation step, do not propagate the error - // but log it. - #[cfg(not(test))] - warn!("Failed to vacuum database: {error}"); - - // We want to know if there is an error with this step during tests. - #[cfg(test)] - return Err(error.into()); - } + conn.vacuum().await?; } Ok(()) diff --git a/crates/matrix-sdk-sqlite/src/state_store.rs b/crates/matrix-sdk-sqlite/src/state_store.rs index c08e5ed8a..1f863f45b 100644 --- a/crates/matrix-sdk-sqlite/src/state_store.rs +++ b/crates/matrix-sdk-sqlite/src/state_store.rs @@ -336,7 +336,7 @@ impl SqliteStateStore { // Defragment the DB and optimize its size on the filesystem. // This should have been run in the migration for version 7, to reduce the size // of the DB as we removed the media cache. - conn.execute_batch("VACUUM").await?; + conn.vacuum().await?; conn.set_kv("version", vec![12]).await?; } @@ -1739,40 +1739,42 @@ impl StateStore for SqliteStateStore { let this = self.clone(); let room_id = room_id.to_owned(); - self.acquire() - .await? - .with_transaction(move |txn| { - let room_info_room_id = this.encode_key(keys::ROOM_INFO, &room_id); - txn.remove_room_info(&room_info_room_id)?; + let conn = self.acquire().await?; - let state_event_room_id = this.encode_key(keys::STATE_EVENT, &room_id); - txn.remove_room_state_events(&state_event_room_id, None)?; + conn.with_transaction(move |txn| -> Result<()> { + let room_info_room_id = this.encode_key(keys::ROOM_INFO, &room_id); + txn.remove_room_info(&room_info_room_id)?; - let member_room_id = this.encode_key(keys::MEMBER, &room_id); - txn.remove_room_members(&member_room_id, None)?; + let state_event_room_id = this.encode_key(keys::STATE_EVENT, &room_id); + txn.remove_room_state_events(&state_event_room_id, None)?; - let profile_room_id = this.encode_key(keys::PROFILE, &room_id); - txn.remove_room_profiles(&profile_room_id)?; + let member_room_id = this.encode_key(keys::MEMBER, &room_id); + txn.remove_room_members(&member_room_id, None)?; - let room_account_data_room_id = this.encode_key(keys::ROOM_ACCOUNT_DATA, &room_id); - txn.remove_room_account_data(&room_account_data_room_id)?; + let profile_room_id = this.encode_key(keys::PROFILE, &room_id); + txn.remove_room_profiles(&profile_room_id)?; - let receipt_room_id = this.encode_key(keys::RECEIPT, &room_id); - txn.remove_room_receipts(&receipt_room_id)?; + let room_account_data_room_id = this.encode_key(keys::ROOM_ACCOUNT_DATA, &room_id); + txn.remove_room_account_data(&room_account_data_room_id)?; - let display_name_room_id = this.encode_key(keys::DISPLAY_NAME, &room_id); - txn.remove_room_display_names(&display_name_room_id)?; + let receipt_room_id = this.encode_key(keys::RECEIPT, &room_id); + txn.remove_room_receipts(&receipt_room_id)?; - let send_queue_room_id = this.encode_key(keys::SEND_QUEUE, &room_id); - txn.remove_room_send_queue(&send_queue_room_id)?; + let display_name_room_id = this.encode_key(keys::DISPLAY_NAME, &room_id); + txn.remove_room_display_names(&display_name_room_id)?; - let dependent_send_queue_room_id = - this.encode_key(keys::DEPENDENTS_SEND_QUEUE, &room_id); - txn.remove_room_dependent_send_queue(&dependent_send_queue_room_id)?; + let send_queue_room_id = this.encode_key(keys::SEND_QUEUE, &room_id); + txn.remove_room_send_queue(&send_queue_room_id)?; - Ok(()) - }) - .await + let dependent_send_queue_room_id = + this.encode_key(keys::DEPENDENTS_SEND_QUEUE, &room_id); + txn.remove_room_dependent_send_queue(&dependent_send_queue_room_id)?; + + Ok(()) + }) + .await?; + + conn.vacuum().await } async fn save_send_queue_request( diff --git a/crates/matrix-sdk-sqlite/src/utils.rs b/crates/matrix-sdk-sqlite/src/utils.rs index ca56f8381..724dcbc3e 100644 --- a/crates/matrix-sdk-sqlite/src/utils.rs +++ b/crates/matrix-sdk-sqlite/src/utils.rs @@ -136,6 +136,24 @@ pub(crate) trait SqliteAsyncConnExt { self.execute_batch("PRAGMA journal_size_limit = 10000000;").await.map_err(Error::from)?; Ok(()) } + + /// Defragment the database and free space on the filesystem. + /// + /// Only returns an error in tests, otherwise the error is only logged. + async fn vacuum(&self) -> Result<()> { + if let Err(error) = self.execute_batch("VACUUM").await { + // Since this is an optimisation step, do not propagate the error + // but log it. + #[cfg(not(any(test, debug_assertions)))] + tracing::warn!("Failed to vacuum database: {error}"); + + // We want to know if there is an error with this step during tests. + #[cfg(any(test, debug_assertions))] + return Err(error.into()); + } + + Ok(()) + } } #[async_trait]