Perf: Insert outgoing message into conversation before save completes.

This was a huge savings - e.g. 50-70% of the time between tapping send and
rendering the message takes place in the save/postWriteTransaction blocks
pull/1/head
Michael Kirk 6 years ago
parent 176543d2af
commit 668cc22af3

@ -3887,13 +3887,14 @@ typedef enum : NSUInteger {
inThread:self.thread inThread:self.thread
quotedReplyModel:self.inputToolbar.quotedReply]; quotedReplyModel:self.inputToolbar.quotedReply];
} else { } else {
[self.editingDatabaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
message = [ThreadUtil enqueueMessageWithText:text message = [ThreadUtil enqueueMessageWithText:text
inThread:self.thread inThread:self.thread
quotedReplyModel:self.inputToolbar.quotedReply quotedReplyModel:self.inputToolbar.quotedReply
transaction:transaction]; transaction:transaction];
}]; }];
} }
[self.conversationViewModel appendUnsavedOutgoingMessage:message];
[self messageWasSent:message]; [self messageWasSent:message];

@ -7,6 +7,7 @@ NS_ASSUME_NONNULL_BEGIN
@class ConversationStyle; @class ConversationStyle;
@class ConversationViewModel; @class ConversationViewModel;
@class OWSQuotedReplyModel; @class OWSQuotedReplyModel;
@class TSOutgoingMessage;
@class TSThread; @class TSThread;
@class ThreadDynamicInteractions; @class ThreadDynamicInteractions;
@ -101,6 +102,7 @@ typedef NS_ENUM(NSUInteger, ConversationUpdateItemType) {
- (BOOL)canLoadMoreItems; - (BOOL)canLoadMoreItems;
- (nullable NSIndexPath *)ensureLoadWindowContainsQuotedReply:(OWSQuotedReplyModel *)quotedReply; - (nullable NSIndexPath *)ensureLoadWindowContainsQuotedReply:(OWSQuotedReplyModel *)quotedReply;
- (void)appendUnsavedOutgoingMessage:(TSOutgoingMessage *)outgoingMessage;
@end @end

@ -12,6 +12,7 @@
#import <SignalMessaging/OWSContactOffersInteraction.h> #import <SignalMessaging/OWSContactOffersInteraction.h>
#import <SignalMessaging/OWSContactsManager.h> #import <SignalMessaging/OWSContactsManager.h>
#import <SignalMessaging/OWSUnreadIndicator.h> #import <SignalMessaging/OWSUnreadIndicator.h>
#import <SignalMessaging/SignalMessaging-Swift.h>
#import <SignalMessaging/ThreadUtil.h> #import <SignalMessaging/ThreadUtil.h>
#import <SignalServiceKit/OWSBlockingManager.h> #import <SignalServiceKit/OWSBlockingManager.h>
#import <SignalServiceKit/OWSPrimaryStorage.h> #import <SignalServiceKit/OWSPrimaryStorage.h>
@ -1491,6 +1492,33 @@ static const int kYapDatabaseRangeMinLength = 0;
return !hasError; return !hasError;
} }
- (void)appendUnsavedOutgoingMessage:(TSOutgoingMessage *)outgoingMessage
{
// id<ConversationViewItem> viewItem = [[OutgoingUnsavedConversationViewItem alloc] initWithOutgoingMessage:outgoingMessage];
__block ConversationInteractionViewItem *viewItem;
[self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction * _Nonnull transaction) {
viewItem =
[[ConversationInteractionViewItem alloc] initWithInteraction:outgoingMessage
isGroupThread:self.thread.isGroupThread
transaction:transaction
conversationStyle:self.delegate.conversationStyle];
}];
ConversationUpdateItem *updateItem = [[ConversationUpdateItem alloc] initWithUpdateItemType:ConversationUpdateItemType_Insert
oldIndex:0
newIndex:self.viewItems.count
viewItem:viewItem];
NSMutableArray<id <ConversationViewItem>> *viewItems = [self.viewItems mutableCopy];
[viewItems addObject:viewItem];
self.viewItems = viewItems;
ConversationUpdate *conversationUpdate = [[ConversationUpdate alloc] initWithConversationUpdateType:ConversationUpdateType_Diff
updateItems:@[updateItem]
shouldAnimateUpdates:NO];
[self.delegate conversationViewModelDidUpdate:conversationUpdate];
}
// Whenever an interaction is modified, we need to reload it from the DB // Whenever an interaction is modified, we need to reload it from the DB
// and update the corresponding view item. // and update the corresponding view item.
- (void)reloadInteractionForViewItem:(id<ConversationViewItem>)viewItem - (void)reloadInteractionForViewItem:(id<ConversationViewItem>)viewItem

@ -47,7 +47,7 @@ NS_ASSUME_NONNULL_BEGIN
+ (TSOutgoingMessage *)enqueueMessageWithText:(NSString *)text + (TSOutgoingMessage *)enqueueMessageWithText:(NSString *)text
inThread:(TSThread *)thread inThread:(TSThread *)thread
quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel
transaction:(YapDatabaseReadWriteTransaction *)transaction; transaction:(YapDatabaseReadTransaction *)transaction;
+ (TSOutgoingMessage *)enqueueMessageWithAttachment:(SignalAttachment *)attachment + (TSOutgoingMessage *)enqueueMessageWithAttachment:(SignalAttachment *)attachment
inThread:(TSThread *)thread inThread:(TSThread *)thread

@ -68,7 +68,7 @@ NS_ASSUME_NONNULL_BEGIN
+ (TSOutgoingMessage *)enqueueMessageWithText:(NSString *)text + (TSOutgoingMessage *)enqueueMessageWithText:(NSString *)text
inThread:(TSThread *)thread inThread:(TSThread *)thread
quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel
transaction:(YapDatabaseReadWriteTransaction *)transaction transaction:(YapDatabaseReadTransaction *)transaction
{ {
OWSDisappearingMessagesConfiguration *configuration = OWSDisappearingMessagesConfiguration *configuration =
[OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:thread.uniqueId transaction:transaction]; [OWSDisappearingMessagesConfiguration fetchObjectWithUniqueID:thread.uniqueId transaction:transaction];
@ -82,9 +82,13 @@ NS_ASSUME_NONNULL_BEGIN
expiresInSeconds:expiresInSeconds expiresInSeconds:expiresInSeconds
quotedMessage:[quotedReplyModel buildQuotedMessageForSending]]; quotedMessage:[quotedReplyModel buildQuotedMessageForSending]];
[message saveWithTransaction:transaction]; [BenchManager benchWithTitle:@"Saving outgoing message" block:^{
// To avoid blocking the send flow, we disapatch an async write from within this read transaction
[self.messageSenderJobQueue addMessage:message transaction:transaction]; [self.dbConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction * _Nonnull writeTransaction) {
[message saveWithTransaction:writeTransaction];
[self.messageSenderJobQueue addMessage:message transaction:writeTransaction];
}];
}];
return message; return message;
} }

@ -38,6 +38,7 @@ public class MessageSenderJobQueue: NSObject, JobQueue {
@objc(addMessage:transaction:) @objc(addMessage:transaction:)
public func add(message: TSOutgoingMessage, transaction: YapDatabaseReadWriteTransaction) { public func add(message: TSOutgoingMessage, transaction: YapDatabaseReadWriteTransaction) {
message.save(with: transaction)
self.add(message: message, removeMessageAfterSending: false, transaction: transaction) self.add(message: message, removeMessageAfterSending: false, transaction: transaction)
} }

Loading…
Cancel
Save