From ae3cd709049432ca4544a60df276189d1be297e7 Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Wed, 4 May 2022 16:39:08 +0200 Subject: [PATCH 1/2] feat(sled): Add store db schema version support --- crates/matrix-sdk-base/src/store/mod.rs | 7 ++++ crates/matrix-sdk-sled/src/state_store.rs | 48 ++++++++++++++++++++++- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/crates/matrix-sdk-base/src/store/mod.rs b/crates/matrix-sdk-base/src/store/mod.rs index e2f6fce90..7ab480487 100644 --- a/crates/matrix-sdk-base/src/store/mod.rs +++ b/crates/matrix-sdk-base/src/store/mod.rs @@ -94,6 +94,13 @@ pub enum StoreError { /// The store failed to encode or decode some data. #[error("Error encoding or decoding data from the store: {0}")] Codec(String), + + /// The database format has changed in a backwards incompatible way. + #[error( + "The database format changed in an incompatible way, current \ + version: {0}, latest version: {1}" + )] + UnsupportedDatabaseVersion(usize, usize), /// Redacting an event in the store has failed. /// /// This should never happen. diff --git a/crates/matrix-sdk-sled/src/state_store.rs b/crates/matrix-sdk-sled/src/state_store.rs index a2bca8276..371a557f2 100644 --- a/crates/matrix-sdk-sled/src/state_store.rs +++ b/crates/matrix-sdk-sled/src/state_store.rs @@ -111,6 +111,9 @@ impl Into for SledStoreError { } } } +const DATABASE_VERSION: u8 = 1; + +const VERSION_KEY: &str = "state-store-version"; const ACCOUNT_DATA: &str = "account-data"; const CUSTOM: &str = "custom"; @@ -210,7 +213,7 @@ impl SledStore { let room_timeline_metadata = db.open_tree(TIMELINE_METADATA)?; let room_event_id_to_position = db.open_tree(ROOM_EVENT_ID_POSITION)?; - Ok(Self { + let database = Self { path, inner: db, store_cipher, @@ -235,7 +238,10 @@ impl SledStore { room_timeline, room_timeline_metadata, room_event_id_to_position, - }) + }; + + database.upgrade()?; + Ok(database) } pub fn open() -> StoreResult { @@ -290,6 +296,44 @@ impl SledStore { SledStore::open_helper(db, Some(path), None) } + fn upgrade(&self) -> StoreResult<()> { + let db_version = + self.inner.get(VERSION_KEY).map_err(|e| StoreError::Backend(anyhow!(e)))?.map(|v| { + let (version_bytes, _) = v.split_at(std::mem::size_of::()); + u8::from_be_bytes(version_bytes.try_into().unwrap_or_default()) + }); + + let old_version = match db_version { + None => { + // we are fresh, let's write the current version + self.inner + .insert(VERSION_KEY, DATABASE_VERSION.to_be_bytes().as_ref()) + .map_err(|e| StoreError::Backend(anyhow!(e)))?; + self.inner.flush().map_err(|e| StoreError::Backend(anyhow!(e)))?; + return Ok(()); + } + Some(version) if version == DATABASE_VERSION => { + // current, we don't have to do anything + return Ok(()); + } + Some(version) => version, + }; + + tracing::debug!( + old_version, + new_version = DATABASE_VERSION, + "Upgrading the Sled state store" + ); + + // FUTURE UPGRADE CODE GOES HERE + + // can't upgrade from that version to the new one + Err(StoreError::UnsupportedDatabaseVersion( + old_version.into(), + DATABASE_VERSION.into(), + )) + } + /// Open a `CryptoStore` that uses the same database as this store. /// /// The given passphrase will be used to encrypt private data. From ab08ce6ff126b5895b1d7f20cf03635498cd4fbc Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Wed, 4 May 2022 16:54:03 +0200 Subject: [PATCH 2/2] style(sled): cargo fmt --- crates/matrix-sdk-sled/src/state_store.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/crates/matrix-sdk-sled/src/state_store.rs b/crates/matrix-sdk-sled/src/state_store.rs index 371a557f2..6bd6a4a8a 100644 --- a/crates/matrix-sdk-sled/src/state_store.rs +++ b/crates/matrix-sdk-sled/src/state_store.rs @@ -328,10 +328,7 @@ impl SledStore { // FUTURE UPGRADE CODE GOES HERE // can't upgrade from that version to the new one - Err(StoreError::UnsupportedDatabaseVersion( - old_version.into(), - DATABASE_VERSION.into(), - )) + Err(StoreError::UnsupportedDatabaseVersion(old_version.into(), DATABASE_VERSION.into())) } /// Open a `CryptoStore` that uses the same database as this store.