diff --git a/SignalServiceKit/src/Storage/Database/GRDBDatabaseStorageAdapter.swift b/SignalServiceKit/src/Storage/Database/GRDBDatabaseStorageAdapter.swift index c7abbf8a2a..e19c0c2cef 100644 --- a/SignalServiceKit/src/Storage/Database/GRDBDatabaseStorageAdapter.swift +++ b/SignalServiceKit/src/Storage/Database/GRDBDatabaseStorageAdapter.swift @@ -124,6 +124,12 @@ public class GRDBDatabaseStorageAdapter: NSObject { } } + // NOTE: This should only be used in exceptional circumstances, + // e.g. after reloading the database due to a device transfer. + func forceUpdateSnapshot() { + uiDatabaseObserver?.forceUpdateSnapshot() + } + func testing_tearDownUIDatabase() { // UIDatabaseObserver is a general purpose observer, whose delegates // are notified when things change, but are not given any specific details diff --git a/SignalServiceKit/src/Storage/Database/GRDBSchemaMigrator.swift b/SignalServiceKit/src/Storage/Database/GRDBSchemaMigrator.swift index 1a9c0f8141..36e89dfa62 100644 --- a/SignalServiceKit/src/Storage/Database/GRDBSchemaMigrator.swift +++ b/SignalServiceKit/src/Storage/Database/GRDBSchemaMigrator.swift @@ -15,10 +15,13 @@ public class GRDBSchemaMigrator: NSObject { @objc public func runSchemaMigrations() { if hasCreatedInitialSchema { + Logger.info("Using incrementalMigrator.") try! incrementalMigrator.migrate(grdbStorage.pool) } else { + Logger.info("Using newUserMigrator.") try! newUserMigrator.migrate(grdbStorage.pool) } + Logger.info("Migrations complete.") SSKPreferences.markGRDBSchemaAsLatest() } @@ -32,6 +35,7 @@ public class GRDBSchemaMigrator: NSObject { } let appliedMigrations = try! incrementalMigrator.appliedMigrations(in: grdbStorage.pool) + Logger.info("appliedMigrations: \(appliedMigrations).") return appliedMigrations.contains(MigrationId.createInitialSchema.rawValue) } @@ -132,20 +136,31 @@ public class GRDBSchemaMigrator: NSObject { return migrator }() + class DatabaseMigratorWrapper { + var migrator = DatabaseMigrator() + + func registerMigration(_ identifier: String, migrate: @escaping (Database) throws -> Void) { + migrator.registerMigration(identifier) { (database: Database) throws in + Logger.info("Running migration: \(identifier)") + try migrate(database) + } + } + } + // Used by existing users to incrementally update from their existing schema // to the latest. private lazy var incrementalMigrator: DatabaseMigrator = { - var migrator = DatabaseMigrator() + var migratorWrapper = DatabaseMigratorWrapper() - registerSchemaMigrations(migrator: &migrator) + registerSchemaMigrations(migrator: migratorWrapper) // Data Migrations must run *after* schema migrations - registerDataMigrations(migrator: &migrator) + registerDataMigrations(migrator: migratorWrapper) - return migrator + return migratorWrapper.migrator }() - private func registerSchemaMigrations(migrator: inout DatabaseMigrator) { + private func registerSchemaMigrations(migrator: DatabaseMigratorWrapper) { // The migration blocks should never throw. If we introduce a crashing // migration, we want the crash logs reflect where it occurred. @@ -703,7 +718,7 @@ public class GRDBSchemaMigrator: NSObject { // MARK: - Schema Migration Insertion Point } - func registerDataMigrations(migrator: inout DatabaseMigrator) { + func registerDataMigrations(migrator: DatabaseMigratorWrapper) { // The migration blocks should never throw. If we introduce a crashing // migration, we want the crash logs reflect where it occurred. diff --git a/SignalServiceKit/src/Storage/Database/SDSDatabaseStorage.swift b/SignalServiceKit/src/Storage/Database/SDSDatabaseStorage.swift index f73d7858e4..12f23d339e 100644 --- a/SignalServiceKit/src/Storage/Database/SDSDatabaseStorage.swift +++ b/SignalServiceKit/src/Storage/Database/SDSDatabaseStorage.swift @@ -132,11 +132,15 @@ public class SDSDatabaseStorage: SDSTransactable { AssertIsOnMainThread() assert(storageCoordinatorState == .GRDB) + Logger.info("") + let wasRegistered = TSAccountManager.sharedInstance().isRegistered - _grdbStorage = createGrdbStorage() + let grdbStorage = createGrdbStorage() + _grdbStorage = grdbStorage GRDBSchemaMigrator().runSchemaMigrations() + grdbStorage.forceUpdateSnapshot() SSKEnvironment.shared.warmCaches() OWSIdentityManager.shared().recreateDatabaseQueue() diff --git a/SignalServiceKit/src/Storage/Database/Snapshots/ObservedDatabaseChanges.swift b/SignalServiceKit/src/Storage/Database/Snapshots/ObservedDatabaseChanges.swift index 1a7d204178..53b224dbf1 100644 --- a/SignalServiceKit/src/Storage/Database/Snapshots/ObservedDatabaseChanges.swift +++ b/SignalServiceKit/src/Storage/Database/Snapshots/ObservedDatabaseChanges.swift @@ -595,6 +595,9 @@ extension ObservedDatabaseChanges: UIDatabaseChanges { owsFailDebug("should not have been notified for changes to FTS tables") continue } + guard tableName != "grdb_migrations" else { + continue + } guard let collection = tableNameToCollectionMap[tableName] else { owsFailDebug("Unknown table: \(tableName)") continue diff --git a/SignalServiceKit/src/Storage/Database/Snapshots/UIDatabaseSnapshot.swift b/SignalServiceKit/src/Storage/Database/Snapshots/UIDatabaseSnapshot.swift index 68eb271657..55277a5ccb 100644 --- a/SignalServiceKit/src/Storage/Database/Snapshots/UIDatabaseSnapshot.swift +++ b/SignalServiceKit/src/Storage/Database/Snapshots/UIDatabaseSnapshot.swift @@ -361,7 +361,6 @@ extension UIDatabaseObserver: TransactionObserver { } // Update the snapshot now. - lastSnapshotUpdateDate = Date() updateSnapshot() } @@ -413,10 +412,22 @@ extension UIDatabaseObserver: TransactionObserver { return targetUpdateFrequencySeconds } - // See comment on databaseDidChange. - private func updateSnapshot() { + // NOTE: This should only be used in exceptional circumstances, + // e.g. after reloading the database due to a device transfer. + func forceUpdateSnapshot() { AssertIsOnMainThread() + Logger.info("") + + updateSnapshot(canCheckpoint: false) + } + + // See comment on databaseDidChange. + private func updateSnapshot(canCheckpoint: Bool = true) { + AssertIsOnMainThread() + + lastSnapshotUpdateDate = Date() + Logger.verbose("databaseSnapshotWillUpdate") for delegate in snapshotDelegates { delegate.uiDatabaseSnapshotWillUpdate() @@ -424,7 +435,7 @@ extension UIDatabaseObserver: TransactionObserver { latestSnapshot.read { db in do { - try self.fastForwardDatabaseSnapshot(db: db) + try self.fastForwardDatabaseSnapshot(db: db, canCheckpoint: canCheckpoint) } catch { owsFailDebug("\(error)") } @@ -469,14 +480,16 @@ extension UIDatabaseObserver: TransactionObserver { // Currently GRDB offers no built in way to fast-forward a // database snapshot. // See: https://github.com/groue/GRDB.swift/issues/619 - func fastForwardDatabaseSnapshot(db: Database) throws { + func fastForwardDatabaseSnapshot(db: Database, canCheckpoint: Bool = true) throws { AssertIsOnMainThread() // [1] end the old transaction from the old db state try db.commit() // [2] Checkpoint the WAL - checkpointIfNecessary() + if canCheckpoint { + checkpointIfNecessary() + } // [3] open a new transaction from the current db state try db.beginTransaction(.deferred)