use dedicated read connection to pre-populate cache

// FREEBIE
pull/1/head
Michael Kirk 7 years ago
parent 336c92ddab
commit 42dc872c9a

@ -38,7 +38,7 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>2.19.2</string> <string>2.19.3</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleURLTypes</key> <key>CFBundleURLTypes</key>
@ -55,7 +55,7 @@
</dict> </dict>
</array> </array>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>2.19.2.0</string> <string>2.19.3.0</string>
<key>ITSAppUsesNonExemptEncryption</key> <key>ITSAppUsesNonExemptEncryption</key>
<false/> <false/>
<key>LOGS_EMAIL</key> <key>LOGS_EMAIL</key>
@ -101,10 +101,10 @@
<string>Signal uses your contacts to find users you know. We do not store your contacts on the server.</string> <string>Signal uses your contacts to find users you know. We do not store your contacts on the server.</string>
<key>NSMicrophoneUsageDescription</key> <key>NSMicrophoneUsageDescription</key>
<string>Signal needs access to your microphone to make and receive phone calls and record voice messages.</string> <string>Signal needs access to your microphone to make and receive phone calls and record voice messages.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Signal will let you choose which photos from your library to send.</string>
<key>NSPhotoLibraryAddUsageDescription</key> <key>NSPhotoLibraryAddUsageDescription</key>
<string>Signal will save photos to your library.</string> <string>Signal will save photos to your library.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Signal will let you choose which photos from your library to send.</string>
<key>UIAppFonts</key> <key>UIAppFonts</key>
<array> <array>
<string>dripicons-v2.ttf</string> <string>dripicons-v2.ttf</string>

@ -858,6 +858,8 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
[AppVersion.instance appLaunchDidComplete]; [AppVersion.instance appLaunchDidComplete];
[[Environment getCurrent].contactsManager loadSignalAccountsFromCache];
[self ensureRootViewController]; [self ensureRootViewController];
// If there were any messages in our local queue which we hadn't yet processed. // If there were any messages in our local queue which we hadn't yet processed.

@ -34,6 +34,7 @@ extern NSString *const OWSContactsManagerSignalAccountsDidChangeNotification;
@property (atomic, readonly) NSArray<SignalAccount *> *signalAccounts; @property (atomic, readonly) NSArray<SignalAccount *> *signalAccounts;
- (nullable SignalAccount *)signalAccountForRecipientId:(NSString *)recipientId; - (nullable SignalAccount *)signalAccountForRecipientId:(NSString *)recipientId;
- (void)loadSignalAccountsFromCache;
#pragma mark - System Contact Fetching #pragma mark - System Contact Fetching
// Must call `requestSystemContactsOnce` before accessing this method // Must call `requestSystemContactsOnce` before accessing this method

@ -29,6 +29,8 @@ NSString *const OWSContactsManagerSignalAccountsDidChangeNotification
@property (atomic) NSArray<SignalAccount *> *signalAccounts; @property (atomic) NSArray<SignalAccount *> *signalAccounts;
@property (atomic) NSDictionary<NSString *, SignalAccount *> *signalAccountMap; @property (atomic) NSDictionary<NSString *, SignalAccount *> *signalAccountMap;
@property (nonatomic, readonly) SystemContactsFetcher *systemContactsFetcher; @property (nonatomic, readonly) SystemContactsFetcher *systemContactsFetcher;
@property (nonatomic, readonly) YapDatabaseConnection *dbReadConnection;
@property (nonatomic, readonly) YapDatabaseConnection *dbWriteConnection;
@end @end
@ -42,18 +44,36 @@ NSString *const OWSContactsManagerSignalAccountsDidChangeNotification
// TODO: We need to configure the limits of this cache. // TODO: We need to configure the limits of this cache.
_avatarCache = [ImageCache new]; _avatarCache = [ImageCache new];
_dbReadConnection = [TSStorageManager sharedManager].newDatabaseConnection;
_dbWriteConnection = [TSStorageManager sharedManager].newDatabaseConnection;
_allContacts = @[]; _allContacts = @[];
_allContactsMap = @{}; _allContactsMap = @{};
_signalAccountMap = @{}; _signalAccountMap = @{};
_signalAccounts = @[]; _signalAccounts = @[];
_systemContactsFetcher = [SystemContactsFetcher new]; _systemContactsFetcher = [SystemContactsFetcher new];
_systemContactsFetcher.delegate = self; _systemContactsFetcher.delegate = self;
OWSSingletonAssert(); OWSSingletonAssert();
return self; return self;
} }
- (void)loadSignalAccountsFromCache
{
__block NSMutableArray<SignalAccount *> *signalAccounts;
[self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction * _Nonnull transaction) {
signalAccounts = [[NSMutableArray alloc] initWithCapacity:[SignalAccount numberOfKeysInCollectionWithTransaction:transaction]];
[SignalAccount enumerateCollectionObjectsWithTransaction:transaction usingBlock:^(SignalAccount *signalAccount, BOOL * _Nonnull stop) {
[signalAccounts addObject:signalAccount];
}];
}];
[self updateSignalAccounts:signalAccounts];
}
#pragma mark - System Contact Fetching #pragma mark - System Contact Fetching
// Request contacts access if you haven't asked recently. // Request contacts access if you haven't asked recently.
@ -111,7 +131,7 @@ NSString *const OWSContactsManagerSignalAccountsDidChangeNotification
{ {
void (^success)(void) = ^{ void (^success)(void) = ^{
DDLogInfo(@"%@ Successfully intersected contacts.", self.logTag); DDLogInfo(@"%@ Successfully intersected contacts.", self.logTag);
[self updateSignalAccounts]; [self buildSignalAccounts];
}; };
void (^failure)(NSError *error) = ^(NSError *error) { void (^failure)(NSError *error) = ^(NSError *error) {
if ([error.domain isEqualToString:OWSSignalServiceKitErrorDomain] if ([error.domain isEqualToString:OWSSignalServiceKitErrorDomain]
@ -175,12 +195,12 @@ NSString *const OWSContactsManagerSignalAccountsDidChangeNotification
[self intersectContacts]; [self intersectContacts];
[self updateSignalAccounts]; [self buildSignalAccounts];
}); });
}); });
} }
- (void)updateSignalAccounts - (void)buildSignalAccounts
{ {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSMutableDictionary<NSString *, SignalAccount *> *signalAccountMap = [NSMutableDictionary new]; NSMutableDictionary<NSString *, SignalAccount *> *signalAccountMap = [NSMutableDictionary new];
@ -191,7 +211,7 @@ NSString *const OWSContactsManagerSignalAccountsDidChangeNotification
// in order to avoid database deadlock. // in order to avoid database deadlock.
NSMutableDictionary<NSString *, NSArray<SignalRecipient *> *> *contactIdToSignalRecipientsMap = NSMutableDictionary<NSString *, NSArray<SignalRecipient *> *> *contactIdToSignalRecipientsMap =
[NSMutableDictionary new]; [NSMutableDictionary new];
[[TSStorageManager sharedManager].dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { [self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
for (Contact *contact in contacts) { for (Contact *contact in contacts) {
NSArray<SignalRecipient *> *signalRecipients = [contact signalRecipientsWithTransaction:transaction]; NSArray<SignalRecipient *> *signalRecipients = [contact signalRecipientsWithTransaction:transaction];
contactIdToSignalRecipientsMap[contact.uniqueId] = signalRecipients; contactIdToSignalRecipientsMap[contact.uniqueId] = signalRecipients;
@ -212,31 +232,48 @@ NSString *const OWSContactsManagerSignalAccountsDidChangeNotification
DDLogDebug(@"Ignoring duplicate contact: %@, %@", signalAccount.recipientId, contact.fullName); DDLogDebug(@"Ignoring duplicate contact: %@, %@", signalAccount.recipientId, contact.fullName);
continue; continue;
} }
signalAccountMap[signalAccount.recipientId] = signalAccount;
[signalAccounts addObject:signalAccount]; [signalAccounts addObject:signalAccount];
} }
} }
[TSStorageManager.sharedManager.newDatabaseConnection // Update cached SignalAccounts on disk
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { [self.dbWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
// TODO we can be more efficient here. NSArray<NSString *> *allKeys = [transaction allKeysInCollection:[SignalAccount collection]];
// - only save the ones that changed NSMutableSet<NSString *> *orphanedKeys = [NSMutableSet setWithArray:allKeys];
// - only remove the ones which no longer exist
[transaction removeAllObjectsInCollection:[SignalAccount collection]]; for (SignalAccount *signalAccount in signalAccounts) {
for (SignalAccount *signalAccount in signalAccounts) { // TODO only save the ones that changed
[signalAccount saveWithTransaction:transaction]; [orphanedKeys removeObject:signalAccount.uniqueId];
} [signalAccount saveWithTransaction:transaction];
}]; }
if (orphanedKeys.count > 0) {
DDLogInfo(@"%@ Removing %lu orphaned SignalAccounts", self.logTag, (unsigned long)orphanedKeys.count);
[transaction removeObjectsForKeys:orphanedKeys.allObjects inCollection:[SignalAccount collection]];
}
}];
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
self.signalAccountMap = [signalAccountMap copy]; [self updateSignalAccounts:signalAccounts];
self.signalAccounts = [signalAccounts copy];
[self.profileManager setContactRecipientIds:signalAccountMap.allKeys];
}); });
}); });
} }
- (void)updateSignalAccounts:(NSArray<SignalAccount *> *)signalAccounts
{
AssertIsOnMainThread();
NSMutableDictionary<NSString *, SignalAccount *> *signalAccountMap = [NSMutableDictionary new];
for (SignalAccount *signalAccount in signalAccounts) {
signalAccountMap[signalAccount.recipientId] = signalAccount;
}
self.signalAccountMap = [signalAccountMap copy];
self.signalAccounts = [signalAccounts copy];
[self.profileManager setContactRecipientIds:signalAccountMap.allKeys];
}
// TODO dependency inject, avoid circular dependencies. // TODO dependency inject, avoid circular dependencies.
- (OWSProfileManager *)profileManager - (OWSProfileManager *)profileManager
{ {
@ -543,12 +580,14 @@ NSString *const OWSContactsManagerSignalAccountsDidChangeNotification
{ {
OWSAssert(recipientId.length > 0); OWSAssert(recipientId.length > 0);
SignalAccount *signalAccount = self.signalAccountMap[recipientId]; __block SignalAccount *signalAccount = self.signalAccountMap[recipientId];
// If contact intersection hasn't completed, it might exist on disk // If contact intersection hasn't completed, it might exist on disk
// even if it doesn't exist in memory yet. // even if it doesn't exist in memory yet.
if (!signalAccount) { if (!signalAccount) {
signalAccount = [SignalAccount fetchObjectWithUniqueID:recipientId]; [self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction * _Nonnull transaction) {
signalAccount = [SignalAccount fetchObjectWithUniqueID:recipientId transaction: transaction];
}];
} }
return signalAccount; return signalAccount;

Loading…
Cancel
Save