crossmate

A collaborative crossword app for iOS
Log | Files | Refs | LICENSE

commit d537bc60350fdd2b614fb698f183cb1e5b7c59ee
parent 7434e62513449d783bce6112fbaee72a21a5f4a6
Author: Michael Camilleri <[email protected]>
Date:   Wed, 13 May 2026 05:08:25 +0900

Parallelise refreshLibrary across database scopes

Pull-to-refresh ran five phases strictly back-to-back: private discovery,
shared discovery, private known-zone updates, shared known-zone updates, and a
final engine fetch. The four direct-fetch phases hit two independent CloudKit
databases, so the private and shared sides had no reason to wait for each other
— but the serial structure made the wall-time the sum of all four rather than
the slowest pair.

The two scope-specific pipelines now run concurrently via async let.  Discovery
still completes before known-zone updates within a scope so any zone that
discovery just inserted is included in the same refresh — the known-zone list
is read from Core Data at the start of its phase, so overlapping the two within
a scope would leave new zones for the next pull. Engine fetch keeps its
position as the final step; it already parallelises private and shared
internally, so wrapping it would gain nothing.

Co-Authored-By: Claude Opus 4.7 <[email protected]>

Diffstat:
MCrossmate/Services/AppServices.swift | 28++++++++++++++++------------
1 file changed, 16 insertions(+), 12 deletions(-)

diff --git a/Crossmate/Services/AppServices.swift b/Crossmate/Services/AppServices.swift @@ -266,24 +266,28 @@ final class AppServices { /// reality when the engine has been idle. func refreshLibrary() async { guard await ensureICloudSyncStarted() else { return } - await syncMonitor.run("library refresh: private discovery") { - _ = try await syncEngine.discoverNewZonesDirect(scope: .private) - } - await syncMonitor.run("library refresh: shared discovery") { - _ = try await syncEngine.discoverNewZonesDirect(scope: .shared) - } - await syncMonitor.run("library refresh: private known-zone updates") { - _ = try await syncEngine.fetchKnownZoneUpdatesDirect(scope: .private) - } - await syncMonitor.run("library refresh: shared known-zone updates") { - _ = try await syncEngine.fetchKnownZoneUpdatesDirect(scope: .shared) - } + // Private and shared hit different CloudKit databases, so their + // direct-fetch phases run as an independent pair. Within each + // scope, discovery still completes before known-zone updates so + // any zone discovery just added is included in the same refresh. + async let privatePhase: Void = refreshLibraryScope(.private, label: "private") + async let sharedPhase: Void = refreshLibraryScope(.shared, label: "shared") + _ = await (privatePhase, sharedPhase) await syncMonitor.run("library refresh: engine fetch") { try await syncEngine.fetchChanges(source: "library refresh") } await refreshSnapshot() } + private func refreshLibraryScope(_ scope: CKDatabase.Scope, label: String) async { + await syncMonitor.run("library refresh: \(label) discovery") { + _ = try await self.syncEngine.discoverNewZonesDirect(scope: scope) + } + await syncMonitor.run("library refresh: \(label) known-zone updates") { + _ = try await self.syncEngine.fetchKnownZoneUpdatesDirect(scope: scope) + } + } + func syncOpenSharedPuzzle() async { await movesUpdater.flush() guard await ensureICloudSyncStarted() else { return }