diff --git a/SignalServiceKit/src/Storage/Database/GRDBSchemaMigrator.swift b/SignalServiceKit/src/Storage/Database/GRDBSchemaMigrator.swift index fd4b49fe8b..1ca83b8300 100644 --- a/SignalServiceKit/src/Storage/Database/GRDBSchemaMigrator.swift +++ b/SignalServiceKit/src/Storage/Database/GRDBSchemaMigrator.swift @@ -19,6 +19,8 @@ public class GRDBSchemaMigrator: NSObject { } else { try! newUserMigrator.migrate(grdbStorage.pool) } + + SSKPreferences.markGRDBSchemaAsLatest() } private var hasCreatedInitialSchema: Bool { @@ -44,8 +46,15 @@ public class GRDBSchemaMigrator: NSObject { case signalAccount_add_contactAvatars case signalAccount_add_contactAvatars_indices case jobRecords_add_attachmentId + + // NOTE: Every time we add a migration id, consider + // incrementing grdbSchemaVersionLatest. + // We only need to do this for breaking changes. } + public static let grdbSchemaVersionDefault: UInt = 0 + public static let grdbSchemaVersionLatest: UInt = 1 + // An optimization for new users, we have the first migration import the latest schema // and mark any other migrations as "already run". private lazy var newUserMigrator: DatabaseMigrator = { diff --git a/SignalServiceKit/src/Storage/StorageCoordinator.m b/SignalServiceKit/src/Storage/StorageCoordinator.m index f060405ad2..4d7e9e7f0f 100644 --- a/SignalServiceKit/src/Storage/StorageCoordinator.m +++ b/SignalServiceKit/src/Storage/StorageCoordinator.m @@ -113,10 +113,14 @@ NSString *NSStringForDataStore(DataStore value) // Allow developers to do this, but not QA, internal, // public beta or production. !SSKFeatureFlags.canRevertToYDB) { + OWSFailDebug(@"Reverting to YDB."); return YES; } - // TODO: also return true if unknown GRDB version. + if (SSKPreferences.hasUnknownGRDBSchema) { + OWSFailDebug(@"Unknown GRDB schema."); + return YES; + } return NO; } diff --git a/SignalServiceKit/src/Util/SSKPreferences.swift b/SignalServiceKit/src/Util/SSKPreferences.swift index 2449542fe6..43a94ff11b 100644 --- a/SignalServiceKit/src/Util/SSKPreferences.swift +++ b/SignalServiceKit/src/Util/SSKPreferences.swift @@ -107,4 +107,52 @@ public class SSKPreferences: NSObject { appUserDefaults.set(value, forKey: didEverUseYdbKey) appUserDefaults.synchronize() } + + // MARK: - + + public class var grdbSchemaVersionDefault: UInt { + return GRDBSchemaMigrator.grdbSchemaVersionDefault + } + public class var grdbSchemaVersionLatest: UInt { + return GRDBSchemaMigrator.grdbSchemaVersionLatest + } + + private static let grdbSchemaVersionKey = "grdbSchemaVersion" + + private static func grdbSchemaVersion() -> UInt { + let appUserDefaults = CurrentAppContext().appUserDefaults() + guard let preference = appUserDefaults.object(forKey: grdbSchemaVersionKey) as? NSNumber else { + return grdbSchemaVersionDefault + } + return preference.uintValue + } + + private static func setGrdbSchemaVersion(_ value: UInt) { + let lastKnownGrdbSchemaVersion = grdbSchemaVersion() + guard value != lastKnownGrdbSchemaVersion else { + return + } + guard value > lastKnownGrdbSchemaVersion else { + owsFailDebug("Reverting to earlier schema version: \(value)") + return + } + Logger.info("Updating schema version: \(lastKnownGrdbSchemaVersion) -> \(value)") + let appUserDefaults = CurrentAppContext().appUserDefaults() + appUserDefaults.set(value, forKey: grdbSchemaVersionKey) + appUserDefaults.synchronize() + } + + @objc + public static func markGRDBSchemaAsLatest() { + setGrdbSchemaVersion(grdbSchemaVersionLatest) + } + + @objc + public static func hasUnknownGRDBSchema() -> Bool { + guard grdbSchemaVersion() <= grdbSchemaVersionLatest else { + owsFailDebug("grdbSchemaVersion: \(grdbSchemaVersion()), grdbSchemaVersionLatest: \(grdbSchemaVersionLatest)") + return true + } + return false + } }