|
25 | 25 | import static com.google.common.cache.TestingRemovalListeners.countingRemovalListener; |
26 | 26 | import static com.google.common.cache.TestingRemovalListeners.queuingRemovalListener; |
27 | 27 | import static com.google.common.cache.TestingWeighers.constantWeigher; |
28 | | -import static com.google.common.collect.Lists.newArrayList; |
29 | 28 | import static com.google.common.collect.Maps.immutableEntry; |
30 | 29 | import static com.google.common.truth.Truth.assertThat; |
| 30 | +import static com.google.common.util.concurrent.MoreExecutors.listeningDecorator; |
| 31 | +import static java.lang.Thread.State.WAITING; |
| 32 | +import static java.util.concurrent.Executors.newSingleThreadExecutor; |
| 33 | +import static java.util.concurrent.TimeUnit.MILLISECONDS; |
31 | 34 | import static java.util.concurrent.TimeUnit.MINUTES; |
32 | 35 | import static java.util.concurrent.TimeUnit.NANOSECONDS; |
33 | 36 | import static java.util.concurrent.TimeUnit.SECONDS; |
|
47 | 50 | import com.google.common.collect.ImmutableList; |
48 | 51 | import com.google.common.collect.ImmutableMap; |
49 | 52 | import com.google.common.collect.ImmutableSet; |
| 53 | +import com.google.common.collect.Iterables; |
50 | 54 | import com.google.common.collect.Lists; |
51 | 55 | import com.google.common.collect.Maps; |
52 | 56 | import com.google.common.collect.testing.ConcurrentMapTestSuiteBuilder; |
|
58 | 62 | import com.google.common.testing.NullPointerTester; |
59 | 63 | import com.google.common.testing.SerializableTester; |
60 | 64 | import com.google.common.testing.TestLogHandler; |
| 65 | +import com.google.common.util.concurrent.ListenableFuture; |
| 66 | +import com.google.common.util.concurrent.ListeningExecutorService; |
| 67 | +import com.google.common.util.concurrent.SettableFuture; |
61 | 68 | import com.google.common.util.concurrent.UncheckedExecutionException; |
62 | 69 | import java.io.Serializable; |
63 | 70 | import java.lang.ref.Reference; |
64 | 71 | import java.lang.ref.ReferenceQueue; |
| 72 | +import java.util.ArrayList; |
65 | 73 | import java.util.Iterator; |
66 | 74 | import java.util.LinkedHashMap; |
67 | 75 | import java.util.List; |
@@ -247,11 +255,24 @@ private void checkLogged(Throwable t) { |
247 | 255 | assertSame(t, popLoggedThrowable()); |
248 | 256 | } |
249 | 257 |
|
| 258 | + /* |
| 259 | + * TODO(cpovirk): Can we replace makeLocalCache with a call to builder.build()? Some tests may |
| 260 | + * need access to LocalCache APIs, but maybe we can at least make makeLocalCache use |
| 261 | + * builder.build() and then cast? |
| 262 | + */ |
| 263 | + |
250 | 264 | private static <K, V> LocalCache<K, V> makeLocalCache( |
251 | 265 | CacheBuilder<? super K, ? super V> builder) { |
252 | 266 | return new LocalCache<>(builder, null); |
253 | 267 | } |
254 | 268 |
|
| 269 | + private static <K, V> LocalCache<K, V> makeLocalCache( |
| 270 | + CacheBuilder<? super K, ? super V> builder, CacheLoader<? super K, V> loader) { |
| 271 | + return new LocalCache<>(builder, loader); |
| 272 | + } |
| 273 | + |
| 274 | + // TODO(cpovirk): Inline createCacheBuilder()? |
| 275 | + |
255 | 276 | private static CacheBuilder<Object, Object> createCacheBuilder() { |
256 | 277 | return CacheBuilder.newBuilder(); |
257 | 278 | } |
@@ -516,6 +537,57 @@ public void testSetRefresh() { |
516 | 537 | assertEquals(unit.toNanos(duration), map.refreshNanos); |
517 | 538 | } |
518 | 539 |
|
| 540 | + public void testLongAsyncRefresh() throws Exception { |
| 541 | + FakeTicker ticker = new FakeTicker(); |
| 542 | + CountDownLatch reloadStarted = new CountDownLatch(1); |
| 543 | + SettableFuture<Thread> threadAboutToBlockForRefresh = SettableFuture.create(); |
| 544 | + |
| 545 | + ListeningExecutorService refreshExecutor = listeningDecorator(newSingleThreadExecutor()); |
| 546 | + try { |
| 547 | + CacheBuilder<Object, Object> builder = |
| 548 | + createCacheBuilder() |
| 549 | + .expireAfterWrite(100, MILLISECONDS) |
| 550 | + .refreshAfterWrite(5, MILLISECONDS) |
| 551 | + .ticker(ticker); |
| 552 | + |
| 553 | + CacheLoader<String, String> loader = |
| 554 | + new CacheLoader<String, String>() { |
| 555 | + @Override |
| 556 | + public String load(String key) { |
| 557 | + return key + "Load"; |
| 558 | + } |
| 559 | + |
| 560 | + @Override |
| 561 | + public ListenableFuture<String> reload(String key, String oldValue) { |
| 562 | + return refreshExecutor.submit( |
| 563 | + () -> { |
| 564 | + reloadStarted.countDown(); |
| 565 | + |
| 566 | + Thread blockingForRefresh = threadAboutToBlockForRefresh.get(); |
| 567 | + while (blockingForRefresh.isAlive() |
| 568 | + && blockingForRefresh.getState() != WAITING) { |
| 569 | + Thread.yield(); |
| 570 | + } |
| 571 | + |
| 572 | + return key + "Reload"; |
| 573 | + }); |
| 574 | + } |
| 575 | + }; |
| 576 | + LocalCache<String, String> cache = makeLocalCache(builder, loader); |
| 577 | + |
| 578 | + assertThat(cache.getOrLoad("test")).isEqualTo("testLoad"); |
| 579 | + |
| 580 | + ticker.advance(10, MILLISECONDS); // so that the next call will trigger refresh |
| 581 | + assertThat(cache.getOrLoad("test")).isEqualTo("testLoad"); |
| 582 | + reloadStarted.await(); |
| 583 | + ticker.advance(500, MILLISECONDS); // so that the entry expires during the reload |
| 584 | + threadAboutToBlockForRefresh.set(Thread.currentThread()); |
| 585 | + assertThat(cache.getOrLoad("test")).isEqualTo("testReload"); |
| 586 | + } finally { |
| 587 | + refreshExecutor.shutdown(); |
| 588 | + } |
| 589 | + } |
| 590 | + |
519 | 591 | public void testSetRemovalListener() { |
520 | 592 | RemovalListener<Object, Object> testListener = TestingRemovalListeners.nullRemovalListener(); |
521 | 593 | LocalCache<Object, Object> map = |
@@ -584,7 +656,7 @@ public void testRecordReadOnCompute() throws ExecutionException { |
584 | 656 |
|
585 | 657 | // access some of the elements |
586 | 658 | Random random = new Random(); |
587 | | - List<ReferenceEntry<Object, Object>> reads = Lists.newArrayList(); |
| 659 | + List<ReferenceEntry<Object, Object>> reads = new ArrayList<>(); |
588 | 660 | Iterator<ReferenceEntry<Object, Object>> i = readOrder.iterator(); |
589 | 661 | while (i.hasNext()) { |
590 | 662 | ReferenceEntry<Object, Object> entry = i.next(); |
@@ -2097,7 +2169,7 @@ public void testRecordRead() { |
2097 | 2169 |
|
2098 | 2170 | // access some of the elements |
2099 | 2171 | Random random = new Random(); |
2100 | | - List<ReferenceEntry<Object, Object>> reads = Lists.newArrayList(); |
| 2172 | + List<ReferenceEntry<Object, Object>> reads = new ArrayList<>(); |
2101 | 2173 | Iterator<ReferenceEntry<Object, Object>> i = readOrder.iterator(); |
2102 | 2174 | while (i.hasNext()) { |
2103 | 2175 | ReferenceEntry<Object, Object> entry = i.next(); |
@@ -2138,7 +2210,7 @@ public void testRecordReadOnGet() { |
2138 | 2210 |
|
2139 | 2211 | // access some of the elements |
2140 | 2212 | Random random = new Random(); |
2141 | | - List<ReferenceEntry<Object, Object>> reads = Lists.newArrayList(); |
| 2213 | + List<ReferenceEntry<Object, Object>> reads = new ArrayList<>(); |
2142 | 2214 | Iterator<ReferenceEntry<Object, Object>> i = readOrder.iterator(); |
2143 | 2215 | while (i.hasNext()) { |
2144 | 2216 | ReferenceEntry<Object, Object> entry = i.next(); |
@@ -2179,7 +2251,7 @@ public void testRecordWrite() { |
2179 | 2251 |
|
2180 | 2252 | // access some of the elements |
2181 | 2253 | Random random = new Random(); |
2182 | | - List<ReferenceEntry<Object, Object>> writes = Lists.newArrayList(); |
| 2254 | + List<ReferenceEntry<Object, Object>> writes = new ArrayList<>(); |
2183 | 2255 | Iterator<ReferenceEntry<Object, Object>> i = writeOrder.iterator(); |
2184 | 2256 | while (i.hasNext()) { |
2185 | 2257 | ReferenceEntry<Object, Object> entry = i.next(); |
@@ -2725,7 +2797,8 @@ private void testLoadThrows( |
2725 | 2797 | * weakKeys and weak/softValues. |
2726 | 2798 | */ |
2727 | 2799 | private static Iterable<CacheBuilder<Object, Object>> allEntryTypeMakers() { |
2728 | | - List<CacheBuilder<Object, Object>> result = newArrayList(allKeyValueStrengthMakers()); |
| 2800 | + List<CacheBuilder<Object, Object>> result = new ArrayList<>(); |
| 2801 | + Iterables.addAll(result, allKeyValueStrengthMakers()); |
2729 | 2802 | for (CacheBuilder<Object, Object> builder : allKeyValueStrengthMakers()) { |
2730 | 2803 | result.add(builder.maximumSize(SMALL_MAX_SIZE)); |
2731 | 2804 | } |
|
0 commit comments