Avoid deadlocks in contact manager.

pull/1/head
Matthew Chen 7 years ago
parent bf140971e2
commit f26241ebd0

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

@ -87,7 +87,7 @@ NSString *const OWSContactsManagerKeyNextFullIntersectionDate = @"OWSContactsMan
- (void)setup { - (void)setup {
__block NSMutableArray<SignalAccount *> *signalAccounts; __block NSMutableArray<SignalAccount *> *signalAccounts;
[self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) { [self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
NSUInteger signalAccountCount = [SignalAccount numberOfKeysInCollectionWithTransaction:transaction]; NSUInteger signalAccountCount = [SignalAccount numberOfKeysInCollectionWithTransaction:transaction];
OWSLogInfo(@"loading %lu signal accounts from cache.", (unsigned long)signalAccountCount); OWSLogInfo(@"loading %lu signal accounts from cache.", (unsigned long)signalAccountCount);
@ -480,7 +480,7 @@ NSString *const OWSContactsManagerKeyNextFullIntersectionDate = @"OWSContactsMan
} }
NSMutableDictionary<NSString *, SignalAccount *> *oldSignalAccounts = [NSMutableDictionary new]; NSMutableDictionary<NSString *, SignalAccount *> *oldSignalAccounts = [NSMutableDictionary new];
[self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) { [self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
[SignalAccount [SignalAccount
enumerateCollectionObjectsWithTransaction:transaction enumerateCollectionObjectsWithTransaction:transaction
usingBlock:^(id _Nonnull object, BOOL *_Nonnull stop) { usingBlock:^(id _Nonnull object, BOOL *_Nonnull stop) {
@ -585,10 +585,27 @@ NSString *const OWSContactsManagerKeyNextFullIntersectionDate = @"OWSContactsMan
} }
- (NSString *_Nullable)cachedContactNameForRecipientId:(NSString *)recipientId - (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); OWSAssertDebug(recipientId.length > 0);
SignalAccount *_Nullable signalAccount = [self fetchSignalAccountForRecipientId:recipientId];
if (!signalAccount) { if (!signalAccount) {
// search system contacts for no-longer-registered signal users, for which there will be no SignalAccount // search system contacts for no-longer-registered signal users, for which there will be no SignalAccount
OWSLogDebug(@"no signal account"); OWSLogDebug(@"no signal account");
@ -723,8 +740,19 @@ NSString *const OWSContactsManagerKeyNextFullIntersectionDate = @"OWSContactsMan
return [self cachedContactNameForRecipientId:recipientId]; 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 - (NSString *_Nonnull)displayNameForPhoneIdentifier:(NSString *_Nullable)recipientId
{ {
OWSAssertDebug(recipientId.length > 0);
if (!recipientId) { if (!recipientId) {
return self.unknownContactName; return self.unknownContactName;
} }
@ -739,6 +767,26 @@ NSString *const OWSContactsManagerKeyNextFullIntersectionDate = @"OWSContactsMan
return displayName; 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 - (NSString *_Nonnull)displayNameForSignalAccount:(SignalAccount *)signalAccount
{ {
OWSAssertDebug(signalAccount); OWSAssertDebug(signalAccount);
@ -925,7 +973,7 @@ NSString *const OWSContactsManagerKeyNextFullIntersectionDate = @"OWSContactsMan
if (profileName.length > 0) { if (profileName.length > 0) {
NSString *numberAndProfileNameFormat = NSLocalizedString(@"PROFILE_NAME_AND_PHONE_NUMBER_LABEL_FORMAT", 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. " @"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}}"); @"with {{profile name}}");
NSString *numberAndProfileName = NSString *numberAndProfileName =
@ -947,7 +995,7 @@ NSString *const OWSContactsManagerKeyNextFullIntersectionDate = @"OWSContactsMan
// 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) {
[self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) { [self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
signalAccount = [SignalAccount fetchObjectWithUniqueID:recipientId transaction:transaction]; signalAccount = [SignalAccount fetchObjectWithUniqueID:recipientId transaction:transaction];
}]; }];
} }
@ -955,6 +1003,23 @@ NSString *const OWSContactsManagerKeyNextFullIntersectionDate = @"OWSContactsMan
return signalAccount; 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 - (SignalAccount *)fetchOrBuildSignalAccountForRecipientId:(NSString *)recipientId
{ {
OWSAssertDebug(recipientId.length > 0); OWSAssertDebug(recipientId.length > 0);

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

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

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

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

@ -9,10 +9,13 @@ NS_ASSUME_NONNULL_BEGIN
@class PhoneNumber; @class PhoneNumber;
@class SignalAccount; @class SignalAccount;
@class UIImage; @class UIImage;
@class YapDatabaseReadTransaction;
@protocol ContactsManagerProtocol <NSObject> @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; - (NSArray<SignalAccount *> *)signalAccounts;
- (BOOL)isSystemContact:(NSString *)recipientId; - (BOOL)isSystemContact:(NSString *)recipientId;

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

Loading…
Cancel
Save