-
Notifications
You must be signed in to change notification settings - Fork 12.9k
Tune FAR aggregation #49581
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Tune FAR aggregation #49581
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -380,7 +380,7 @@ namespace ts.server { | |
// correct results to all other projects. | ||
|
||
const defaultProjectResults = perProjectResults.get(defaultProject); | ||
if (defaultProjectResults?.[0].references[0]?.isDefinition === undefined) { | ||
if (defaultProjectResults?.[0]?.references[0]?.isDefinition === undefined) { | ||
// Clear all isDefinition properties | ||
perProjectResults.forEach(projectResults => { | ||
for (const referencedSymbol of projectResults) { | ||
|
@@ -531,26 +531,35 @@ namespace ts.server { | |
defaultDefinition : | ||
defaultProject.getLanguageService().getSourceMapper().tryGetSourcePosition(defaultDefinition!)); | ||
|
||
// Track which projects we have already searched so that we don't repeat searches. | ||
// We store the project key, rather than the project, because that's what `loadAncestorProjectTree` wants. | ||
// (For that same reason, we don't use `resultsMap` for this check.) | ||
const searchedProjects = new Set<string>(); | ||
// The keys of resultsMap allow us to check which projects have already been searched, but we also | ||
// maintain a set of strings because that's what `loadAncestorProjectTree` wants. | ||
const searchedProjectKeys = new Set<string>(); | ||
|
||
onCancellation: | ||
while (queue.length) { | ||
while (queue.length) { | ||
if (cancellationToken.isCancellationRequested()) break onCancellation; | ||
|
||
let skipCount = 0; | ||
for (; skipCount < queue.length && resultsMap.has(queue[skipCount].project); skipCount++); | ||
|
||
if (skipCount === queue.length) { | ||
queue.length = 0; | ||
break; | ||
} | ||
|
||
if (skipCount > 0) { | ||
queue.splice(0, skipCount); | ||
} | ||
|
||
// NB: we may still skip if it's a project reference redirect | ||
const { project, location } = queue.shift()!; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it make more sense long-term not to de-queue at all? Just iterate through and toss the array at the end? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess not, then it would just get longer and longer. |
||
|
||
if (isLocationProjectReferenceRedirect(project, location)) continue; | ||
|
||
if (!tryAddToSet(searchedProjects, getProjectKey(project))) continue; | ||
|
||
const projectResults = searchPosition(project, location); | ||
if (projectResults) { | ||
resultsMap.set(project, projectResults); | ||
} | ||
resultsMap.set(project, projectResults ?? emptyArray); | ||
searchedProjectKeys.add(getProjectKey(project)); | ||
} | ||
|
||
// At this point, we know about all projects passed in as arguments and any projects in which | ||
|
@@ -559,10 +568,10 @@ namespace ts.server { | |
// containing `initialLocation`. | ||
if (defaultDefinition) { | ||
// This seems to mean "load all projects downstream from any member of `seenProjects`". | ||
projectService.loadAncestorProjectTree(searchedProjects); | ||
projectService.loadAncestorProjectTree(searchedProjectKeys); | ||
projectService.forEachEnabledProject(project => { | ||
if (cancellationToken.isCancellationRequested()) return; // There's no mechanism for skipping the remaining projects | ||
if (searchedProjects.has(getProjectKey(project))) return; // Can loop forever without this (enqueue here, dequeue above, repeat) | ||
if (resultsMap.has(project)) return; // Can loop forever without this (enqueue here, dequeue above, repeat) | ||
const location = mapDefinitionInProject(defaultDefinition, project, getGeneratedDefinition, getSourceDefinition); | ||
if (location) { | ||
queue.push({ project, location }); | ||
|
@@ -573,9 +582,10 @@ namespace ts.server { | |
|
||
// In the common case where there's only one project, return a simpler result to make | ||
// it easier for the caller to skip post-processing. | ||
if (searchedProjects.size === 1) { | ||
if (resultsMap.size === 1) { | ||
const it = resultsMap.values().next(); | ||
return it.done ? emptyArray : it.value; // There may not be any results at all | ||
Debug.assert(!it.done); | ||
return it.value; | ||
} | ||
|
||
return resultsMap; | ||
|
@@ -593,7 +603,7 @@ namespace ts.server { | |
const originalScriptInfo = projectService.getScriptInfo(originalLocation.fileName)!; | ||
|
||
for (const project of originalScriptInfo.containingProjects) { | ||
if (!project.isOrphan()) { | ||
if (!project.isOrphan() && !resultsMap.has(project)) { // Optimization: don't enqueue if will be discarded | ||
queue.push({ project, location: originalLocation }); | ||
} | ||
} | ||
|
@@ -602,7 +612,7 @@ namespace ts.server { | |
if (symlinkedProjectsMap) { | ||
symlinkedProjectsMap.forEach((symlinkedProjects, symlinkedPath) => { | ||
for (const symlinkedProject of symlinkedProjects) { | ||
if (!symlinkedProject.isOrphan()) { | ||
if (!symlinkedProject.isOrphan() && !resultsMap.has(symlinkedProject)) { // Optimization: don't enqueue if will be discarded | ||
queue.push({ project: symlinkedProject, location: { fileName: symlinkedPath as string, pos: originalLocation.pos } }); | ||
} | ||
} | ||
|
Uh oh!
There was an error while loading. Please reload this page.