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