gnodet commented on issue #12586:
URL: https://github.com/apache/maven/issues/12586#issuecomment-5437590397
> :robot: **Note:** This analysis was generated by a coding agent and
requires manual verification. The hypotheses and suggestions below should be
reviewed by a human before taking action.
## Analysis
After deep investigation of the codebase, this appears to be **intentional
design**, not a bug.
The concurrent executor and the default executor use fundamentally different
architectures:
| Aspect | Default/Multithreaded Path | Concurrent Path |
|---|---|---|
| Concurrency unit | Entire projects | Individual lifecycle phases |
| Scheduling | Project-level DAG | Phase-level DAG (`BuildPlan`) |
| Intra-project concurrency | Never | Yes — by design |
| Safety mechanism | Runtime locks (`ProjectLock`) | Compile-time ordering
(DAG edges) |
The Maven 4 lifecycle is a **DAG, not a linear chain**. Independent phases
like `SOURCES` and `RESOURCES` are deliberate parallel siblings with no
ordering edge between them:
```
BUILD
SOURCES --| parallel siblings
RESOURCES --| (no ordering constraint)
COMPILE (after SOURCES)
READY (after COMPILE, after RESOURCES) ← join point
```
The `BuildPlanExecutor` only schedules a step when **all its predecessors
have completed** (via `AtomicInteger` CAS in `BuildStep.status`). Enabling the
per-project lock would serialize these parallel siblings, destroying the
concurrent executor's core feature.
### Direct evidence from the codebase
**1. Code comment in `DefaultLifecycleRegistry.addPhases()`** — when
computing a flat phase list for v3-compatible display:
> *"We add ordering between internal phases. This would be wrong at
execution time, but we are here computing a list and not a graph."*
**2. Test Javadoc in `BuildPlanCreatorTest.testAfterLinkProjectOrdering()`:**
> *"This is a real constraint: in the V4 lifecycle, 'compile' and
'resources' are parallel siblings (compile depends on sources, not resources),
so the @After link creates a genuine ordering edge that doesn't exist
naturally."*
**3. Fork handling is structural** — `computeForkPlan()` injects DAG nodes
with proper ordering at plan time. By the time `MojoExecutor.doExecute()` runs,
`forkedExecutions` is empty.
**4. Aggregation is plan-level** — aggregating goals get their own
`TaskSegment` with only the root project, making the aggregator lock
unnecessary.
### Conclusion
The DAG-based scheduling in `BuildPlanExecutor` subsumes the purpose of the
per-project lock. Multiple mojos *can* run concurrently on the same project,
but only when they belong to independent phases with no ordering constraint.
Phases that share state are connected via `after()` edges and execute
sequentially. Plugins needing additional ordering can declare `@After`
annotations.
Closing as works-as-designed.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]