Avoid deadlocks in contact manager.

This commit is contained in:
Matthew Chen 2018-10-26 13:21:08 -04:00
parent bf140971e2
commit f26241ebd0
8 changed files with 85 additions and 14 deletions

View File

@ -76,7 +76,6 @@ extern NSString *const OWSContactsManagerSignalAccountsDidChangeNotification;
- (BOOL)isSystemContact:(NSString *)recipientId;
- (BOOL)isSystemContactWithSignalAccount:(NSString *)recipientId;
- (BOOL)hasNameInSystemContactsForRecipientId:(NSString *)recipientId;
- (NSString *)displayNameForPhoneIdentifier:(nullable NSString *)identifier;
- (NSString *)displayNameForSignalAccount:(SignalAccount *)signalAccount;
/**

View File

@ -87,7 +87,7 @@ NSString *const OWSContactsManagerKeyNextFullIntersectionDate = @"OWSContactsMan
- (void)setup {
__block NSMutableArray<SignalAccount *> *signalAccounts;
[self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
[self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
NSUInteger signalAccountCount = [SignalAccount numberOfKeysInCollectionWithTransaction:transaction];
OWSLogInfo(@"loading %lu signal accounts from cache.", (unsigned long)signalAccountCount);
@ -480,7 +480,7 @@ NSString *const OWSContactsManagerKeyNextFullIntersectionDate = @"OWSContactsMan
}
NSMutableDictionary<NSString *, SignalAccount *> *oldSignalAccounts = [NSMutableDictionary new];
[self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
[self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
[SignalAccount
enumerateCollectionObjectsWithTransaction:transaction
usingBlock:^(id _Nonnull object, BOOL *_Nonnull stop) {
@ -585,10 +585,27 @@ NSString *const OWSContactsManagerKeyNextFullIntersectionDate = @"OWSContactsMan
}
- (NSString *_Nullable)cachedContactNameForRecipientId:(NSString *)recipientId
{
SignalAccount *_Nullable signalAccount = [self fetchSignalAccountForRecipientId:recipientId];
return [self cachedContactNameForRecipientId:recipientId signalAccount:signalAccount];
}
- (NSString *_Nullable)cachedContactNameForRecipientId:(NSString *)recipientId
transaction:(YapDatabaseReadTransaction *)transaction
{
OWSAssertDebug(recipientId.length > 0);
OWSAssertDebug(transaction);
SignalAccount *_Nullable signalAccount =
[self fetchSignalAccountForRecipientId:recipientId transaction:transaction];
return [self cachedContactNameForRecipientId:recipientId signalAccount:signalAccount];
}
- (NSString *_Nullable)cachedContactNameForRecipientId:(NSString *)recipientId
signalAccount:(nullable SignalAccount *)signalAccount
{
OWSAssertDebug(recipientId.length > 0);
SignalAccount *_Nullable signalAccount = [self fetchSignalAccountForRecipientId:recipientId];
if (!signalAccount) {
// search system contacts for no-longer-registered signal users, for which there will be no SignalAccount
OWSLogDebug(@"no signal account");
@ -723,8 +740,19 @@ NSString *const OWSContactsManagerKeyNextFullIntersectionDate = @"OWSContactsMan
return [self cachedContactNameForRecipientId:recipientId];
}
- (nullable NSString *)nameFromSystemContactsForRecipientId:(NSString *)recipientId
transaction:(YapDatabaseReadTransaction *)transaction
{
OWSAssertDebug(recipientId.length > 0);
OWSAssertDebug(transaction);
return [self cachedContactNameForRecipientId:recipientId transaction:transaction];
}
- (NSString *_Nonnull)displayNameForPhoneIdentifier:(NSString *_Nullable)recipientId
{
OWSAssertDebug(recipientId.length > 0);
if (!recipientId) {
return self.unknownContactName;
}
@ -739,6 +767,26 @@ NSString *const OWSContactsManagerKeyNextFullIntersectionDate = @"OWSContactsMan
return displayName;
}
- (NSString *_Nonnull)displayNameForPhoneIdentifier:(NSString *_Nullable)recipientId
transaction:(YapDatabaseReadTransaction *)transaction
{
OWSAssertDebug(recipientId.length > 0);
OWSAssertDebug(transaction);
if (!recipientId) {
return self.unknownContactName;
}
NSString *_Nullable displayName = [self nameFromSystemContactsForRecipientId:recipientId transaction:transaction];
// Fall back to just using their recipientId
if (displayName.length < 1) {
displayName = recipientId;
}
return displayName;
}
- (NSString *_Nonnull)displayNameForSignalAccount:(SignalAccount *)signalAccount
{
OWSAssertDebug(signalAccount);
@ -925,7 +973,7 @@ NSString *const OWSContactsManagerKeyNextFullIntersectionDate = @"OWSContactsMan
if (profileName.length > 0) {
NSString *numberAndProfileNameFormat = NSLocalizedString(@"PROFILE_NAME_AND_PHONE_NUMBER_LABEL_FORMAT",
@"Label text combining the phone number and profile name separated by a simple demarcation character. "
@"Phone number should be most prominent. '%1$@' is replaced with {{phone number}} and '%2$@' is replaced "
@"Phone number should be masost prominent. '%1$@' is replaced with {{phone number}} and '%2$@' is replaced "
@"with {{profile name}}");
NSString *numberAndProfileName =
@ -947,7 +995,7 @@ NSString *const OWSContactsManagerKeyNextFullIntersectionDate = @"OWSContactsMan
// If contact intersection hasn't completed, it might exist on disk
// even if it doesn't exist in memory yet.
if (!signalAccount) {
[self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
[self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
signalAccount = [SignalAccount fetchObjectWithUniqueID:recipientId transaction:transaction];
}];
}
@ -955,6 +1003,23 @@ NSString *const OWSContactsManagerKeyNextFullIntersectionDate = @"OWSContactsMan
return signalAccount;
}
- (nullable SignalAccount *)fetchSignalAccountForRecipientId:(NSString *)recipientId
transaction:(YapDatabaseReadTransaction *)transaction
{
OWSAssertDebug(recipientId.length > 0);
OWSAssertDebug(transaction);
__block SignalAccount *signalAccount = self.signalAccountMap[recipientId];
// If contact intersection hasn't completed, it might exist on disk
// even if it doesn't exist in memory yet.
if (!signalAccount) {
signalAccount = [SignalAccount fetchObjectWithUniqueID:recipientId transaction:transaction];
}
return signalAccount;
}
- (SignalAccount *)fetchOrBuildSignalAccountForRecipientId:(NSString *)recipientId
{
OWSAssertDebug(recipientId.length > 0);

View File

@ -125,7 +125,8 @@ NSUInteger TSErrorMessageSchemaVersion = 1;
@"Shown when signal users safety numbers changed, embeds the user's {{name or phone number}}");
NSString *recipientDisplayName =
[SSKEnvironment.shared.contactsManager displayNameForPhoneIdentifier:self.recipientId];
[SSKEnvironment.shared.contactsManager displayNameForPhoneIdentifier:self.recipientId
transaction:transaction];
return [NSString stringWithFormat:messageFormat, recipientDisplayName];
} else {
// recipientId will be nil for legacy errors

View File

@ -121,7 +121,8 @@ NSUInteger TSInfoMessageSchemaVersion = 1;
case TSInfoMessageUserNotRegistered:
if (self.unregisteredRecipientId.length > 0) {
id<ContactsManagerProtocol> contactsManager = SSKEnvironment.shared.contactsManager;
NSString *recipientName = [contactsManager displayNameForPhoneIdentifier:self.unregisteredRecipientId];
NSString *recipientName = [contactsManager displayNameForPhoneIdentifier:self.unregisteredRecipientId
transaction:transaction];
return [NSString stringWithFormat:NSLocalizedString(@"ERROR_UNREGISTERED_USER_FORMAT",
@"Format string for 'unregistered user' error. Embeds {{the "
@"unregistered user's name or signal id}}."),

View File

@ -199,7 +199,8 @@ void AssertIsOnDisappearingMessagesQueue()
NSString *remoteContactName = nil;
if ([message isKindOfClass:[TSIncomingMessage class]]) {
TSIncomingMessage *incomingMessage = (TSIncomingMessage *)message;
remoteContactName = [contactsManager displayNameForPhoneIdentifier:incomingMessage.messageAuthorId];
remoteContactName =
[contactsManager displayNameForPhoneIdentifier:incomingMessage.messageAuthorId transaction:transaction];
}
[self becomeConsistentWithDisappearingDuration:message.expiresInSeconds

View File

@ -934,7 +934,7 @@ NS_ASSUME_NONNULL_BEGIN
}
OWSAssertDebug(disappearingMessagesConfiguration);
[disappearingMessagesConfiguration saveWithTransaction:transaction];
NSString *name = [self.contactsManager displayNameForPhoneIdentifier:envelope.source];
NSString *name = [self.contactsManager displayNameForPhoneIdentifier:envelope.source transaction:transaction];
OWSDisappearingConfigurationUpdateInfoMessage *message =
[[OWSDisappearingConfigurationUpdateInfoMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
thread:thread
@ -1192,7 +1192,8 @@ NS_ASSUME_NONNULL_BEGIN
oldGroupThread.groupModel.groupMemberIds = [newMemberIds.allObjects mutableCopy];
[oldGroupThread saveWithTransaction:transaction];
NSString *nameString = [self.contactsManager displayNameForPhoneIdentifier:envelope.source];
NSString *nameString =
[self.contactsManager displayNameForPhoneIdentifier:envelope.source transaction:transaction];
NSString *updateGroupInfo =
[NSString stringWithFormat:NSLocalizedString(@"GROUP_MEMBER_LEFT", @""), nameString];
[[[TSInfoMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]

View File

@ -9,10 +9,13 @@ NS_ASSUME_NONNULL_BEGIN
@class PhoneNumber;
@class SignalAccount;
@class UIImage;
@class YapDatabaseReadTransaction;
@protocol ContactsManagerProtocol <NSObject>
- (NSString *)displayNameForPhoneIdentifier:(NSString *_Nullable)phoneNumber;
- (NSString *)displayNameForPhoneIdentifier:(nullable NSString *)recipientId;
- (NSString *_Nonnull)displayNameForPhoneIdentifier:(NSString *_Nullable)recipientId
transaction:(YapDatabaseReadTransaction *)transaction;
- (NSArray<SignalAccount *> *)signalAccounts;
- (BOOL)isSystemContact:(NSString *)recipientId;

View File

@ -172,8 +172,8 @@ public class FullTextSearchFinder: NSObject {
return recipientIndexer.index(recipientId, transaction: transaction)
}
private static let recipientIndexer: SearchIndexer<String> = SearchIndexer { (recipientId: String, _: YapDatabaseReadTransaction) in
let displayName = contactsManager.displayName(forPhoneIdentifier: recipientId)
private static let recipientIndexer: SearchIndexer<String> = SearchIndexer { (recipientId: String, transaction: YapDatabaseReadTransaction) in
let displayName = contactsManager.displayName(forPhoneIdentifier: recipientId, transaction: transaction)
let nationalNumber: String = { (recipientId: String) -> String in