Fix database issues around device transfer.

This commit is contained in:
Matthew Chen 2020-07-03 13:25:47 -03:00
parent d8edbce0a3
commit a261fcda06
5 changed files with 54 additions and 13 deletions

View File

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

View File

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

View File

@ -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()

View File

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

View File

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