Skip to content

Commit 263d012

Browse files
Put interaction-index manipulations inside a Bencher
1 parent 96a7606 commit 263d012

File tree

4 files changed

+93
-47
lines changed

4 files changed

+93
-47
lines changed

.swiftlint.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ excluded:
88
- Signal/Emoji/EmojiWithSkinTones+String.swift
99
disabled_rules:
1010
- block_based_kvo
11+
- closure_parameter_position
1112
- compiler_protocol_init
1213
- control_statement
1314
- cyclomatic_complexity

SignalServiceKit/Environment/AppSetup.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1081,6 +1081,7 @@ public class AppSetup {
10811081
appVersion: appVersion,
10821082
attachmentDownloadManager: attachmentDownloadManager,
10831083
attachmentUploadManager: attachmentUploadManager,
1084+
avatarFetcher: messageBackupAvatarFetcher,
10841085
backupAttachmentDownloadManager: backupAttachmentDownloadManager,
10851086
backupAttachmentUploadManager: backupAttachmentUploadManager,
10861087
backupRequestManager: messageBackupRequestManager,

SignalServiceKit/MessageBackup/MessageBackup+Bench.swift

Lines changed: 48 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ extension MessageBackup {
1616
private let startDate: MonotonicDate
1717

1818
private var totalFramesProcessed: UInt64 = 0
19-
private var metrics = [FrameType: Metrics]()
19+
private var preFrameMetrics = [PreFrameRestoreAction: Metrics]()
20+
private var frameMetrics = [FrameType: Metrics]()
2021
private var postFrameMetrics = [PostFrameRestoreAction: Metrics]()
2122

2223
init(
@@ -50,18 +51,6 @@ extension MessageBackup {
5051
return try block(frameBencher)
5152
}
5253

53-
/// Measures the clock time spent in the provided block.
54-
func benchPostFrameAction(_ action: PostFrameRestoreAction, _ block: () throws -> Void) rethrows -> Void {
55-
let startDate = dateProvider()
56-
try block()
57-
let durationMs = dateProvider().millisSince(startDate)
58-
var metrics = postFrameMetrics[action] ?? Metrics()
59-
metrics.frameCount += 1
60-
metrics.totalDurationMs += durationMs
61-
metrics.maxDurationMs = max(durationMs, metrics.maxDurationMs)
62-
postFrameMetrics[action] = metrics
63-
}
64-
6554
/// Given a block that does an enumeration over db objects, wraps that enumeration to instead take
6655
/// a closure with a FrameBencher that also measures the time spent enumerating.
6756
func wrapEnumeration<Input, T, Output>(
@@ -102,6 +91,33 @@ extension MessageBackup {
10291
}
10392
}
10493

94+
func benchPreFrameAction<T>(_ action: PreFrameRestoreAction, _ block: () throws -> T) rethrows -> T {
95+
return try benchAction(action, actionMetricsKeyPath: \.preFrameMetrics, block: block)
96+
}
97+
98+
func benchPostFrameAction<T>(_ action: PostFrameRestoreAction, _ block: () throws -> T) rethrows -> T {
99+
return try benchAction(action, actionMetricsKeyPath: \.postFrameMetrics, block: block)
100+
}
101+
102+
/// Measures the clock time spent in the provided block.
103+
private func benchAction<Action: Hashable, T>(
104+
_ action: Action,
105+
actionMetricsKeyPath: ReferenceWritableKeyPath<Bencher, [Action: Metrics]>,
106+
block: () throws -> T
107+
) rethrows -> T {
108+
let startDate = dateProvider()
109+
let result = try block()
110+
let durationMs = dateProvider().millisSince(startDate)
111+
112+
var metrics = self[keyPath: actionMetricsKeyPath][action] ?? Metrics()
113+
metrics.frameCount += 1
114+
metrics.totalDurationMs += durationMs
115+
metrics.maxDurationMs = max(durationMs, metrics.maxDurationMs)
116+
self[keyPath: actionMetricsKeyPath][action] = metrics
117+
118+
return result
119+
}
120+
105121
class DBFileSizeBencher {
106122
private let dateProvider: DateProviderMonotonic
107123
private let dbFileSizeProvider: DBFileSizeProvider
@@ -165,7 +181,7 @@ extension MessageBackup {
165181
let durationMs = bencher.dateProvider().millisSince(startDate)
166182
bencher.totalFramesProcessed += 1
167183

168-
var metrics = bencher.metrics[frameType] ?? Metrics()
184+
var metrics = bencher.frameMetrics[frameType] ?? Metrics()
169185
metrics.frameCount += 1
170186
metrics.totalDurationMs += durationMs
171187
metrics.maxDurationMs = max(durationMs, metrics.maxDurationMs)
@@ -182,12 +198,12 @@ extension MessageBackup {
182198
metrics.totalEnumerationDurationMs += startDate.millisSince(beforeEnumerationStartDate)
183199
}
184200

185-
bencher.metrics[frameType] = metrics
201+
bencher.frameMetrics[frameType] = metrics
186202
}
187203
}
188204

189205
func logResults() {
190-
let totalFrameCount = metrics.reduce(0, { $0 + $1.value.frameCount })
206+
let totalFrameCount = frameMetrics.reduce(0, { $0 + $1.value.frameCount })
191207
Logger.info("Processed \(loggableCountString(totalFrameCount)) frames in \(dateProvider().millisSince(startDate))ms")
192208

193209
func logMetrics(_ metrics: Metrics, typeString: String) {
@@ -212,9 +228,17 @@ extension MessageBackup {
212228
Logger.info(logString)
213229
}
214230

215-
for (frameType, metrics) in self.metrics.sorted(by: { $0.value.totalDurationMs > $1.value.totalDurationMs }) {
231+
Logger.info("Pre-Frame Metrics:")
232+
for (action, metrics) in self.preFrameMetrics.sorted(by: { $0.value.totalDurationMs > $1.value.totalDurationMs }) {
233+
logMetrics(metrics, typeString: action.rawValue)
234+
}
235+
236+
Logger.info("Frame Metrics:")
237+
for (frameType, metrics) in self.frameMetrics.sorted(by: { $0.value.totalDurationMs > $1.value.totalDurationMs }) {
216238
logMetrics(metrics, typeString: frameType.rawValue)
217239
}
240+
241+
Logger.info("Post-Frame Metrics:")
218242
for (action, metrics) in self.postFrameMetrics.sorted(by: { $0.value.totalDurationMs > $1.value.totalDurationMs }) {
219243
logMetrics(metrics, typeString: action.rawValue)
220244
}
@@ -280,7 +304,7 @@ extension MessageBackup {
280304
}
281305
}
282306

283-
private enum FrameType: String, CaseIterable {
307+
private enum FrameType: String {
284308
case AccountData
285309

286310
case Recipient_Contact
@@ -414,12 +438,17 @@ extension MessageBackup {
414438
}
415439
}
416440

417-
enum PostFrameRestoreAction: String, CaseIterable {
441+
enum PreFrameRestoreAction: String {
442+
case DropInteractionIndexes
443+
}
444+
445+
enum PostFrameRestoreAction: String {
418446
case InsertContactHiddenInfoMessage
419447
case InsertPhoneNumberMissingAci
420448
case UpdateThreadMetadata
421449
case EnqueueAvatarFetch
422450
case IndexThreads
451+
case RecreateInteractionIndexes
423452
}
424453
}
425454
}

SignalServiceKit/MessageBackup/MessageBackupManagerImpl.swift

Lines changed: 43 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public class MessageBackupManagerImpl: MessageBackupManager {
3636
private let appVersion: AppVersion
3737
private let attachmentDownloadManager: AttachmentDownloadManager
3838
private let attachmentUploadManager: AttachmentUploadManager
39+
private let avatarFetcher: MessageBackupAvatarFetcher
3940
private let backupAttachmentDownloadManager: BackupAttachmentDownloadManager
4041
private let backupAttachmentUploadManager: BackupAttachmentUploadManager
4142
private let backupRequestManager: MessageBackupRequestManager
@@ -72,6 +73,7 @@ public class MessageBackupManagerImpl: MessageBackupManager {
7273
appVersion: AppVersion,
7374
attachmentDownloadManager: AttachmentDownloadManager,
7475
attachmentUploadManager: AttachmentUploadManager,
76+
avatarFetcher: MessageBackupAvatarFetcher,
7577
backupAttachmentDownloadManager: BackupAttachmentDownloadManager,
7678
backupAttachmentUploadManager: BackupAttachmentUploadManager,
7779
backupRequestManager: MessageBackupRequestManager,
@@ -105,6 +107,7 @@ public class MessageBackupManagerImpl: MessageBackupManager {
105107
self.appVersion = appVersion
106108
self.attachmentDownloadManager = attachmentDownloadManager
107109
self.attachmentUploadManager = attachmentUploadManager
110+
self.avatarFetcher = avatarFetcher
108111
self.backupAttachmentDownloadManager = backupAttachmentDownloadManager
109112
self.backupAttachmentUploadManager = backupAttachmentUploadManager
110113
self.backupRequestManager = backupRequestManager
@@ -675,14 +678,6 @@ public class MessageBackupManagerImpl: MessageBackupManager {
675678
) async throws {
676679
let result: Result<BackupProto_BackupInfo, Error> = await db.awaitableWriteWithTxCompletion { tx in
677680
do {
678-
/// Drops all indexes on the `TSInteraction` table before doing
679-
/// the import, which dramatically speeds up the import. We'll
680-
/// then recreate all these indexes in bulk afterwards.
681-
let interactionIndexes = try dropAllIndexes(
682-
forTable: InteractionRecord.databaseTableName,
683-
tx: tx
684-
)
685-
686681
let backupInfo = try Bench(
687682
title: benchTitle,
688683
memorySamplerRatio: FeatureFlags.messageBackupMemorySamplerRatio,
@@ -709,19 +704,6 @@ public class MessageBackupManagerImpl: MessageBackupManager {
709704
}
710705
}
711706

712-
let timeBeforeCreatingIndexes = dateProviderMonotonic()
713-
714-
/// Now that we've imported successfully, we want to recreate
715-
/// the indexes we temporarily dropped.
716-
try createIndexes(
717-
interactionIndexes,
718-
onTable: InteractionRecord.databaseTableName,
719-
tx: tx
720-
)
721-
722-
let timeAfterCreatingIndexes = dateProviderMonotonic()
723-
Logger.info("Created indexes in \(timeAfterCreatingIndexes.millisSince(timeBeforeCreatingIndexes))ms")
724-
725707
return .commit(.success(backupInfo))
726708
} catch let error {
727709
return .rollback(.failure(error))
@@ -750,6 +732,16 @@ public class MessageBackupManagerImpl: MessageBackupManager {
750732
throw OWSAssertionError("Restoring from backup twice!")
751733
}
752734

735+
// Drops all indexes on the `TSInteraction` table before doing the
736+
// import, which dramatically speeds up the import. We'll then recreate
737+
// all these indexes in bulk afterwards.
738+
let interactionIndexes = try bencher.benchPreFrameAction(.DropInteractionIndexes) {
739+
try dropAllIndexes(
740+
forTable: InteractionRecord.databaseTableName,
741+
tx: tx
742+
)
743+
}
744+
753745
var frameErrors = [LoggableErrorAndProto]()
754746
let result = Result<BackupProto_BackupInfo, Error>(catching: {
755747

@@ -1042,26 +1034,50 @@ public class MessageBackupManagerImpl: MessageBackupManager {
10421034

10431035
stream.closeFileStream()
10441036

1045-
/// Take any necessary post-frame-restore actions.
1037+
// Now that we've imported successfully, we want to recreate the
1038+
// the indexes we temporarily dropped.
1039+
try bencher.benchPostFrameAction(.RecreateInteractionIndexes) {
1040+
try createIndexes(
1041+
interactionIndexes,
1042+
onTable: InteractionRecord.databaseTableName,
1043+
tx: tx
1044+
)
1045+
}
1046+
1047+
// Take any necessary post-frame-restore actions.
10461048
try postFrameRestoreActionManager.performPostFrameRestoreActions(
10471049
recipientActions: contexts.recipient.postFrameRestoreActions,
10481050
chatActions: contexts.chat.postFrameRestoreActions,
10491051
bencher: bencher,
10501052
chatItemContext: contexts.chatItem
10511053
)
10521054

1053-
// Index threads synchronously
1055+
// Index threads synchronously, since that should be fast.
10541056
bencher.benchPostFrameAction(.IndexThreads) {
10551057
fullTextSearchIndexer.indexThreads(tx: tx)
10561058
}
1057-
// Schedule message indexing asynchronously
1059+
1060+
// Schedule background message indexing, since that'll be slow.
10581061
try fullTextSearchIndexer.scheduleMessagesJob(tx: tx)
10591062

1060-
tx.addAsyncCompletion(on: DispatchQueue.global()) { [backupAttachmentDownloadManager, disappearingMessagesJob] in
1063+
// Record that we've restored a Backup!
1064+
kvStore.setBool(true, key: Constants.keyValueStoreHasRestoredBackupKey, transaction: tx)
1065+
1066+
tx.addAsyncCompletion(on: DispatchQueue.global()) { [
1067+
avatarFetcher,
1068+
backupAttachmentDownloadManager,
1069+
disappearingMessagesJob
1070+
] in
1071+
Task {
1072+
// Kick off avatar fetches enqueued during restore.
1073+
try await avatarFetcher.runIfNeeded()
1074+
}
1075+
10611076
Task {
1062-
// Enqueue downloads for all the attachments.
1077+
// Kick off attachment downloads enqueued during restore.
10631078
try await backupAttachmentDownloadManager.restoreAttachmentsIfNeeded()
10641079
}
1080+
10651081
// Start ticking down for disappearing messages.
10661082
disappearingMessagesJob.startIfNecessary()
10671083
}
@@ -1071,10 +1087,9 @@ public class MessageBackupManagerImpl: MessageBackupManager {
10711087
Logger.info("Backup first app version: \(backupInfo.firstAppVersion.nilIfEmpty ?? "Missing!")")
10721088
bencher.logResults()
10731089

1074-
kvStore.setBool(true, key: Constants.keyValueStoreHasRestoredBackupKey, transaction: tx)
1075-
10761090
return backupInfo
10771091
})
1092+
10781093
processErrors(errors: frameErrors, didFail: result.isSuccess.negated, tx: tx)
10791094
return try result.get()
10801095
}

0 commit comments

Comments
 (0)