Detect and handle corrupt database views.

pull/1/head
Matthew Chen 7 years ago
parent 66459af997
commit d3b484482c

@ -14,6 +14,8 @@ NS_ASSUME_NONNULL_BEGIN
@interface OWSBatchMessageProcessor : NSObject
+ (instancetype)sharedInstance;
+ (NSString *)databaseExtensionName;
+ (void)asyncRegisterDatabaseExtension:(OWSStorage *)storage;
- (void)enqueueEnvelopeData:(NSData *)envelopeData

@ -464,6 +464,11 @@ NSString *const OWSMessageContentJobFinderExtensionGroup = @"OWSMessageContentJo
#pragma mark - class methods
+ (NSString *)databaseExtensionName
{
return OWSMessageContentJobFinderExtensionName;
}
+ (void)asyncRegisterDatabaseExtension:(OWSStorage *)storage
{
[OWSMessageContentJobFinder asyncRegisterDatabaseExtension:storage];

@ -25,9 +25,8 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (nullable NSNumber *)nextExpirationTimestampWithTransaction:(YapDatabaseReadTransaction *_Nonnull)transaction;
/**
* Database extensions required for class to work.
*/
+ (NSString *)databaseExtensionName;
+ (void)asyncRegisterDatabaseExtensions:(OWSStorage *)storage;
#ifdef DEBUG

@ -196,6 +196,11 @@ static NSString *const OWSDisappearingMessageFinderExpiresAtIndex = @"index_mess
}
#endif
+ (NSString *)databaseExtensionName
{
return OWSDisappearingMessageFinderExpiresAtIndex;
}
+ (void)asyncRegisterDatabaseExtensions:(OWSStorage *)storage
{
[storage asyncRegisterExtension:[self indexDatabaseExtension] withName:OWSDisappearingMessageFinderExpiresAtIndex];

@ -14,9 +14,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)run;
/**
* Database extensions required for class to work.
*/
+ (NSString *)databaseExtensionName;
+ (void)asyncRegisterDatabaseExtensionsWithPrimaryStorage:(OWSStorage *)storage;
#ifdef DEBUG

@ -126,6 +126,11 @@ static NSString *const OWSFailedAttachmentDownloadsJobAttachmentStateIndex = @"i
}
#endif
+ (NSString *)databaseExtensionName
{
return OWSFailedAttachmentDownloadsJobAttachmentStateIndex;
}
+ (void)asyncRegisterDatabaseExtensionsWithPrimaryStorage:(OWSStorage *)storage
{
[storage asyncRegisterExtension:[self indexDatabaseExtension]

@ -14,9 +14,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)run;
/**
* Database extensions required for class to work.
*/
+ (NSString *)databaseExtensionName;
+ (void)asyncRegisterDatabaseExtensionsWithPrimaryStorage:(OWSStorage *)storage;
#ifdef DEBUG

@ -136,6 +136,11 @@ static NSString *const OWSFailedMessagesJobMessageStateIndex = @"index_outoing_m
}
#endif
+ (NSString *)databaseExtensionName
{
return OWSFailedMessagesJobMessageStateIndex;
}
+ (void)asyncRegisterDatabaseExtensionsWithPrimaryStorage:(OWSStorage *)storage
{
[storage asyncRegisterExtension:[self indexDatabaseExtension] withName:OWSFailedMessagesJobMessageStateIndex];

@ -14,6 +14,8 @@ NS_ASSUME_NONNULL_BEGIN
@interface OWSMessageReceiver : NSObject
+ (instancetype)sharedInstance;
+ (NSString *)databaseExtensionName;
+ (void)asyncRegisterDatabaseExtension:(OWSStorage *)storage;
- (void)handleReceivedEnvelope:(OWSSignalServiceProtosEnvelope *)envelope;

@ -424,6 +424,11 @@ NSString *const OWSMessageDecryptJobFinderExtensionGroup = @"OWSMessageProcessin
#pragma mark - class methods
+ (NSString *)databaseExtensionName
{
return OWSMessageDecryptJobFinderExtensionName;
}
+ (void)asyncRegisterDatabaseExtension:(OWSStorage *)storage
{
[OWSMessageDecryptJobFinder asyncRegisterDatabaseExtension:storage];

@ -12,9 +12,7 @@ NS_ASSUME_NONNULL_BEGIN
- (instancetype)initWithPrimaryStorage:(OWSPrimaryStorage *)primaryStorage NS_DESIGNATED_INITIALIZER;
/**
* Must be called before using this finder.
*/
+ (NSString *)databaseExtensionName;
+ (void)asyncRegisterExtensionWithPrimaryStorage:(OWSStorage *)storage;
/**

@ -92,6 +92,11 @@ NSString *const OWSIncomingMessageFinderColumnSourceDeviceId = @"OWSIncomingMess
return [[YapDatabaseSecondaryIndex alloc] initWithSetup:setup handler:handler];
}
+ (NSString *)databaseExtensionName
{
return OWSIncomingMessageFinderExtensionName;
}
+ (void)asyncRegisterExtensionWithPrimaryStorage:(OWSStorage *)storage
{
DDLogInfo(@"%@ registering async.", self.logTag);

@ -28,6 +28,7 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark - Extension registration
+ (NSString *)databaseExtensionName;
+ (void)asyncRegisterDatabaseExtensionsWithPrimaryStorage:(OWSStorage *)storage;
@end

@ -111,6 +111,11 @@ static NSString *const OWSMediaGalleryFinderExtensionName = @"OWSMediaGalleryFin
#pragma mark - Extension registration
+ (NSString *)databaseExtensionName
{
return OWSMediaGalleryFinderExtensionName;
}
+ (void)asyncRegisterDatabaseExtensionsWithPrimaryStorage:(OWSStorage *)storage
{
[storage asyncRegisterExtension:[self mediaGalleryDatabaseExtension]

@ -22,7 +22,7 @@ NS_ASSUME_NONNULL_BEGIN
NSString *const OWSPrimaryStorageExceptionName_CouldNotCreateDatabaseDirectory
= @"TSStorageManagerExceptionName_CouldNotCreateDatabaseDirectory";
void runSyncRegistrationsForStorage(OWSStorage *storage)
void RunSyncRegistrationsForStorage(OWSStorage *storage)
{
OWSCAssert(storage);
@ -30,7 +30,7 @@ void runSyncRegistrationsForStorage(OWSStorage *storage)
[TSDatabaseView registerCrossProcessNotifier:storage];
}
void runAsyncRegistrationsForStorage(OWSStorage *storage, dispatch_block_t completion)
void RunAsyncRegistrationsForStorage(OWSStorage *storage, dispatch_block_t completion)
{
OWSCAssert(storage);
OWSCAssert(completion);
@ -63,6 +63,84 @@ void runAsyncRegistrationsForStorage(OWSStorage *storage, dispatch_block_t compl
[TSDatabaseView asyncRegisterLazyRestoreAttachmentsDatabaseView:storage completion:completion];
}
extern NSString *const TSThreadOutgoingMessageDatabaseViewExtensionName;
extern NSString *const TSUnseenDatabaseViewExtensionName;
extern NSString *const TSThreadSpecialMessagesDatabaseViewExtensionName;
void VerifyRegistrationsForStorage(OWSStorage *storage)
{
OWSCAssert(storage);
// This should 1:1 correspond to the database view registrations
// done in RunSyncRegistrationsForStorage() and
// RunAsyncRegistrationsForStorage().
NSArray<NSString *> *databaseViewNames = @[
// We don't need to verify the cross process notifier.
// [TSDatabaseView registerCrossProcessNotifier:storage];
// [TSDatabaseView asyncRegisterThreadInteractionsDatabaseView:storage];
TSMessageDatabaseViewExtensionName,
// [TSDatabaseView asyncRegisterThreadDatabaseView:storage];
TSThreadDatabaseViewExtensionName,
// [TSDatabaseView asyncRegisterUnreadDatabaseView:storage];
TSUnreadDatabaseViewExtensionName,
// [storage asyncRegisterExtension:[TSDatabaseSecondaryIndexes registerTimeStampIndex] withName:@"idx"];
@"idx",
// [OWSMessageReceiver asyncRegisterDatabaseExtension:storage];
[OWSMessageReceiver databaseExtensionName],
// [OWSBatchMessageProcessor asyncRegisterDatabaseExtension:storage];
[OWSBatchMessageProcessor databaseExtensionName],
// [TSDatabaseView asyncRegisterUnseenDatabaseView:storage];
TSUnseenDatabaseViewExtensionName,
// [TSDatabaseView asyncRegisterThreadOutgoingMessagesDatabaseView:storage];
TSThreadOutgoingMessageDatabaseViewExtensionName,
// [TSDatabaseView asyncRegisterThreadSpecialMessagesDatabaseView:storage];
TSThreadSpecialMessagesDatabaseViewExtensionName,
// [OWSIncomingMessageFinder asyncRegisterExtensionWithPrimaryStorage:storage];
[OWSIncomingMessageFinder databaseExtensionName],
// [TSDatabaseView asyncRegisterSecondaryDevicesDatabaseView:storage];
TSSecondaryDevicesDatabaseViewExtensionName,
// [OWSDisappearingMessagesFinder asyncRegisterDatabaseExtensions:storage];
[OWSDisappearingMessagesFinder databaseExtensionName],
// [OWSFailedMessagesJob asyncRegisterDatabaseExtensionsWithPrimaryStorage:storage];
[OWSFailedMessagesJob databaseExtensionName],
// [OWSFailedAttachmentDownloadsJob asyncRegisterDatabaseExtensionsWithPrimaryStorage:storage];
[OWSFailedAttachmentDownloadsJob databaseExtensionName],
// [OWSMediaGalleryFinder asyncRegisterDatabaseExtensionsWithPrimaryStorage:storage];
[OWSMediaGalleryFinder databaseExtensionName],
// NOTE: Always pass the completion to the _LAST_ of the async database
// view registrations.
// [TSDatabaseView asyncRegisterLazyRestoreAttachmentsDatabaseView:storage completion:completion];
TSLazyRestoreAttachmentsDatabaseViewExtensionName,
];
__block BOOL hasMissingDatabaseView = NO;
[[storage newDatabaseConnection] asyncReadWithBlock:^(YapDatabaseReadTransaction *transaction) {
for (NSString *databaseViewName in databaseViewNames) {
YapDatabaseViewTransaction *_Nullable viewTransaction = [transaction ext:databaseViewName];
if (!viewTransaction) {
OWSProdLogAndCFail(@"VerifyRegistrationsForStorage missing database view: %@", databaseViewName);
hasMissingDatabaseView = YES;
}
}
}];
}
#pragma mark -
@interface OWSPrimaryStorage ()
@ -119,7 +197,7 @@ void runAsyncRegistrationsForStorage(OWSStorage *storage, dispatch_block_t compl
- (void)runSyncRegistrations
{
runSyncRegistrationsForStorage(self);
RunSyncRegistrationsForStorage(self);
// See comments on OWSDatabaseConnection.
//
@ -137,7 +215,7 @@ void runAsyncRegistrationsForStorage(OWSStorage *storage, dispatch_block_t compl
DDLogVerbose(@"%@ async registrations enqueuing.", self.logTag);
runAsyncRegistrationsForStorage(self, ^{
RunAsyncRegistrationsForStorage(self, ^{
OWSAssertIsOnMainThread();
OWSAssert(!self.areAsyncRegistrationsComplete);
@ -147,9 +225,16 @@ void runAsyncRegistrationsForStorage(OWSStorage *storage, dispatch_block_t compl
self.areAsyncRegistrationsComplete = YES;
completion();
[self verifyDatabaseViews];
});
}
- (void)verifyDatabaseViews
{
VerifyRegistrationsForStorage(self);
}
+ (void)protectFiles
{
DDLogInfo(

@ -128,6 +128,13 @@ NS_ASSUME_NONNULL_BEGIN
OWSFail(_messageFormat, ##__VA_ARGS__); \
}
#define OWSProdLogAndCFail(_messageFormat, ...) \
{ \
DDLogError(_messageFormat, ##__VA_ARGS__); \
[DDLog flushLog]; \
OWSCFail(_messageFormat, ##__VA_ARGS__); \
}
// This function is intended for use in Swift.
void SwiftAssertIsOnMainThread(NSString *functionName);

Loading…
Cancel
Save