> The key detail is that classified/attached artifacts (sources.jar,
test-jar, javadoc.jar, consumer POMs) are only resolvable from
project-local-repo during resume. The target/classes fallback in
ReactorReader only handles plain jars without classifiers. <

Ok, is it an option to create module/target/local-repo-classifier.xml with
the index of exposed artifacts, create only on successful build, so module
of the reactor (which is even skipped in "-pl" option) is aware of which
artifacts it can take from the module target directory. In this case we do
not need a special rootDir/target/project-local-repo


On Wed, Aug 5, 2026 at 5:07 PM Sergey Chernov <[email protected]>
wrote:

> >I am by no means familiar with this part of Maven, but would it be an
> option to place "clean" and "install" in separate TaskSegments to avoid
> the race condition completely?
>
> Yes, I was talking about the same. There was a comment regarding it that
> "compile 4.x+ plugin will compile the code of all modules", but I have very
> strong concerns it's how actually the thing work.
>
> "mvn clean install -T4" now executes all phases of clean lifecycle +
> all phases of install lifecycle (subset of "default" lifecycle) in a list
> of mojos, in a single foreach loop.
> Instead, it should run clean lifecycle for all modules, and only then run
> install lifecycle for all modules.
>
> For example, Gradle does it this way and I find this more correct.
>
>
> On Wed, Aug 5, 2026 at 10:49 AM Maarten Mulders <[email protected]>
> wrote:
>
>> Hi Guillaume,
>>
>> Your problem statement seems clear to me, but from the three approaches,
>> it seems to me all three target a consequence of the root cause.
>> > Since clean and install are placed into the same TaskSegment [...]
>>
>> I am by no means familiar with this part of Maven, but would it be an
>> option to place "clean" and "install" in separate TaskSegments to avoid
>> the race condition completely? If I understand correctly, it would also
>> make it practically impossible to "clean" something that was "install"ed
>> just (the ordering problem when using a lock-based approach).
>>
>> Apart from that, I would not be a big fan of a solution that moves the
>> project-local-repo *outside* the project directory (approach 2).
>>
>> Thanks,
>>
>> Maarten
>>
>> On 03/08/2026 14:09, Guillaume Nodet wrote:
>> > Hi all,
>> >
>> > I'd like to get your input on the fix for GH-12646 — a race condition
>> with
>> > project-local-repo during parallel clean install builds.
>> >
>> > The problem
>> >
>> > When the root pom.xml has a parent that is also part of the reactor
>> (e.g. a
>> > super-pom), MultiThreadedBuilder schedules the parent first, then runs
>> the
>> > root project and child modules concurrently. Since clean and install are
>> > placed into the same TaskSegment, there is no barrier between them — the
>> > root project's maven-clean-plugin can delete target/ while sibling
>> modules
>> > are concurrently writing artifacts into target/project-local-repo,
>> causing
>> > the build to fail.
>> >
>> > Approaches considered
>> >
>> > 1. Lock-based synchronization (ReentrantReadWriteLock in ReactorReader)
>> >
>> > Acquire a write lock when the project owning target/ enters its clean
>> > phase, and a read lock when installing artifacts. This prevents the
>> crash
>> > (concurrent access) but does not guarantee ordering — a module could
>> > install artifacts before the root's clean starts, only to have them
>> wiped.
>> > It also adds complexity to ReactorReader for what is fundamentally an
>> > architectural problem.
>> >
>> > 2. Move project-local-repo to ~/.m2/ (user home)
>> >
>> > E.g. ~/.m2/local-repository/${projectName}_${hash}, similar to how
>> IntelliJ
>> > stores project caches. This avoids both the race and the git concern,
>> but:
>> > - Hard links (already used by ReactorReader) cannot cross filesystem
>> > boundaries — if ~/.m2/ is on a different volume, every artifact becomes
>> a
>> > full copy
>> > - Stale directories accumulate when projects are deleted/moved, with no
>> > cleanup mechanism
>> > - CI containers often share ~/.m2/ across builds, causing unwanted
>> > accumulation
>> > - Loses project locality (harder to inspect/debug)
>> >
>> > 3. Move project-local-repo to .mvn/project-local-repo (chosen)
>> >
>> > Move the directory from target/project-local-repo to
>> > .mvn/project-local-repo. Since maven-clean-plugin only deletes target/,
>> the
>> > race becomes structurally impossible. ReactorReader fully owns the
>> > lifecycle — per-GAV cleanup when a project enters its clean phase,
>> install
>> > on project success. The existing hard-link optimization continues to
>> work
>> > since both directories are on the same filesystem.
>> >
>> > The trade-off is that .mvn/project-local-repo needs to be gitignored.
>> This
>> > follows the Gradle convention where .gradle/ at the project root is
>> > universally in .gitignore templates. Maven could also document this
>> > convention or consider auto-appending the entry.
>> >
>> > The fix itself is minimal — the core change is a single line in
>> > getProjectLocalRepo(), and the rest is removing the lock infrastructure
>> > (net -40 lines).
>> >
>> > 4. Keep in target/ but use maven-clean-plugin fast mode
>> >
>> > The fast clean option (maven.clean.fast=true, since plugin 3.2)
>> atomically
>> > renames target/ instead of recursively deleting it. This would likely
>> avoid
>> > the race, but it's opt-in and not the default — users hitting the bug
>> would
>> > need to know about it.
>> >
>> > FWIW, a PR has been raised on m-clean-p master branch (4.x) to refactor
>> the
>> > fast cleaner (fixing problems) and make it the default.
>> >
>> > Open questions
>> >
>> > - Is .mvn/ the right location, or should we consider a different
>> > project-root directory?
>> > - Should Maven auto-add .mvn/project-local-repo to .gitignore, or
>> document
>> > it as a convention?
>> > - Are there other considerations I'm missing?
>> >
>> > PR: https://github.com/apache/maven/pull/12650
>> > Issue: https://github.com/apache/maven/issues/12646
>> >
>> > Looking forward to your thoughts.
>> >
>> >   Cheers
>> > Guillaume Nodet
>> >
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: [email protected]
>> For additional commands, e-mail: [email protected]
>>
>>

Reply via email to