From 147107d76cdbc7079668b6d8dfc0079f74071f02 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Tue, 2 May 2017 13:59:35 -0400 Subject: [PATCH] Fix database deadlock in contacts manager. // FREEBIE --- Signal/src/contact/OWSContactsManager.m | 41 +++++++++++++++---------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/Signal/src/contact/OWSContactsManager.m b/Signal/src/contact/OWSContactsManager.m index 40136a885..508078a69 100644 --- a/Signal/src/contact/OWSContactsManager.m +++ b/Signal/src/contact/OWSContactsManager.m @@ -207,28 +207,37 @@ void onAddressBookChanged(ABAddressBookRef notifyAddressBook, CFDictionaryRef in NSMutableDictionary *signalAccountMap = [NSMutableDictionary new]; NSMutableArray *signalAccounts = [NSMutableArray new]; NSArray *contacts = self.allContacts; + + // We use a transaction only to load the SignalRecipients for each contact, + // in order to avoid database deadlock. + NSMutableDictionary *> *contactIdToSignalRecipientsMap = + [NSMutableDictionary new]; [[TSStorageManager sharedManager].dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { for (Contact *contact in contacts) { NSArray *signalRecipients = [contact signalRecipientsWithTransaction:transaction]; - for (SignalRecipient *signalRecipient in - [signalRecipients sortedArrayUsingSelector:@selector(compare:)]) { - SignalAccount *signalAccount = [[SignalAccount alloc] initWithSignalRecipient:signalRecipient]; - signalAccount.contact = contact; - if (signalRecipients.count > 1) { - signalAccount.hasMultipleAccountContact = YES; - signalAccount.multipleAccountLabelText = - [[self class] accountLabelForContact:contact recipientId:signalRecipient.recipientId]; - } - if (signalAccountMap[signalAccount.recipientId]) { - DDLogInfo(@"Ignoring duplicate contact: %@, %@", signalAccount.recipientId, contact.fullName); - continue; - } - signalAccountMap[signalAccount.recipientId] = signalAccount; - [signalAccounts addObject:signalAccount]; - } + contactIdToSignalRecipientsMap[contact.uniqueId] = signalRecipients; } }]; + for (Contact *contact in contacts) { + NSArray *signalRecipients = contactIdToSignalRecipientsMap[contact.uniqueId]; + for (SignalRecipient *signalRecipient in [signalRecipients sortedArrayUsingSelector:@selector(compare:)]) { + SignalAccount *signalAccount = [[SignalAccount alloc] initWithSignalRecipient:signalRecipient]; + signalAccount.contact = contact; + if (signalRecipients.count > 1) { + signalAccount.hasMultipleAccountContact = YES; + signalAccount.multipleAccountLabelText = + [[self class] accountLabelForContact:contact recipientId:signalRecipient.recipientId]; + } + if (signalAccountMap[signalAccount.recipientId]) { + DDLogInfo(@"Ignoring duplicate contact: %@, %@", signalAccount.recipientId, contact.fullName); + continue; + } + signalAccountMap[signalAccount.recipientId] = signalAccount; + [signalAccounts addObject:signalAccount]; + } + } + dispatch_async(dispatch_get_main_queue(), ^{ self.signalAccountMap = [signalAccountMap copy]; self.signalAccounts = [signalAccounts copy];