diff --git a/Signal/src/AppDelegate.m b/Signal/src/AppDelegate.m index 26c9d996d..1b029bb3b 100644 --- a/Signal/src/AppDelegate.m +++ b/Signal/src/AppDelegate.m @@ -199,8 +199,8 @@ static NSString *const kURLHostVerifyPrefix = @"verify"; // Every time we change or add a database view in such a way that // might cause a delay on launch, we need to bump this constant. // - // We added a new database view in v2.17.0. - NSString *kLastVersionWithDatabaseViewChange = @"2.17.0"; + // We added a number of database views in v2.13.0. + NSString *kLastVersionWithDatabaseViewChange = @"2.13.0"; BOOL mayNeedUpgrade = ([TSAccountManager isRegistered] && lastLaunchedAppVersion && (!lastCompletedLaunchAppVersion || [VersionMigrations isVersion:lastCompletedLaunchAppVersion diff --git a/SignalServiceKit/src/Messages/Interactions/TSInteraction.h b/SignalServiceKit/src/Messages/Interactions/TSInteraction.h index 8e2991fb5..bcc4e67d7 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSInteraction.h +++ b/SignalServiceKit/src/Messages/Interactions/TSInteraction.h @@ -28,6 +28,9 @@ NS_ASSUME_NONNULL_BEGIN + (instancetype)interactionForTimestamp:(uint64_t)timestamp withTransaction:(YapDatabaseReadWriteTransaction *)transaction; ++ (NSArray *)interactionsWithTimestamp:(uint64_t)timestamp + ofClass:(Class)clazz + withTransaction:(YapDatabaseReadWriteTransaction *)transaction; - (NSDate *)dateForSorting; - (uint64_t)timestampForSorting; diff --git a/SignalServiceKit/src/Messages/Interactions/TSInteraction.m b/SignalServiceKit/src/Messages/Interactions/TSInteraction.m index 032f61aaa..30ebfb849 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSInteraction.m +++ b/SignalServiceKit/src/Messages/Interactions/TSInteraction.m @@ -16,25 +16,60 @@ NS_ASSUME_NONNULL_BEGIN withTransaction:(YapDatabaseReadWriteTransaction *)transaction { OWSAssert(timestamp > 0); - __block int counter = 0; - __block TSInteraction *interaction; + // Accept any interaction. + NSArray *interactions = [self interactionsWithTimestamp:timestamp + withFilter:^(TSInteraction *interaction) { + return YES; + } + withTransaction:transaction]; + + if (interactions.count < 1) { + // TODO: OWSFail()? + return nil; + } + if (interactions.count > 1) { + DDLogWarn(@"The database contains %zd colliding timestamps at: %lld.", interactions.count, timestamp); + } + TSInteraction *lastInteraction = interactions.lastObject; + return lastInteraction; +} + ++ (NSArray *)interactionsWithTimestamp:(uint64_t)timestamp + ofClass:(Class)clazz + withTransaction:(YapDatabaseReadWriteTransaction *)transaction +{ + OWSAssert(timestamp > 0); + + // Accept any interaction. + return [self interactionsWithTimestamp:timestamp + withFilter:^(TSInteraction *interaction) { + return [interaction isKindOfClass:clazz]; + } + withTransaction:transaction]; +} + ++ (NSArray *)interactionsWithTimestamp:(uint64_t)timestamp + withFilter:(BOOL (^_Nonnull)(TSInteraction *))filter + withTransaction:(YapDatabaseReadWriteTransaction *)transaction +{ + OWSAssert(timestamp > 0); + + NSMutableArray *interactions = [NSMutableArray new]; [TSDatabaseSecondaryIndexes enumerateMessagesWithTimestamp:timestamp withBlock:^(NSString *collection, NSString *key, BOOL *stop) { - if (counter != 0) { - DDLogWarn(@"The database contains two colliding timestamps at: %lld.", timestamp); + TSInteraction *interaction = + [TSInteraction fetchObjectWithUniqueID:key transaction:transaction]; + if (!filter(interaction)) { return; } - - interaction = [TSInteraction fetchObjectWithUniqueID:key transaction:transaction]; - - counter++; + [interactions addObject:interaction]; } usingTransaction:transaction]; - return interaction; + return [interactions copy]; } + (NSString *)collection { diff --git a/SignalServiceKit/src/Messages/OWSReadReceiptManager.h b/SignalServiceKit/src/Messages/OWSReadReceiptManager.h index df6aade7e..14fe04909 100644 --- a/SignalServiceKit/src/Messages/OWSReadReceiptManager.h +++ b/SignalServiceKit/src/Messages/OWSReadReceiptManager.h @@ -9,7 +9,6 @@ NS_ASSUME_NONNULL_BEGIN @class TSIncomingMessage; @class TSOutgoingMessage; @class TSThread; -@class YapDatabase; @class YapDatabaseReadWriteTransaction; // There are four kinds of read receipts: @@ -61,10 +60,6 @@ NS_ASSUME_NONNULL_BEGIN - (BOOL)areReadReceiptsEnabled; - (void)setAreReadReceiptsEnabled:(BOOL)value; -#pragma mark - Database Extension - -+ (void)asyncRegisterDatabaseExtension:(YapDatabase *)database; - @end NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Messages/OWSReadReceiptManager.m b/SignalServiceKit/src/Messages/OWSReadReceiptManager.m index 0788dd9e3..2a1b0a3ef 100644 --- a/SignalServiceKit/src/Messages/OWSReadReceiptManager.m +++ b/SignalServiceKit/src/Messages/OWSReadReceiptManager.m @@ -14,137 +14,9 @@ #import "TSStorageManager.h" #import "TextSecureKitEnv.h" #import "Threading.h" -#import NS_ASSUME_NONNULL_BEGIN -//#pragma mark - Finder - -NSString *const OWSOutgoingMessageFinderExtensionName = @"OWSOutgoingMessageFinderExtensionName"; - -@interface OWSOutgoingMessageFinder : NSObject - -@end - -#pragma mark - - -@interface OWSOutgoingMessageFinder () - -@property (nonatomic, readonly) YapDatabaseConnection *dbConnection; - -@end - -#pragma mark - - -@implementation OWSOutgoingMessageFinder - -- (instancetype)initWithDBConnection:(YapDatabaseConnection *)dbConnection -{ - OWSSingletonAssert(); - - self = [super init]; - if (!self) { - return self; - } - - _dbConnection = dbConnection; - - return self; -} - -- (NSArray *)outgoingMessagesWithTimestamp:(uint64_t)timestamp - transaction:(YapDatabaseReadTransaction *)transaction -{ - OWSAssert(transaction); - NSMutableArray *result = [NSMutableArray new]; - YapDatabaseViewTransaction *viewTransaction = [transaction ext:OWSOutgoingMessageFinderExtensionName]; - OWSAssert(viewTransaction); - [viewTransaction - enumerateKeysAndObjectsInGroup:[OWSOutgoingMessageFinder groupForTimestamp:timestamp] - usingBlock:^(NSString *collection, NSString *key, id object, NSUInteger index, BOOL *stop) { - OWSAssert([object isKindOfClass:[TSOutgoingMessage class]]); - TSOutgoingMessage *message = (TSOutgoingMessage *)object; - OWSAssert(message.timestamp == timestamp); - [result addObject:object]; - }]; - - return [result copy]; -} - -+ (NSString *)groupForTimestamp:(uint64_t)timestamp -{ - return [NSString stringWithFormat:@"%llu", timestamp]; -} - -+ (YapDatabaseView *)databaseExtension -{ - YapDatabaseViewSorting *sorting = - [YapDatabaseViewSorting withObjectBlock:^NSComparisonResult(YapDatabaseReadTransaction *transaction, - NSString *group, - NSString *collection1, - NSString *key1, - id object1, - NSString *collection2, - NSString *key2, - id object2) { - // The ordering doesn't matter as long as its consistent. - return [key1 compare:key2]; - }]; - - YapDatabaseViewGrouping *grouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *_Nullable( - YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) { - if (![object isKindOfClass:[TSOutgoingMessage class]]) { - return nil; - } - - TSOutgoingMessage *message = (TSOutgoingMessage *)object; - - // Arbitrary string - all in the same group. We're only using the view for sorting. - return [OWSOutgoingMessageFinder groupForTimestamp:message.timestamp]; - }]; - - YapDatabaseViewOptions *options = [YapDatabaseViewOptions new]; - options.allowedCollections = - [[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:[TSOutgoingMessage collection]]]; - - return [[YapDatabaseView alloc] initWithGrouping:grouping sorting:sorting versionTag:@"1" options:options]; -} - - -+ (void)asyncRegisterDatabaseExtension:(YapDatabase *)database -{ - YapDatabaseView *existingView = [database registeredExtension:OWSOutgoingMessageFinderExtensionName]; - if (existingView) { - OWSFail(@"%@ was already initialized.", OWSOutgoingMessageFinderExtensionName); - return; - } - [database - asyncRegisterExtension:[self databaseExtension] - withName:OWSOutgoingMessageFinderExtensionName - completionBlock:^(BOOL ready) { - OWSCAssert(ready); - - DDLogInfo( - @"%@ asyncRegisterExtension: %@ -> %d", self.tag, OWSOutgoingMessageFinderExtensionName, ready); - }]; -} - -#pragma mark - Logging - -+ (NSString *)tag -{ - return [NSString stringWithFormat:@"[%@]", self.class]; -} - -- (NSString *)tag -{ - return self.class.tag; -} - -@end - -#pragma mark - - NSString *const OWSReadReceiptManagerCollection = @"OWSReadReceiptManagerCollection"; NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsEnabled"; NSString *const OWSRecipientReadReceiptCollection = @"OWSRecipientReadReceiptCollection"; @@ -155,8 +27,6 @@ NSString *const OWSRecipientReadReceiptCollection = @"OWSRecipientReadReceiptCol @property (nonatomic, readonly) YapDatabaseConnection *dbConnection; -@property (nonatomic, readonly) OWSOutgoingMessageFinder *outgoingMessageFinder; - // A map of "thread unique id"-to-"read receipt" for read receipts that // we will send to our linked devices. // @@ -211,8 +81,6 @@ NSString *const OWSRecipientReadReceiptCollection = @"OWSRecipientReadReceiptCol _messageSender = messageSender; _dbConnection = storageManager.newDatabaseConnection; - _outgoingMessageFinder = [[OWSOutgoingMessageFinder alloc] initWithDBConnection:self.dbConnection]; - _toLinkedDevicesReadReceiptMap = [NSMutableDictionary new]; _toSenderReadReceiptMap = [NSMutableDictionary new]; @@ -443,8 +311,10 @@ NSString *const OWSRecipientReadReceiptCollection = @"OWSRecipientReadReceiptCol for (int i = 0; i < timestamps.count; i++) { UInt64 timestamp = [timestamps uint64AtIndex:i]; - NSArray *messages = - [self.outgoingMessageFinder outgoingMessagesWithTimestamp:timestamp transaction:transaction]; + NSArray *messages + = (NSArray *)[TSInteraction interactionsWithTimestamp:timestamp + ofClass:[TSOutgoingMessage class] + withTransaction:transaction]; OWSAssert(messages.count <= 1); if (messages.count > 0) { // TODO: We might also need to "mark as read by recipient" any older messages @@ -518,13 +388,6 @@ NSString *const OWSRecipientReadReceiptCollection = @"OWSRecipientReadReceiptCol } } -#pragma mark - Database Extension - -+ (void)asyncRegisterDatabaseExtension:(YapDatabase *)database -{ - [OWSOutgoingMessageFinder asyncRegisterDatabaseExtension:database]; -} - #pragma mark - Logging + (NSString *)tag diff --git a/SignalServiceKit/src/Storage/TSStorageManager.m b/SignalServiceKit/src/Storage/TSStorageManager.m index f4046e262..898432694 100644 --- a/SignalServiceKit/src/Storage/TSStorageManager.m +++ b/SignalServiceKit/src/Storage/TSStorageManager.m @@ -20,7 +20,6 @@ #import #import #import -#import #import NS_ASSUME_NONNULL_BEGIN @@ -343,7 +342,6 @@ void setDatabaseInitialized() OWSFailedAttachmentDownloadsJob *failedAttachmentDownloadsMessagesJob = [[OWSFailedAttachmentDownloadsJob alloc] initWithStorageManager:self]; [failedAttachmentDownloadsMessagesJob asyncRegisterDatabaseExtensions]; - [OWSReadReceiptManager asyncRegisterDatabaseExtension:self.database]; // NOTE: [TSDatabaseView asyncRegistrationCompletion] ensures that // kNSNotificationName_DatabaseViewRegistrationComplete is not fired until all