Fix BuildPlanExecutor thread pool leak on constructor failure - #12748
Fix BuildPlanExecutor thread pool leak on constructor failure#12748ulofiai wants to merge 1 commit into
Conversation
Signed-off-by: ulofiai <monsterking@tutamail.com>
gnodet
left a comment
There was a problem hiding this comment.
Verdict: APPROVE ✅
Correct and minimal fix for a real thread pool resource leak. Reordering the executor creation to after buildInitialPlan() ensures that if plan initialization throws, no thread pool is leaked because it has not yet been allocated.
Key verification:
buildInitialPlan()does not referencethis.executor, so the reordering is safe and preserves identical behavior on the success path.- Since
BuildContextis used in a try-with-resources and Java only callsclose()after a constructor completes successfully, the pre-fix code leaked the thread pool on any exception frombuildInitialPlan().
Clean, surgical fix.
This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.
Claude Code on behalf of gnodet
gnodet
left a comment
There was a problem hiding this comment.
APPROVE — Correct and minimal fix for a real thread pool resource leak.
Reordering executor creation to after buildInitialPlan() ensures no thread pool is allocated if plan construction throws, with no behavioral change on the success path.
Analysis:
- The bug is real: on
master, theBuildContextconstructor creates aPhasingExecutor(wrappingExecutors.newFixedThreadPool) before callingbuildInitialPlan(). Since the constructor is invoked insideexecute()'s try-with-resources, a throw frombuildInitialPlan()means the constructor never completes, Java never callsclose(), and the thread pool leaks indefinitely. - The reorder is safe:
buildInitialPlan()does not referencethis.executor, either directly or transitively. It only readsthis.session(already assigned), outer-class fields, and thetaskSegmentsparameter. - No null-safety concern:
close()doesthis.executor.close()without a null check, butclose()is only reachable via try-with-resources after a successful constructor, soexecutoris always non-null at that point.
Minor observations (non-blocking, pre-existing):
buildInitialPlan()redundantly recalculatesnThreadsand callssession.setParallel(), duplicating the constructor setup.close()has no null guard onthis.executor, which would NPE if invoked on the unused no-arg constructor. Theoretical only.
This review was generated by an AI agent (Claude Code) and may contain inaccuracies. Please verify all suggestions before applying.
Claude Code on behalf of Guillaume Nodet
Fixes #12599.
Build the initial plan before creating the
PhasingExecutor. If plan construction throws,BuildContextnow fails before allocating the executor, so cleanup cannot be skipped.The change is limited to the initialization order in
BuildPlanExecutor.