From 6bf9af9be3bc5a84089db094d587f9ec5ab2d459 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Wed, 3 Jun 2020 11:40:37 -0300 Subject: [PATCH] De-bounce database observation. --- .../ViewControllers/DebugUI/DebugUIStress.m | 119 ++++++++++++++---- .../Snapshots/UIDatabaseSnapshot.swift | 3 +- 2 files changed, 100 insertions(+), 22 deletions(-) diff --git a/Signal/src/ViewControllers/DebugUI/DebugUIStress.m b/Signal/src/ViewControllers/DebugUI/DebugUIStress.m index 49adea5802..c86e6abbef 100644 --- a/Signal/src/ViewControllers/DebugUI/DebugUIStress.m +++ b/Signal/src/ViewControllers/DebugUI/DebugUIStress.m @@ -14,6 +14,7 @@ #import #import #import +#import #import #import @@ -21,8 +22,26 @@ NS_ASSUME_NONNULL_BEGIN +@interface DebugUIStress () + +@property (nonatomic, nullable) NSTimer *thrashTimer; + +@end + +#pragma mark - + @implementation DebugUIStress ++ (instancetype)shared +{ + static DebugUIStress *instance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + instance = [self new]; + }); + return instance; +} + #pragma mark - Dependencies + (MessageSenderJobQueue *)messageSenderJobQueue @@ -40,6 +59,11 @@ NS_ASSUME_NONNULL_BEGIN return SDSDatabaseStorage.shared; } +- (SDSDatabaseStorage *)databaseStorage +{ + return SDSDatabaseStorage.shared; +} + + (TSAccountManager *)tsAccountManager { return TSAccountManager.sharedInstance; @@ -457,14 +481,18 @@ NS_ASSUME_NONNULL_BEGIN [DebugUIStress makeUnregisteredGroup]; }]]; + __weak DebugUIStress *weakSelf = self; [items addObject:[OWSTableItem itemWithTitle:@"Thrash writes 10/second" actionBlock:^{ - [DebugUIStress thrashWithMaxWritesPerSecond:10 thread:thread]; + [weakSelf thrashWithMaxWritesPerSecond:10 thread:thread]; }]]; - [items addObject:[OWSTableItem itemWithTitle:@"Thrash writes 100/second" actionBlock:^{ - [DebugUIStress thrashWithMaxWritesPerSecond:100 thread:thread]; + [weakSelf thrashWithMaxWritesPerSecond:100 thread:thread]; + }]]; + [items addObject:[OWSTableItem itemWithTitle:@"Stop thrash" + actionBlock:^{ + [weakSelf stopThrash]; }]]; return [OWSTableSection sectionWithTitle:self.name items:items]; @@ -572,36 +600,85 @@ NS_ASSUME_NONNULL_BEGIN }]; } -+ (void)thrashWithMaxWritesPerSecond:(NSUInteger)maxWritesPerSecond thread:(TSThread *)thread +- (void)thrashWithMaxWritesPerSecond:(NSUInteger)maxWritesPerSecond thread:(TSThread *)thread { + NSTimeInterval delaySeconds = kSecondInterval / maxWritesPerSecond; + __block uint64_t counter = 0; + [self stopThrash]; + DebugUIStress.shared.thrashTimer = [NSTimer + scheduledTimerWithTimeInterval:delaySeconds + repeats:YES + block:^(NSTimer *timer) { + counter = counter + 1; + OWSLogVerbose(@"counter: %llu", counter); + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [self thrashWritesWithThread:thread]; + }); + }]; +} + +- (void)thrashWritesWithThread:(TSThread *)thread +{ + __block TSThread *interactionThread = thread; + __block TSThread *_Nullable otherThread = nil; + BOOL shouldUseOtherThread = arc4random_uniform(2) == 0; + if (shouldUseOtherThread) { + [self.databaseStorage writeWithBlock:^(SDSAnyWriteTransaction *transaction) { + BOOL shouldUseGroupThread = arc4random_uniform(2) == 0; + if (shouldUseGroupThread) { + NSError *_Nullable error; + otherThread = + [GroupManager remoteUpsertExistingGroupV1WithGroupId:[TSGroupModel generateRandomV1GroupId] + name:NSUUID.UUID.UUIDString + avatarData:nil + members:@[] + disappearingMessageToken:nil + groupUpdateSourceAddress:nil + infoMessagePolicy:InfoMessagePolicyAlways + transaction:transaction + error:&error] + .groupThread; + if (error != nil) { + OWSFailDebug(@"error: %@", error); + } + } else { + SignalServiceAddress *otherAddress = [[SignalServiceAddress alloc] initWithUuid:NSUUID.UUID]; + otherThread = [TSContactThread getOrCreateThreadWithContactAddress:otherAddress + transaction:transaction]; + } + interactionThread = otherThread; + }]; + } + NSString *text = NSUUID.UUID.UUIDString; - TSOutgoingMessageBuilder *messageBuilder = [TSOutgoingMessageBuilder outgoingMessageBuilderWithThread:thread - messageBody:text]; + TSOutgoingMessageBuilder *messageBuilder = + [TSOutgoingMessageBuilder outgoingMessageBuilderWithThread:interactionThread messageBody:text]; TSOutgoingMessage *message = [messageBuilder build]; [self.databaseStorage writeWithBlock:^(SDSAnyWriteTransaction *transaction) { [message anyInsertWithTransaction:transaction]; }]; - NSTimeInterval delaySeconds = kSecondInterval / maxWritesPerSecond; - __block uint64_t counter = 0; - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - [NSTimer scheduledTimerWithTimeInterval:delaySeconds - repeats:YES - block:^(NSTimer *timer) { - counter = counter + 1; - OWSLogVerbose(@"counter: %llu", counter); - [self thrashWritesWithThread:thread message:message]; - }]; - }); -} - -+ (void)thrashWritesWithThread:(TSThread *)thread message:(TSOutgoingMessage *)message -{ [self.databaseStorage writeWithBlock:^(SDSAnyWriteTransaction *transaction) { [message updateWithFakeMessageState:TSOutgoingMessageStateSending transaction:transaction]; [message updateWithFakeMessageState:TSOutgoingMessageStateFailed transaction:transaction]; }]; + + BOOL shouldDelete = arc4random_uniform(2) == 0; + if (shouldDelete) { + [self.databaseStorage writeWithBlock:^(SDSAnyWriteTransaction *transaction) { + [message anyRemoveWithTransaction:transaction]; + if (otherThread != nil) { + [otherThread anyRemoveWithTransaction:transaction]; + } + }]; + } +} + +- (void)stopThrash +{ + [DebugUIStress.shared.thrashTimer invalidate]; + DebugUIStress.shared.thrashTimer = nil; } @end diff --git a/SignalServiceKit/src/Storage/Database/Snapshots/UIDatabaseSnapshot.swift b/SignalServiceKit/src/Storage/Database/Snapshots/UIDatabaseSnapshot.swift index 915abfd0e0..f3d6aabd4b 100644 --- a/SignalServiceKit/src/Storage/Database/Snapshots/UIDatabaseSnapshot.swift +++ b/SignalServiceKit/src/Storage/Database/Snapshots/UIDatabaseSnapshot.swift @@ -161,7 +161,8 @@ extension UIDatabaseObserver: TransactionObserver { if let lastSnapshotUpdateDate = self.lastSnapshotUpdateDate { let secondsSinceLastUpdate = abs(lastSnapshotUpdateDate.timeIntervalSinceNow) // Don't update UI more often than Nx/second. - let maxUpdateFrequencySeconds: TimeInterval = 1/TimeInterval(5) + let maxUpdatesPerSecond: UInt = 5 + let maxUpdateFrequencySeconds: TimeInterval = 1 / TimeInterval(maxUpdatesPerSecond) let delaySeconds = maxUpdateFrequencySeconds - secondsSinceLastUpdate if delaySeconds > 0 { Logger.verbose("Updating db snapshot after: \(delaySeconds).")