Skip to content

Commit 1a32c4a

Browse files
committed
Fix a race that could lead to unnecessary scheduling of two update index store tasks
1 parent 0cb7c82 commit 1a32c4a

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
@@ -327,6 +335,8 @@ package final actor SemanticIndexManager {
327335

328336
await inProgressIndexTasks.concurrentForEach { (_, status) in
329337
switch status {
338+
case .creatingIndexTask:
339+
break
330340
case .waitingForPreparation(preparationTaskID: _, indexTask: let indexTask),
331341
.preparing(preparationTaskID: _, indexTask: let indexTask),
332342
.updatingIndexStore(updateIndexStoreTask: _, indexTask: let indexTask):
@@ -448,7 +458,7 @@ package final actor SemanticIndexManager {
448458
}
449459
.filter {
450460
switch inProgressIndexTasks[$0] {
451-
case .waitingForPreparation:
461+
case .waitingForPreparation, .creatingIndexTask:
452462
return false
453463
default:
454464
return true
@@ -639,7 +649,7 @@ package final actor SemanticIndexManager {
639649
if registeredTask == preparationTaskID {
640650
self.inProgressIndexTasks[fileAndTarget.file] = nil
641651
}
642-
case nil:
652+
case .creatingIndexTask, nil:
643653
break
644654
}
645655
}
@@ -687,6 +697,19 @@ package final actor SemanticIndexManager {
687697
// Sort the targets in topological order so that low-level targets get built before high-level targets, allowing us
688698
// to index the low-level targets ASAP.
689699
var filesByTarget: [BuildTargetIdentifier: [FileToIndex]] = [:]
700+
701+
// The number of index tasks that don't currently have an in-progress task associated with it.
702+
// The denominator in the index progress should get incremented by this amount.
703+
// We don't want to increment the denominator for tasks that already have an index in progress.
704+
var newIndexTasks = 0
705+
for file in outOfDateFiles {
706+
if inProgressIndexTasks[file] == nil {
707+
newIndexTasks += 1
708+
}
709+
inProgressIndexTasks[file] = .creatingIndexTask
710+
}
711+
indexTasksWereScheduled(newIndexTasks)
712+
690713
for fileToIndex in outOfDateFiles {
691714
guard let target = await buildSystemManager.canonicalTarget(for: fileToIndex.mainFile) else {
692715
logger.error(
@@ -767,10 +790,6 @@ package final actor SemanticIndexManager {
767790
}
768791
indexTasks.append(indexTask)
769792

770-
// The number of index tasks that don't currently have an in-progress task associated with it.
771-
// The denominator in the index progress should get incremented by this amount.
772-
// We don't want to increment the denominator for tasks that already have an index in progress.
773-
let newIndexTasks = filesToIndex.filter { inProgressIndexTasks[$0] == nil }.count
774793
for file in filesToIndex {
775794
// The state of `inProgressIndexTasks` will get pushed on from `updateIndexStore`.
776795
// The updates to `inProgressIndexTasks` from `updateIndexStore` cannot race with setting it to
@@ -782,7 +801,6 @@ package final actor SemanticIndexManager {
782801
indexTask: indexTask
783802
)
784803
}
785-
indexTasksWereScheduled(newIndexTasks)
786804
}
787805

788806
return Task(priority: priority) {

0 commit comments

Comments
 (0)