ascheman commented on PR #12478:
URL: https://github.com/apache/maven/pull/12478#issuecomment-5011044438

   I tried to verify this PR empirically, and I think the two new tests don't 
actually guard against #12472:
   
   **Method**: checked out a pre-fix tree (`AbstractRequestCache` still with 
the old `individualSupplier` wait-on-map pattern, i.e. before c6de104bff) and 
ran the exact tests from this PR against it.
   
   | Test | pre-fix | PR head |
   |---|---|---|
   | `testConcurrentBatchRequestsWithSharedKeyDoNotDeadlock` / 
`testSequentialBatchRequestsWithSharedKeyReuseResult` | **pass** (4/4 runs, 
~0.5s — no hang) | pass |
   | variant with mutating `equals()`/`hashCode()` (below) | **deadlock** (10s 
timeout) | pass (1.5s) |
   
   So the pure identity-mismatch scenario as constructed here doesn't deadlock 
pre-fix. The ingredient that actually reproduces the #12472 hang is a shared 
key whose `equals()`/`hashCode()` change **during** batch resolution (mirroring 
mutable `RequestTrace` data in real requests): pre-fix, thread B waits on 
thread A's equals-based map for a key that no longer matches — forever. Good 
news: the variant passes on this PR's head, so the c6de104bff fix itself holds; 
it's only the regression guard that doesn't bite.
   
   Suggest replacing (or complementing) the concurrent test with this variant:
   
   ```java
   /**
    * Variant of the #12472 regression scenario where the shared request's
    * equals()/hashCode() change during batch resolution (mirroring mutable
    * RequestTrace data in real requests). Pre-fix, thread B waits on thread A's
    * equals-based nonCachedResults map for a key that no longer matches — 
forever.
    */
   @Test
   void testConcurrentBatchRequestsWithMutatingSharedKeyDoNotDeadlock() throws 
Exception {
       GenericCachingTestRequestCache cachingCache = new 
GenericCachingTestRequestCache();
   
       MutableHashCodeRequest reqOnlyA = new MutableHashCodeRequest("onlyA", 
"trace");
       MutableHashCodeRequest reqOnlyB = new MutableHashCodeRequest("onlyB", 
"trace");
       MutableHashCodeRequest sharedByA = new MutableHashCodeRequest("shared", 
"trace");
       MutableHashCodeRequest sharedByB = new MutableHashCodeRequest("shared", 
"trace");
   
       CountDownLatch aInBatch = new CountDownLatch(1);
   
       Function<List<MutableHashCodeRequest>, List<MutableHashCodeResult>> 
supplierA = reqs -> {
           aInBatch.countDown();
           try {
               Thread.sleep(1500);
           } catch (InterruptedException e) {
               Thread.currentThread().interrupt();
           }
           for (MutableHashCodeRequest r : reqs) {
               r.setTraceData(r.getTraceData() + "-A");
           }
           return reqs.stream().map(MutableHashCodeResult::new).toList();
       };
   
       Function<List<MutableHashCodeRequest>, List<MutableHashCodeResult>> 
supplierB = reqs -> {
           for (MutableHashCodeRequest r : reqs) {
               r.setTraceData(r.getTraceData() + "-B");
           }
           return reqs.stream().map(MutableHashCodeResult::new).toList();
       };
   
       ExecutorService executor = Executors.newFixedThreadPool(2);
       try {
           Future<List<MutableHashCodeResult>> futureA =
                   executor.submit(() -> 
cachingCache.requests(List.of(reqOnlyA, sharedByA), supplierA));
           assertTrue(aInBatch.await(5, TimeUnit.SECONDS), "Thread A should 
have entered its batch supplier");
           Future<List<MutableHashCodeResult>> futureB =
                   executor.submit(() -> 
cachingCache.requests(List.of(reqOnlyB, sharedByB), supplierB));
   
           List<MutableHashCodeResult> resultsA = futureA.get(10, 
TimeUnit.SECONDS);
           List<MutableHashCodeResult> resultsB = futureB.get(10, 
TimeUnit.SECONDS);
   
           assertEquals(2, resultsA.size());
           assertEquals(2, resultsB.size());
       } catch (TimeoutException e) {
           throw new AssertionError(
                   "Cross-thread deadlock detected: batch requests() with a 
shared key whose "
                           + "equals()/hashCode() mutate during resolution did 
not complete (#12472)",
                   e);
       } finally {
           executor.shutdownNow();
       }
   }
   ```
   
   It needs two small helpers (a `MutableHashCodeRequest` whose `hashCode()` 
includes the mutable trace data, and an equals-based generic test cache). 
**Offer: we can push the complete, verified change (test + helpers) directly to 
this branch** — just say the word.
   


-- 
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]

Reply via email to