mirror of
https://forgejo.ellis.link/continuwuation/continuwuity.git
synced 2026-11-15 13:16:56 +00:00
refactor: Clean up migration logic
This commit is contained in:
1 parent
1220144495
commit
23d07e3d4f
1 file changed
+186
-249
+186
-249
@@ -2,6 +2,7 @@ use std::{
|
|||||||
cmp,
|
cmp,
|
||||||
collections::{BTreeMap, HashMap},
|
collections::{BTreeMap, HashMap},
|
||||||
future::ready,
|
future::ready,
|
||||||
|
pin::Pin,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
time::Instant,
|
time::Instant,
|
||||||
};
|
};
|
||||||
@@ -17,7 +18,7 @@ use conduwuit::{
|
|||||||
},
|
},
|
||||||
warn,
|
warn,
|
||||||
};
|
};
|
||||||
use database::{Database, Json};
|
use database::Json;
|
||||||
use futures::{FutureExt, StreamExt, TryStreamExt};
|
use futures::{FutureExt, StreamExt, TryStreamExt};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use ruma::{
|
use ruma::{
|
||||||
@@ -34,13 +35,159 @@ use serde_json::value::to_raw_value;
|
|||||||
|
|
||||||
use crate::{Services, media, rooms, rooms::short::ShortStateHash};
|
use crate::{Services, media, rooms, rooms::short::ShortStateHash};
|
||||||
|
|
||||||
/// The current schema version.
|
type MigrationFn =
|
||||||
/// - If database is opened at greater version we reject with error. The
|
for<'a> fn(&'a Services) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'a>>;
|
||||||
/// software must be updated for backward-incompatible changes.
|
|
||||||
/// - If database is opened at lesser version we apply migrations up to this.
|
enum DatabaseMigrationStep {
|
||||||
/// Note that named-feature migrations may also be performed when opening at
|
Migration(&'static str, MigrationFn),
|
||||||
/// equal or lesser version. These are expected to be backward-compatible.
|
VersionBump(u64),
|
||||||
pub(crate) const DATABASE_VERSION: u64 = 19;
|
}
|
||||||
|
|
||||||
|
static MIGRATIONS: &[DatabaseMigrationStep] = const {
|
||||||
|
use DatabaseMigrationStep::*;
|
||||||
|
|
||||||
|
macro_rules! migration {
|
||||||
|
($name:expr => $function:path) => {
|
||||||
|
Migration($name, |services| {
|
||||||
|
Box::pin(async {
|
||||||
|
let db = &services.db;
|
||||||
|
#[allow(clippy::string_lit_as_bytes)]
|
||||||
|
let key = $name.as_bytes();
|
||||||
|
|
||||||
|
if db["global"].get(key).await.is_not_found() {
|
||||||
|
info!("Starting migration {}", $name);
|
||||||
|
let cork = db.cork_and_sync();
|
||||||
|
|
||||||
|
$function(services)
|
||||||
|
.await
|
||||||
|
.map_err(|err| err!("Failed to run migration {}: {err}", $name))?;
|
||||||
|
|
||||||
|
drop(cork);
|
||||||
|
db["global"].insert(key, []);
|
||||||
|
db.db.sort()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
($name:ident) => {
|
||||||
|
// cargo fmt really wants this to be left-aligned, I guess?
|
||||||
|
migration!(stringify!($name) => $name)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// When you're writing a migration that makes backwards-incompatible
|
||||||
|
// changes, you need to use `VersionBump` to keep old versions from
|
||||||
|
// accepting the new database. The `VersionBump` command should come
|
||||||
|
// _before_ your migration, which ensures that old versions will reject
|
||||||
|
// the new database even if the server crashes or restarts while your
|
||||||
|
// migration is running.
|
||||||
|
|
||||||
|
// If your migration is backwards-compatible, meaning that its changes can
|
||||||
|
// be understood by a version of continuwuity that has not run it, it
|
||||||
|
// doesn't need a version bump. Use your best discretion when deciding what
|
||||||
|
// "be understood" means. Also, make sure to add a comment that explains
|
||||||
|
// why the bump was necessary, for the sake of future developers.
|
||||||
|
|
||||||
|
// Database versions should increase monotonically (you'll get a const-eval
|
||||||
|
// panic if they don't) and linearly. I don't know why conduit skipped
|
||||||
|
// from 13 to 17, don't bother asking.
|
||||||
|
|
||||||
|
&[
|
||||||
|
// Begin pre-fork logic. We don't have insight into why this works
|
||||||
|
// the way it does, so there are no comments here.
|
||||||
|
VersionBump(12),
|
||||||
|
migration!(fix_push_rule_names),
|
||||||
|
VersionBump(13),
|
||||||
|
migration!(fix_server_default_push_rules),
|
||||||
|
VersionBump(17),
|
||||||
|
migration!("feat_sha256_media" => media::migrations::migrate_sha256_media),
|
||||||
|
migration!(fix_bad_double_separator_in_state_cache),
|
||||||
|
migration!(retroactively_fix_bad_data_from_roomuserid_joined),
|
||||||
|
migration!(fix_referencedevents_missing_sep),
|
||||||
|
migration!(fix_readreceiptid_readreceipt_duplicates),
|
||||||
|
// End pre-fork logic.
|
||||||
|
|
||||||
|
// v18: `fix_corrupt_msc4133_fields` will change the `us.cloke.msc4175.tz` field
|
||||||
|
// in a way that old versions don't understand.
|
||||||
|
VersionBump(18),
|
||||||
|
migration!(fix_corrupt_msc4133_fields),
|
||||||
|
// v19: `populate_userroomid_leftstate_table` will put data in the values of
|
||||||
|
// `userroomid_leftstate` that old versions will fail to deserialize because
|
||||||
|
// they expect the values to be empty.
|
||||||
|
VersionBump(19),
|
||||||
|
migration!(populate_userroomid_leftstate_table),
|
||||||
|
// This is backwards compatible because it fixes some data that clients care about but we
|
||||||
|
// don't.
|
||||||
|
migration!(fix_local_invite_state),
|
||||||
|
// v20: Old versions expect remote users to be tracked in `userid_password`. This
|
||||||
|
// migration moves them to a different keyspace.
|
||||||
|
VersionBump(20),
|
||||||
|
migration!(split_userid_password),
|
||||||
|
// This is backwards compatible because old versions will recreate the keyspace if it's
|
||||||
|
// missing.
|
||||||
|
migration!("drop_roomsynctoken_shortstatehash" => obliterate_roomsynctoken_shortstatehash_with_extreme_prejudice),
|
||||||
|
// v21: `unembed_unsigned_info` will remove `unsigned` data from PDUs that old versions
|
||||||
|
// expect to be embedded.
|
||||||
|
VersionBump(21),
|
||||||
|
// This migration can take several hours on old databases, so we run it in the background
|
||||||
|
// to keep the service manager from killing us for taking too long to start.
|
||||||
|
// Future maintainers: !!! BE VERY CAREFUL !!! if you need to write more migrations like
|
||||||
|
// this! This one is fine because it deletes data that we don't check anymore,
|
||||||
|
// but migrations which replace existing data that we do check should NOT run in
|
||||||
|
// the background. If they do, the server will finish starting up and might
|
||||||
|
// access data that the migration hasn't gotten to yet.
|
||||||
|
Migration("unembed_unsigned_info", |services| {
|
||||||
|
Box::pin(async {
|
||||||
|
if services.db["global"]
|
||||||
|
.get(b"unembed_unsigned_info")
|
||||||
|
.await
|
||||||
|
.is_not_found()
|
||||||
|
{
|
||||||
|
let db = services.db.clone();
|
||||||
|
let metadata = services.rooms.metadata.clone();
|
||||||
|
let timeline = services.rooms.timeline.clone();
|
||||||
|
|
||||||
|
services.server.runtime().spawn(async move {
|
||||||
|
unembed_unsigned_info(metadata, timeline).await.expect(
|
||||||
|
"unembed_unsigned_info failed! your database is broken, sorry >.>",
|
||||||
|
);
|
||||||
|
db["global"].insert(b"unembed_unsigned_info", []);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
// This is backwards compatible because old versions will recreate the keyspace if it's
|
||||||
|
// missing.
|
||||||
|
migration!(drop_server_signingkeys),
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
pub(crate) const DATABASE_VERSION: u64 = const {
|
||||||
|
let mut latest_version = 0_u64;
|
||||||
|
// TODO: refactor once slice iter is const stable
|
||||||
|
let mut i = 0;
|
||||||
|
|
||||||
|
while i < MIGRATIONS.len() {
|
||||||
|
if let DatabaseMigrationStep::VersionBump(version) = &MIGRATIONS[i] {
|
||||||
|
if *version > latest_version {
|
||||||
|
latest_version = *version;
|
||||||
|
} else {
|
||||||
|
panic!("Database version must monotonically increase");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
latest_version
|
||||||
|
};
|
||||||
|
|
||||||
|
// This should match the first `VersionBump` in `MIGRATIONS`.
|
||||||
|
const OLDEST_SUPPORTED_VERSION: u64 = 11;
|
||||||
|
|
||||||
pub(crate) async fn migrations(services: &Services) -> Result<()> {
|
pub(crate) async fn migrations(services: &Services) -> Result<()> {
|
||||||
let users_count = services.users.count().await;
|
let users_count = services.users.count().await;
|
||||||
@@ -71,18 +218,11 @@ async fn fresh(services: &Services) -> Result<()> {
|
|||||||
|
|
||||||
services.globals.db.bump_database_version(DATABASE_VERSION);
|
services.globals.db.bump_database_version(DATABASE_VERSION);
|
||||||
|
|
||||||
db["global"].insert(b"feat_sha256_media", []);
|
for step in MIGRATIONS {
|
||||||
db["global"].insert(b"fix_bad_double_separator_in_state_cache", []);
|
if let DatabaseMigrationStep::Migration(key, _) = step {
|
||||||
db["global"].insert(b"retroactively_fix_bad_data_from_roomuserid_joined", []);
|
db["global"].insert(key, []);
|
||||||
db["global"].insert(b"fix_referencedevents_missing_sep", []);
|
}
|
||||||
db["global"].insert(b"fix_readreceiptid_readreceipt_duplicates", []);
|
}
|
||||||
db["global"].insert(b"fix_corrupt_msc4133_fields", []);
|
|
||||||
db["global"].insert(b"populate_userroomid_leftstate_table", []);
|
|
||||||
db["global"].insert(b"fix_local_invite_state", []);
|
|
||||||
db["global"].insert(SPLIT_USERID_PASSWORD, []);
|
|
||||||
db["global"].insert(DROP_ROOMSYNCTOKEN_SHORTSTATEHASH, []);
|
|
||||||
db["global"].insert(UNEMBED_UNSIGNED_INFO, []);
|
|
||||||
db["global"].insert(DROP_OLD_SIGNING_KEYS_STORAGE, []);
|
|
||||||
|
|
||||||
// Create the admin room and server user on first run
|
// Create the admin room and server user on first run
|
||||||
info!("Creating admin room and server user");
|
info!("Creating admin room and server user");
|
||||||
@@ -98,35 +238,27 @@ async fn fresh(services: &Services) -> Result<()> {
|
|||||||
|
|
||||||
/// Apply any migrations
|
/// Apply any migrations
|
||||||
async fn migrate(services: &Services) -> Result<()> {
|
async fn migrate(services: &Services) -> Result<()> {
|
||||||
let db = &services.db;
|
if services.globals.db.database_version().await < OLDEST_SUPPORTED_VERSION {
|
||||||
let config = &services.server.config;
|
|
||||||
|
|
||||||
if services.globals.db.database_version().await < 11 {
|
|
||||||
return Err!(Database(
|
return Err!(Database(
|
||||||
"Database schema version {} is no longer supported",
|
"Database schema version {} is too old to migrate. Please use an old version of \
|
||||||
|
conduwuit to migrate to version 11 and then run Continuwuity again.",
|
||||||
services.globals.db.database_version().await
|
services.globals.db.database_version().await
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if services.globals.db.database_version().await < 12 {
|
for step in MIGRATIONS {
|
||||||
db_lt_12(services)
|
match step {
|
||||||
.await
|
| DatabaseMigrationStep::Migration(_, migration) => {
|
||||||
.map_err(|e| err!("Failed to run v12 migrations: {e}"))?;
|
migration(services).await?;
|
||||||
|
},
|
||||||
|
| DatabaseMigrationStep::VersionBump(version) => {
|
||||||
|
services.globals.db.bump_database_version(*version);
|
||||||
|
info!("Bumped database version to {version}.");
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This migration can be reused as-is anytime the server-default rules are
|
if services.config.media_startup_check {
|
||||||
// updated.
|
|
||||||
if services.globals.db.database_version().await < 13 {
|
|
||||||
db_lt_13(services)
|
|
||||||
.await
|
|
||||||
.map_err(|e| err!("Failed to run v13 migrations: {e}"))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if db["global"].get(b"feat_sha256_media").await.is_not_found() {
|
|
||||||
media::migrations::migrate_sha256_media(services)
|
|
||||||
.await
|
|
||||||
.map_err(|e| err!("Failed to run SHA256 media migration: {e}"))?;
|
|
||||||
} else if config.media_startup_check {
|
|
||||||
info!("Starting media startup integrity check.");
|
info!("Starting media startup integrity check.");
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
media::migrations::checkup_sha256_media(services)
|
media::migrations::checkup_sha256_media(services)
|
||||||
@@ -138,154 +270,6 @@ async fn migrate(services: &Services) -> Result<()> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if db["global"]
|
|
||||||
.get(b"fix_bad_double_separator_in_state_cache")
|
|
||||||
.await
|
|
||||||
.is_not_found()
|
|
||||||
{
|
|
||||||
info!("Running migration 'fix_bad_double_separator_in_state_cache'");
|
|
||||||
fix_bad_double_separator_in_state_cache(services)
|
|
||||||
.await
|
|
||||||
.map_err(|e| {
|
|
||||||
err!("Failed to run 'fix_bad_double_separator_in_state_cache' migration: {e}")
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if db["global"]
|
|
||||||
.get(b"retroactively_fix_bad_data_from_roomuserid_joined")
|
|
||||||
.await
|
|
||||||
.is_not_found()
|
|
||||||
{
|
|
||||||
info!("Running migration 'retroactively_fix_bad_data_from_roomuserid_joined'");
|
|
||||||
retroactively_fix_bad_data_from_roomuserid_joined(services)
|
|
||||||
.await
|
|
||||||
.map_err(|e| {
|
|
||||||
err!(
|
|
||||||
"Failed to run 'retroactively_fix_bad_data_from_roomuserid_joined' \
|
|
||||||
migration: {e}"
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if db["global"]
|
|
||||||
.get(b"fix_referencedevents_missing_sep")
|
|
||||||
.await
|
|
||||||
.is_not_found()
|
|
||||||
|| services.globals.db.database_version().await < 17
|
|
||||||
{
|
|
||||||
info!("Running migration 'fix_referencedevents_missing_sep'");
|
|
||||||
fix_referencedevents_missing_sep(services)
|
|
||||||
.await
|
|
||||||
.map_err(|e| {
|
|
||||||
err!("Failed to run 'fix_referencedevents_missing_sep' migration': {e}")
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if db["global"]
|
|
||||||
.get(b"fix_readreceiptid_readreceipt_duplicates")
|
|
||||||
.await
|
|
||||||
.is_not_found()
|
|
||||||
|| services.globals.db.database_version().await < 17
|
|
||||||
{
|
|
||||||
info!("Running migration 'fix_readreceiptid_readreceipt_duplicates'");
|
|
||||||
fix_readreceiptid_readreceipt_duplicates(services)
|
|
||||||
.await
|
|
||||||
.map_err(|e| {
|
|
||||||
err!("Failed to run 'fix_readreceiptid_readreceipt_duplicates' migration': {e}")
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if services.globals.db.database_version().await < 17 {
|
|
||||||
services.globals.db.bump_database_version(17);
|
|
||||||
info!("Migration: Bumped database version to 17");
|
|
||||||
}
|
|
||||||
|
|
||||||
if db["global"]
|
|
||||||
.get(FIXED_CORRUPT_MSC4133_FIELDS_MARKER)
|
|
||||||
.await
|
|
||||||
.is_not_found()
|
|
||||||
{
|
|
||||||
info!("Running migration 'fix_corrupt_msc4133_fields'");
|
|
||||||
fix_corrupt_msc4133_fields(services)
|
|
||||||
.await
|
|
||||||
.map_err(|e| err!("Failed to run 'fix_corrupt_msc4133_fields' migration': {e}"))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if services.globals.db.database_version().await < 18 {
|
|
||||||
services.globals.db.bump_database_version(18);
|
|
||||||
info!("Migration: Bumped database version to 18");
|
|
||||||
}
|
|
||||||
|
|
||||||
if db["global"]
|
|
||||||
.get(POPULATED_USERROOMID_LEFTSTATE_TABLE_MARKER)
|
|
||||||
.await
|
|
||||||
.is_not_found()
|
|
||||||
{
|
|
||||||
info!("Running migration 'populate_userroomid_leftstate_table'");
|
|
||||||
populate_userroomid_leftstate_table(services)
|
|
||||||
.await
|
|
||||||
.map_err(|e| {
|
|
||||||
err!("Failed to run 'populate_userroomid_leftstate_table' migration': {e}")
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if db["global"]
|
|
||||||
.get(FIXED_LOCAL_INVITE_STATE_MARKER)
|
|
||||||
.await
|
|
||||||
.is_not_found()
|
|
||||||
{
|
|
||||||
info!("Running migration 'fix_local_invite_state'");
|
|
||||||
fix_local_invite_state(services)
|
|
||||||
.await
|
|
||||||
.map_err(|e| err!("Failed to run 'fix_local_invite_state' migration': {e}"))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if services.globals.db.database_version().await < 19 {
|
|
||||||
services.globals.db.bump_database_version(19);
|
|
||||||
info!("Migration: Bumped database version to 19");
|
|
||||||
}
|
|
||||||
|
|
||||||
if db["global"].get(SPLIT_USERID_PASSWORD).await.is_not_found() {
|
|
||||||
info!("Running migration 'split_userid_password'");
|
|
||||||
split_userid_password(services)
|
|
||||||
.await
|
|
||||||
.map_err(|e| err!("Failed to run 'split_userid_password' migration': {e}"))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if db["global"]
|
|
||||||
.get(DROP_ROOMSYNCTOKEN_SHORTSTATEHASH)
|
|
||||||
.await
|
|
||||||
.is_not_found()
|
|
||||||
{
|
|
||||||
info!("Running migration 'drop_roomsynctoken_shortstatehash'");
|
|
||||||
obliterate_roomsynctoken_shortstatehash_with_extreme_prejudice(services)
|
|
||||||
.await
|
|
||||||
.map_err(|e| {
|
|
||||||
err!("Failed to run 'drop_roomsynctoken_shortstatehash' migration': {e}")
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if db["global"].get(UNEMBED_UNSIGNED_INFO).await.is_not_found() {
|
|
||||||
services.server.runtime().spawn(unembed_unsigned_info(
|
|
||||||
services.db.clone(),
|
|
||||||
services.rooms.metadata.clone(),
|
|
||||||
services.rooms.timeline.clone(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
if db["global"]
|
|
||||||
.get(DROP_OLD_SIGNING_KEYS_STORAGE)
|
|
||||||
.await
|
|
||||||
.is_not_found()
|
|
||||||
{
|
|
||||||
services
|
|
||||||
.db
|
|
||||||
.db
|
|
||||||
.drop_column("server_signingkeys")
|
|
||||||
.inspect(|()| services.db["global"].insert(DROP_OLD_SIGNING_KEYS_STORAGE, []))
|
|
||||||
.map_err(|e| err!("Failed to drop server_signingkeys: {e:?}"))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
services.globals.db.database_version().await,
|
services.globals.db.database_version().await,
|
||||||
DATABASE_VERSION,
|
DATABASE_VERSION,
|
||||||
@@ -358,7 +342,7 @@ async fn migrate(services: &Services) -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn db_lt_12(services: &Services) -> Result<()> {
|
async fn fix_push_rule_names(services: &Services) -> Result<()> {
|
||||||
for username in &services
|
for username in &services
|
||||||
.users
|
.users
|
||||||
.stream_local_users()
|
.stream_local_users()
|
||||||
@@ -433,12 +417,10 @@ async fn db_lt_12(services: &Services) -> Result<()> {
|
|||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
services.globals.db.bump_database_version(12);
|
|
||||||
info!("Migration: 11 -> 12 finished");
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn db_lt_13(services: &Services) -> Result<()> {
|
async fn fix_server_default_push_rules(services: &Services) -> Result<()> {
|
||||||
for username in &services
|
for username in &services
|
||||||
.users
|
.users
|
||||||
.stream_local_users()
|
.stream_local_users()
|
||||||
@@ -478,8 +460,6 @@ async fn db_lt_13(services: &Services) -> Result<()> {
|
|||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
services.globals.db.bump_database_version(13);
|
|
||||||
info!("Migration: 12 -> 13 finished");
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -488,7 +468,6 @@ async fn fix_bad_double_separator_in_state_cache(services: &Services) -> Result<
|
|||||||
|
|
||||||
let db = &services.db;
|
let db = &services.db;
|
||||||
let roomuserid_joined = &db["roomuserid_joined"];
|
let roomuserid_joined = &db["roomuserid_joined"];
|
||||||
let _cork = db.cork_and_sync();
|
|
||||||
|
|
||||||
let mut iter_count: usize = 0;
|
let mut iter_count: usize = 0;
|
||||||
roomuserid_joined
|
roomuserid_joined
|
||||||
@@ -520,9 +499,6 @@ async fn fix_bad_double_separator_in_state_cache(services: &Services) -> Result<
|
|||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
db.db.sort()?;
|
|
||||||
db["global"].insert(b"fix_bad_double_separator_in_state_cache", []);
|
|
||||||
|
|
||||||
info!("Finished fixing");
|
info!("Finished fixing");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -530,9 +506,6 @@ async fn fix_bad_double_separator_in_state_cache(services: &Services) -> Result<
|
|||||||
async fn retroactively_fix_bad_data_from_roomuserid_joined(services: &Services) -> Result<()> {
|
async fn retroactively_fix_bad_data_from_roomuserid_joined(services: &Services) -> Result<()> {
|
||||||
info!("Retroactively fixing bad data from broken roomuserid_joined");
|
info!("Retroactively fixing bad data from broken roomuserid_joined");
|
||||||
|
|
||||||
let db = &services.db;
|
|
||||||
let _cork = db.cork_and_sync();
|
|
||||||
|
|
||||||
let room_ids = services.rooms.metadata.iter_ids().collect::<Vec<_>>().await;
|
let room_ids = services.rooms.metadata.iter_ids().collect::<Vec<_>>().await;
|
||||||
|
|
||||||
for room_id in &room_ids {
|
for room_id in &room_ids {
|
||||||
@@ -603,9 +576,6 @@ async fn retroactively_fix_bad_data_from_roomuserid_joined(services: &Services)
|
|||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
db.db.sort()?;
|
|
||||||
db["global"].insert(b"retroactively_fix_bad_data_from_roomuserid_joined", []);
|
|
||||||
|
|
||||||
info!("Finished fixing");
|
info!("Finished fixing");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -613,10 +583,7 @@ async fn retroactively_fix_bad_data_from_roomuserid_joined(services: &Services)
|
|||||||
async fn fix_referencedevents_missing_sep(services: &Services) -> Result {
|
async fn fix_referencedevents_missing_sep(services: &Services) -> Result {
|
||||||
info!("Fixing missing record separator between room_id and event_id in referencedevents");
|
info!("Fixing missing record separator between room_id and event_id in referencedevents");
|
||||||
|
|
||||||
let db = &services.db;
|
let referencedevents = services.db["referencedevents"].clone();
|
||||||
let cork = db.cork_and_sync();
|
|
||||||
|
|
||||||
let referencedevents = db["referencedevents"].clone();
|
|
||||||
|
|
||||||
let totals: (usize, usize) = (0, 0);
|
let totals: (usize, usize) = (0, 0);
|
||||||
let (total, fixed) = referencedevents
|
let (total, fixed) = referencedevents
|
||||||
@@ -645,11 +612,8 @@ async fn fix_referencedevents_missing_sep(services: &Services) -> Result {
|
|||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
drop(cork);
|
|
||||||
info!(?total, ?fixed, "Fixed missing record separators in 'referencedevents'.");
|
info!(?total, ?fixed, "Fixed missing record separators in 'referencedevents'.");
|
||||||
|
Ok(())
|
||||||
db["global"].insert(b"fix_referencedevents_missing_sep", []);
|
|
||||||
db.db.sort()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn fix_readreceiptid_readreceipt_duplicates(services: &Services) -> Result {
|
async fn fix_readreceiptid_readreceipt_duplicates(services: &Services) -> Result {
|
||||||
@@ -659,7 +623,6 @@ async fn fix_readreceiptid_readreceipt_duplicates(services: &Services) -> Result
|
|||||||
info!("Fixing undeleted entries in readreceiptid_readreceipt...");
|
info!("Fixing undeleted entries in readreceiptid_readreceipt...");
|
||||||
|
|
||||||
let db = &services.db;
|
let db = &services.db;
|
||||||
let cork = db.cork_and_sync();
|
|
||||||
let readreceiptid_readreceipt = db["readreceiptid_readreceipt"].clone();
|
let readreceiptid_readreceipt = db["readreceiptid_readreceipt"].clone();
|
||||||
|
|
||||||
let mut cur_room: Option<ArrayId> = None;
|
let mut cur_room: Option<ArrayId> = None;
|
||||||
@@ -684,14 +647,10 @@ async fn fix_readreceiptid_readreceipt_duplicates(services: &Services) -> Result
|
|||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
drop(cork);
|
|
||||||
info!(?total, ?fixed, "Fixed undeleted entries in readreceiptid_readreceipt.");
|
info!(?total, ?fixed, "Fixed undeleted entries in readreceiptid_readreceipt.");
|
||||||
|
Ok(())
|
||||||
db["global"].insert(b"fix_readreceiptid_readreceipt_duplicates", []);
|
|
||||||
db.db.sort()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const FIXED_CORRUPT_MSC4133_FIELDS_MARKER: &[u8] = b"fix_corrupt_msc4133_fields";
|
|
||||||
async fn fix_corrupt_msc4133_fields(services: &Services) -> Result {
|
async fn fix_corrupt_msc4133_fields(services: &Services) -> Result {
|
||||||
// Due to an old bug, some conduwuit databases have `us.cloke.msc4175.tz`
|
// Due to an old bug, some conduwuit databases have `us.cloke.msc4175.tz`
|
||||||
// user profile fields with raw strings instead of quoted JSON ones.
|
// user profile fields with raw strings instead of quoted JSON ones.
|
||||||
@@ -703,7 +662,6 @@ async fn fix_corrupt_msc4133_fields(services: &Services) -> Result {
|
|||||||
info!("Fixing corrupted `us.cloke.msc4175.tz` fields...");
|
info!("Fixing corrupted `us.cloke.msc4175.tz` fields...");
|
||||||
|
|
||||||
let db = &services.db;
|
let db = &services.db;
|
||||||
let cork = db.cork_and_sync();
|
|
||||||
let useridprofilekey_value = db["useridprofilekey_value"].clone();
|
let useridprofilekey_value = db["useridprofilekey_value"].clone();
|
||||||
|
|
||||||
let (total, fixed) = useridprofilekey_value
|
let (total, fixed) = useridprofilekey_value
|
||||||
@@ -742,21 +700,15 @@ async fn fix_corrupt_msc4133_fields(services: &Services) -> Result {
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
drop(cork);
|
|
||||||
info!(?total, ?fixed, "Fixed corrupted `us.cloke.msc4175.tz` fields.");
|
info!(?total, ?fixed, "Fixed corrupted `us.cloke.msc4175.tz` fields.");
|
||||||
|
|
||||||
db["global"].insert(FIXED_CORRUPT_MSC4133_FIELDS_MARKER, []);
|
|
||||||
db.db.sort()?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
const POPULATED_USERROOMID_LEFTSTATE_TABLE_MARKER: &str = "populate_userroomid_leftstate_table";
|
|
||||||
async fn populate_userroomid_leftstate_table(services: &Services) -> Result {
|
async fn populate_userroomid_leftstate_table(services: &Services) -> Result {
|
||||||
type KeyVal = (Key, Raw<Option<Pdu>>);
|
type KeyVal = (Key, Raw<Option<Pdu>>);
|
||||||
type Key = (OwnedUserId, OwnedRoomId);
|
type Key = (OwnedUserId, OwnedRoomId);
|
||||||
|
|
||||||
let db = &services.db;
|
let db = &services.db;
|
||||||
let cork = db.cork_and_sync();
|
|
||||||
let userroomid_leftstate = db["userroomid_leftstate"].clone();
|
let userroomid_leftstate = db["userroomid_leftstate"].clone();
|
||||||
|
|
||||||
let (total, fixed, _) = userroomid_leftstate
|
let (total, fixed, _) = userroomid_leftstate
|
||||||
@@ -817,15 +769,10 @@ async fn populate_userroomid_leftstate_table(services: &Services) -> Result {
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
drop(cork);
|
|
||||||
info!(?total, ?fixed, "Fixed entries in `userroomid_leftstate`.");
|
info!(?total, ?fixed, "Fixed entries in `userroomid_leftstate`.");
|
||||||
|
|
||||||
db["global"].insert(POPULATED_USERROOMID_LEFTSTATE_TABLE_MARKER, []);
|
|
||||||
db.db.sort()?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
const FIXED_LOCAL_INVITE_STATE_MARKER: &str = "fix_local_invite_state";
|
|
||||||
async fn fix_local_invite_state(services: &Services) -> Result {
|
async fn fix_local_invite_state(services: &Services) -> Result {
|
||||||
// Clean up the effects of !1249 by caching stripped state for invites
|
// Clean up the effects of !1249 by caching stripped state for invites
|
||||||
|
|
||||||
@@ -833,7 +780,6 @@ async fn fix_local_invite_state(services: &Services) -> Result {
|
|||||||
type Key = (OwnedUserId, OwnedRoomId);
|
type Key = (OwnedUserId, OwnedRoomId);
|
||||||
|
|
||||||
let db = &services.db;
|
let db = &services.db;
|
||||||
let cork = db.cork_and_sync();
|
|
||||||
let userroomid_invitestate = db["userroomid_invitestate"].clone();
|
let userroomid_invitestate = db["userroomid_invitestate"].clone();
|
||||||
|
|
||||||
// for each user invited to a room
|
// for each user invited to a room
|
||||||
@@ -871,20 +817,14 @@ async fn fix_local_invite_state(services: &Services) -> Result {
|
|||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
drop(cork);
|
|
||||||
info!(?fixed, "Fixed local invite state cache entries.");
|
info!(?fixed, "Fixed local invite state cache entries.");
|
||||||
|
|
||||||
db["global"].insert(FIXED_LOCAL_INVITE_STATE_MARKER, []);
|
|
||||||
db.db.sort()?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
const SPLIT_USERID_PASSWORD: &str = "split_userid_password";
|
|
||||||
async fn split_userid_password(services: &Services) -> Result {
|
async fn split_userid_password(services: &Services) -> Result {
|
||||||
// Split remote and deactivated users out from the `userid_password` table
|
// Split remote and deactivated users out from the `userid_password` table
|
||||||
|
|
||||||
let db = &services.db;
|
let db = &services.db;
|
||||||
let cork = db.cork_and_sync();
|
|
||||||
let userid_password = db["userid_password"].clone();
|
let userid_password = db["userid_password"].clone();
|
||||||
let remoteuserid_remoteuser = db["remoteuserid_remoteuser"].clone();
|
let remoteuserid_remoteuser = db["remoteuserid_remoteuser"].clone();
|
||||||
let userid_deactivated = db["userid_deactivated"].clone();
|
let userid_deactivated = db["userid_deactivated"].clone();
|
||||||
@@ -912,15 +852,11 @@ async fn split_userid_password(services: &Services) -> Result {
|
|||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
drop(cork);
|
|
||||||
info!(?remote_users, "Split userid_password.");
|
info!(?remote_users, "Split userid_password.");
|
||||||
|
|
||||||
db["global"].insert(SPLIT_USERID_PASSWORD, []);
|
|
||||||
db.db.sort()?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
const DROP_ROOMSYNCTOKEN_SHORTSTATEHASH: &str = "drop_roomsynctoken_shortstatehash";
|
|
||||||
async fn obliterate_roomsynctoken_shortstatehash_with_extreme_prejudice(
|
async fn obliterate_roomsynctoken_shortstatehash_with_extreme_prejudice(
|
||||||
services: &Services,
|
services: &Services,
|
||||||
) -> Result {
|
) -> Result {
|
||||||
@@ -928,15 +864,11 @@ async fn obliterate_roomsynctoken_shortstatehash_with_extreme_prejudice(
|
|||||||
|
|
||||||
info!("Cleared roomsynctoken_shortstatehash.");
|
info!("Cleared roomsynctoken_shortstatehash.");
|
||||||
|
|
||||||
services.db["global"].insert(DROP_ROOMSYNCTOKEN_SHORTSTATEHASH, []);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
const UNEMBED_UNSIGNED_INFO: &str = "unembed_unsigned_info";
|
|
||||||
#[tracing::instrument(name = "unembed_unsigned_info", skip_all)]
|
#[tracing::instrument(name = "unembed_unsigned_info", skip_all)]
|
||||||
async fn unembed_unsigned_info(
|
async fn unembed_unsigned_info(
|
||||||
db: Arc<Database>,
|
|
||||||
metadata: Arc<rooms::metadata::Service>,
|
metadata: Arc<rooms::metadata::Service>,
|
||||||
timeline: Arc<rooms::timeline::Service>,
|
timeline: Arc<rooms::timeline::Service>,
|
||||||
) -> Result {
|
) -> Result {
|
||||||
@@ -996,10 +928,15 @@ async fn unembed_unsigned_info(
|
|||||||
info!(elapsed=?start.elapsed(), "Migrated {migrated} PDUs in {room_id}");
|
info!(elapsed=?start.elapsed(), "Migrated {migrated} PDUs in {room_id}");
|
||||||
}
|
}
|
||||||
|
|
||||||
db["global"].insert(UNEMBED_UNSIGNED_INFO, []);
|
|
||||||
info!(elapsed=?start.elapsed(), total_migrated_pdus=total_migrated, "Finished migration.");
|
info!(elapsed=?start.elapsed(), total_migrated_pdus=total_migrated, "Finished migration.");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
const DROP_OLD_SIGNING_KEYS_STORAGE: &str = "drop_server_signingkeys";
|
async fn drop_server_signingkeys(services: &Services) -> Result<()> {
|
||||||
|
services.db.db.drop_column("server_signingkeys")?;
|
||||||
|
|
||||||
|
info!("Cleared server_signingkeys.");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
Reference in new issue
Block a user