Skip to content

Commit 9e0da9d

Browse files
committed
Fix a race that could lead to unnecessary scheduling of two update index store tasks
1 parent ba35f6d commit 9e0da9d

File tree

1 file changed

+26
-8
lines changed

1 file changed

+26
-8
lines changed

Sources/SemanticIndex/SemanticIndexManager.swift

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,14 @@ private struct OpaqueQueuedIndexTask: Equatable {
5353
}
5454

5555
private enum InProgressIndexStore {
56+
/// We know that we need to index the file but and are currently gathering all information to create the `indexTask`
57+
/// that will index it.
58+
///
59+
/// This is needed to avoid the following race: We request indexing of file A. Getting the canonical target for A
60+
/// takes a bit and before that finishes, we request another index of A. In this case, we don't want to kick off
61+
/// two tasks to update the index store.
62+
case creatingIndexTask
63+
5664
/// We are waiting for preparation of the file's target to be scheduled. The next step is that we wait for
5765
/// preparation to finish before we can update the index store for this file.
5866
///
@@ -223,7 +231,7 @@ package final actor SemanticIndexManager {
223231
}
224232
let indexTasks = inProgressIndexTasks.mapValues { status in
225233
switch status {
226-
case .waitingForPreparation, .preparing:
234+
case .creatingIndexTask, .waitingForPreparation, .preparing:
227235
return IndexTaskStatus.scheduled
228236
case .updatingIndexStore(updateIndexStoreTask: let updateIndexStoreTask, indexTask: _):
229237
return updateIndexStoreTask.isExecuting ? IndexTaskStatus.executing : IndexTaskStatus.scheduled
@@ -334,6 +342,8 @@ package final actor SemanticIndexManager {
334342
await withTaskGroup(of: Void.self) { taskGroup in
335343
for (_, status) in inProgressIndexTasks {
336344
switch status {
345+
case .creatingIndexTask:
346+
break
337347
case .waitingForPreparation(preparationTaskID: _, indexTask: let indexTask),
338348
.preparing(preparationTaskID: _, indexTask: let indexTask),
339349
.updatingIndexStore(updateIndexStoreTask: _, indexTask: let indexTask):
@@ -459,7 +469,7 @@ package final actor SemanticIndexManager {
459469
}
460470
.filter {
461471
switch inProgressIndexTasks[$0] {
462-
case .waitingForPreparation:
472+
case .waitingForPreparation, .creatingIndexTask:
463473
return false
464474
default:
465475
return true
@@ -650,7 +660,7 @@ package final actor SemanticIndexManager {
650660
if registeredTask == preparationTaskID {
651661
self.inProgressIndexTasks[fileAndTarget.file] = nil
652662
}
653-
case nil:
663+
case .creatingIndexTask, nil:
654664
break
655665
}
656666
}
@@ -698,6 +708,19 @@ package final actor SemanticIndexManager {
698708
// Sort the targets in topological order so that low-level targets get built before high-level targets, allowing us
699709
// to index the low-level targets ASAP.
700710
var filesByTarget: [BuildTargetIdentifier: [FileToIndex]] = [:]
711+
712+
// The number of index tasks that don't currently have an in-progress task associated with it.
713+
// The denominator in the index progress should get incremented by this amount.
714+
// We don't want to increment the denominator for tasks that already have an index in progress.
715+
var newIndexTasks = 0
716+
for file in outOfDateFiles {
717+
if inProgressIndexTasks[file] == nil {
718+
newIndexTasks += 1
719+
}
720+
inProgressIndexTasks[file] = .creatingIndexTask
721+
}
722+
indexTasksWereScheduled(newIndexTasks)
723+
701724
for fileToIndex in outOfDateFiles {
702725
guard let target = await buildSystemManager.canonicalTarget(for: fileToIndex.mainFile) else {
703726
logger.error(
@@ -778,10 +801,6 @@ package final actor SemanticIndexManager {
778801
}
779802
indexTasks.append(indexTask)
780803

781-
// The number of index tasks that don't currently have an in-progress task associated with it.
782-
// The denominator in the index progress should get incremented by this amount.
783-
// We don't want to increment the denominator for tasks that already have an index in progress.
784-
let newIndexTasks = filesToIndex.filter { inProgressIndexTasks[$0] == nil }.count
785804
for file in filesToIndex {
786805
// The state of `inProgressIndexTasks` will get pushed on from `updateIndexStore`.
787806
// The updates to `inProgressIndexTasks` from `updateIndexStore` cannot race with setting it to
@@ -793,7 +812,6 @@ package final actor SemanticIndexManager {
793812
indexTask: indexTask
794813
)
795814
}
796-
indexTasksWereScheduled(newIndexTasks)
797815
}
798816
let indexTasksImmutable = indexTasks
799817

0 commit comments

Comments
 (0)