Skip to content

Commit c01c676

Browse files
committed
Extract tuple from SemanticIndexManager.preparationStatus into a struct
1 parent fb0801a commit c01c676

File tree

1 file changed

+28
-17
lines changed

1 file changed

+28
-17
lines changed

Sources/SemanticIndex/SemanticIndexManager.swift

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,19 @@ private enum IndexStatus<T> {
3838
}
3939
}
4040

41+
/// See `SemanticIndexManager.preparationStatus`
42+
private struct PreparationTaskStatusData {
43+
/// A UUID to track the task. This is used to ensure that status updates from this task don't update
44+
/// `preparationStatus` for targets that are tracked by a different task.
45+
let taskID: UUID
46+
47+
/// The list of targets that are being prepared in a joint preparation operation.
48+
let targets: [ConfiguredTarget]
49+
50+
/// The task that prepares the target
51+
let task: Task<Void, Never>
52+
}
53+
4154
/// Schedules index tasks and keeps track of the index status of files.
4255
public final actor SemanticIndexManager {
4356
/// The underlying index. This is used to check if the index of a file is already up-to-date, in which case it doesn't
@@ -54,13 +67,7 @@ public final actor SemanticIndexManager {
5467
/// The preparation status of the targets that the `SemanticIndexManager` has started preparation for.
5568
///
5669
/// Targets will be removed from this dictionary when they are no longer known to be up-to-date.
57-
///
58-
/// The associated values of the `IndexStatus` are:
59-
/// - A UUID to track the task. This is used to ensure that status updates from this task don't update
60-
/// `preparationStatus` for targets that are tracked by a different task.
61-
/// - The list of targets that are being prepared in a joint preparation operation
62-
/// - The task that prepares the target
63-
private var preparationStatus: [ConfiguredTarget: IndexStatus<(UUID, [ConfiguredTarget], Task<Void, Never>)>] = [:]
70+
private var preparationStatus: [ConfiguredTarget: IndexStatus<PreparationTaskStatusData>] = [:]
6471

6572
/// The index status of the source files that the `SemanticIndexManager` knows about.
6673
///
@@ -268,16 +275,16 @@ public final actor SemanticIndexManager {
268275
switch preparationStatus[target] {
269276
case .upToDate:
270277
break
271-
case .scheduled((_, let existingTaskTargets, let task)), .executing((_, let existingTaskTargets, let task)):
278+
case .scheduled(let existingTaskData), .executing(let existingTaskData):
272279
// If we already have a task scheduled that prepares fewer targets, await that instead of overriding the
273280
// target's preparation status with a longer-running task. The key benefit here is that when we get many
274281
// preparation requests for the same target (eg. one for every text document request sent to a file), we don't
275282
// re-create new `PreparationTaskDescription`s for every preparation request. Instead, all the preparation
276283
// requests await the same task. At the same time, if we have a multi-file preparation request and then get a
277284
// single-file preparation request, we will override the preparation of that target with the single-file
278285
// preparation task, ensuring that the task gets prepared as quickly as possible.
279-
if existingTaskTargets.count <= targets.count {
280-
preparationTasksToAwait.append(task)
286+
if existingTaskData.targets.count <= targets.count {
287+
preparationTasksToAwait.append(existingTaskData.task)
281288
} else {
282289
targetsToPrepare.append(target)
283290
}
@@ -301,20 +308,22 @@ public final actor SemanticIndexManager {
301308
switch newState {
302309
case .executing:
303310
for target in targetsToPrepare {
304-
if case .scheduled((taskID, let targets, let task)) = self.preparationStatus[target] {
305-
self.preparationStatus[target] = .executing((taskID, targets, task))
311+
if case .scheduled(let existingTaskData) = self.preparationStatus[target], existingTaskData.taskID == taskID
312+
{
313+
self.preparationStatus[target] = .executing(existingTaskData)
306314
}
307315
}
308316
case .cancelledToBeRescheduled:
309317
for target in targetsToPrepare {
310-
if case .executing((taskID, let targets, let task)) = self.preparationStatus[target] {
311-
self.preparationStatus[target] = .scheduled((taskID, targets, task))
318+
if case .executing(let existingTaskData) = self.preparationStatus[target], existingTaskData.taskID == taskID
319+
{
320+
self.preparationStatus[target] = .scheduled(existingTaskData)
312321
}
313322
}
314323
case .finished:
315324
for target in targetsToPrepare {
316325
switch self.preparationStatus[target] {
317-
case .executing((taskID, _, _)):
326+
case .executing(let existingTaskData) where existingTaskData.taskID == taskID:
318327
self.preparationStatus[target] = .upToDate
319328
default:
320329
break
@@ -324,14 +333,16 @@ public final actor SemanticIndexManager {
324333
}
325334
}
326335
for target in targetsToPrepare {
327-
preparationStatus[target] = .scheduled((taskID, targetsToPrepare, preparationTask))
336+
preparationStatus[target] = .scheduled(
337+
PreparationTaskStatusData(taskID: taskID, targets: targetsToPrepare, task: preparationTask)
338+
)
328339
}
329340
preparationTasksToAwait.append(preparationTask)
330341
}
331342
await withTaskGroup(of: Void.self) { taskGroup in
332343
for task in preparationTasksToAwait {
333344
taskGroup.addTask {
334-
await task.value
345+
await task.valuePropagatingCancellation
335346
}
336347
}
337348
await taskGroup.waitForAll()

0 commit comments

Comments
 (0)