Skip to content

Commit 6ae6927

Browse files
committed
Fix a race that could lead to unnecessary scheduling of two update index store tasks
1 parent 3787ca8 commit 6ae6927

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
@@ -638,7 +648,7 @@ package final actor SemanticIndexManager {
638648
if registeredTask == preparationTaskID {
639649
self.inProgressIndexTasks[fileAndTarget.file] = nil
640650
}
641-
case nil:
651+
case .creatingIndexTask, nil:
642652
break
643653
}
644654
}
@@ -686,6 +696,19 @@ package final actor SemanticIndexManager {
686696
// Sort the targets in topological order so that low-level targets get built before high-level targets, allowing us
687697
// to index the low-level targets ASAP.
688698
var filesByTarget: [BuildTargetIdentifier: [FileToIndex]] = [:]
699+
700+
// The number of index tasks that don't currently have an in-progress task associated with it.
701+
// The denominator in the index progress should get incremented by this amount.
702+
// We don't want to increment the denominator for tasks that already have an index in progress.
703+
var newIndexTasks = 0
704+
for file in outOfDateFiles {
705+
if inProgressIndexTasks[file] == nil {
706+
newIndexTasks += 1
707+
}
708+
inProgressIndexTasks[file] = .creatingIndexTask
709+
}
710+
indexTasksWereScheduled(newIndexTasks)
711+
689712
for fileToIndex in outOfDateFiles {
690713
guard let target = await buildSystemManager.canonicalTarget(for: fileToIndex.mainFile) else {
691714
logger.error(
@@ -766,10 +789,6 @@ package final actor SemanticIndexManager {
766789
}
767790
indexTasks.append(indexTask)
768791

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

0 commit comments

Comments
 (0)