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