indexeddb: Comments explaining the migration methods and modules

Signed-off-by: Andy Balaam <andy.balaam@matrix.org>
This commit is contained in:
Andy Balaam
2024-02-05 14:57:28 +00:00
parent a1f1992d7e
commit 49630fdd9f
6 changed files with 29 additions and 27 deletions

View File

@@ -34,42 +34,37 @@ pub async fn open_and_upgrade_db(
name: &str,
serializer: &IndexeddbSerializer,
) -> Result<IdbDatabase, IndexeddbCryptoStoreError> {
// This is all a bit of a hack. Some of the version migrations require a data
// migration, which has to be done via async APIs; however, the
// JS `upgrade_needed` mechanism does not allow for async calls.
// Move the DB version up from where it is to the latest version.
//
// Start by finding out what the existing version is, if any.
// Schema changes need to be separate from data migrations, so we often
// have a pattern of:
//
// 1. schema_add - create new object stores, indices etc.
// 2. data_migrate - move data from the old stores to the new ones
// 3. schema_delete - delete any now-unused stores etc.
//
// Migrations like these require the schema version to be bumped twice,
// because of the separate "add" and "delete" stages.
let old_version = db_version(name).await?;
// Perform the schema-only migrations
if old_version < 5 {
v0_to_v5::migrate_schema_up_to_v5(name).await?;
}
// If we have yet to complete the migration to V7, migrate the schema to V6
// (if necessary), and then migrate any remaining data.
if old_version < 6 {
v5_to_v7::migrate_schema_up_to_v6(name).await?;
}
if old_version < 7 {
v5_to_v7::prepare_data_for_v7(name, serializer).await?;
// Now we can safely complete the migration to V7 which will drop the old store.
v5_to_v7::migrate_schema_for_v7(name).await?;
}
// Migrate to v8, keeping the same schema but fixing the keys in
// inbound_group_sessions2
if old_version < 8 {
v7_to_v8::prepare_data_for_v8(name, serializer).await?;
v7_to_v8::migrate_schema_for_v8(name).await?;
}
// Migrate to v10, moving from inbound_group_sessions2 to
// inbound_group_sessions3, which has smaller values by storing JavaScript
// objects instead of serialized arrays, and base64 strings instead of
// arrays of ints. inbound_group_sessions3 also has backed_up_to, which is
// indexed.
if old_version < 9 {
v8_to_v10::upgrade_scheme_to_v9_create_inbound_group_sessions3(name).await?;
}
@@ -79,8 +74,7 @@ pub async fn open_and_upgrade_db(
v8_to_v10::upgrade_scheme_to_v10_delete_inbound_group_sessions2(name).await?;
}
// We know we've upgraded to v10 now, so we can open the DB at that version and
// return it
// Open and return the DB (we know it's at the latest version)
Ok(IdbDatabase::open_u32(name, 10)?.await?)
}

View File

@@ -12,6 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//! Schema-only migrations adding various stores and indices, notably
//! the first version of `inbound_group_sessions`.
use indexed_db_futures::{IdbDatabase, IdbKeyPath};
use web_sys::{DomException, IdbIndexParameters};
@@ -21,6 +24,7 @@ use crate::crypto_store::{
Result,
};
/// Perform schema migrations as needed, up to schema version 5.
pub(crate) async fn migrate_schema_up_to_v5(name: &str) -> Result<(), DomException> {
do_schema_upgrade(name, 5, |db, old_version| {
// An old_version of 1 could either mean actually the first version of the

View File

@@ -34,6 +34,7 @@ use crate::{
IndexeddbCryptoStoreError,
};
/// Perform the schema upgrade v5 to v6, creating `inbound_group_sessions2`.
pub(crate) async fn migrate_schema_up_to_v6(name: &str) -> Result<(), DomException> {
do_schema_upgrade(name, 6, |db, _| {
let object_store = db.create_object_store(old_keys::INBOUND_GROUP_SESSIONS_V2)?;
@@ -51,6 +52,7 @@ pub(crate) async fn migrate_schema_up_to_v6(name: &str) -> Result<(), DomExcepti
.await
}
/// Migrate data from `inbound_group_sessions` into `inbound_group_sessions2`.
pub(crate) async fn prepare_data_for_v7(
name: &str,
serializer: &IndexeddbSerializer,
@@ -118,6 +120,7 @@ async fn do_prepare_data_for_v7(serializer: &IndexeddbSerializer, db: &IdbDataba
Ok(txn.await.into_result()?)
}
/// Perform the schema upgrade v6 to v7, deleting `inbound_group_sessions`.
pub(crate) async fn migrate_schema_for_v7(name: &str) -> Result<(), DomException> {
do_schema_upgrade(name, 7, |db, _| {
db.delete_object_store(old_keys::INBOUND_GROUP_SESSIONS_V1)?;

View File

@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//! Structs and keys used for reading/writing objects in schema v7
/// The objects we store in the inbound_group_sessions2 indexeddb object
/// store (in schemas v7 and v8)
#[derive(Debug, serde::Serialize, serde::Deserialize)]

View File

@@ -29,15 +29,14 @@ use crate::{
IndexeddbCryptoStoreError,
};
/// In the migration v5 to v7, we incorrectly copied the keys in
/// `inbound_group_sessions` verbatim into `inbound_group_sessions2`. What we
/// should have done is re-hash them using the new table name, so we fix them up
/// here.
pub(crate) async fn prepare_data_for_v8(
name: &str,
serializer: &IndexeddbSerializer,
) -> Result<()> {
// In prepare_data_for_v6, we incorrectly copied the keys in
// inbound_group_sessions verbatim into inbound_group_sessions2. What we
// should have done is re-hash them using the new table name, so we fix
// them up here.
info!("IndexeddbCryptoStore upgrade data -> v8 starting");
let db = IdbDatabase::open(name)?.await?;
@@ -119,6 +118,7 @@ pub(crate) async fn prepare_data_for_v8(
Ok(())
}
/// Perform the schema upgrade v7 to v8, Just bumping the schema version.
pub(crate) async fn migrate_schema_for_v8(name: &str) -> Result<(), DomException> {
do_schema_upgrade(name, 8, |_, _| {
// Just bump the version number to 8 to demonstrate that we have run the data

View File

@@ -14,10 +14,6 @@
//! Migration code that moves from inbound_group_sessions2 to
//! inbound_group_sessions3, shrinking the values stored in each record.
//!
//! The migration 8->9 creates the new store inbound_group_sessions3.
//! Then we move the data into the new store.
//! The migration 9->10 deletes the old store inbound_group_sessions2.
use indexed_db_futures::{
idb_object_store::IdbObjectStore, IdbDatabase, IdbIndex, IdbKeyPath, IdbQuerySource,
@@ -46,6 +42,7 @@ fn add_nonunique_index<'a>(
object_store.create_index_with_params(name, &IdbKeyPath::str(key_path), &params)
}
/// Perform the schema upgrade v8 to v9, creating `inbound_group_sessions3`.
pub(crate) async fn upgrade_scheme_to_v9_create_inbound_group_sessions3(
name: &str,
) -> Result<(), DomException> {
@@ -72,6 +69,7 @@ pub(crate) async fn upgrade_scheme_to_v9_create_inbound_group_sessions3(
.await
}
/// Migrate data from `inbound_group_sessions2` into `inbound_group_sessions3`.
pub(crate) async fn migrate_data_before_v10_populate_inbound_group_sessions3(
name: &str,
serializer: &IndexeddbSerializer,
@@ -141,6 +139,7 @@ pub(crate) async fn migrate_data_before_v10_populate_inbound_group_sessions3(
Ok(())
}
/// Perform the schema upgrade v8 to v10, deleting `inbound_group_sessions2`.
pub(crate) async fn upgrade_scheme_to_v10_delete_inbound_group_sessions2(
name: &str,
) -> Result<(), DomException> {