1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package com.google.common.cache;
16
17 import static com.google.common.cache.TestingCacheLoaders.bulkLoader;
18 import static com.google.common.cache.TestingCacheLoaders.constantLoader;
19 import static com.google.common.cache.TestingCacheLoaders.errorLoader;
20 import static com.google.common.cache.TestingCacheLoaders.exceptionLoader;
21 import static com.google.common.cache.TestingCacheLoaders.identityLoader;
22 import static com.google.common.cache.TestingRemovalListeners.countingRemovalListener;
23 import static com.google.common.truth.Truth.assertThat;
24 import static java.lang.Thread.currentThread;
25 import static java.util.Arrays.asList;
26 import static java.util.concurrent.TimeUnit.MILLISECONDS;
27
28 import com.google.common.cache.CacheLoader.InvalidCacheLoadException;
29 import com.google.common.cache.TestingCacheLoaders.CountingLoader;
30 import com.google.common.cache.TestingCacheLoaders.IdentityLoader;
31 import com.google.common.cache.TestingRemovalListeners.CountingRemovalListener;
32 import com.google.common.collect.ImmutableList;
33 import com.google.common.collect.ImmutableMap;
34 import com.google.common.collect.Lists;
35 import com.google.common.collect.Maps;
36 import com.google.common.testing.FakeTicker;
37 import com.google.common.testing.TestLogHandler;
38 import com.google.common.util.concurrent.Callables;
39 import com.google.common.util.concurrent.ExecutionError;
40 import com.google.common.util.concurrent.Futures;
41 import com.google.common.util.concurrent.ListenableFuture;
42 import com.google.common.util.concurrent.UncheckedExecutionException;
43
44 import junit.framework.TestCase;
45
46 import java.io.IOException;
47 import java.lang.ref.WeakReference;
48 import java.util.List;
49 import java.util.Map;
50 import java.util.concurrent.Callable;
51 import java.util.concurrent.ConcurrentMap;
52 import java.util.concurrent.CountDownLatch;
53 import java.util.concurrent.ExecutionException;
54 import java.util.concurrent.TimeUnit;
55 import java.util.concurrent.atomic.AtomicInteger;
56 import java.util.concurrent.atomic.AtomicReferenceArray;
57 import java.util.logging.LogRecord;
58
59
60
61
62
63
64 public class CacheLoadingTest extends TestCase {
65 TestLogHandler logHandler;
66
67 @Override
68 public void setUp() throws Exception {
69 super.setUp();
70 logHandler = new TestLogHandler();
71 LocalCache.logger.addHandler(logHandler);
72 }
73
74 @Override
75 public void tearDown() throws Exception {
76 super.tearDown();
77
78 currentThread().interrupted();
79 LocalCache.logger.removeHandler(logHandler);
80 }
81
82 private Throwable popLoggedThrowable() {
83 List<LogRecord> logRecords = logHandler.getStoredLogRecords();
84 assertEquals(1, logRecords.size());
85 LogRecord logRecord = logRecords.get(0);
86 logHandler.clear();
87 return logRecord.getThrown();
88 }
89
90 private void checkNothingLogged() {
91 assertTrue(logHandler.getStoredLogRecords().isEmpty());
92 }
93
94 private void checkLoggedCause(Throwable t) {
95 assertSame(t, popLoggedThrowable().getCause());
96 }
97
98 private void checkLoggedInvalidLoad() {
99 assertTrue(popLoggedThrowable() instanceof InvalidCacheLoadException);
100 }
101
102 public void testLoad() throws ExecutionException {
103 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder()
104 .recordStats()
105 .build(identityLoader());
106 CacheStats stats = cache.stats();
107 assertEquals(0, stats.missCount());
108 assertEquals(0, stats.loadSuccessCount());
109 assertEquals(0, stats.loadExceptionCount());
110 assertEquals(0, stats.hitCount());
111
112 Object key = new Object();
113 assertSame(key, cache.get(key));
114 stats = cache.stats();
115 assertEquals(1, stats.missCount());
116 assertEquals(1, stats.loadSuccessCount());
117 assertEquals(0, stats.loadExceptionCount());
118 assertEquals(0, stats.hitCount());
119
120 key = new Object();
121 assertSame(key, cache.getUnchecked(key));
122 stats = cache.stats();
123 assertEquals(2, stats.missCount());
124 assertEquals(2, stats.loadSuccessCount());
125 assertEquals(0, stats.loadExceptionCount());
126 assertEquals(0, stats.hitCount());
127
128 key = new Object();
129 cache.refresh(key);
130 checkNothingLogged();
131 stats = cache.stats();
132 assertEquals(2, stats.missCount());
133 assertEquals(3, stats.loadSuccessCount());
134 assertEquals(0, stats.loadExceptionCount());
135 assertEquals(0, stats.hitCount());
136
137 assertSame(key, cache.get(key));
138 stats = cache.stats();
139 assertEquals(2, stats.missCount());
140 assertEquals(3, stats.loadSuccessCount());
141 assertEquals(0, stats.loadExceptionCount());
142 assertEquals(1, stats.hitCount());
143
144 Object value = new Object();
145
146 assertSame(key, cache.get(key, throwing(new Exception())));
147 stats = cache.stats();
148 assertEquals(2, stats.missCount());
149 assertEquals(3, stats.loadSuccessCount());
150 assertEquals(0, stats.loadExceptionCount());
151 assertEquals(2, stats.hitCount());
152
153 key = new Object();
154 assertSame(value, cache.get(key, Callables.returning(value)));
155 stats = cache.stats();
156 assertEquals(3, stats.missCount());
157 assertEquals(4, stats.loadSuccessCount());
158 assertEquals(0, stats.loadExceptionCount());
159 assertEquals(2, stats.hitCount());
160 }
161
162 public void testReload() throws ExecutionException {
163 final Object one = new Object();
164 final Object two = new Object();
165 CacheLoader<Object, Object> loader = new CacheLoader<Object, Object>() {
166 @Override
167 public Object load(Object key) {
168 return one;
169 }
170
171 @Override
172 public ListenableFuture<Object> reload(Object key, Object oldValue) {
173 return Futures.immediateFuture(two);
174 }
175 };
176
177 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().recordStats().build(loader);
178 Object key = new Object();
179 CacheStats stats = cache.stats();
180 assertEquals(0, stats.missCount());
181 assertEquals(0, stats.loadSuccessCount());
182 assertEquals(0, stats.loadExceptionCount());
183 assertEquals(0, stats.hitCount());
184
185 assertSame(one, cache.getUnchecked(key));
186 stats = cache.stats();
187 assertEquals(1, stats.missCount());
188 assertEquals(1, stats.loadSuccessCount());
189 assertEquals(0, stats.loadExceptionCount());
190 assertEquals(0, stats.hitCount());
191
192 cache.refresh(key);
193 checkNothingLogged();
194 stats = cache.stats();
195 assertEquals(1, stats.missCount());
196 assertEquals(2, stats.loadSuccessCount());
197 assertEquals(0, stats.loadExceptionCount());
198 assertEquals(0, stats.hitCount());
199
200 assertSame(two, cache.getUnchecked(key));
201 stats = cache.stats();
202 assertEquals(1, stats.missCount());
203 assertEquals(2, stats.loadSuccessCount());
204 assertEquals(0, stats.loadExceptionCount());
205 assertEquals(1, stats.hitCount());
206 }
207
208 public void testRefresh() {
209 final Object one = new Object();
210 final Object two = new Object();
211 FakeTicker ticker = new FakeTicker();
212 CacheLoader<Object, Object> loader = new CacheLoader<Object, Object>() {
213 @Override
214 public Object load(Object key) {
215 return one;
216 }
217
218 @Override
219 public ListenableFuture<Object> reload(Object key, Object oldValue) {
220 return Futures.immediateFuture(two);
221 }
222 };
223
224 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder()
225 .recordStats()
226 .ticker(ticker)
227 .refreshAfterWrite(1, MILLISECONDS)
228 .build(loader);
229 Object key = new Object();
230 CacheStats stats = cache.stats();
231 assertEquals(0, stats.missCount());
232 assertEquals(0, stats.loadSuccessCount());
233 assertEquals(0, stats.loadExceptionCount());
234 assertEquals(0, stats.hitCount());
235
236 assertSame(one, cache.getUnchecked(key));
237 stats = cache.stats();
238 assertEquals(1, stats.missCount());
239 assertEquals(1, stats.loadSuccessCount());
240 assertEquals(0, stats.loadExceptionCount());
241 assertEquals(0, stats.hitCount());
242
243 ticker.advance(1, MILLISECONDS);
244 assertSame(one, cache.getUnchecked(key));
245 stats = cache.stats();
246 assertEquals(1, stats.missCount());
247 assertEquals(1, stats.loadSuccessCount());
248 assertEquals(0, stats.loadExceptionCount());
249 assertEquals(1, stats.hitCount());
250
251 ticker.advance(1, MILLISECONDS);
252 assertSame(two, cache.getUnchecked(key));
253 stats = cache.stats();
254 assertEquals(1, stats.missCount());
255 assertEquals(2, stats.loadSuccessCount());
256 assertEquals(0, stats.loadExceptionCount());
257 assertEquals(2, stats.hitCount());
258
259 ticker.advance(1, MILLISECONDS);
260 assertSame(two, cache.getUnchecked(key));
261 stats = cache.stats();
262 assertEquals(1, stats.missCount());
263 assertEquals(2, stats.loadSuccessCount());
264 assertEquals(0, stats.loadExceptionCount());
265 assertEquals(3, stats.hitCount());
266 }
267
268 public void testRefresh_getIfPresent() {
269 final Object one = new Object();
270 final Object two = new Object();
271 FakeTicker ticker = new FakeTicker();
272 CacheLoader<Object, Object> loader = new CacheLoader<Object, Object>() {
273 @Override
274 public Object load(Object key) {
275 return one;
276 }
277
278 @Override
279 public ListenableFuture<Object> reload(Object key, Object oldValue) {
280 return Futures.immediateFuture(two);
281 }
282 };
283
284 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder()
285 .recordStats()
286 .ticker(ticker)
287 .refreshAfterWrite(1, MILLISECONDS)
288 .build(loader);
289 Object key = new Object();
290 CacheStats stats = cache.stats();
291 assertEquals(0, stats.missCount());
292 assertEquals(0, stats.loadSuccessCount());
293 assertEquals(0, stats.loadExceptionCount());
294 assertEquals(0, stats.hitCount());
295
296 assertSame(one, cache.getUnchecked(key));
297 stats = cache.stats();
298 assertEquals(1, stats.missCount());
299 assertEquals(1, stats.loadSuccessCount());
300 assertEquals(0, stats.loadExceptionCount());
301 assertEquals(0, stats.hitCount());
302
303 ticker.advance(1, MILLISECONDS);
304 assertSame(one, cache.getIfPresent(key));
305 stats = cache.stats();
306 assertEquals(1, stats.missCount());
307 assertEquals(1, stats.loadSuccessCount());
308 assertEquals(0, stats.loadExceptionCount());
309 assertEquals(1, stats.hitCount());
310
311 ticker.advance(1, MILLISECONDS);
312 assertSame(two, cache.getIfPresent(key));
313 stats = cache.stats();
314 assertEquals(1, stats.missCount());
315 assertEquals(2, stats.loadSuccessCount());
316 assertEquals(0, stats.loadExceptionCount());
317 assertEquals(2, stats.hitCount());
318
319 ticker.advance(1, MILLISECONDS);
320 assertSame(two, cache.getIfPresent(key));
321 stats = cache.stats();
322 assertEquals(1, stats.missCount());
323 assertEquals(2, stats.loadSuccessCount());
324 assertEquals(0, stats.loadExceptionCount());
325 assertEquals(3, stats.hitCount());
326 }
327
328 public void testBulkLoad_default() throws ExecutionException {
329 LoadingCache<Integer, Integer> cache = CacheBuilder.newBuilder()
330 .recordStats()
331 .build(TestingCacheLoaders.<Integer>identityLoader());
332 CacheStats stats = cache.stats();
333 assertEquals(0, stats.missCount());
334 assertEquals(0, stats.loadSuccessCount());
335 assertEquals(0, stats.loadExceptionCount());
336 assertEquals(0, stats.hitCount());
337
338 assertEquals(ImmutableMap.of(), cache.getAll(ImmutableList.<Integer>of()));
339 assertEquals(0, stats.missCount());
340 assertEquals(0, stats.loadSuccessCount());
341 assertEquals(0, stats.loadExceptionCount());
342 assertEquals(0, stats.hitCount());
343
344 assertEquals(ImmutableMap.of(1, 1), cache.getAll(asList(1)));
345 stats = cache.stats();
346 assertEquals(1, stats.missCount());
347 assertEquals(1, stats.loadSuccessCount());
348 assertEquals(0, stats.loadExceptionCount());
349 assertEquals(0, stats.hitCount());
350
351 assertEquals(ImmutableMap.of(1, 1, 2, 2, 3, 3, 4, 4), cache.getAll(asList(1, 2, 3, 4)));
352 stats = cache.stats();
353 assertEquals(4, stats.missCount());
354 assertEquals(4, stats.loadSuccessCount());
355 assertEquals(0, stats.loadExceptionCount());
356 assertEquals(1, stats.hitCount());
357
358 assertEquals(ImmutableMap.of(2, 2, 3, 3), cache.getAll(asList(2, 3)));
359 stats = cache.stats();
360 assertEquals(4, stats.missCount());
361 assertEquals(4, stats.loadSuccessCount());
362 assertEquals(0, stats.loadExceptionCount());
363 assertEquals(3, stats.hitCount());
364
365
366 assertEquals(ImmutableMap.of(4, 4, 5, 5), cache.getAll(asList(4, 5)));
367 stats = cache.stats();
368 assertEquals(5, stats.missCount());
369 assertEquals(5, stats.loadSuccessCount());
370 assertEquals(0, stats.loadExceptionCount());
371 assertEquals(4, stats.hitCount());
372 }
373
374 public void testBulkLoad_loadAll() throws ExecutionException {
375 IdentityLoader<Integer> backingLoader = identityLoader();
376 CacheLoader<Integer, Integer> loader = bulkLoader(backingLoader);
377 LoadingCache<Integer, Integer> cache = CacheBuilder.newBuilder().recordStats().build(loader);
378 CacheStats stats = cache.stats();
379 assertEquals(0, stats.missCount());
380 assertEquals(0, stats.loadSuccessCount());
381 assertEquals(0, stats.loadExceptionCount());
382 assertEquals(0, stats.hitCount());
383
384 assertEquals(ImmutableMap.of(), cache.getAll(ImmutableList.<Integer>of()));
385 assertEquals(0, stats.missCount());
386 assertEquals(0, stats.loadSuccessCount());
387 assertEquals(0, stats.loadExceptionCount());
388 assertEquals(0, stats.hitCount());
389
390 assertEquals(ImmutableMap.of(1, 1), cache.getAll(asList(1)));
391 stats = cache.stats();
392 assertEquals(1, stats.missCount());
393 assertEquals(1, stats.loadSuccessCount());
394 assertEquals(0, stats.loadExceptionCount());
395 assertEquals(0, stats.hitCount());
396
397 assertEquals(ImmutableMap.of(1, 1, 2, 2, 3, 3, 4, 4), cache.getAll(asList(1, 2, 3, 4)));
398 stats = cache.stats();
399 assertEquals(4, stats.missCount());
400 assertEquals(2, stats.loadSuccessCount());
401 assertEquals(0, stats.loadExceptionCount());
402 assertEquals(1, stats.hitCount());
403
404 assertEquals(ImmutableMap.of(2, 2, 3, 3), cache.getAll(asList(2, 3)));
405 stats = cache.stats();
406 assertEquals(4, stats.missCount());
407 assertEquals(2, stats.loadSuccessCount());
408 assertEquals(0, stats.loadExceptionCount());
409 assertEquals(3, stats.hitCount());
410
411
412 assertEquals(ImmutableMap.of(4, 4, 5, 5), cache.getAll(asList(4, 5)));
413 stats = cache.stats();
414 assertEquals(5, stats.missCount());
415 assertEquals(3, stats.loadSuccessCount());
416 assertEquals(0, stats.loadExceptionCount());
417 assertEquals(4, stats.hitCount());
418 }
419
420 public void testBulkLoad_extra() throws ExecutionException {
421 CacheLoader<Object, Object> loader = new CacheLoader<Object, Object>() {
422 @Override
423 public Object load(Object key) throws Exception {
424 return new Object();
425 }
426
427 @Override
428 public Map<Object, Object> loadAll(Iterable<? extends Object> keys) throws Exception {
429 Map<Object, Object> result = Maps.newHashMap();
430 for (Object key : keys) {
431 Object value = new Object();
432 result.put(key, value);
433
434 result.put(value, key);
435 }
436 return result;
437 }
438 };
439 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().build(loader);
440
441 Object[] lookupKeys = new Object[] { new Object(), new Object(), new Object() };
442 Map<Object, Object> result = cache.getAll(asList(lookupKeys));
443 assertThat(result.keySet()).has().exactlyAs(asList(lookupKeys));
444 for (Map.Entry<Object, Object> entry : result.entrySet()) {
445 Object key = entry.getKey();
446 Object value = entry.getValue();
447 assertSame(value, result.get(key));
448 assertNull(result.get(value));
449 assertSame(value, cache.asMap().get(key));
450 assertSame(key, cache.asMap().get(value));
451 }
452 }
453
454 public void testBulkLoad_clobber() throws ExecutionException {
455 final Object extraKey = new Object();
456 final Object extraValue = new Object();
457 CacheLoader<Object, Object> loader = new CacheLoader<Object, Object>() {
458 @Override
459 public Object load(Object key) throws Exception {
460 throw new AssertionError();
461 }
462
463 @Override
464 public Map<Object, Object> loadAll(Iterable<? extends Object> keys) throws Exception {
465 Map<Object, Object> result = Maps.newHashMap();
466 for (Object key : keys) {
467 Object value = new Object();
468 result.put(key, value);
469 }
470 result.put(extraKey, extraValue);
471 return result;
472 }
473 };
474 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().build(loader);
475 cache.asMap().put(extraKey, extraKey);
476 assertSame(extraKey, cache.asMap().get(extraKey));
477
478 Object[] lookupKeys = new Object[] { new Object(), new Object(), new Object() };
479 Map<Object, Object> result = cache.getAll(asList(lookupKeys));
480 assertThat(result.keySet()).has().exactlyAs(asList(lookupKeys));
481 for (Map.Entry<Object, Object> entry : result.entrySet()) {
482 Object key = entry.getKey();
483 Object value = entry.getValue();
484 assertSame(value, result.get(key));
485 assertSame(value, cache.asMap().get(key));
486 }
487 assertNull(result.get(extraKey));
488 assertSame(extraValue, cache.asMap().get(extraKey));
489 }
490
491 public void testBulkLoad_clobberNullValue() throws ExecutionException {
492 final Object extraKey = new Object();
493 final Object extraValue = new Object();
494 CacheLoader<Object, Object> loader = new CacheLoader<Object, Object>() {
495 @Override
496 public Object load(Object key) throws Exception {
497 throw new AssertionError();
498 }
499
500 @Override
501 public Map<Object, Object> loadAll(Iterable<? extends Object> keys) throws Exception {
502 Map<Object, Object> result = Maps.newHashMap();
503 for (Object key : keys) {
504 Object value = new Object();
505 result.put(key, value);
506 }
507 result.put(extraKey, extraValue);
508 result.put(extraValue, null);
509 return result;
510 }
511 };
512 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().build(loader);
513 cache.asMap().put(extraKey, extraKey);
514 assertSame(extraKey, cache.asMap().get(extraKey));
515
516 Object[] lookupKeys = new Object[] { new Object(), new Object(), new Object() };
517 try {
518 cache.getAll(asList(lookupKeys));
519 fail();
520 } catch (InvalidCacheLoadException expected) {}
521
522 for (Object key : lookupKeys) {
523 assertTrue(cache.asMap().containsKey(key));
524 }
525 assertSame(extraValue, cache.asMap().get(extraKey));
526 assertFalse(cache.asMap().containsKey(extraValue));
527 }
528
529 public void testBulkLoad_clobberNullKey() throws ExecutionException {
530 final Object extraKey = new Object();
531 final Object extraValue = new Object();
532 CacheLoader<Object, Object> loader = new CacheLoader<Object, Object>() {
533 @Override
534 public Object load(Object key) throws Exception {
535 throw new AssertionError();
536 }
537
538 @Override
539 public Map<Object, Object> loadAll(Iterable<? extends Object> keys) throws Exception {
540 Map<Object, Object> result = Maps.newHashMap();
541 for (Object key : keys) {
542 Object value = new Object();
543 result.put(key, value);
544 }
545 result.put(extraKey, extraValue);
546 result.put(null, extraKey);
547 return result;
548 }
549 };
550 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().build(loader);
551 cache.asMap().put(extraKey, extraKey);
552 assertSame(extraKey, cache.asMap().get(extraKey));
553
554 Object[] lookupKeys = new Object[] { new Object(), new Object(), new Object() };
555 try {
556 cache.getAll(asList(lookupKeys));
557 fail();
558 } catch (InvalidCacheLoadException expected) {}
559
560 for (Object key : lookupKeys) {
561 assertTrue(cache.asMap().containsKey(key));
562 }
563 assertSame(extraValue, cache.asMap().get(extraKey));
564 assertFalse(cache.asMap().containsValue(extraKey));
565 }
566
567 public void testBulkLoad_partial() throws ExecutionException {
568 final Object extraKey = new Object();
569 final Object extraValue = new Object();
570 CacheLoader<Object, Object> loader = new CacheLoader<Object, Object>() {
571 @Override
572 public Object load(Object key) throws Exception {
573 throw new AssertionError();
574 }
575
576 @Override
577 public Map<Object, Object> loadAll(Iterable<? extends Object> keys) throws Exception {
578 Map<Object, Object> result = Maps.newHashMap();
579
580 result.put(extraKey, extraValue);
581 return result;
582 }
583 };
584 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().build(loader);
585
586 Object[] lookupKeys = new Object[] { new Object(), new Object(), new Object() };
587 try {
588 cache.getAll(asList(lookupKeys));
589 fail();
590 } catch (InvalidCacheLoadException expected) {}
591 assertSame(extraValue, cache.asMap().get(extraKey));
592 }
593
594 public void testLoadNull() throws ExecutionException {
595 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder()
596 .recordStats()
597 .build(constantLoader(null));
598 CacheStats stats = cache.stats();
599 assertEquals(0, stats.missCount());
600 assertEquals(0, stats.loadSuccessCount());
601 assertEquals(0, stats.loadExceptionCount());
602 assertEquals(0, stats.hitCount());
603
604 try {
605 cache.get(new Object());
606 fail();
607 } catch (InvalidCacheLoadException expected) {}
608 stats = cache.stats();
609 assertEquals(1, stats.missCount());
610 assertEquals(0, stats.loadSuccessCount());
611 assertEquals(1, stats.loadExceptionCount());
612 assertEquals(0, stats.hitCount());
613
614 try {
615 cache.getUnchecked(new Object());
616 fail();
617 } catch (InvalidCacheLoadException expected) {}
618 stats = cache.stats();
619 assertEquals(2, stats.missCount());
620 assertEquals(0, stats.loadSuccessCount());
621 assertEquals(2, stats.loadExceptionCount());
622 assertEquals(0, stats.hitCount());
623
624 cache.refresh(new Object());
625 checkLoggedInvalidLoad();
626 stats = cache.stats();
627 assertEquals(2, stats.missCount());
628 assertEquals(0, stats.loadSuccessCount());
629 assertEquals(3, stats.loadExceptionCount());
630 assertEquals(0, stats.hitCount());
631
632 try {
633 cache.get(new Object(), Callables.returning(null));
634 fail();
635 } catch (InvalidCacheLoadException expected) {}
636 stats = cache.stats();
637 assertEquals(3, stats.missCount());
638 assertEquals(0, stats.loadSuccessCount());
639 assertEquals(4, stats.loadExceptionCount());
640 assertEquals(0, stats.hitCount());
641
642 try {
643 cache.getAll(asList(new Object()));
644 fail();
645 } catch (InvalidCacheLoadException expected) {}
646 stats = cache.stats();
647 assertEquals(4, stats.missCount());
648 assertEquals(0, stats.loadSuccessCount());
649 assertEquals(5, stats.loadExceptionCount());
650 assertEquals(0, stats.hitCount());
651 }
652
653 public void testReloadNull() throws ExecutionException {
654 final Object one = new Object();
655 CacheLoader<Object, Object> loader = new CacheLoader<Object, Object>() {
656 @Override
657 public Object load(Object key) {
658 return one;
659 }
660
661 @Override
662 public ListenableFuture<Object> reload(Object key, Object oldValue) {
663 return null;
664 }
665 };
666
667 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().recordStats().build(loader);
668 Object key = new Object();
669 CacheStats stats = cache.stats();
670 assertEquals(0, stats.missCount());
671 assertEquals(0, stats.loadSuccessCount());
672 assertEquals(0, stats.loadExceptionCount());
673 assertEquals(0, stats.hitCount());
674
675 assertSame(one, cache.getUnchecked(key));
676 stats = cache.stats();
677 assertEquals(1, stats.missCount());
678 assertEquals(1, stats.loadSuccessCount());
679 assertEquals(0, stats.loadExceptionCount());
680 assertEquals(0, stats.hitCount());
681
682 cache.refresh(key);
683 checkLoggedInvalidLoad();
684 stats = cache.stats();
685 assertEquals(1, stats.missCount());
686 assertEquals(1, stats.loadSuccessCount());
687 assertEquals(1, stats.loadExceptionCount());
688 assertEquals(0, stats.hitCount());
689
690 assertSame(one, cache.getUnchecked(key));
691 stats = cache.stats();
692 assertEquals(1, stats.missCount());
693 assertEquals(1, stats.loadSuccessCount());
694 assertEquals(1, stats.loadExceptionCount());
695 assertEquals(1, stats.hitCount());
696 }
697
698 public void testReloadNullFuture() throws ExecutionException {
699 final Object one = new Object();
700 CacheLoader<Object, Object> loader = new CacheLoader<Object, Object>() {
701 @Override
702 public Object load(Object key) {
703 return one;
704 }
705
706 @Override
707 public ListenableFuture<Object> reload(Object key, Object oldValue) {
708 return Futures.immediateFuture(null);
709 }
710 };
711
712 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().recordStats().build(loader);
713 Object key = new Object();
714 CacheStats stats = cache.stats();
715 assertEquals(0, stats.missCount());
716 assertEquals(0, stats.loadSuccessCount());
717 assertEquals(0, stats.loadExceptionCount());
718 assertEquals(0, stats.hitCount());
719
720 assertSame(one, cache.getUnchecked(key));
721 stats = cache.stats();
722 assertEquals(1, stats.missCount());
723 assertEquals(1, stats.loadSuccessCount());
724 assertEquals(0, stats.loadExceptionCount());
725 assertEquals(0, stats.hitCount());
726
727 cache.refresh(key);
728 checkLoggedInvalidLoad();
729 stats = cache.stats();
730 assertEquals(1, stats.missCount());
731 assertEquals(1, stats.loadSuccessCount());
732 assertEquals(1, stats.loadExceptionCount());
733 assertEquals(0, stats.hitCount());
734
735 assertSame(one, cache.getUnchecked(key));
736 stats = cache.stats();
737 assertEquals(1, stats.missCount());
738 assertEquals(1, stats.loadSuccessCount());
739 assertEquals(1, stats.loadExceptionCount());
740 assertEquals(1, stats.hitCount());
741 }
742
743 public void testRefreshNull() {
744 final Object one = new Object();
745 FakeTicker ticker = new FakeTicker();
746 CacheLoader<Object, Object> loader = new CacheLoader<Object, Object>() {
747 @Override
748 public Object load(Object key) {
749 return one;
750 }
751
752 @Override
753 public ListenableFuture<Object> reload(Object key, Object oldValue) {
754 return Futures.immediateFuture(null);
755 }
756 };
757
758 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder()
759 .recordStats()
760 .ticker(ticker)
761 .refreshAfterWrite(1, MILLISECONDS)
762 .build(loader);
763 Object key = new Object();
764 CacheStats stats = cache.stats();
765 assertEquals(0, stats.missCount());
766 assertEquals(0, stats.loadSuccessCount());
767 assertEquals(0, stats.loadExceptionCount());
768 assertEquals(0, stats.hitCount());
769
770 assertSame(one, cache.getUnchecked(key));
771 stats = cache.stats();
772 assertEquals(1, stats.missCount());
773 assertEquals(1, stats.loadSuccessCount());
774 assertEquals(0, stats.loadExceptionCount());
775 assertEquals(0, stats.hitCount());
776
777 ticker.advance(1, MILLISECONDS);
778 assertSame(one, cache.getUnchecked(key));
779 stats = cache.stats();
780 assertEquals(1, stats.missCount());
781 assertEquals(1, stats.loadSuccessCount());
782 assertEquals(0, stats.loadExceptionCount());
783 assertEquals(1, stats.hitCount());
784
785 ticker.advance(1, MILLISECONDS);
786 assertSame(one, cache.getUnchecked(key));
787
788 stats = cache.stats();
789 assertEquals(1, stats.missCount());
790 assertEquals(1, stats.loadSuccessCount());
791 assertEquals(1, stats.loadExceptionCount());
792 assertEquals(2, stats.hitCount());
793
794 ticker.advance(1, MILLISECONDS);
795 assertSame(one, cache.getUnchecked(key));
796 stats = cache.stats();
797 assertEquals(1, stats.missCount());
798 assertEquals(1, stats.loadSuccessCount());
799 assertEquals(2, stats.loadExceptionCount());
800 assertEquals(3, stats.hitCount());
801 }
802
803 public void testBulkLoadNull() throws ExecutionException {
804 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder()
805 .recordStats()
806 .build(bulkLoader(constantLoader(null)));
807 CacheStats stats = cache.stats();
808 assertEquals(0, stats.missCount());
809 assertEquals(0, stats.loadSuccessCount());
810 assertEquals(0, stats.loadExceptionCount());
811 assertEquals(0, stats.hitCount());
812
813 try {
814 cache.getAll(asList(new Object()));
815 fail();
816 } catch (InvalidCacheLoadException expected) {}
817 stats = cache.stats();
818 assertEquals(1, stats.missCount());
819 assertEquals(0, stats.loadSuccessCount());
820 assertEquals(1, stats.loadExceptionCount());
821 assertEquals(0, stats.hitCount());
822 }
823
824 public void testBulkLoadNullMap() throws ExecutionException {
825 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder()
826 .recordStats()
827 .build(new CacheLoader<Object, Object>() {
828 @Override
829 public Object load(Object key) {
830 throw new AssertionError();
831 }
832
833 @Override
834 public Map<Object, Object> loadAll(Iterable<? extends Object> keys) {
835 return null;
836 }
837 });
838
839 CacheStats stats = cache.stats();
840 assertEquals(0, stats.missCount());
841 assertEquals(0, stats.loadSuccessCount());
842 assertEquals(0, stats.loadExceptionCount());
843 assertEquals(0, stats.hitCount());
844
845 try {
846 cache.getAll(asList(new Object()));
847 fail();
848 } catch (InvalidCacheLoadException expected) {}
849 stats = cache.stats();
850 assertEquals(1, stats.missCount());
851 assertEquals(0, stats.loadSuccessCount());
852 assertEquals(1, stats.loadExceptionCount());
853 assertEquals(0, stats.hitCount());
854 }
855
856 public void testLoadError() throws ExecutionException {
857 Error e = new Error();
858 CacheLoader<Object, Object> loader = errorLoader(e);
859 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().recordStats().build(loader);
860 CacheStats stats = cache.stats();
861 assertEquals(0, stats.missCount());
862 assertEquals(0, stats.loadSuccessCount());
863 assertEquals(0, stats.loadExceptionCount());
864 assertEquals(0, stats.hitCount());
865
866 try {
867 cache.get(new Object());
868 fail();
869 } catch (ExecutionError expected) {
870 assertSame(e, expected.getCause());
871 }
872 stats = cache.stats();
873 assertEquals(1, stats.missCount());
874 assertEquals(0, stats.loadSuccessCount());
875 assertEquals(1, stats.loadExceptionCount());
876 assertEquals(0, stats.hitCount());
877
878 try {
879 cache.getUnchecked(new Object());
880 fail();
881 } catch (ExecutionError expected) {
882 assertSame(e, expected.getCause());
883 }
884 stats = cache.stats();
885 assertEquals(2, stats.missCount());
886 assertEquals(0, stats.loadSuccessCount());
887 assertEquals(2, stats.loadExceptionCount());
888 assertEquals(0, stats.hitCount());
889
890 cache.refresh(new Object());
891 checkLoggedCause(e);
892 stats = cache.stats();
893 assertEquals(2, stats.missCount());
894 assertEquals(0, stats.loadSuccessCount());
895 assertEquals(3, stats.loadExceptionCount());
896 assertEquals(0, stats.hitCount());
897
898 final Error callableError = new Error();
899 try {
900 cache.get(new Object(), new Callable<Object>() {
901 @Override
902 public Object call() {
903 throw callableError;
904 }
905 });
906 fail();
907 } catch (ExecutionError expected) {
908 assertSame(callableError, expected.getCause());
909 }
910 stats = cache.stats();
911 assertEquals(3, stats.missCount());
912 assertEquals(0, stats.loadSuccessCount());
913 assertEquals(4, stats.loadExceptionCount());
914 assertEquals(0, stats.hitCount());
915
916 try {
917 cache.getAll(asList(new Object()));
918 fail();
919 } catch (ExecutionError expected) {
920 assertSame(e, expected.getCause());
921 }
922 stats = cache.stats();
923 assertEquals(4, stats.missCount());
924 assertEquals(0, stats.loadSuccessCount());
925 assertEquals(5, stats.loadExceptionCount());
926 assertEquals(0, stats.hitCount());
927 }
928
929 public void testReloadError() throws ExecutionException {
930 final Object one = new Object();
931 final Error e = new Error();
932 CacheLoader<Object, Object> loader = new CacheLoader<Object, Object>() {
933 @Override
934 public Object load(Object key) {
935 return one;
936 }
937
938 @Override
939 public ListenableFuture<Object> reload(Object key, Object oldValue) {
940 throw e;
941 }
942 };
943
944 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().recordStats().build(loader);
945 Object key = new Object();
946 CacheStats stats = cache.stats();
947 assertEquals(0, stats.missCount());
948 assertEquals(0, stats.loadSuccessCount());
949 assertEquals(0, stats.loadExceptionCount());
950 assertEquals(0, stats.hitCount());
951
952 assertSame(one, cache.getUnchecked(key));
953 stats = cache.stats();
954 assertEquals(1, stats.missCount());
955 assertEquals(1, stats.loadSuccessCount());
956 assertEquals(0, stats.loadExceptionCount());
957 assertEquals(0, stats.hitCount());
958
959 cache.refresh(key);
960 checkLoggedCause(e);
961 stats = cache.stats();
962 assertEquals(1, stats.missCount());
963 assertEquals(1, stats.loadSuccessCount());
964 assertEquals(1, stats.loadExceptionCount());
965 assertEquals(0, stats.hitCount());
966
967 assertSame(one, cache.getUnchecked(key));
968 stats = cache.stats();
969 assertEquals(1, stats.missCount());
970 assertEquals(1, stats.loadSuccessCount());
971 assertEquals(1, stats.loadExceptionCount());
972 assertEquals(1, stats.hitCount());
973 }
974
975 public void testReloadFutureError() throws ExecutionException {
976 final Object one = new Object();
977 final Error e = new Error();
978 CacheLoader<Object, Object> loader = new CacheLoader<Object, Object>() {
979 @Override
980 public Object load(Object key) {
981 return one;
982 }
983
984 @Override
985 public ListenableFuture<Object> reload(Object key, Object oldValue) {
986 return Futures.immediateFailedFuture(e);
987 }
988 };
989
990 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().recordStats().build(loader);
991 Object key = new Object();
992 CacheStats stats = cache.stats();
993 assertEquals(0, stats.missCount());
994 assertEquals(0, stats.loadSuccessCount());
995 assertEquals(0, stats.loadExceptionCount());
996 assertEquals(0, stats.hitCount());
997
998 assertSame(one, cache.getUnchecked(key));
999 stats = cache.stats();
1000 assertEquals(1, stats.missCount());
1001 assertEquals(1, stats.loadSuccessCount());
1002 assertEquals(0, stats.loadExceptionCount());
1003 assertEquals(0, stats.hitCount());
1004
1005 cache.refresh(key);
1006 checkLoggedCause(e);
1007 stats = cache.stats();
1008 assertEquals(1, stats.missCount());
1009 assertEquals(1, stats.loadSuccessCount());
1010 assertEquals(1, stats.loadExceptionCount());
1011 assertEquals(0, stats.hitCount());
1012
1013 assertSame(one, cache.getUnchecked(key));
1014 stats = cache.stats();
1015 assertEquals(1, stats.missCount());
1016 assertEquals(1, stats.loadSuccessCount());
1017 assertEquals(1, stats.loadExceptionCount());
1018 assertEquals(1, stats.hitCount());
1019 }
1020
1021 public void testRefreshError() {
1022 final Object one = new Object();
1023 final Error e = new Error();
1024 FakeTicker ticker = new FakeTicker();
1025 CacheLoader<Object, Object> loader = new CacheLoader<Object, Object>() {
1026 @Override
1027 public Object load(Object key) {
1028 return one;
1029 }
1030
1031 @Override
1032 public ListenableFuture<Object> reload(Object key, Object oldValue) {
1033 return Futures.immediateFailedFuture(e);
1034 }
1035 };
1036
1037 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder()
1038 .recordStats()
1039 .ticker(ticker)
1040 .refreshAfterWrite(1, MILLISECONDS)
1041 .build(loader);
1042 Object key = new Object();
1043 CacheStats stats = cache.stats();
1044 assertEquals(0, stats.missCount());
1045 assertEquals(0, stats.loadSuccessCount());
1046 assertEquals(0, stats.loadExceptionCount());
1047 assertEquals(0, stats.hitCount());
1048
1049 assertSame(one, cache.getUnchecked(key));
1050 stats = cache.stats();
1051 assertEquals(1, stats.missCount());
1052 assertEquals(1, stats.loadSuccessCount());
1053 assertEquals(0, stats.loadExceptionCount());
1054 assertEquals(0, stats.hitCount());
1055
1056 ticker.advance(1, MILLISECONDS);
1057 assertSame(one, cache.getUnchecked(key));
1058 stats = cache.stats();
1059 assertEquals(1, stats.missCount());
1060 assertEquals(1, stats.loadSuccessCount());
1061 assertEquals(0, stats.loadExceptionCount());
1062 assertEquals(1, stats.hitCount());
1063
1064 ticker.advance(1, MILLISECONDS);
1065 assertSame(one, cache.getUnchecked(key));
1066
1067 stats = cache.stats();
1068 assertEquals(1, stats.missCount());
1069 assertEquals(1, stats.loadSuccessCount());
1070 assertEquals(1, stats.loadExceptionCount());
1071 assertEquals(2, stats.hitCount());
1072
1073 ticker.advance(1, MILLISECONDS);
1074 assertSame(one, cache.getUnchecked(key));
1075 stats = cache.stats();
1076 assertEquals(1, stats.missCount());
1077 assertEquals(1, stats.loadSuccessCount());
1078 assertEquals(2, stats.loadExceptionCount());
1079 assertEquals(3, stats.hitCount());
1080 }
1081
1082 public void testBulkLoadError() throws ExecutionException {
1083 Error e = new Error();
1084 CacheLoader<Object, Object> loader = errorLoader(e);
1085 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder()
1086 .recordStats()
1087 .build(bulkLoader(loader));
1088 CacheStats stats = cache.stats();
1089 assertEquals(0, stats.missCount());
1090 assertEquals(0, stats.loadSuccessCount());
1091 assertEquals(0, stats.loadExceptionCount());
1092 assertEquals(0, stats.hitCount());
1093
1094 try {
1095 cache.getAll(asList(new Object()));
1096 fail();
1097 } catch (ExecutionError expected) {
1098 assertSame(e, expected.getCause());
1099 }
1100 stats = cache.stats();
1101 assertEquals(1, stats.missCount());
1102 assertEquals(0, stats.loadSuccessCount());
1103 assertEquals(1, stats.loadExceptionCount());
1104 assertEquals(0, stats.hitCount());
1105 }
1106
1107 public void testLoadCheckedException() {
1108 Exception e = new Exception();
1109 CacheLoader<Object, Object> loader = exceptionLoader(e);
1110 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().recordStats().build(loader);
1111 CacheStats stats = cache.stats();
1112 assertEquals(0, stats.missCount());
1113 assertEquals(0, stats.loadSuccessCount());
1114 assertEquals(0, stats.loadExceptionCount());
1115 assertEquals(0, stats.hitCount());
1116
1117 try {
1118 cache.get(new Object());
1119 fail();
1120 } catch (ExecutionException expected) {
1121 assertSame(e, expected.getCause());
1122 }
1123 stats = cache.stats();
1124 assertEquals(1, stats.missCount());
1125 assertEquals(0, stats.loadSuccessCount());
1126 assertEquals(1, stats.loadExceptionCount());
1127 assertEquals(0, stats.hitCount());
1128
1129 try {
1130 cache.getUnchecked(new Object());
1131 fail();
1132 } catch (UncheckedExecutionException expected) {
1133 assertSame(e, expected.getCause());
1134 }
1135 stats = cache.stats();
1136 assertEquals(2, stats.missCount());
1137 assertEquals(0, stats.loadSuccessCount());
1138 assertEquals(2, stats.loadExceptionCount());
1139 assertEquals(0, stats.hitCount());
1140
1141 cache.refresh(new Object());
1142 checkLoggedCause(e);
1143 stats = cache.stats();
1144 assertEquals(2, stats.missCount());
1145 assertEquals(0, stats.loadSuccessCount());
1146 assertEquals(3, stats.loadExceptionCount());
1147 assertEquals(0, stats.hitCount());
1148
1149 Exception callableException = new Exception();
1150 try {
1151 cache.get(new Object(), throwing(callableException));
1152 fail();
1153 } catch (ExecutionException expected) {
1154 assertSame(callableException, expected.getCause());
1155 }
1156 stats = cache.stats();
1157 assertEquals(3, stats.missCount());
1158 assertEquals(0, stats.loadSuccessCount());
1159 assertEquals(4, stats.loadExceptionCount());
1160 assertEquals(0, stats.hitCount());
1161
1162 try {
1163 cache.getAll(asList(new Object()));
1164 fail();
1165 } catch (ExecutionException expected) {
1166 assertSame(e, expected.getCause());
1167 }
1168 stats = cache.stats();
1169 assertEquals(4, stats.missCount());
1170 assertEquals(0, stats.loadSuccessCount());
1171 assertEquals(5, stats.loadExceptionCount());
1172 assertEquals(0, stats.hitCount());
1173 }
1174
1175 public void testLoadInterruptedException() {
1176 Exception e = new InterruptedException();
1177 CacheLoader<Object, Object> loader = exceptionLoader(e);
1178 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().recordStats().build(loader);
1179 CacheStats stats = cache.stats();
1180 assertEquals(0, stats.missCount());
1181 assertEquals(0, stats.loadSuccessCount());
1182 assertEquals(0, stats.loadExceptionCount());
1183 assertEquals(0, stats.hitCount());
1184
1185
1186 assertFalse(currentThread().interrupted());
1187
1188 try {
1189 cache.get(new Object());
1190 fail();
1191 } catch (ExecutionException expected) {
1192 assertSame(e, expected.getCause());
1193 }
1194 assertTrue(currentThread().interrupted());
1195 stats = cache.stats();
1196 assertEquals(1, stats.missCount());
1197 assertEquals(0, stats.loadSuccessCount());
1198 assertEquals(1, stats.loadExceptionCount());
1199 assertEquals(0, stats.hitCount());
1200
1201 try {
1202 cache.getUnchecked(new Object());
1203 fail();
1204 } catch (UncheckedExecutionException expected) {
1205 assertSame(e, expected.getCause());
1206 }
1207 assertTrue(currentThread().interrupted());
1208 stats = cache.stats();
1209 assertEquals(2, stats.missCount());
1210 assertEquals(0, stats.loadSuccessCount());
1211 assertEquals(2, stats.loadExceptionCount());
1212 assertEquals(0, stats.hitCount());
1213
1214 cache.refresh(new Object());
1215 assertTrue(currentThread().interrupted());
1216 checkLoggedCause(e);
1217 stats = cache.stats();
1218 assertEquals(2, stats.missCount());
1219 assertEquals(0, stats.loadSuccessCount());
1220 assertEquals(3, stats.loadExceptionCount());
1221 assertEquals(0, stats.hitCount());
1222
1223 Exception callableException = new InterruptedException();
1224 try {
1225 cache.get(new Object(), throwing(callableException));
1226 fail();
1227 } catch (ExecutionException expected) {
1228 assertSame(callableException, expected.getCause());
1229 }
1230 assertTrue(currentThread().interrupted());
1231 stats = cache.stats();
1232 assertEquals(3, stats.missCount());
1233 assertEquals(0, stats.loadSuccessCount());
1234 assertEquals(4, stats.loadExceptionCount());
1235 assertEquals(0, stats.hitCount());
1236
1237 try {
1238 cache.getAll(asList(new Object()));
1239 fail();
1240 } catch (ExecutionException expected) {
1241 assertSame(e, expected.getCause());
1242 }
1243 assertTrue(currentThread().interrupted());
1244 stats = cache.stats();
1245 assertEquals(4, stats.missCount());
1246 assertEquals(0, stats.loadSuccessCount());
1247 assertEquals(5, stats.loadExceptionCount());
1248 assertEquals(0, stats.hitCount());
1249 }
1250
1251 public void testReloadCheckedException() {
1252 final Object one = new Object();
1253 final Exception e = new Exception();
1254 CacheLoader<Object, Object> loader = new CacheLoader<Object, Object>() {
1255 @Override
1256 public Object load(Object key) {
1257 return one;
1258 }
1259
1260 @Override
1261 public ListenableFuture<Object> reload(Object key, Object oldValue) throws Exception {
1262 throw e;
1263 }
1264 };
1265
1266 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().recordStats().build(loader);
1267 Object key = new Object();
1268 CacheStats stats = cache.stats();
1269 assertEquals(0, stats.missCount());
1270 assertEquals(0, stats.loadSuccessCount());
1271 assertEquals(0, stats.loadExceptionCount());
1272 assertEquals(0, stats.hitCount());
1273
1274 assertSame(one, cache.getUnchecked(key));
1275 stats = cache.stats();
1276 assertEquals(1, stats.missCount());
1277 assertEquals(1, stats.loadSuccessCount());
1278 assertEquals(0, stats.loadExceptionCount());
1279 assertEquals(0, stats.hitCount());
1280
1281 cache.refresh(key);
1282 checkLoggedCause(e);
1283 stats = cache.stats();
1284 assertEquals(1, stats.missCount());
1285 assertEquals(1, stats.loadSuccessCount());
1286 assertEquals(1, stats.loadExceptionCount());
1287 assertEquals(0, stats.hitCount());
1288
1289 assertSame(one, cache.getUnchecked(key));
1290 stats = cache.stats();
1291 assertEquals(1, stats.missCount());
1292 assertEquals(1, stats.loadSuccessCount());
1293 assertEquals(1, stats.loadExceptionCount());
1294 assertEquals(1, stats.hitCount());
1295 }
1296
1297 public void testReloadFutureCheckedException() {
1298 final Object one = new Object();
1299 final Exception e = new Exception();
1300 CacheLoader<Object, Object> loader = new CacheLoader<Object, Object>() {
1301 @Override
1302 public Object load(Object key) {
1303 return one;
1304 }
1305
1306 @Override
1307 public ListenableFuture<Object> reload(Object key, Object oldValue) {
1308 return Futures.immediateFailedFuture(e);
1309 }
1310 };
1311
1312 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().recordStats().build(loader);
1313 Object key = new Object();
1314 CacheStats stats = cache.stats();
1315 assertEquals(0, stats.missCount());
1316 assertEquals(0, stats.loadSuccessCount());
1317 assertEquals(0, stats.loadExceptionCount());
1318 assertEquals(0, stats.hitCount());
1319
1320 assertSame(one, cache.getUnchecked(key));
1321 stats = cache.stats();
1322 assertEquals(1, stats.missCount());
1323 assertEquals(1, stats.loadSuccessCount());
1324 assertEquals(0, stats.loadExceptionCount());
1325 assertEquals(0, stats.hitCount());
1326
1327 cache.refresh(key);
1328 checkLoggedCause(e);
1329 stats = cache.stats();
1330 assertEquals(1, stats.missCount());
1331 assertEquals(1, stats.loadSuccessCount());
1332 assertEquals(1, stats.loadExceptionCount());
1333 assertEquals(0, stats.hitCount());
1334
1335 assertSame(one, cache.getUnchecked(key));
1336 stats = cache.stats();
1337 assertEquals(1, stats.missCount());
1338 assertEquals(1, stats.loadSuccessCount());
1339 assertEquals(1, stats.loadExceptionCount());
1340 assertEquals(1, stats.hitCount());
1341 }
1342
1343 public void testRefreshCheckedException() {
1344 final Object one = new Object();
1345 final Exception e = new Exception();
1346 FakeTicker ticker = new FakeTicker();
1347 CacheLoader<Object, Object> loader = new CacheLoader<Object, Object>() {
1348 @Override
1349 public Object load(Object key) {
1350 return one;
1351 }
1352
1353 @Override
1354 public ListenableFuture<Object> reload(Object key, Object oldValue) {
1355 return Futures.immediateFailedFuture(e);
1356 }
1357 };
1358
1359 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder()
1360 .recordStats()
1361 .ticker(ticker)
1362 .refreshAfterWrite(1, MILLISECONDS)
1363 .build(loader);
1364 Object key = new Object();
1365 CacheStats stats = cache.stats();
1366 assertEquals(0, stats.missCount());
1367 assertEquals(0, stats.loadSuccessCount());
1368 assertEquals(0, stats.loadExceptionCount());
1369 assertEquals(0, stats.hitCount());
1370
1371 assertSame(one, cache.getUnchecked(key));
1372 stats = cache.stats();
1373 assertEquals(1, stats.missCount());
1374 assertEquals(1, stats.loadSuccessCount());
1375 assertEquals(0, stats.loadExceptionCount());
1376 assertEquals(0, stats.hitCount());
1377
1378 ticker.advance(1, MILLISECONDS);
1379 assertSame(one, cache.getUnchecked(key));
1380 stats = cache.stats();
1381 assertEquals(1, stats.missCount());
1382 assertEquals(1, stats.loadSuccessCount());
1383 assertEquals(0, stats.loadExceptionCount());
1384 assertEquals(1, stats.hitCount());
1385
1386 ticker.advance(1, MILLISECONDS);
1387 assertSame(one, cache.getUnchecked(key));
1388
1389 stats = cache.stats();
1390 assertEquals(1, stats.missCount());
1391 assertEquals(1, stats.loadSuccessCount());
1392 assertEquals(1, stats.loadExceptionCount());
1393 assertEquals(2, stats.hitCount());
1394
1395 ticker.advance(1, MILLISECONDS);
1396 assertSame(one, cache.getUnchecked(key));
1397 stats = cache.stats();
1398 assertEquals(1, stats.missCount());
1399 assertEquals(1, stats.loadSuccessCount());
1400 assertEquals(2, stats.loadExceptionCount());
1401 assertEquals(3, stats.hitCount());
1402 }
1403
1404 public void testBulkLoadCheckedException() {
1405 Exception e = new Exception();
1406 CacheLoader<Object, Object> loader = exceptionLoader(e);
1407 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder()
1408 .recordStats()
1409 .build(bulkLoader(loader));
1410 CacheStats stats = cache.stats();
1411 assertEquals(0, stats.missCount());
1412 assertEquals(0, stats.loadSuccessCount());
1413 assertEquals(0, stats.loadExceptionCount());
1414 assertEquals(0, stats.hitCount());
1415
1416 try {
1417 cache.getAll(asList(new Object()));
1418 fail();
1419 } catch (ExecutionException expected) {
1420 assertSame(e, expected.getCause());
1421 }
1422 stats = cache.stats();
1423 assertEquals(1, stats.missCount());
1424 assertEquals(0, stats.loadSuccessCount());
1425 assertEquals(1, stats.loadExceptionCount());
1426 assertEquals(0, stats.hitCount());
1427 }
1428
1429 public void testBulkLoadInterruptedException() {
1430 Exception e = new InterruptedException();
1431 CacheLoader<Object, Object> loader = exceptionLoader(e);
1432 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder()
1433 .recordStats()
1434 .build(bulkLoader(loader));
1435 CacheStats stats = cache.stats();
1436 assertEquals(0, stats.missCount());
1437 assertEquals(0, stats.loadSuccessCount());
1438 assertEquals(0, stats.loadExceptionCount());
1439 assertEquals(0, stats.hitCount());
1440
1441 try {
1442 cache.getAll(asList(new Object()));
1443 fail();
1444 } catch (ExecutionException expected) {
1445 assertSame(e, expected.getCause());
1446 }
1447 assertTrue(currentThread().interrupted());
1448 stats = cache.stats();
1449 assertEquals(1, stats.missCount());
1450 assertEquals(0, stats.loadSuccessCount());
1451 assertEquals(1, stats.loadExceptionCount());
1452 assertEquals(0, stats.hitCount());
1453 }
1454
1455 public void testLoadUncheckedException() throws ExecutionException {
1456 Exception e = new RuntimeException();
1457 CacheLoader<Object, Object> loader = exceptionLoader(e);
1458 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().recordStats().build(loader);
1459 CacheStats stats = cache.stats();
1460 assertEquals(0, stats.missCount());
1461 assertEquals(0, stats.loadSuccessCount());
1462 assertEquals(0, stats.loadExceptionCount());
1463 assertEquals(0, stats.hitCount());
1464
1465 try {
1466 cache.get(new Object());
1467 fail();
1468 } catch (UncheckedExecutionException expected) {
1469 assertSame(e, expected.getCause());
1470 }
1471 stats = cache.stats();
1472 assertEquals(1, stats.missCount());
1473 assertEquals(0, stats.loadSuccessCount());
1474 assertEquals(1, stats.loadExceptionCount());
1475 assertEquals(0, stats.hitCount());
1476
1477 try {
1478 cache.getUnchecked(new Object());
1479 fail();
1480 } catch (UncheckedExecutionException expected) {
1481 assertSame(e, expected.getCause());
1482 }
1483 stats = cache.stats();
1484 assertEquals(2, stats.missCount());
1485 assertEquals(0, stats.loadSuccessCount());
1486 assertEquals(2, stats.loadExceptionCount());
1487 assertEquals(0, stats.hitCount());
1488
1489 cache.refresh(new Object());
1490 checkLoggedCause(e);
1491 stats = cache.stats();
1492 assertEquals(2, stats.missCount());
1493 assertEquals(0, stats.loadSuccessCount());
1494 assertEquals(3, stats.loadExceptionCount());
1495 assertEquals(0, stats.hitCount());
1496
1497 Exception callableException = new RuntimeException();
1498 try {
1499 cache.get(new Object(), throwing(callableException));
1500 fail();
1501 } catch (UncheckedExecutionException expected) {
1502 assertSame(callableException, expected.getCause());
1503 }
1504 stats = cache.stats();
1505 assertEquals(3, stats.missCount());
1506 assertEquals(0, stats.loadSuccessCount());
1507 assertEquals(4, stats.loadExceptionCount());
1508 assertEquals(0, stats.hitCount());
1509
1510 try {
1511 cache.getAll(asList(new Object()));
1512 fail();
1513 } catch (UncheckedExecutionException expected) {
1514 assertSame(e, expected.getCause());
1515 }
1516 stats = cache.stats();
1517 assertEquals(4, stats.missCount());
1518 assertEquals(0, stats.loadSuccessCount());
1519 assertEquals(5, stats.loadExceptionCount());
1520 assertEquals(0, stats.hitCount());
1521 }
1522
1523 public void testReloadUncheckedException() throws ExecutionException {
1524 final Object one = new Object();
1525 final Exception e = new RuntimeException();
1526 CacheLoader<Object, Object> loader = new CacheLoader<Object, Object>() {
1527 @Override
1528 public Object load(Object key) {
1529 return one;
1530 }
1531
1532 @Override
1533 public ListenableFuture<Object> reload(Object key, Object oldValue) throws Exception {
1534 throw e;
1535 }
1536 };
1537
1538 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().recordStats().build(loader);
1539 Object key = new Object();
1540 CacheStats stats = cache.stats();
1541 assertEquals(0, stats.missCount());
1542 assertEquals(0, stats.loadSuccessCount());
1543 assertEquals(0, stats.loadExceptionCount());
1544 assertEquals(0, stats.hitCount());
1545
1546 assertSame(one, cache.getUnchecked(key));
1547 stats = cache.stats();
1548 assertEquals(1, stats.missCount());
1549 assertEquals(1, stats.loadSuccessCount());
1550 assertEquals(0, stats.loadExceptionCount());
1551 assertEquals(0, stats.hitCount());
1552
1553 cache.refresh(key);
1554 checkLoggedCause(e);
1555 stats = cache.stats();
1556 assertEquals(1, stats.missCount());
1557 assertEquals(1, stats.loadSuccessCount());
1558 assertEquals(1, stats.loadExceptionCount());
1559 assertEquals(0, stats.hitCount());
1560
1561 assertSame(one, cache.getUnchecked(key));
1562 stats = cache.stats();
1563 assertEquals(1, stats.missCount());
1564 assertEquals(1, stats.loadSuccessCount());
1565 assertEquals(1, stats.loadExceptionCount());
1566 assertEquals(1, stats.hitCount());
1567 }
1568
1569 public void testReloadFutureUncheckedException() throws ExecutionException {
1570 final Object one = new Object();
1571 final Exception e = new RuntimeException();
1572 CacheLoader<Object, Object> loader = new CacheLoader<Object, Object>() {
1573 @Override
1574 public Object load(Object key) {
1575 return one;
1576 }
1577
1578 @Override
1579 public ListenableFuture<Object> reload(Object key, Object oldValue) {
1580 return Futures.immediateFailedFuture(e);
1581 }
1582 };
1583
1584 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder().recordStats().build(loader);
1585 Object key = new Object();
1586 CacheStats stats = cache.stats();
1587 assertEquals(0, stats.missCount());
1588 assertEquals(0, stats.loadSuccessCount());
1589 assertEquals(0, stats.loadExceptionCount());
1590 assertEquals(0, stats.hitCount());
1591
1592 assertSame(one, cache.getUnchecked(key));
1593 stats = cache.stats();
1594 assertEquals(1, stats.missCount());
1595 assertEquals(1, stats.loadSuccessCount());
1596 assertEquals(0, stats.loadExceptionCount());
1597 assertEquals(0, stats.hitCount());
1598
1599 cache.refresh(key);
1600 checkLoggedCause(e);
1601 stats = cache.stats();
1602 assertEquals(1, stats.missCount());
1603 assertEquals(1, stats.loadSuccessCount());
1604 assertEquals(1, stats.loadExceptionCount());
1605 assertEquals(0, stats.hitCount());
1606
1607 assertSame(one, cache.getUnchecked(key));
1608 stats = cache.stats();
1609 assertEquals(1, stats.missCount());
1610 assertEquals(1, stats.loadSuccessCount());
1611 assertEquals(1, stats.loadExceptionCount());
1612 assertEquals(1, stats.hitCount());
1613 }
1614
1615 public void testRefreshUncheckedException() {
1616 final Object one = new Object();
1617 final Exception e = new RuntimeException();
1618 FakeTicker ticker = new FakeTicker();
1619 CacheLoader<Object, Object> loader = new CacheLoader<Object, Object>() {
1620 @Override
1621 public Object load(Object key) {
1622 return one;
1623 }
1624
1625 @Override
1626 public ListenableFuture<Object> reload(Object key, Object oldValue) {
1627 return Futures.immediateFailedFuture(e);
1628 }
1629 };
1630
1631 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder()
1632 .recordStats()
1633 .ticker(ticker)
1634 .refreshAfterWrite(1, MILLISECONDS)
1635 .build(loader);
1636 Object key = new Object();
1637 CacheStats stats = cache.stats();
1638 assertEquals(0, stats.missCount());
1639 assertEquals(0, stats.loadSuccessCount());
1640 assertEquals(0, stats.loadExceptionCount());
1641 assertEquals(0, stats.hitCount());
1642
1643 assertSame(one, cache.getUnchecked(key));
1644 stats = cache.stats();
1645 assertEquals(1, stats.missCount());
1646 assertEquals(1, stats.loadSuccessCount());
1647 assertEquals(0, stats.loadExceptionCount());
1648 assertEquals(0, stats.hitCount());
1649
1650 ticker.advance(1, MILLISECONDS);
1651 assertSame(one, cache.getUnchecked(key));
1652 stats = cache.stats();
1653 assertEquals(1, stats.missCount());
1654 assertEquals(1, stats.loadSuccessCount());
1655 assertEquals(0, stats.loadExceptionCount());
1656 assertEquals(1, stats.hitCount());
1657
1658 ticker.advance(1, MILLISECONDS);
1659 assertSame(one, cache.getUnchecked(key));
1660
1661 stats = cache.stats();
1662 assertEquals(1, stats.missCount());
1663 assertEquals(1, stats.loadSuccessCount());
1664 assertEquals(1, stats.loadExceptionCount());
1665 assertEquals(2, stats.hitCount());
1666
1667 ticker.advance(1, MILLISECONDS);
1668 assertSame(one, cache.getUnchecked(key));
1669 stats = cache.stats();
1670 assertEquals(1, stats.missCount());
1671 assertEquals(1, stats.loadSuccessCount());
1672 assertEquals(2, stats.loadExceptionCount());
1673 assertEquals(3, stats.hitCount());
1674 }
1675
1676 public void testBulkLoadUncheckedException() throws ExecutionException {
1677 Exception e = new RuntimeException();
1678 CacheLoader<Object, Object> loader = exceptionLoader(e);
1679 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder()
1680 .recordStats()
1681 .build(bulkLoader(loader));
1682 CacheStats stats = cache.stats();
1683 assertEquals(0, stats.missCount());
1684 assertEquals(0, stats.loadSuccessCount());
1685 assertEquals(0, stats.loadExceptionCount());
1686 assertEquals(0, stats.hitCount());
1687
1688 try {
1689 cache.getAll(asList(new Object()));
1690 fail();
1691 } catch (UncheckedExecutionException expected) {
1692 assertSame(e, expected.getCause());
1693 }
1694 stats = cache.stats();
1695 assertEquals(1, stats.missCount());
1696 assertEquals(0, stats.loadSuccessCount());
1697 assertEquals(1, stats.loadExceptionCount());
1698 assertEquals(0, stats.hitCount());
1699 }
1700
1701 public void testReloadAfterFailure() throws ExecutionException {
1702 final AtomicInteger count = new AtomicInteger();
1703 final Exception e = new IllegalStateException("exception to trigger failure on first load()");
1704 CacheLoader<Integer, String> failOnceFunction = new CacheLoader<Integer, String>() {
1705
1706 @Override
1707 public String load(Integer key) throws Exception {
1708 if (count.getAndIncrement() == 0) {
1709 throw e;
1710 }
1711 return key.toString();
1712 }
1713 };
1714 CountingRemovalListener<Integer, String> removalListener = countingRemovalListener();
1715 LoadingCache<Integer, String> cache = CacheBuilder.newBuilder()
1716 .removalListener(removalListener)
1717 .build(failOnceFunction);
1718
1719 try {
1720 cache.getUnchecked(1);
1721 fail();
1722 } catch (UncheckedExecutionException ue) {
1723 assertSame(e, ue.getCause());
1724 }
1725
1726 assertEquals("1", cache.getUnchecked(1));
1727 assertEquals(0, removalListener.getCount());
1728
1729 count.set(0);
1730 cache.refresh(2);
1731 checkLoggedCause(e);
1732
1733 assertEquals("2", cache.getUnchecked(2));
1734 assertEquals(0, removalListener.getCount());
1735
1736 }
1737
1738 public void testReloadAfterValueReclamation() throws InterruptedException, ExecutionException {
1739 CountingLoader countingLoader = new CountingLoader();
1740 LoadingCache<Object, Object> cache =
1741 CacheBuilder.newBuilder().weakValues().build(countingLoader);
1742 ConcurrentMap<Object, Object> map = cache.asMap();
1743
1744 int iterations = 10;
1745 WeakReference<Object> ref = new WeakReference<Object>(null);
1746 int expectedComputations = 0;
1747 for (int i = 0; i < iterations; i++) {
1748
1749 Object oldValue = ref.get();
1750 if (oldValue == null) {
1751 expectedComputations++;
1752 }
1753 ref = new WeakReference<Object>(cache.getUnchecked(1));
1754 oldValue = null;
1755 Thread.sleep(i);
1756 System.gc();
1757 }
1758 assertEquals(expectedComputations, countingLoader.getCount());
1759
1760 for (int i = 0; i < iterations; i++) {
1761
1762 Object oldValue = ref.get();
1763 if (oldValue == null) {
1764 expectedComputations++;
1765 }
1766 cache.refresh(1);
1767 checkNothingLogged();
1768 ref = new WeakReference<Object>(map.get(1));
1769 oldValue = null;
1770 Thread.sleep(i);
1771 System.gc();
1772 }
1773 assertEquals(expectedComputations, countingLoader.getCount());
1774 }
1775
1776 public void testReloadAfterSimulatedValueReclamation() throws ExecutionException {
1777 CountingLoader countingLoader = new CountingLoader();
1778 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder()
1779 .concurrencyLevel(1)
1780 .weakValues()
1781 .build(countingLoader);
1782
1783 Object key = new Object();
1784 assertNotNull(cache.getUnchecked(key));
1785
1786 CacheTesting.simulateValueReclamation(cache, key);
1787
1788
1789 assertNotNull(cache.getUnchecked(key));
1790 assertEquals(1, cache.size());
1791 assertEquals(2, countingLoader.getCount());
1792
1793 CacheTesting.simulateValueReclamation(cache, key);
1794 cache.refresh(key);
1795 checkNothingLogged();
1796 assertEquals(1, cache.size());
1797 assertEquals(3, countingLoader.getCount());
1798 }
1799
1800 public void testReloadAfterSimulatedKeyReclamation() throws ExecutionException {
1801 CountingLoader countingLoader = new CountingLoader();
1802 LoadingCache<Object, Object> cache = CacheBuilder.newBuilder()
1803 .concurrencyLevel(1)
1804 .weakKeys()
1805 .build(countingLoader);
1806
1807 Object key = new Object();
1808 assertNotNull(cache.getUnchecked(key));
1809 assertEquals(1, cache.size());
1810
1811 CacheTesting.simulateKeyReclamation(cache, key);
1812
1813
1814 assertNotNull(cache.getUnchecked(key));
1815 assertEquals(2, countingLoader.getCount());
1816
1817 CacheTesting.simulateKeyReclamation(cache, key);
1818 cache.refresh(key);
1819 checkNothingLogged();
1820 assertEquals(3, countingLoader.getCount());
1821 }
1822
1823
1824
1825
1826 public void testLoadingExceptionWithCause() {
1827 final Exception cause = new Exception();
1828 final UncheckedExecutionException uee = new UncheckedExecutionException(cause);
1829 final ExecutionException ee = new ExecutionException(cause);
1830
1831 LoadingCache<Object, Object> cacheUnchecked =
1832 CacheBuilder.newBuilder().build(exceptionLoader(uee));
1833 LoadingCache<Object, Object> cacheChecked =
1834 CacheBuilder.newBuilder().build(exceptionLoader(ee));
1835
1836 try {
1837 cacheUnchecked.get(new Object());
1838 fail();
1839 } catch (ExecutionException e) {
1840 fail();
1841 } catch (UncheckedExecutionException caughtEe) {
1842 assertSame(uee, caughtEe.getCause());
1843 }
1844
1845 try {
1846 cacheUnchecked.getUnchecked(new Object());
1847 fail();
1848 } catch (UncheckedExecutionException caughtUee) {
1849 assertSame(uee, caughtUee.getCause());
1850 }
1851
1852 cacheUnchecked.refresh(new Object());
1853 checkLoggedCause(uee);
1854
1855 try {
1856 cacheUnchecked.getAll(asList(new Object()));
1857 fail();
1858 } catch (ExecutionException e) {
1859 fail();
1860 } catch (UncheckedExecutionException caughtEe) {
1861 assertSame(uee, caughtEe.getCause());
1862 }
1863
1864 try {
1865 cacheChecked.get(new Object());
1866 fail();
1867 } catch (ExecutionException caughtEe) {
1868 assertSame(ee, caughtEe.getCause());
1869 }
1870
1871 try {
1872 cacheChecked.getUnchecked(new Object());
1873 fail();
1874 } catch (UncheckedExecutionException caughtUee) {
1875 assertSame(ee, caughtUee.getCause());
1876 }
1877
1878 cacheChecked.refresh(new Object());
1879 checkLoggedCause(ee);
1880
1881 try {
1882 cacheChecked.getAll(asList(new Object()));
1883 fail();
1884 } catch (ExecutionException caughtEe) {
1885 assertSame(ee, caughtEe.getCause());
1886 }
1887 }
1888
1889 public void testBulkLoadingExceptionWithCause() {
1890 final Exception cause = new Exception();
1891 final UncheckedExecutionException uee = new UncheckedExecutionException(cause);
1892 final ExecutionException ee = new ExecutionException(cause);
1893
1894 LoadingCache<Object, Object> cacheUnchecked =
1895 CacheBuilder.newBuilder().build(bulkLoader(exceptionLoader(uee)));
1896 LoadingCache<Object, Object> cacheChecked =
1897 CacheBuilder.newBuilder().build(bulkLoader(exceptionLoader(ee)));
1898
1899 try {
1900 cacheUnchecked.getAll(asList(new Object()));
1901 fail();
1902 } catch (ExecutionException e) {
1903 fail();
1904 } catch (UncheckedExecutionException caughtEe) {
1905 assertSame(uee, caughtEe.getCause());
1906 }
1907
1908 try {
1909 cacheChecked.getAll(asList(new Object()));
1910 fail();
1911 } catch (ExecutionException caughtEe) {
1912 assertSame(ee, caughtEe.getCause());
1913 }
1914 }
1915
1916 public void testConcurrentLoading() throws InterruptedException {
1917 testConcurrentLoading(CacheBuilder.newBuilder());
1918 }
1919
1920 public void testConcurrentExpirationLoading() throws InterruptedException {
1921 testConcurrentLoading(CacheBuilder.newBuilder().expireAfterWrite(10, TimeUnit.SECONDS));
1922 }
1923
1924 private static void testConcurrentLoading(CacheBuilder<Object, Object> builder)
1925 throws InterruptedException {
1926 testConcurrentLoadingDefault(builder);
1927 testConcurrentLoadingNull(builder);
1928 testConcurrentLoadingUncheckedException(builder);
1929 testConcurrentLoadingCheckedException(builder);
1930 }
1931
1932
1933
1934
1935
1936 private static void testConcurrentLoadingDefault(CacheBuilder<Object, Object> builder)
1937 throws InterruptedException {
1938
1939 int count = 10;
1940 final AtomicInteger callCount = new AtomicInteger();
1941 final CountDownLatch startSignal = new CountDownLatch(count + 1);
1942 final Object result = new Object();
1943
1944 LoadingCache<String, Object> cache = builder.build(
1945 new CacheLoader<String, Object>() {
1946 @Override public Object load(String key) throws InterruptedException {
1947 callCount.incrementAndGet();
1948 startSignal.await();
1949 return result;
1950 }
1951 });
1952
1953 List<Object> resultArray = doConcurrentGet(cache, "bar", count, startSignal);
1954
1955 assertEquals(1, callCount.get());
1956 for (int i = 0; i < count; i++) {
1957 assertSame("result(" + i + ") didn't match expected", result, resultArray.get(i));
1958 }
1959 }
1960
1961
1962
1963
1964
1965
1966 private static void testConcurrentLoadingNull(CacheBuilder<Object, Object> builder)
1967 throws InterruptedException {
1968
1969 int count = 10;
1970 final AtomicInteger callCount = new AtomicInteger();
1971 final CountDownLatch startSignal = new CountDownLatch(count + 1);
1972
1973 LoadingCache<String, String> cache = builder.build(
1974 new CacheLoader<String, String>() {
1975 @Override public String load(String key) throws InterruptedException {
1976 callCount.incrementAndGet();
1977 startSignal.await();
1978 return null;
1979 }
1980 });
1981
1982 List<Object> result = doConcurrentGet(cache, "bar", count, startSignal);
1983
1984 assertEquals(1, callCount.get());
1985 for (int i = 0; i < count; i++) {
1986 assertTrue(result.get(i) instanceof InvalidCacheLoadException);
1987 }
1988
1989
1990 try {
1991 cache.getUnchecked("bar");
1992 fail();
1993 } catch (InvalidCacheLoadException expected) {
1994 }
1995 assertEquals(2, callCount.get());
1996 }
1997
1998
1999
2000
2001
2002
2003 private static void testConcurrentLoadingUncheckedException(
2004 CacheBuilder<Object, Object> builder) throws InterruptedException {
2005
2006 int count = 10;
2007 final AtomicInteger callCount = new AtomicInteger();
2008 final CountDownLatch startSignal = new CountDownLatch(count + 1);
2009 final RuntimeException e = new RuntimeException();
2010
2011 LoadingCache<String, String> cache = builder.build(
2012 new CacheLoader<String, String>() {
2013 @Override public String load(String key) throws InterruptedException {
2014 callCount.incrementAndGet();
2015 startSignal.await();
2016 throw e;
2017 }
2018 });
2019
2020 List<Object> result = doConcurrentGet(cache, "bar", count, startSignal);
2021
2022 assertEquals(1, callCount.get());
2023 for (int i = 0; i < count; i++) {
2024
2025
2026 assertTrue(result.get(i) instanceof UncheckedExecutionException);
2027 assertSame(e, ((UncheckedExecutionException) result.get(i)).getCause());
2028 }
2029
2030
2031 try {
2032 cache.getUnchecked("bar");
2033 fail();
2034 } catch (UncheckedExecutionException expected) {
2035 }
2036 assertEquals(2, callCount.get());
2037 }
2038
2039
2040
2041
2042
2043
2044 private static void testConcurrentLoadingCheckedException(
2045 CacheBuilder<Object, Object> builder) throws InterruptedException {
2046
2047 int count = 10;
2048 final AtomicInteger callCount = new AtomicInteger();
2049 final CountDownLatch startSignal = new CountDownLatch(count + 1);
2050 final IOException e = new IOException();
2051
2052 LoadingCache<String, String> cache = builder.build(
2053 new CacheLoader<String, String>() {
2054 @Override public String load(String key) throws IOException, InterruptedException {
2055 callCount.incrementAndGet();
2056 startSignal.await();
2057 throw e;
2058 }
2059 });
2060
2061 List<Object> result = doConcurrentGet(cache, "bar", count, startSignal);
2062
2063 assertEquals(1, callCount.get());
2064 for (int i = 0; i < count; i++) {
2065
2066
2067
2068 int mod = i % 3;
2069 if (mod == 0 || mod == 2) {
2070 assertTrue(result.get(i) instanceof ExecutionException);
2071 assertSame(e, ((ExecutionException) result.get(i)).getCause());
2072 } else {
2073 assertTrue(result.get(i) instanceof UncheckedExecutionException);
2074 assertSame(e, ((UncheckedExecutionException) result.get(i)).getCause());
2075 }
2076 }
2077
2078
2079 try {
2080 cache.getUnchecked("bar");
2081 fail();
2082 } catch (UncheckedExecutionException expected) {
2083 }
2084 assertEquals(2, callCount.get());
2085 }
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097 private static <K> List<Object> doConcurrentGet(final LoadingCache<K, ?> cache, final K key,
2098 int nThreads, final CountDownLatch gettersStartedSignal) throws InterruptedException {
2099
2100 final AtomicReferenceArray<Object> result = new AtomicReferenceArray<Object>(nThreads);
2101 final CountDownLatch gettersComplete = new CountDownLatch(nThreads);
2102 for (int i = 0; i < nThreads; i++) {
2103 final int index = i;
2104 Thread thread = new Thread(new Runnable() {
2105 @Override public void run() {
2106 gettersStartedSignal.countDown();
2107 Object value = null;
2108 try {
2109 int mod = index % 3;
2110 if (mod == 0) {
2111 value = cache.get(key);
2112 } else if (mod == 1) {
2113 value = cache.getUnchecked(key);
2114 } else {
2115 cache.refresh(key);
2116 value = cache.get(key);
2117 }
2118 result.set(index, value);
2119 } catch (Throwable t) {
2120 result.set(index, t);
2121 }
2122 gettersComplete.countDown();
2123 }
2124 });
2125 thread.start();
2126
2127
2128 while (thread.isAlive() && thread.getState() != Thread.State.WAITING) {
2129 Thread.yield();
2130 }
2131 }
2132 gettersStartedSignal.countDown();
2133 gettersComplete.await();
2134
2135 List<Object> resultList = Lists.newArrayListWithExpectedSize(nThreads);
2136 for (int i = 0; i < nThreads; i++) {
2137 resultList.add(result.get(i));
2138 }
2139 return resultList;
2140 }
2141
2142 public void testAsMapDuringLoading() throws InterruptedException, ExecutionException {
2143 final CountDownLatch getStartedSignal = new CountDownLatch(2);
2144 final CountDownLatch letGetFinishSignal = new CountDownLatch(1);
2145 final CountDownLatch getFinishedSignal = new CountDownLatch(2);
2146 final String getKey = "get";
2147 final String refreshKey = "refresh";
2148 final String suffix = "Suffix";
2149
2150 CacheLoader<String, String> computeFunction = new CacheLoader<String, String>() {
2151 @Override
2152 public String load(String key) throws InterruptedException {
2153 getStartedSignal.countDown();
2154 letGetFinishSignal.await();
2155 return key + suffix;
2156 }
2157 };
2158
2159 final LoadingCache<String, String> cache = CacheBuilder.newBuilder()
2160 .build(computeFunction);
2161 ConcurrentMap<String,String> map = cache.asMap();
2162 map.put(refreshKey, refreshKey);
2163 assertEquals(1, map.size());
2164 assertFalse(map.containsKey(getKey));
2165 assertSame(refreshKey, map.get(refreshKey));
2166
2167 new Thread() {
2168 @Override
2169 public void run() {
2170 cache.getUnchecked(getKey);
2171 getFinishedSignal.countDown();
2172 }
2173 }.start();
2174 new Thread() {
2175 @Override
2176 public void run() {
2177 cache.refresh(refreshKey);
2178 getFinishedSignal.countDown();
2179 }
2180 }.start();
2181
2182 getStartedSignal.await();
2183
2184
2185 assertEquals(1, map.size());
2186 assertFalse(map.containsKey(getKey));
2187 assertSame(refreshKey, map.get(refreshKey));
2188
2189
2190 letGetFinishSignal.countDown();
2191 getFinishedSignal.await();
2192 checkNothingLogged();
2193
2194
2195 assertEquals(2, cache.size());
2196 assertEquals(getKey + suffix, map.get(getKey));
2197 assertEquals(refreshKey + suffix, map.get(refreshKey));
2198 }
2199
2200 public void testInvalidateDuringLoading() throws InterruptedException, ExecutionException {
2201
2202 final CountDownLatch computationStarted = new CountDownLatch(2);
2203 final CountDownLatch letGetFinishSignal = new CountDownLatch(1);
2204 final CountDownLatch getFinishedSignal = new CountDownLatch(2);
2205 final String getKey = "get";
2206 final String refreshKey = "refresh";
2207 final String suffix = "Suffix";
2208
2209 CacheLoader<String, String> computeFunction = new CacheLoader<String, String>() {
2210 @Override
2211 public String load(String key) throws InterruptedException {
2212 computationStarted.countDown();
2213 letGetFinishSignal.await();
2214 return key + suffix;
2215 }
2216 };
2217
2218 final LoadingCache<String, String> cache = CacheBuilder.newBuilder()
2219 .build(computeFunction);
2220 ConcurrentMap<String,String> map = cache.asMap();
2221 map.put(refreshKey, refreshKey);
2222
2223 new Thread() {
2224 @Override
2225 public void run() {
2226 cache.getUnchecked(getKey);
2227 getFinishedSignal.countDown();
2228 }
2229 }.start();
2230 new Thread() {
2231 @Override
2232 public void run() {
2233 cache.refresh(refreshKey);
2234 getFinishedSignal.countDown();
2235 }
2236 }.start();
2237
2238 computationStarted.await();
2239 cache.invalidate(getKey);
2240 cache.invalidate(refreshKey);
2241 assertFalse(map.containsKey(getKey));
2242 assertFalse(map.containsKey(refreshKey));
2243
2244
2245 letGetFinishSignal.countDown();
2246 getFinishedSignal.await();
2247 checkNothingLogged();
2248
2249
2250 assertEquals(2, cache.size());
2251 assertEquals(getKey + suffix, map.get(getKey));
2252 assertEquals(refreshKey + suffix, map.get(refreshKey));
2253 assertEquals(2, cache.size());
2254 }
2255
2256 public void testInvalidateAndReloadDuringLoading()
2257 throws InterruptedException, ExecutionException {
2258
2259 final CountDownLatch computationStarted = new CountDownLatch(2);
2260 final CountDownLatch letGetFinishSignal = new CountDownLatch(1);
2261 final CountDownLatch getFinishedSignal = new CountDownLatch(4);
2262 final String getKey = "get";
2263 final String refreshKey = "refresh";
2264 final String suffix = "Suffix";
2265
2266 CacheLoader<String, String> computeFunction = new CacheLoader<String, String>() {
2267 @Override
2268 public String load(String key) throws InterruptedException {
2269 computationStarted.countDown();
2270 letGetFinishSignal.await();
2271 return key + suffix;
2272 }
2273 };
2274
2275 final LoadingCache<String, String> cache = CacheBuilder.newBuilder()
2276 .build(computeFunction);
2277 ConcurrentMap<String,String> map = cache.asMap();
2278 map.put(refreshKey, refreshKey);
2279
2280 new Thread() {
2281 @Override
2282 public void run() {
2283 cache.getUnchecked(getKey);
2284 getFinishedSignal.countDown();
2285 }
2286 }.start();
2287 new Thread() {
2288 @Override
2289 public void run() {
2290 cache.refresh(refreshKey);
2291 getFinishedSignal.countDown();
2292 }
2293 }.start();
2294
2295 computationStarted.await();
2296 cache.invalidate(getKey);
2297 cache.invalidate(refreshKey);
2298 assertFalse(map.containsKey(getKey));
2299 assertFalse(map.containsKey(refreshKey));
2300
2301
2302 new Thread() {
2303 @Override
2304 public void run() {
2305 cache.getUnchecked(getKey);
2306 getFinishedSignal.countDown();
2307 }
2308 }.start();
2309 new Thread() {
2310 @Override
2311 public void run() {
2312 cache.refresh(refreshKey);
2313 getFinishedSignal.countDown();
2314 }
2315 }.start();
2316
2317
2318 letGetFinishSignal.countDown();
2319 getFinishedSignal.await();
2320 checkNothingLogged();
2321
2322
2323 assertEquals(2, cache.size());
2324 assertEquals(getKey + suffix, map.get(getKey));
2325 assertEquals(refreshKey + suffix, map.get(refreshKey));
2326 }
2327
2328 public void testExpandDuringLoading() throws InterruptedException {
2329 final int count = 3;
2330 final AtomicInteger callCount = new AtomicInteger();
2331
2332 final CountDownLatch computeSignal = new CountDownLatch(1);
2333
2334 final CountDownLatch secondSignal = new CountDownLatch(1);
2335
2336 final CountDownLatch thirdSignal = new CountDownLatch(1);
2337
2338 final CountDownLatch fourthSignal = new CountDownLatch(1);
2339
2340 final CountDownLatch doneSignal = new CountDownLatch(count);
2341
2342 CacheLoader<String, String> computeFunction = new CacheLoader<String, String>() {
2343 @Override
2344 public String load(String key) throws InterruptedException {
2345 callCount.incrementAndGet();
2346 secondSignal.countDown();
2347 computeSignal.await();
2348 return key + "foo";
2349 }
2350 };
2351
2352 final LoadingCache<String, String> cache = CacheBuilder.newBuilder()
2353 .weakKeys()
2354 .build(computeFunction);
2355
2356 final AtomicReferenceArray<String> result = new AtomicReferenceArray<String>(count);
2357
2358 final String key = "bar";
2359
2360
2361 new Thread() {
2362 @Override
2363 public void run() {
2364 result.set(0, cache.getUnchecked(key));
2365 doneSignal.countDown();
2366 }
2367 }.start();
2368
2369
2370 secondSignal.await();
2371
2372
2373 new Thread() {
2374 @Override
2375 public void run() {
2376 thirdSignal.countDown();
2377 result.set(1, cache.getUnchecked(key));
2378 doneSignal.countDown();
2379 }
2380 }.start();
2381
2382
2383
2384 thirdSignal.await();
2385 Thread.yield();
2386
2387
2388 CacheTesting.forceExpandSegment(cache, key);
2389
2390
2391 new Thread() {
2392 @Override
2393 public void run() {
2394 fourthSignal.countDown();
2395 result.set(2, cache.getUnchecked(key));
2396 doneSignal.countDown();
2397 }
2398 }.start();
2399
2400
2401
2402 fourthSignal.await();
2403 Thread.yield();
2404
2405
2406 computeSignal.countDown();
2407 doneSignal.await();
2408
2409 assertTrue(callCount.get() == 1);
2410 assertEquals("barfoo", result.get(0));
2411 assertEquals("barfoo", result.get(1));
2412 assertEquals("barfoo", result.get(2));
2413 assertEquals("barfoo", cache.getUnchecked(key));
2414 }
2415
2416 public void testExpandDuringRefresh() throws InterruptedException, ExecutionException {
2417 final AtomicInteger callCount = new AtomicInteger();
2418
2419 final CountDownLatch computeSignal = new CountDownLatch(1);
2420
2421 final CountDownLatch secondSignal = new CountDownLatch(1);
2422
2423 final CountDownLatch thirdSignal = new CountDownLatch(1);
2424
2425 final CountDownLatch fourthSignal = new CountDownLatch(1);
2426
2427 final CountDownLatch doneSignal = new CountDownLatch(3);
2428 final String suffix = "Suffix";
2429
2430 CacheLoader<String, String> computeFunction = new CacheLoader<String, String>() {
2431 @Override
2432 public String load(String key) throws InterruptedException {
2433 callCount.incrementAndGet();
2434 secondSignal.countDown();
2435 computeSignal.await();
2436 return key + suffix;
2437 }
2438 };
2439
2440 final AtomicReferenceArray<String> result = new AtomicReferenceArray<String>(2);
2441
2442 final LoadingCache<String, String> cache = CacheBuilder.newBuilder()
2443 .build(computeFunction);
2444 final String key = "bar";
2445 cache.asMap().put(key, key);
2446
2447
2448 new Thread() {
2449 @Override
2450 public void run() {
2451 cache.refresh(key);
2452 doneSignal.countDown();
2453 }
2454 }.start();
2455
2456
2457 secondSignal.await();
2458 checkNothingLogged();
2459
2460
2461 new Thread() {
2462 @Override
2463 public void run() {
2464 thirdSignal.countDown();
2465 result.set(0, cache.getUnchecked(key));
2466 doneSignal.countDown();
2467 }
2468 }.start();
2469
2470
2471
2472 thirdSignal.await();
2473 Thread.yield();
2474
2475
2476 CacheTesting.forceExpandSegment(cache, key);
2477
2478
2479 new Thread() {
2480 @Override
2481 public void run() {
2482 fourthSignal.countDown();
2483 result.set(1, cache.getUnchecked(key));
2484 doneSignal.countDown();
2485 }
2486 }.start();
2487
2488
2489
2490 fourthSignal.await();
2491 Thread.yield();
2492
2493
2494 computeSignal.countDown();
2495 doneSignal.await();
2496
2497 assertTrue(callCount.get() == 1);
2498 assertEquals(key, result.get(0));
2499 assertEquals(key, result.get(1));
2500 assertEquals(key + suffix, cache.getUnchecked(key));
2501 }
2502
2503 static <T> Callable<T> throwing(final Exception exception) {
2504 return new Callable<T>() {
2505 @Override public T call() throws Exception {
2506 throw exception;
2507 }
2508 };
2509 }
2510 }