mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
Add logging, error checking and recovery around corrupt message mappings.
This commit is contained in:
parent
8f6151048c
commit
420f5f88ff
1 changed files with 65 additions and 30 deletions
|
@ -455,29 +455,11 @@ typedef enum : NSUInteger {
|
|||
[self ensureDynamicInteractions];
|
||||
[[OWSPrimaryStorage sharedManager] updateUIDatabaseConnectionToLatest];
|
||||
|
||||
if (thread.uniqueId.length > 0) {
|
||||
self.messageMappings = [[YapDatabaseViewMappings alloc] initWithGroups:@[ thread.uniqueId ]
|
||||
view:TSMessageDatabaseViewExtensionName];
|
||||
} else {
|
||||
OWSFail(@"uniqueId unexpectedly empty for thread: %@", thread);
|
||||
self.messageMappings =
|
||||
[[YapDatabaseViewMappings alloc] initWithGroups:@[] view:TSMessageDatabaseViewExtensionName];
|
||||
return;
|
||||
[self createNewMessageMappings];
|
||||
if (![self reloadViewItems]) {
|
||||
OWSFail(@"%@ failed to reload view items in configureForThread.", self.logTag);
|
||||
}
|
||||
|
||||
// Cells' appearance can depend on adjacent cells in both directions.
|
||||
[self.messageMappings setCellDrawingDependencyOffsets:[NSSet setWithArray:@[
|
||||
@(-1),
|
||||
@(+1),
|
||||
]]
|
||||
forGroup:self.thread.uniqueId];
|
||||
|
||||
// We need to impose the range restrictions on the mappings immediately to avoid
|
||||
// doing a great deal of unnecessary work and causing a perf hotspot.
|
||||
[self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
[self.messageMappings updateWithTransaction:transaction];
|
||||
}];
|
||||
[self updateMessageMappingRangeOptions];
|
||||
[self updateShouldObserveDBModifications];
|
||||
|
||||
self.reloadTimer = [NSTimer weakScheduledTimerWithTimeInterval:1.f
|
||||
|
@ -814,7 +796,9 @@ typedef enum : NSUInteger {
|
|||
// Avoid layout corrupt issues and out-of-date message subtitles.
|
||||
self.lastReloadDate = [NSDate new];
|
||||
self.collapseCutoffDate = [NSDate new];
|
||||
[self reloadViewItems];
|
||||
if (![self reloadViewItems]) {
|
||||
OWSFail(@"%@ failed to reload view items in resetContentAndLayout.", self.logTag);
|
||||
}
|
||||
[self.collectionView.collectionViewLayout invalidateLayout];
|
||||
[self.collectionView reloadData];
|
||||
}
|
||||
|
@ -1771,7 +1755,6 @@ typedef enum : NSUInteger {
|
|||
[self.messageMappings setRangeOptions:rangeOptions forGroup:self.thread.uniqueId];
|
||||
[self updateShowLoadMoreHeader];
|
||||
self.collapseCutoffDate = [NSDate new];
|
||||
[self reloadViewItems];
|
||||
}
|
||||
|
||||
#pragma mark Bubble User Actions
|
||||
|
@ -3241,7 +3224,7 @@ typedef enum : NSUInteger {
|
|||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
|
||||
DDLogVerbose(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
|
||||
DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
|
||||
|
||||
if (self.shouldObserveDBModifications) {
|
||||
// External database modifications can't be converted into incremental updates,
|
||||
|
@ -3250,12 +3233,14 @@ typedef enum : NSUInteger {
|
|||
//
|
||||
// We don't need to do this if we're not observing db modifications since we'll
|
||||
// do it when we resume.
|
||||
[self resetMappings];
|
||||
[self hardResetMappings];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)uiDatabaseWillUpdate:(NSNotification *)notification
|
||||
{
|
||||
DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
|
||||
|
||||
// HACK to work around radar #28167779
|
||||
// "UICollectionView performBatchUpdates can trigger a crash if the collection view is flagged for layout"
|
||||
// more: https://github.com/PSPDFKit-labs/radar.apple.com/tree/master/28167779%20-%20CollectionViewBatchingIssue
|
||||
|
@ -3265,14 +3250,17 @@ typedef enum : NSUInteger {
|
|||
// We want to relayout our contents using the old message mappings and
|
||||
// view items before they are updated.
|
||||
[self.collectionView layoutIfNeeded];
|
||||
// ENDHACK to work around radar #28167779
|
||||
// ENDHACK to work around radar #28167779)
|
||||
}
|
||||
|
||||
- (void)uiDatabaseDidUpdate:(NSNotification *)notification
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
|
||||
DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
|
||||
|
||||
if (!self.shouldObserveDBModifications) {
|
||||
DDLogInfo(@"%@ %s ignoring", self.logTag, __PRETTY_FUNCTION__);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -3378,14 +3366,21 @@ typedef enum : NSUInteger {
|
|||
// These errors seems to be very rare; they can only be reproduced
|
||||
// using the more extreme actions in the debug UI.
|
||||
OWSFail(@"%@ hasMalformedRowChange", self.logTag);
|
||||
[self resetContentAndLayout];
|
||||
[self hardResetMappings];
|
||||
[self updateLastVisibleTimestamp];
|
||||
[self scrollToBottomAnimated:NO];
|
||||
return;
|
||||
}
|
||||
|
||||
NSUInteger oldViewItemCount = self.viewItems.count;
|
||||
[self reloadViewItems];
|
||||
if (![self reloadViewItems]) {
|
||||
// These errors are rare.
|
||||
OWSFail(@"%@ could not reload view items; hard resetting message mappings.", self.logTag);
|
||||
[self hardResetMappings];
|
||||
[self updateLastVisibleTimestamp];
|
||||
[self scrollToBottomAnimated:NO];
|
||||
return;
|
||||
}
|
||||
|
||||
BOOL wasAtBottom = [self isScrolledToBottom];
|
||||
// We want sending messages to feel snappy. So, if the only
|
||||
|
@ -4800,6 +4795,40 @@ typedef enum : NSUInteger {
|
|||
self.previousLastTimestamp = nil;
|
||||
}
|
||||
|
||||
- (void)createNewMessageMappings
|
||||
{
|
||||
if (self.thread.uniqueId.length > 0) {
|
||||
self.messageMappings = [[YapDatabaseViewMappings alloc] initWithGroups:@[ self.thread.uniqueId ]
|
||||
view:TSMessageDatabaseViewExtensionName];
|
||||
} else {
|
||||
OWSFail(@"uniqueId unexpectedly empty for thread: %@", self.thread);
|
||||
self.messageMappings =
|
||||
[[YapDatabaseViewMappings alloc] initWithGroups:@[] view:TSMessageDatabaseViewExtensionName];
|
||||
}
|
||||
|
||||
// Cells' appearance can depend on adjacent cells in both directions.
|
||||
[self.messageMappings setCellDrawingDependencyOffsets:[NSSet setWithArray:@[
|
||||
@(-1),
|
||||
@(+1),
|
||||
]]
|
||||
forGroup:self.thread.uniqueId];
|
||||
|
||||
// We need to impose the range restrictions on the mappings immediately to avoid
|
||||
// doing a great deal of unnecessary work and causing a perf hotspot.
|
||||
[self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
[self.messageMappings updateWithTransaction:transaction];
|
||||
}];
|
||||
[self updateMessageMappingRangeOptions];
|
||||
}
|
||||
|
||||
- (void)hardResetMappings
|
||||
{
|
||||
DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
|
||||
|
||||
[self createNewMessageMappings];
|
||||
[self resetMappings];
|
||||
}
|
||||
|
||||
- (void)resetMappings
|
||||
{
|
||||
// If we're entering "active" mode (e.g. view is visible and app is in foreground),
|
||||
|
@ -4814,7 +4843,6 @@ typedef enum : NSUInteger {
|
|||
[self updateMessageMappingRangeOptions];
|
||||
}
|
||||
self.collapseCutoffDate = [NSDate new];
|
||||
[self reloadViewItems];
|
||||
|
||||
[self resetContentAndLayout];
|
||||
[self ensureDynamicInteractions];
|
||||
|
@ -4849,7 +4877,9 @@ typedef enum : NSUInteger {
|
|||
|
||||
// This is a key method. It builds or rebuilds the list of
|
||||
// cell view models.
|
||||
- (void)reloadViewItems
|
||||
//
|
||||
// Returns NO on error.
|
||||
- (BOOL)reloadViewItems
|
||||
{
|
||||
NSMutableArray<ConversationViewItem *> *viewItems = [NSMutableArray new];
|
||||
NSMutableDictionary<NSString *, ConversationViewItem *> *viewItemCache = [NSMutableDictionary new];
|
||||
|
@ -4857,6 +4887,7 @@ typedef enum : NSUInteger {
|
|||
NSUInteger count = [self.messageMappings numberOfItemsInSection:0];
|
||||
BOOL isGroupThread = self.isGroupConversation;
|
||||
|
||||
__block BOOL hasError = NO;
|
||||
[self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
YapDatabaseViewTransaction *viewTransaction = [transaction ext:TSMessageDatabaseViewExtensionName];
|
||||
OWSAssert(viewTransaction);
|
||||
|
@ -4869,6 +4900,7 @@ typedef enum : NSUInteger {
|
|||
(unsigned long)row,
|
||||
(unsigned long)count);
|
||||
// TODO: Add analytics.
|
||||
hasError = YES;
|
||||
continue;
|
||||
}
|
||||
if (!interaction.uniqueId) {
|
||||
|
@ -4878,6 +4910,7 @@ typedef enum : NSUInteger {
|
|||
(unsigned long)count,
|
||||
interaction);
|
||||
// TODO: Add analytics.
|
||||
hasError = YES;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -5122,6 +5155,8 @@ typedef enum : NSUInteger {
|
|||
|
||||
self.viewItems = viewItems;
|
||||
self.viewItemCache = viewItemCache;
|
||||
|
||||
return !hasError;
|
||||
}
|
||||
|
||||
// Whenever an interaction is modified, we need to reload it from the DB
|
||||
|
|
Loading…
Reference in a new issue