feat(sled): Add state store db schema version support

Merge pull request #640 from matrix-org/gnunicorn/issue585
This commit is contained in:
Benjamin Kampmann
2022-05-05 12:13:30 +02:00
committed by GitHub
2 changed files with 50 additions and 2 deletions

View File

@@ -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.

View File

@@ -111,6 +111,9 @@ impl Into<StoreError> for SledStoreError {
}
}
}
const DATABASE_VERSION: u8 = 1;
const VERSION_KEY: &str = "state-store-version";
const ACCOUNT_DATA: &str = "account-data";
const CUSTOM: &str = "custom";
@@ -216,7 +219,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,
@@ -243,7 +246,10 @@ impl SledStore {
room_timeline,
room_timeline_metadata,
room_event_id_to_position,
})
};
database.upgrade()?;
Ok(database)
}
pub fn open() -> StoreResult<Self> {
@@ -298,6 +304,41 @@ 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>());
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.