Detect and handle corrupt database views.

pull/1/head
Matthew Chen 7 years ago
parent d3b484482c
commit 50a59c907d

@ -120,6 +120,11 @@ NS_ASSUME_NONNULL_BEGIN
}]]; }]];
#endif #endif
[items addObject:[OWSTableItem itemWithTitle:@"Increment database extension version suffix"
actionBlock:^() {
[OWSStorage incrementDatabaseExtensionVersionSuffix];
}]];
return [OWSTableSection sectionWithTitle:self.name items:items]; return [OWSTableSection sectionWithTitle:self.name items:items];
} }

@ -203,7 +203,11 @@ NSString *const OWSMessageContentJobFinderExtensionGroup = @"OWSMessageContentJo
options.allowedCollections = options.allowedCollections =
[[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:[OWSMessageContentJob collection]]]; [[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:[OWSMessageContentJob collection]]];
return [[YapDatabaseAutoView alloc] initWithGrouping:grouping sorting:sorting versionTag:@"1" options:options]; return [[YapDatabaseAutoView alloc]
initWithGrouping:grouping
sorting:sorting
versionTag:[OWSStorage appendSuffixToDatabaseExtensionVersionIfNecessary:@"1"]
options:options];
} }

@ -185,7 +185,10 @@ static NSString *const OWSDisappearingMessageFinderExpiresAtIndex = @"index_mess
dict[OWSDisappearingMessageFinderThreadIdColumn] = message.uniqueThreadId; dict[OWSDisappearingMessageFinderThreadIdColumn] = message.uniqueThreadId;
}]; }];
return [[YapDatabaseSecondaryIndex alloc] initWithSetup:setup handler:handler]; return [[YapDatabaseSecondaryIndex alloc]
initWithSetup:setup
handler:handler
versionTag:[OWSStorage appendSuffixToDatabaseExtensionVersionIfNecessary:@"1"]];
} }
#ifdef DEBUG #ifdef DEBUG

@ -114,7 +114,10 @@ static NSString *const OWSFailedAttachmentDownloadsJobAttachmentStateIndex = @"i
dict[OWSFailedAttachmentDownloadsJobAttachmentStateColumn] = @(attachment.state); dict[OWSFailedAttachmentDownloadsJobAttachmentStateColumn] = @(attachment.state);
}]; }];
return [[YapDatabaseSecondaryIndex alloc] initWithSetup:setup handler:handler]; return [[YapDatabaseSecondaryIndex alloc]
initWithSetup:setup
handler:handler
versionTag:[OWSStorage appendSuffixToDatabaseExtensionVersionIfNecessary:@"1"]];
} }
#ifdef DEBUG #ifdef DEBUG

@ -124,7 +124,10 @@ static NSString *const OWSFailedMessagesJobMessageStateIndex = @"index_outoing_m
dict[OWSFailedMessagesJobMessageStateColumn] = @(message.messageState); dict[OWSFailedMessagesJobMessageStateColumn] = @(message.messageState);
}]; }];
return [[YapDatabaseSecondaryIndex alloc] initWithSetup:setup handler:handler]; return [[YapDatabaseSecondaryIndex alloc]
initWithSetup:setup
handler:handler
versionTag:[OWSStorage appendSuffixToDatabaseExtensionVersionIfNecessary:@"1"]];
} }
#ifdef DEBUG #ifdef DEBUG

@ -183,7 +183,11 @@ NSString *const OWSMessageDecryptJobFinderExtensionGroup = @"OWSMessageProcessin
options.allowedCollections = options.allowedCollections =
[[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:[OWSMessageDecryptJob collection]]]; [[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:[OWSMessageDecryptJob collection]]];
return [[YapDatabaseAutoView alloc] initWithGrouping:grouping sorting:sorting versionTag:@"1" options:options]; return [[YapDatabaseAutoView alloc]
initWithGrouping:grouping
sorting:sorting
versionTag:[OWSStorage appendSuffixToDatabaseExtensionVersionIfNecessary:@"1"]
options:options];
} }
+ (void)registerLegacyClasses + (void)registerLegacyClasses

@ -89,7 +89,10 @@ NSString *const OWSIncomingMessageFinderColumnSourceDeviceId = @"OWSIncomingMess
YapDatabaseSecondaryIndexHandler *handler = [YapDatabaseSecondaryIndexHandler withObjectBlock:block]; YapDatabaseSecondaryIndexHandler *handler = [YapDatabaseSecondaryIndexHandler withObjectBlock:block];
return [[YapDatabaseSecondaryIndex alloc] initWithSetup:setup handler:handler]; return [[YapDatabaseSecondaryIndex alloc]
initWithSetup:setup
handler:handler
versionTag:[OWSStorage appendSuffixToDatabaseExtensionVersionIfNecessary:@"1"]];
} }
+ (NSString *)databaseExtensionName + (NSString *)databaseExtensionName

@ -163,8 +163,12 @@ static NSString *const OWSMediaGalleryFinderExtensionName = @"OWSMediaGalleryFin
YapDatabaseViewOptions *options = [YapDatabaseViewOptions new]; YapDatabaseViewOptions *options = [YapDatabaseViewOptions new];
options.allowedCollections = [[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:TSMessage.collection]]; options.allowedCollections = [[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:TSMessage.collection]];
return [[YapDatabaseAutoView alloc] initWithGrouping:grouping sorting:sorting versionTag:@"1" options:options]; return [[YapDatabaseAutoView alloc]
initWithGrouping:grouping
sorting:sorting
versionTag:[OWSStorage appendSuffixToDatabaseExtensionVersionIfNecessary:@"1"]
options:options];
} }
+ (BOOL)attachmentIdShouldAppearInMediaGallery:(NSString *)attachmentId transaction:(YapDatabaseReadTransaction *)transaction + (BOOL)attachmentIdShouldAppearInMediaGallery:(NSString *)attachmentId transaction:(YapDatabaseReadTransaction *)transaction

@ -139,6 +139,9 @@ void VerifyRegistrationsForStorage(OWSStorage *storage)
} }
} }
}]; }];
if (hasMissingDatabaseView) {
[OWSStorage incrementDatabaseExtensionVersionSuffix];
}
} }
#pragma mark - #pragma mark -

@ -64,9 +64,12 @@ typedef void (^OWSStorageMigrationBlock)(void);
- (YapDatabaseConnection *)newDatabaseConnection; - (YapDatabaseConnection *)newDatabaseConnection;
#ifdef DEBUG #pragma mark - Extension Registration
+ (void)incrementDatabaseExtensionVersionSuffix;
+ (NSString *)appendSuffixToDatabaseExtensionVersionIfNecessary:(NSString *)versionTag;
- (BOOL)registerExtension:(YapDatabaseExtension *)extension withName:(NSString *)extensionName; - (BOOL)registerExtension:(YapDatabaseExtension *)extension withName:(NSString *)extensionName;
#endif
- (void)asyncRegisterExtension:(YapDatabaseExtension *)extension withName:(NSString *)extensionName; - (void)asyncRegisterExtension:(YapDatabaseExtension *)extension withName:(NSString *)extensionName;
- (void)asyncRegisterExtension:(YapDatabaseExtension *)extension - (void)asyncRegisterExtension:(YapDatabaseExtension *)extension
@ -75,6 +78,8 @@ typedef void (^OWSStorageMigrationBlock)(void);
- (nullable id)registeredExtension:(NSString *)extensionName; - (nullable id)registeredExtension:(NSString *)extensionName;
#pragma mark -
- (unsigned long long)databaseFileSize; - (unsigned long long)databaseFileSize;
- (unsigned long long)databaseWALFileSize; - (unsigned long long)databaseWALFileSize;
- (unsigned long long)databaseSHMFileSize; - (unsigned long long)databaseSHMFileSize;

@ -6,6 +6,7 @@
#import "AppContext.h" #import "AppContext.h"
#import "NSData+Base64.h" #import "NSData+Base64.h"
#import "NSNotificationCenter+OWS.h" #import "NSNotificationCenter+OWS.h"
#import "NSUserDefaults+OWS.h"
#import "OWSBackgroundTask.h" #import "OWSBackgroundTask.h"
#import "OWSFileSystem.h" #import "OWSFileSystem.h"
#import "OWSPrimaryStorage.h" #import "OWSPrimaryStorage.h"
@ -15,6 +16,8 @@
#import <SAMKeychain/SAMKeychain.h> #import <SAMKeychain/SAMKeychain.h>
#import <YapDatabase/YapDatabase.h> #import <YapDatabase/YapDatabase.h>
#import <YapDatabase/YapDatabaseCryptoUtils.h> #import <YapDatabase/YapDatabaseCryptoUtils.h>
#import <YapDatabase/YapDatabaseSecondaryIndex.h>
#import <YapDatabase/YapDatabaseView.h>
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
@ -36,6 +39,8 @@ const NSUInteger kDatabasePasswordLength = 30;
typedef NSData *_Nullable (^LoadDatabaseMetadataBlock)(NSError **_Nullable); typedef NSData *_Nullable (^LoadDatabaseMetadataBlock)(NSError **_Nullable);
typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void); typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void);
NSString *const kNSUserDefaults_DatabaseExtensionVersionSuffix = @"kNSUserDefaults_DatabaseExtensionVersionSuffix";
#pragma mark - #pragma mark -
@interface YapDatabaseConnection () @interface YapDatabaseConnection ()
@ -461,6 +466,43 @@ typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void);
return dbConnection; return dbConnection;
} }
#pragma mark - Extension Registration
+ (void)incrementDatabaseExtensionVersionSuffix
{
DDLogError(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
NSUserDefaults *appUserDefaults = [NSUserDefaults appUserDefaults];
OWSAssert(appUserDefaults);
NSNumber *_Nullable suffix = [appUserDefaults valueForKey:kNSUserDefaults_DatabaseExtensionVersionSuffix];
[appUserDefaults setValue:@(suffix.intValue + 1) forKey:kNSUserDefaults_DatabaseExtensionVersionSuffix];
[appUserDefaults synchronize];
}
+ (nullable NSString *)databaseExtensionVersionSuffix
{
NSUserDefaults *appUserDefaults = [NSUserDefaults appUserDefaults];
OWSAssert(appUserDefaults);
NSNumber *_Nullable suffix = [appUserDefaults valueForKey:kNSUserDefaults_DatabaseExtensionVersionSuffix];
if (!suffix) {
return nil;
}
return [NSString stringWithFormat:@".%@", suffix];
}
+ (NSString *)appendSuffixToDatabaseExtensionVersionIfNecessary:(NSString *)versionTag
{
OWSAssertIsOnMainThread();
NSString *_Nullable suffix = [self databaseExtensionVersionSuffix];
if (suffix) {
NSString *result = [versionTag stringByAppendingString:suffix];
DDLogWarn(@"%@ database extension version: %@ + %@ -> %@", self.logTag, versionTag, suffix, result);
return result;
}
return versionTag;
}
- (BOOL)registerExtension:(YapDatabaseExtension *)extension withName:(NSString *)extensionName - (BOOL)registerExtension:(YapDatabaseExtension *)extension withName:(NSString *)extensionName
{ {
return [self.database registerExtension:extension withName:extensionName]; return [self.database registerExtension:extension withName:extensionName];
@ -476,6 +518,24 @@ typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void);
withName:(NSString *)extensionName withName:(NSString *)extensionName
completion:(nullable dispatch_block_t)completion completion:(nullable dispatch_block_t)completion
{ {
if ([extension isKindOfClass:[YapDatabaseView class]]) {
YapDatabaseView *databaseView = (YapDatabaseView *)extension;
NSString *_Nullable databaseExtensionVersionSuffix = [OWSStorage databaseExtensionVersionSuffix];
if (databaseExtensionVersionSuffix) {
OWSAssert([databaseView.versionTag hasSuffix:databaseExtensionVersionSuffix]);
}
} else if ([extension isKindOfClass:[YapDatabaseSecondaryIndex class]]) {
YapDatabaseSecondaryIndex *secondaryIndex = (YapDatabaseSecondaryIndex *)extension;
NSString *_Nullable databaseExtensionVersionSuffix = [OWSStorage databaseExtensionVersionSuffix];
if (databaseExtensionVersionSuffix) {
OWSAssert([secondaryIndex.versionTag hasSuffix:databaseExtensionVersionSuffix]);
}
} else {
OWSProdLogAndFail(@"%@ Unknown extension type: %@", self.logTag, [extension class]);
}
[self.database asyncRegisterExtension:extension [self.database asyncRegisterExtension:extension
withName:extensionName withName:extensionName
completionBlock:^(BOOL ready) { completionBlock:^(BOOL ready) {

@ -3,6 +3,7 @@
// //
#import "TSDatabaseSecondaryIndexes.h" #import "TSDatabaseSecondaryIndexes.h"
#import "OWSStorage.h"
#import "TSInteraction.h" #import "TSInteraction.h"
#define TSTimeStampSQLiteIndex @"messagesTimeStamp" #define TSTimeStampSQLiteIndex @"messagesTimeStamp"
@ -25,7 +26,10 @@
YapDatabaseSecondaryIndexHandler *handler = [YapDatabaseSecondaryIndexHandler withObjectBlock:block]; YapDatabaseSecondaryIndexHandler *handler = [YapDatabaseSecondaryIndexHandler withObjectBlock:block];
YapDatabaseSecondaryIndex *secondaryIndex = [[YapDatabaseSecondaryIndex alloc] initWithSetup:setup handler:handler]; YapDatabaseSecondaryIndex *secondaryIndex = [[YapDatabaseSecondaryIndex alloc]
initWithSetup:setup
handler:handler
versionTag:[OWSStorage appendSuffixToDatabaseExtensionVersionIfNecessary:@"1"]];
return secondaryIndex; return secondaryIndex;
} }

@ -78,10 +78,11 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup"
options.allowedCollections = options.allowedCollections =
[[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:[TSInteraction collection]]]; [[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:[TSInteraction collection]]];
YapDatabaseView *view = [[YapDatabaseAutoView alloc] initWithGrouping:viewGrouping YapDatabaseView *view = [[YapDatabaseAutoView alloc]
sorting:viewSorting initWithGrouping:viewGrouping
versionTag:version sorting:viewSorting
options:options]; versionTag:[OWSStorage appendSuffixToDatabaseExtensionVersionIfNecessary:version]
options:options];
[storage asyncRegisterExtension:view withName:viewName]; [storage asyncRegisterExtension:view withName:viewName];
} }
@ -227,8 +228,11 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup"
options.allowedCollections = options.allowedCollections =
[[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:[TSThread collection]]]; [[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:[TSThread collection]]];
YapDatabaseView *databaseView = YapDatabaseView *databaseView = [[YapDatabaseAutoView alloc]
[[YapDatabaseAutoView alloc] initWithGrouping:viewGrouping sorting:viewSorting versionTag:@"3" options:options]; initWithGrouping:viewGrouping
sorting:viewSorting
versionTag:[OWSStorage appendSuffixToDatabaseExtensionVersionIfNecessary:@"3"]
options:options];
[storage asyncRegisterExtension:databaseView withName:TSThreadDatabaseViewExtensionName]; [storage asyncRegisterExtension:databaseView withName:TSThreadDatabaseViewExtensionName];
} }
@ -336,8 +340,11 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup"
NSSet *deviceCollection = [NSSet setWithObject:[OWSDevice collection]]; NSSet *deviceCollection = [NSSet setWithObject:[OWSDevice collection]];
options.allowedCollections = [[YapWhitelistBlacklist alloc] initWithWhitelist:deviceCollection]; options.allowedCollections = [[YapWhitelistBlacklist alloc] initWithWhitelist:deviceCollection];
YapDatabaseView *view = YapDatabaseView *view = [[YapDatabaseAutoView alloc]
[[YapDatabaseAutoView alloc] initWithGrouping:viewGrouping sorting:viewSorting versionTag:@"3" options:options]; initWithGrouping:viewGrouping
sorting:viewSorting
versionTag:[OWSStorage appendSuffixToDatabaseExtensionVersionIfNecessary:@"3"]
options:options];
[storage asyncRegisterExtension:view withName:TSSecondaryDevicesDatabaseViewExtensionName]; [storage asyncRegisterExtension:view withName:TSSecondaryDevicesDatabaseViewExtensionName];
} }
@ -390,8 +397,11 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup"
options.isPersistent = YES; options.isPersistent = YES;
options.allowedCollections = options.allowedCollections =
[[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:[TSAttachment collection]]]; [[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:[TSAttachment collection]]];
YapDatabaseView *view = YapDatabaseView *view = [[YapDatabaseAutoView alloc]
[[YapDatabaseAutoView alloc] initWithGrouping:viewGrouping sorting:viewSorting versionTag:@"3" options:options]; initWithGrouping:viewGrouping
sorting:viewSorting
versionTag:[OWSStorage appendSuffixToDatabaseExtensionVersionIfNecessary:@"3"]
options:options];
[storage asyncRegisterExtension:view [storage asyncRegisterExtension:view
withName:TSLazyRestoreAttachmentsDatabaseViewExtensionName withName:TSLazyRestoreAttachmentsDatabaseViewExtensionName
completion:completion]; completion:completion];

Loading…
Cancel
Save