Skip to content

Commit 25c5a52

Browse files
committed
Handle prepare task cancellation based on the purpose
1 parent 7c96ab6 commit 25c5a52

File tree

3 files changed

+33
-28
lines changed

3 files changed

+33
-28
lines changed

Sources/SemanticIndex/PreparationTaskDescription.swift

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ package struct PreparationTaskDescription: IndexTaskDescription {
3939

4040
private let preparationUpToDateTracker: UpToDateTracker<BuildTargetIdentifier, DummySecondaryKey>
4141

42+
/// The purpose of the preparation task.
43+
private let purpose: TargetPreparationPurpose
44+
4245
/// See `SemanticIndexManager.logMessageToIndexLog`.
4346
private let logMessageToIndexLog:
4447
@Sendable (_ message: String, _ type: WindowMessageType, _ structure: StructuredLogKind) -> Void
@@ -63,6 +66,7 @@ package struct PreparationTaskDescription: IndexTaskDescription {
6366
targetsToPrepare: [BuildTargetIdentifier],
6467
buildServerManager: BuildServerManager,
6568
preparationUpToDateTracker: UpToDateTracker<BuildTargetIdentifier, DummySecondaryKey>,
69+
purpose: TargetPreparationPurpose,
6670
logMessageToIndexLog:
6771
@escaping @Sendable (
6872
_ message: String, _ type: WindowMessageType, _ structure: StructuredLogKind
@@ -72,6 +76,7 @@ package struct PreparationTaskDescription: IndexTaskDescription {
7276
self.targetsToPrepare = targetsToPrepare
7377
self.buildServerManager = buildServerManager
7478
self.preparationUpToDateTracker = preparationUpToDateTracker
79+
self.purpose = purpose
7580
self.logMessageToIndexLog = logMessageToIndexLog
7681
self.hooks = hooks
7782
}
@@ -119,14 +124,22 @@ package struct PreparationTaskDescription: IndexTaskDescription {
119124
to currentlyExecutingTasks: [PreparationTaskDescription]
120125
) -> [TaskDependencyAction<PreparationTaskDescription>] {
121126
return currentlyExecutingTasks.compactMap { (other) -> TaskDependencyAction<PreparationTaskDescription>? in
122-
if other.targetsToPrepare.count > self.targetsToPrepare.count {
123-
// If there is an prepare operation with more targets already running, suspend it.
124-
// The most common use case for this is if we prepare all targets simultaneously during the initial preparation
125-
// when a project is opened and need a single target indexed for user interaction. We should suspend the
126-
// workspace-wide preparation and just prepare the currently needed target.
127+
if other.purpose == .forIndexing && self.purpose == .forEditorFunctionality {
128+
// If we're running a background indexing operation but need a target indexed for user interaction,
129+
// we should prioritize the latter.
127130
return .cancelAndRescheduleDependency(other)
128131
}
129132
return .waitAndElevatePriorityOfDependency(other)
130133
}
131134
}
132135
}
136+
137+
/// The reason why a target is being prepared. This is used to determine the `IndexProgressStatus`
138+
/// and to prioritize preparation tasks when several of them are running.
139+
package enum TargetPreparationPurpose: Comparable {
140+
/// We are preparing the target so we can index files in it.
141+
case forIndexing
142+
143+
/// We are preparing the target to provide semantic functionality in one of its files.
144+
case forEditorFunctionality
145+
}

Sources/SemanticIndex/SemanticIndexManager.swift

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -145,15 +145,6 @@ private struct InProgressPrepareForEditorTask {
145145
let task: Task<Void, Never>
146146
}
147147

148-
/// The reason why a target is being prepared. This is used to determine the `IndexProgressStatus`.
149-
private enum TargetPreparationPurpose: Comparable {
150-
/// We are preparing the target so we can index files in it.
151-
case forIndexing
152-
153-
/// We are preparing the target to provide semantic functionality in one of its files.
154-
case forEditorFunctionality
155-
}
156-
157148
/// An entry in `SemanticIndexManager.inProgressPreparationTasks`.
158149
private struct InProgressPreparationTask {
159150
let task: OpaqueQueuedIndexTask
@@ -222,8 +213,8 @@ package final actor SemanticIndexManager {
222213
/// The parameter is the number of files that were scheduled to be indexed.
223214
private let indexTasksWereScheduled: @Sendable (_ numberOfFileScheduled: Int) -> Void
224215

225-
/// Determines whether or not the `SemanticIndexManager` should dispatch preparation tasks in batches.
226-
private let shouldIndexInParallel: Bool
216+
/// The size of the batches in which the `SemanticIndexManager` should dispatch preparation tasks.
217+
private let indexTaskBatchSize: Int
227218

228219
/// Callback that is called when `progressStatus` might have changed.
229220
private let indexProgressStatusDidChange: @Sendable () -> Void
@@ -264,7 +255,7 @@ package final actor SemanticIndexManager {
264255
updateIndexStoreTimeout: Duration,
265256
hooks: IndexHooks,
266257
indexTaskScheduler: TaskScheduler<AnyIndexTaskDescription>,
267-
shouldIndexInParallel: Bool,
258+
indexTaskBatchSize: Int,
268259
logMessageToIndexLog:
269260
@escaping @Sendable (
270261
_ message: String, _ type: WindowMessageType, _ structure: StructuredLogKind
@@ -277,7 +268,7 @@ package final actor SemanticIndexManager {
277268
self.updateIndexStoreTimeout = updateIndexStoreTimeout
278269
self.hooks = hooks
279270
self.indexTaskScheduler = indexTaskScheduler
280-
self.shouldIndexInParallel = shouldIndexInParallel
271+
self.indexTaskBatchSize = indexTaskBatchSize
281272
self.logMessageToIndexLog = logMessageToIndexLog
282273
self.indexTasksWereScheduled = indexTasksWereScheduled
283274
self.indexProgressStatusDidChange = indexProgressStatusDidChange
@@ -660,6 +651,7 @@ package final actor SemanticIndexManager {
660651
targetsToPrepare: targetsToPrepare,
661652
buildServerManager: self.buildServerManager,
662653
preparationUpToDateTracker: preparationUpToDateTracker,
654+
purpose: purpose,
663655
logMessageToIndexLog: logMessageToIndexLog,
664656
hooks: hooks
665657
)
@@ -882,14 +874,7 @@ package final actor SemanticIndexManager {
882874

883875
var indexTasks: [Task<Void, Never>] = []
884876

885-
let batchSize: Int
886-
if shouldIndexInParallel {
887-
let processorCount = ProcessInfo.processInfo.activeProcessorCount
888-
batchSize = max(1, processorCount * 5)
889-
} else {
890-
batchSize = 1
891-
}
892-
for targetsBatch in sortedTargets.partition(intoBatchesOfSize: batchSize) {
877+
for targetsBatch in sortedTargets.partition(intoBatchesOfSize: indexTaskBatchSize) {
893878
let preparationTaskID = UUID()
894879
let filesToIndex = targetsBatch.flatMap({ filesByTarget[$0]! })
895880

@@ -913,7 +898,7 @@ package final actor SemanticIndexManager {
913898
// And after preparation is done, index the files in the targets.
914899
await withTaskGroup(of: Void.self) { taskGroup in
915900
for target in targetsBatch {
916-
for fileBatch in filesByTarget[target]!.partition(intoBatchesOfSize: batchSize) {
901+
for fileBatch in filesByTarget[target]!.partition(intoBatchesOfSize: indexTaskBatchSize) {
917902
taskGroup.addTask {
918903
await self.updateIndexStore(
919904
for: fileBatch,

Sources/SourceKitLSP/Workspace.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,13 +163,20 @@ package final class Workspace: Sendable, BuildServerManagerDelegate {
163163
await buildServerManager.initializationData?.prepareProvider ?? false
164164
{
165165
let shouldIndexInParallel = await buildServerManager.initializationData?.multiTargetPreparation?.supported ?? true
166+
let batchSize: Int
167+
if shouldIndexInParallel {
168+
let processorCount = ProcessInfo.processInfo.activeProcessorCount
169+
batchSize = max(1, processorCount * 5)
170+
} else {
171+
batchSize = 1
172+
}
166173
self.semanticIndexManager = SemanticIndexManager(
167174
index: uncheckedIndex,
168175
buildServerManager: buildServerManager,
169176
updateIndexStoreTimeout: options.indexOrDefault.updateIndexStoreTimeoutOrDefault,
170177
hooks: hooks.indexHooks,
171178
indexTaskScheduler: indexTaskScheduler,
172-
shouldIndexInParallel: shouldIndexInParallel,
179+
indexTaskBatchSize: batchSize,
173180
logMessageToIndexLog: { [weak sourceKitLSPServer] in
174181
sourceKitLSPServer?.logMessageToIndexLog(message: $0, type: $1, structure: $2)
175182
},

0 commit comments

Comments
 (0)