gnodet commented on issue #12445:
URL: https://github.com/apache/maven/issues/12445#issuecomment-4916148318
## Detailed Root-Cause Analysis
Looking at the code and thread dump more carefully, here is the full call
chain in the deadlock:
### Stack Trace Breakdown
The main thread holds locks on **three** CachingSupplier instances, nested:
```
CS_inner locked <0x000000070dae4860> ← CachingSupplier for the
ResolverRequest (innermost)
CS_outer locked <0x000000070dadd910> ← CachingSupplier for
ArtifactResolverRequest
CS_model locked <0x000000070dad7c40> ← CachingSupplier for model resolution
```
The call chain is:
1. `ProcessRemoteResourcesMojo.getProjects()` → Velocity template triggers
project building
2. `DefaultModelBuilder.resolveParent()` → needs external parent POM
3. `DefaultModelResolver.resolveModel()` → **`session.request()`**
(singular) → `doCache()` → `CS_model.apply()` → runs lambda
4. Lambda → `AbstractSession.resolveArtifact()` →
`ArtifactResolver.resolve()` → **`session.request()`** (singular) → `doCache()`
→ `CS_outer.apply()` → runs `doResolve()`
5. `doResolve()` → **`session.requests()`** (plural) → creates
`individualSupplier` that waits on `nonCachedResults` HashMap
6. For each ResolverRequest: `doCache(req, individualSupplier)` → creates
`CS_inner(individualSupplier)` → added to `nonCached`
7. Batch execution: `batchSupplier.apply(nonCached)` → calls
`resolveArtifacts()` → **returns results**
8. Results put into `nonCachedResults`, `notifyAll()` called
9. **Result collection**: `CS_inner.apply(req)` →
`individualSupplier.apply(req)` → `nonCachedResults.containsKey(req)` →
**false** → `wait()`
10. **DEADLOCK**: main thread waits forever, all worker threads idle
### The Critical Question
At step 9, `nonCachedResults.containsKey(req)` returns false even though the
batch completed at step 7. This means either:
**A)** The batch supplier returned fewer results than `nonCached.size()` —
in `DefaultArtifactResolver.doResolve()`:
```java
List<ResolverResult> res = new ArrayList<>(resolverResults.size());
for (int i = 0; i < resolverResults.size(); i++) {
res.add(new ResolverResult(list.get(i), resolverResults.get(i)));
}
```
This iterates `resolverResults.size()`, not `list.size()`. If
`resolveArtifacts()` returns fewer results than requests (e.g., due to
deduplication), some requests won't be put into `nonCachedResults`.
**B)** `doCache()` returned a CachingSupplier from a **previous**
`requests()` invocation (via the session-scoped cache). That older
CachingSupplier wraps an `individualSupplier` from a different call, which
waits on a different `nonCachedResults` HashMap that will never be notified
again. This can happen if:
- A previous `requests()` call created the CachingSupplier
- The CachingSupplier's soft reference was GC'd and recreated incorrectly
- Or `computeIfAbsent` on the `RefConcurrentMap` has a race condition
with eviction
**C)** An uncaught exception (not `MavenExecutionException`) was thrown and
handled in a way that makes `nonCachedResults` empty but still reaches the
result collection loop.
### Suggested Fix Direction
The `requests()` method should not use `wait()/notifyAll()` on a local
HashMap shared between the `individualSupplier` closure and the batch
execution. Instead, consider:
1. **Direct approach**: After batch execution, directly set each
`CachingSupplier.value` from the batch results, bypassing `individualSupplier`
entirely for the result collection phase.
2. **Defensive fix**: In the result collection loop (line 144), check if the
result is already in `nonCachedResults` **before** calling `cs.apply()`. If it
is, use the value directly instead of going through the CachingSupplier.
3. **Timeout-based safety**: Add a timeout to `nonCachedResults.wait()` with
a clear error message, so builds fail fast instead of hanging forever.
### Full Thread Dump
The full thread dump is in the issue description. Key observations:
- **Only the main thread is active** — all 15 worker threads
(BfDependencyCollector, BasicRepositoryConnector, resolver) are idle in their
thread pool queues
- The main thread has been stuck for 60 seconds (elapsed=60.30s,
cpu=3900.83ms)
- No other thread is doing any work related to artifact resolution
--
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]