View Javadoc
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 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   * Tests relating to cache loading: concurrent loading, exceptions during loading, etc.
61   *
62   * @author mike nonemacher
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      // TODO(cpovirk): run tests in other thread instead of messing with main thread interrupt status
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     // callable is not called
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     // duplicate keys are ignored, and don't impact stats
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     // duplicate keys are ignored, and don't impact stats
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           // add extra entries
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         // ignore request keys
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     // refreshed
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     // refreshed
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     // Sanity check:
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     // refreshed
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     // refreshed
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       // The entry should get garbage collected and recomputed.
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       // The entry should get garbage collected and recomputed.
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     // this blocks if computation can't deal with partially-collected values
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     // this blocks if computation can't deal with partially-collected values
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    * Make sure LoadingCache correctly wraps ExecutionExceptions and UncheckedExecutionExceptions.
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    * On a successful concurrent computation, only one thread does the work, but all the threads get
1934    * the same result.
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    * On a concurrent computation that returns null, all threads should get an
1963    * InvalidCacheLoadException, with the loader only called once. The result should not be cached
1964    * (a later request should call the loader again).
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     // subsequent calls should call the loader again, not get the old exception
1990     try {
1991       cache.getUnchecked("bar");
1992       fail();
1993     } catch (InvalidCacheLoadException expected) {
1994     }
1995     assertEquals(2, callCount.get());
1996   }
1997 
1998   /**
1999    * On a concurrent computation that throws an unchecked exception, all threads should get the
2000    * (wrapped) exception, with the loader called only once. The result should not be cached (a later
2001    * request should call the loader again).
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       // doConcurrentGet alternates between calling getUnchecked and calling get, but an unchecked
2025       // exception thrown by the loader is always wrapped as an UncheckedExecutionException.
2026       assertTrue(result.get(i) instanceof UncheckedExecutionException);
2027       assertSame(e, ((UncheckedExecutionException) result.get(i)).getCause());
2028     }
2029 
2030     // subsequent calls should call the loader again, not get the old exception
2031     try {
2032       cache.getUnchecked("bar");
2033       fail();
2034     } catch (UncheckedExecutionException expected) {
2035     }
2036     assertEquals(2, callCount.get());
2037   }
2038 
2039   /**
2040    * On a concurrent computation that throws a checked exception, all threads should get the
2041    * (wrapped) exception, with the loader called only once. The result should not be cached (a later
2042    * request should call the loader again).
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       // doConcurrentGet alternates between calling getUnchecked and calling get. If we call get(),
2066       // we should get an ExecutionException; if we call getUnchecked(), we should get an
2067       // UncheckedExecutionException.
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     // subsequent calls should call the loader again, not get the old exception
2079     try {
2080       cache.getUnchecked("bar");
2081       fail();
2082     } catch (UncheckedExecutionException expected) {
2083     }
2084     assertEquals(2, callCount.get());
2085   }
2086 
2087   /**
2088    * Test-helper method that performs {@code nThreads} concurrent calls to {@code cache.get(key)}
2089    * or {@code cache.getUnchecked(key)}, and returns a List containing each of the results. The
2090    * result for any given call to {@code cache.get} or {@code cache.getUnchecked} is the value
2091    * returned, or the exception thrown.
2092    *
2093    * <p>As we iterate from {@code 0} to {@code nThreads}, threads with an even index will call
2094    * {@code getUnchecked}, and threads with an odd index will call {@code get}. If the cache throws
2095    * exceptions, this difference may be visible in the returned List.
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       // we want to wait until each thread is WAITING - one thread waiting inside CacheLoader.load
2127       // (in startSignal.await()), and the others waiting for that thread's result.
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     // computation is in progress; asMap shouldn't have changed
2185     assertEquals(1, map.size());
2186     assertFalse(map.containsKey(getKey));
2187     assertSame(refreshKey, map.get(refreshKey));
2188 
2189     // let computation complete
2190     letGetFinishSignal.countDown();
2191     getFinishedSignal.await();
2192     checkNothingLogged();
2193 
2194     // asMap view should have been updated
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     // computation starts; invalidate() is called on the key being computed, computation finishes
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     // let computation complete
2245     letGetFinishSignal.countDown();
2246     getFinishedSignal.await();
2247     checkNothingLogged();
2248 
2249     // results should be visible
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     // computation starts; clear() is called, computation finishes
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     // start new computations
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     // let computation complete
2318     letGetFinishSignal.countDown();
2319     getFinishedSignal.await();
2320     checkNothingLogged();
2321 
2322     // results should be visible
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     // tells the computing thread when to start computing
2332     final CountDownLatch computeSignal = new CountDownLatch(1);
2333     // tells the main thread when computation is pending
2334     final CountDownLatch secondSignal = new CountDownLatch(1);
2335     // tells the main thread when the second get has started
2336     final CountDownLatch thirdSignal = new CountDownLatch(1);
2337     // tells the main thread when the third get has started
2338     final CountDownLatch fourthSignal = new CountDownLatch(1);
2339     // tells the test when all gets have returned
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     // start computing thread
2361     new Thread() {
2362       @Override
2363       public void run() {
2364         result.set(0, cache.getUnchecked(key));
2365         doneSignal.countDown();
2366       }
2367     }.start();
2368 
2369     // wait for computation to start
2370     secondSignal.await();
2371 
2372     // start waiting thread
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     // give the second get a chance to run; it is okay for this to be racy
2383     // as the end result should be the same either way
2384     thirdSignal.await();
2385     Thread.yield();
2386 
2387     // Expand!
2388     CacheTesting.forceExpandSegment(cache, key);
2389 
2390     // start another waiting thread
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     // give the third get a chance to run; it is okay for this to be racy
2401     // as the end result should be the same either way
2402     fourthSignal.await();
2403     Thread.yield();
2404 
2405     // let computation finish
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     // tells the computing thread when to start computing
2419     final CountDownLatch computeSignal = new CountDownLatch(1);
2420     // tells the main thread when computation is pending
2421     final CountDownLatch secondSignal = new CountDownLatch(1);
2422     // tells the main thread when the second get has started
2423     final CountDownLatch thirdSignal = new CountDownLatch(1);
2424     // tells the main thread when the third get has started
2425     final CountDownLatch fourthSignal = new CountDownLatch(1);
2426     // tells the test when all gets have returned
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     // start computing thread
2448     new Thread() {
2449       @Override
2450       public void run() {
2451         cache.refresh(key);
2452         doneSignal.countDown();
2453       }
2454     }.start();
2455 
2456     // wait for computation to start
2457     secondSignal.await();
2458     checkNothingLogged();
2459 
2460     // start waiting thread
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     // give the second get a chance to run; it is okay for this to be racy
2471     // as the end result should be the same either way
2472     thirdSignal.await();
2473     Thread.yield();
2474 
2475     // Expand!
2476     CacheTesting.forceExpandSegment(cache, key);
2477 
2478     // start another waiting thread
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     // give the third get a chance to run; it is okay for this to be racy
2489     // as the end result should be the same either way
2490     fourthSignal.await();
2491     Thread.yield();
2492 
2493     // let computation finish
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 }