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 @interface OWSBatchMessageProcessor : NSObject
+ (instancetype)sharedInstance; + (instancetype)sharedInstance;
+ (NSString *)databaseExtensionName;
+ (void)asyncRegisterDatabaseExtension:(OWSStorage *)storage; + (void)asyncRegisterDatabaseExtension:(OWSStorage *)storage;
- (void)enqueueEnvelopeData:(NSData *)envelopeData - (void)enqueueEnvelopeData:(NSData *)envelopeData

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -22,7 +22,7 @@ NS_ASSUME_NONNULL_BEGIN
NSString *const OWSPrimaryStorageExceptionName_CouldNotCreateDatabaseDirectory NSString *const OWSPrimaryStorageExceptionName_CouldNotCreateDatabaseDirectory
= @"TSStorageManagerExceptionName_CouldNotCreateDatabaseDirectory"; = @"TSStorageManagerExceptionName_CouldNotCreateDatabaseDirectory";
void runSyncRegistrationsForStorage(OWSStorage *storage) void RunSyncRegistrationsForStorage(OWSStorage *storage)
{ {
OWSCAssert(storage); OWSCAssert(storage);
@ -30,7 +30,7 @@ void runSyncRegistrationsForStorage(OWSStorage *storage)
[TSDatabaseView registerCrossProcessNotifier:storage]; [TSDatabaseView registerCrossProcessNotifier:storage];
} }
void runAsyncRegistrationsForStorage(OWSStorage *storage, dispatch_block_t completion) void RunAsyncRegistrationsForStorage(OWSStorage *storage, dispatch_block_t completion)
{ {
OWSCAssert(storage); OWSCAssert(storage);
OWSCAssert(completion); OWSCAssert(completion);
@ -63,6 +63,84 @@ void runAsyncRegistrationsForStorage(OWSStorage *storage, dispatch_block_t compl
[TSDatabaseView asyncRegisterLazyRestoreAttachmentsDatabaseView:storage completion:completion]; [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 - #pragma mark -
@interface OWSPrimaryStorage () @interface OWSPrimaryStorage ()
@ -119,7 +197,7 @@ void runAsyncRegistrationsForStorage(OWSStorage *storage, dispatch_block_t compl
- (void)runSyncRegistrations - (void)runSyncRegistrations
{ {
runSyncRegistrationsForStorage(self); RunSyncRegistrationsForStorage(self);
// See comments on OWSDatabaseConnection. // See comments on OWSDatabaseConnection.
// //
@ -137,7 +215,7 @@ void runAsyncRegistrationsForStorage(OWSStorage *storage, dispatch_block_t compl
DDLogVerbose(@"%@ async registrations enqueuing.", self.logTag); DDLogVerbose(@"%@ async registrations enqueuing.", self.logTag);
runAsyncRegistrationsForStorage(self, ^{ RunAsyncRegistrationsForStorage(self, ^{
OWSAssertIsOnMainThread(); OWSAssertIsOnMainThread();
OWSAssert(!self.areAsyncRegistrationsComplete); OWSAssert(!self.areAsyncRegistrationsComplete);
@ -147,9 +225,16 @@ void runAsyncRegistrationsForStorage(OWSStorage *storage, dispatch_block_t compl
self.areAsyncRegistrationsComplete = YES; self.areAsyncRegistrationsComplete = YES;
completion(); completion();
[self verifyDatabaseViews];
}); });
} }
- (void)verifyDatabaseViews
{
VerifyRegistrationsForStorage(self);
}
+ (void)protectFiles + (void)protectFiles
{ {
DDLogInfo( DDLogInfo(

@ -128,6 +128,13 @@ NS_ASSUME_NONNULL_BEGIN
OWSFail(_messageFormat, ##__VA_ARGS__); \ 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. // This function is intended for use in Swift.
void SwiftAssertIsOnMainThread(NSString *functionName); void SwiftAssertIsOnMainThread(NSString *functionName);

Loading…
Cancel
Save