|
19 | 19 |
|
20 | 20 | package org.elasticsearch.common.cache;
|
21 | 21 |
|
| 22 | +import org.elasticsearch.common.unit.TimeValue; |
22 | 23 | import org.elasticsearch.test.ESTestCase;
|
23 | 24 | import org.junit.Before;
|
24 | 25 |
|
@@ -343,6 +344,37 @@ protected long now() {
|
343 | 344 | assertEquals(numberOfEntries, cache.stats().getEvictions());
|
344 | 345 | }
|
345 | 346 |
|
| 347 | + @AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/30428") |
| 348 | + public void testComputeIfAbsentDeadlock() throws BrokenBarrierException, InterruptedException { |
| 349 | + final int numberOfThreads = randomIntBetween(2, 32); |
| 350 | + final Cache<Integer, String> cache = CacheBuilder.<Integer, String>builder().setExpireAfterAccess(TimeValue.timeValueNanos(1)).build(); |
| 351 | + |
| 352 | + final CyclicBarrier barrier = new CyclicBarrier(1 + numberOfThreads); |
| 353 | + for (int i = 0; i < numberOfThreads; i++) { |
| 354 | + final Thread thread = new Thread(() -> { |
| 355 | + try { |
| 356 | + barrier.await(); |
| 357 | + for (int j = 0; j < numberOfEntries; j++) { |
| 358 | + try { |
| 359 | + cache.computeIfAbsent(0, k -> Integer.toString(k)); |
| 360 | + } catch (final ExecutionException e) { |
| 361 | + throw new AssertionError(e); |
| 362 | + } |
| 363 | + } |
| 364 | + barrier.await(); |
| 365 | + } catch (final BrokenBarrierException | InterruptedException e) { |
| 366 | + throw new AssertionError(e); |
| 367 | + } |
| 368 | + }); |
| 369 | + thread.start(); |
| 370 | + } |
| 371 | + |
| 372 | + // wait for all threads to be ready |
| 373 | + barrier.await(); |
| 374 | + // wait for all threads to finish |
| 375 | + barrier.await(); |
| 376 | + } |
| 377 | + |
346 | 378 | // randomly promote some entries, step the clock forward, then check that the promoted entries remain and the
|
347 | 379 | // non-promoted entries were removed
|
348 | 380 | public void testPromotion() {
|
|
0 commit comments