Skip to content

ensure shutdown of the symlink planting pool#28657

Closed
benjaminp wants to merge 1 commit intobazelbuild:masterfrom
benjaminp:symlink-leak
Closed

ensure shutdown of the symlink planting pool#28657
benjaminp wants to merge 1 commit intobazelbuild:masterfrom
benjaminp:symlink-leak

Conversation

@benjaminp
Copy link
Copy Markdown
Collaborator

I was iteratively fixing some build failures with bazel and realized bazel was becoming more and more sluggish. Taking a thread dump, I observed way too many symlink planting threads:

$ grep -c 'Non-eager Symlink planter ' stacks.txt
36800

Try harder to ensure the symlink planting thread pool is released after the build is done.

@github-actions github-actions Bot added the awaiting-review PR is awaiting review from an assigned reviewer label Feb 12, 2026
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request addresses a resource leak where the symlink planting thread pool was not being shut down, leading to sluggishness in Bazel. The fix introduces a more robust shutdown mechanism by calling a new shutdown() method from a finally block, ensuring the thread pool is always released. The changes in ExecutionTool.java correctly plumb the IncrementalPackageRoots instance to the finalization logic. My review includes one high-severity comment on a potential race condition in the new shutdown() method in IncrementalPackageRoots.java.

Comment thread src/main/java/com/google/devtools/build/lib/skyframe/IncrementalPackageRoots.java Outdated
@benjaminp
Copy link
Copy Markdown
Collaborator Author

/gemini review

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request addresses a resource leak by ensuring the symlink planting thread pool is shut down at the end of a build. The changes introduce a shutdown() method and call it from a finally block for robustness. My review focuses on consolidating all related cleanup logic into this new robust shutdown() method to prevent other potential memory leaks on build failure paths.

Comment on lines +379 to +385
public void shutdown() {
synchronized (symlinkPlantingPool) {
if (!symlinkPlantingPool.isShutdown()) {
ExecutorUtil.uninterruptibleShutdownNow(symlinkPlantingPool);
}
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

This new shutdown() method is a great step towards preventing thread leaks. However, other cleanup logic in dropIntermediateStatesAndUnregisterFromEventBus() is only triggered on successful analysis, which can lead to memory leaks on failure paths since this IncrementalPackageRoots instance is retained across builds.

To make the cleanup more robust, I recommend consolidating all cleanup logic from dropIntermediateStatesAndUnregisterFromEventBus() into this shutdown() method, as it's called from a finally block in ExecutionTool. This includes unregistering from the event bus and clearing other state.

  public void shutdown() {
    if (eventBus != null) {
      try {
        eventBus.unregister(this);
      } catch (IllegalArgumentException e) {
        // Already unregistered, ignore.
      }
      eventBus = null;
    }

    synchronized (stateLock) {
      donePackages = null;
      lazilyPlantedSymlinks = null;
      maybeConflictingBaseNamesLowercase = ImmutableSet.of();
    }

    synchronized (symlinkPlantingPool) {
      if (!symlinkPlantingPool.isShutdown()) {
        ExecutorUtil.uninterruptibleShutdownNow(symlinkPlantingPool);
      }
    }
  }

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the assumption that IncrementalPackageRoots is retained across builds is not true.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is. Just that it's always replaced by another instance of IncrementalPackageRoots at the beginning of the next build. Feel free to treat that as out of scope for this PR though.

IncrementalPackageRoots incrementalPackageRoots =
IncrementalPackageRoots.createAndRegisterToEventBus(
getExecRoot(),
// Single package path is a Skymeld prerequisite.
Iterables.getOnlyElement(env.getPackageLocator().getPathEntries()),
env.getEventBus(),
env.getDirectories().getProductName() + "-",
skyframeExecutor.getIgnoredPaths(),
request.getOptions(BuildLanguageOptions.class).experimentalSiblingRepositoryLayout,
runtime.getWorkspace().doesAllowExternalRepositories());
incrementalPackageRoots.eagerlyPlantSymlinksToSingleSourceRoot();
env.getSkyframeBuildView()
.getArtifactFactory()
.setPackageRoots(incrementalPackageRoots.getPackageRootLookup());

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose it is nicer for the exceptional and successful cleanup logic to be the same. So, I've updated the PR to put all logic in shutdown and also call that on analysis completion.

@fmeum
Copy link
Copy Markdown
Collaborator

fmeum commented Feb 12, 2026

@joeleba

@iancha1992 iancha1992 added the team-Local-Exec Issues and PRs for the Execution (Local) team label Feb 17, 2026
@meisterT
Copy link
Copy Markdown
Member

Change looks good to me, but I want Joe to also have a look when he is back next week

@joeleba joeleba assigned joeleba and unassigned joeleba Feb 25, 2026
Copy link
Copy Markdown
Member

@joeleba joeleba left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. It's up to you whether you wanna address the suggestion by gemini.

I was iteratively fixing some build failures with bazel and realized bazel was becoming more and more sluggish. Taking a thread dump, I observed way too many symlink planting threads:
```
$ grep -c 'Non-eager Symlink planter ' stacks.txt
36800
```

Try harder to ensure the symlink planting thread pool is released after the build is done.
@joeleba joeleba added awaiting-PR-merge PR has been approved by a reviewer and is ready to be merge internally and removed awaiting-review PR is awaiting review from an assigned reviewer labels Feb 26, 2026
@github-actions github-actions Bot removed the awaiting-PR-merge PR has been approved by a reviewer and is ready to be merge internally label Feb 27, 2026
@benjaminp benjaminp deleted the symlink-leak branch February 27, 2026 14:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

team-Local-Exec Issues and PRs for the Execution (Local) team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants