From 7c032b2b7da6cff9ec5287165a7d158043960d9c Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Thu, 17 Oct 2019 12:15:42 -0300 Subject: [PATCH 1/2] Add GRDB schema version check to prevent reversion. --- .../Storage/Database/GRDBSchemaMigrator.swift | 6 +++ .../src/Storage/StorageCoordinator.m | 6 ++- .../src/Util/SSKPreferences.swift | 45 +++++++++++++++++++ 3 files changed, 56 insertions(+), 1 deletion(-) diff --git a/SignalServiceKit/src/Storage/Database/GRDBSchemaMigrator.swift b/SignalServiceKit/src/Storage/Database/GRDBSchemaMigrator.swift index fd4b49fe8b..9cc1dc4137 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,6 +46,10 @@ 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 SSKPreferences.grdbSchemaVersionLatest. + // We only need to do this for breaking changes. } // An optimization for new users, we have the first migration import the latest schema 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..5a8abb2e0f 100644 --- a/SignalServiceKit/src/Util/SSKPreferences.swift +++ b/SignalServiceKit/src/Util/SSKPreferences.swift @@ -107,4 +107,49 @@ public class SSKPreferences: NSObject { appUserDefaults.set(value, forKey: didEverUseYdbKey) appUserDefaults.synchronize() } + + // MARK: - + + @objc + public static let grdbSchemaVersionDefault: UInt = 0 + public static let grdbSchemaVersionLatest: UInt = 1 + + 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 + } + Logger.verbose("Schema version: \(value)") + guard value > lastKnownGrdbSchemaVersion else { + owsFailDebug("Reverting to earlier schema version: \(value)") + return + } + 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 + } } From 56bfbb61be50ae9cedf5a28a6985970e83e87783 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Tue, 19 Nov 2019 11:02:14 -0300 Subject: [PATCH 2/2] Respond to CR. --- .../src/Storage/Database/GRDBSchemaMigrator.swift | 5 ++++- SignalServiceKit/src/Util/SSKPreferences.swift | 11 +++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/SignalServiceKit/src/Storage/Database/GRDBSchemaMigrator.swift b/SignalServiceKit/src/Storage/Database/GRDBSchemaMigrator.swift index 9cc1dc4137..1ca83b8300 100644 --- a/SignalServiceKit/src/Storage/Database/GRDBSchemaMigrator.swift +++ b/SignalServiceKit/src/Storage/Database/GRDBSchemaMigrator.swift @@ -48,10 +48,13 @@ public class GRDBSchemaMigrator: NSObject { case jobRecords_add_attachmentId // NOTE: Every time we add a migration id, consider - // incrementing SSKPreferences.grdbSchemaVersionLatest. + // 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/Util/SSKPreferences.swift b/SignalServiceKit/src/Util/SSKPreferences.swift index 5a8abb2e0f..43a94ff11b 100644 --- a/SignalServiceKit/src/Util/SSKPreferences.swift +++ b/SignalServiceKit/src/Util/SSKPreferences.swift @@ -110,9 +110,12 @@ public class SSKPreferences: NSObject { // MARK: - - @objc - public static let grdbSchemaVersionDefault: UInt = 0 - public static let grdbSchemaVersionLatest: UInt = 1 + public class var grdbSchemaVersionDefault: UInt { + return GRDBSchemaMigrator.grdbSchemaVersionDefault + } + public class var grdbSchemaVersionLatest: UInt { + return GRDBSchemaMigrator.grdbSchemaVersionLatest + } private static let grdbSchemaVersionKey = "grdbSchemaVersion" @@ -129,11 +132,11 @@ public class SSKPreferences: NSObject { guard value != lastKnownGrdbSchemaVersion else { return } - Logger.verbose("Schema version: \(value)") 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()