11d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/*
21d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Copyright (C) 2011 The Guava Authors
31d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
41d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Licensed under the Apache License, Version 2.0 (the "License");
51d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * you may not use this file except in compliance with the License.
61d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * You may obtain a copy of the License at
71d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
81d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * http://www.apache.org/licenses/LICENSE-2.0
91d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Unless required by applicable law or agreed to in writing, software
111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * distributed under the License is distributed on an "AS IS" BASIS,
121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * See the License for the specific language governing permissions and
141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * limitations under the License.
151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */
161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpackage com.google.common.cache;
181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static com.google.common.cache.CacheBuilder.NULL_TICKER;
201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static com.google.common.cache.LocalCache.DISCARDING_QUEUE;
211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static com.google.common.cache.LocalCache.DRAIN_THRESHOLD;
221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static com.google.common.cache.LocalCache.nullEntry;
231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static com.google.common.cache.LocalCache.unset;
241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static com.google.common.cache.TestingCacheLoaders.identityLoader;
251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static com.google.common.cache.TestingRemovalListeners.countingRemovalListener;
261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static com.google.common.cache.TestingRemovalListeners.queuingRemovalListener;
271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static com.google.common.cache.TestingWeighers.constantWeigher;
281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static com.google.common.collect.Lists.newArrayList;
291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static com.google.common.collect.Maps.immutableEntry;
301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static java.util.concurrent.TimeUnit.NANOSECONDS;
311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static java.util.concurrent.TimeUnit.SECONDS;
321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.base.Equivalence;
341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.base.Ticker;
351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.cache.LocalCache.EntryFactory;
361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.cache.LocalCache.LoadingValueReference;
371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.cache.LocalCache.LocalLoadingCache;
381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.cache.LocalCache.LocalManualCache;
391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.cache.LocalCache.ReferenceEntry;
401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.cache.LocalCache.Segment;
411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.cache.LocalCache.Strength;
421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.cache.LocalCache.ValueReference;
431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.cache.TestingCacheLoaders.CountingLoader;
441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.cache.TestingRemovalListeners.CountingRemovalListener;
451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.cache.TestingRemovalListeners.QueuingRemovalListener;
461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.collect.ImmutableList;
471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.collect.ImmutableMap;
480888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport com.google.common.collect.ImmutableSet;
491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.collect.Lists;
501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.collect.Maps;
510888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport com.google.common.collect.testing.MapTestSuiteBuilder;
520888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport com.google.common.collect.testing.TestStringMapGenerator;
530888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport com.google.common.collect.testing.features.CollectionFeature;
540888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport com.google.common.collect.testing.features.CollectionSize;
550888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport com.google.common.collect.testing.features.MapFeature;
561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.testing.FakeTicker;
571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.testing.NullPointerTester;
581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.testing.SerializableTester;
591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.testing.TestLogHandler;
601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
610888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport junit.framework.Test;
621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport junit.framework.TestCase;
630888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport junit.framework.TestSuite;
641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.io.Serializable;
661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.lang.ref.Reference;
671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.lang.ref.ReferenceQueue;
681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.Iterator;
691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.LinkedHashMap;
701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.List;
711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.Map;
720888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport java.util.Map.Entry;
731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.Random;
740888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport java.util.Set;
751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.CountDownLatch;
761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.ExecutionException;
771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.TimeUnit;
781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.atomic.AtomicReferenceArray;
791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.logging.LogRecord;
801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/**
821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author Charles Fry
831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */
841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpublic class LocalCacheTest extends TestCase {
851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
860888a09821a98ac0680fad765217302858e70fa4Paul Duffin  public static Test suite() {
870888a09821a98ac0680fad765217302858e70fa4Paul Duffin    TestSuite suite = new TestSuite();
880888a09821a98ac0680fad765217302858e70fa4Paul Duffin    suite.addTestSuite(LocalCacheTest.class);
890888a09821a98ac0680fad765217302858e70fa4Paul Duffin    suite.addTest(MapTestSuiteBuilder.using(new TestStringMapGenerator() {
900888a09821a98ac0680fad765217302858e70fa4Paul Duffin          @Override public Map<String, String> create(
910888a09821a98ac0680fad765217302858e70fa4Paul Duffin              Entry<String, String>[] entries) {
920888a09821a98ac0680fad765217302858e70fa4Paul Duffin            LocalCache<String, String> map = makeLocalCache(createCacheBuilder());
930888a09821a98ac0680fad765217302858e70fa4Paul Duffin            for (Entry<String, String> entry : entries) {
940888a09821a98ac0680fad765217302858e70fa4Paul Duffin              map.put(entry.getKey(), entry.getValue());
950888a09821a98ac0680fad765217302858e70fa4Paul Duffin            }
960888a09821a98ac0680fad765217302858e70fa4Paul Duffin            return map;
970888a09821a98ac0680fad765217302858e70fa4Paul Duffin          }
980888a09821a98ac0680fad765217302858e70fa4Paul Duffin
990888a09821a98ac0680fad765217302858e70fa4Paul Duffin        }).named("LocalCache with defaults")
1000888a09821a98ac0680fad765217302858e70fa4Paul Duffin        .withFeatures(CollectionSize.ANY, MapFeature.GENERAL_PURPOSE,
1010888a09821a98ac0680fad765217302858e70fa4Paul Duffin            CollectionFeature.SUPPORTS_ITERATOR_REMOVE)
1020888a09821a98ac0680fad765217302858e70fa4Paul Duffin        .createTestSuite());
1030888a09821a98ac0680fad765217302858e70fa4Paul Duffin    return suite;
1040888a09821a98ac0680fad765217302858e70fa4Paul Duffin  }
1050888a09821a98ac0680fad765217302858e70fa4Paul Duffin
1061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  static final int SMALL_MAX_SIZE = DRAIN_THRESHOLD * 5;
1071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  TestLogHandler logHandler;
1091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  @Override
1111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void setUp() throws Exception {
1121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    super.setUp();
1131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    logHandler = new TestLogHandler();
1141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache.logger.addHandler(logHandler);
1151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  @Override
1181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void tearDown() throws Exception {
1191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    super.tearDown();
1201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache.logger.removeHandler(logHandler);
1211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private Throwable popLoggedThrowable() {
1241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    List<LogRecord> logRecords = logHandler.getStoredLogRecords();
1251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(1, logRecords.size());
1261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LogRecord logRecord = logRecords.get(0);
1271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    logHandler.clear();
1281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return logRecord.getThrown();
1291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private void checkNothingLogged() {
1321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(logHandler.getStoredLogRecords().isEmpty());
1331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private void checkLogged(Throwable t) {
1361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(t, popLoggedThrowable());
1371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1390888a09821a98ac0680fad765217302858e70fa4Paul Duffin  private static <K, V> LocalCache<K, V> makeLocalCache(
1400888a09821a98ac0680fad765217302858e70fa4Paul Duffin      CacheBuilder<? super K, ? super V> builder) {
1411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return new LocalCache<K, V>(builder, null);
1421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static CacheBuilder<Object, Object> createCacheBuilder() {
1451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return new CacheBuilder<Object, Object>();
1461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  // constructor tests
1491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testDefaults() {
1511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map = makeLocalCache(createCacheBuilder());
1521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(Strength.STRONG, map.keyStrength);
1541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(Strength.STRONG, map.valueStrength);
1551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(map.keyStrength.defaultEquivalence(), map.keyEquivalence);
1561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(map.valueStrength.defaultEquivalence(), map.valueEquivalence);
1571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, map.expireAfterAccessNanos);
1591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, map.expireAfterWriteNanos);
1601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, map.refreshNanos);
1611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(CacheBuilder.UNSET_INT, map.maxWeight);
1621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(EntryFactory.STRONG, map.entryFactory);
1641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(CacheBuilder.NullListener.INSTANCE, map.removalListener);
1651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(DISCARDING_QUEUE, map.removalNotificationQueue);
1661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(NULL_TICKER, map.ticker);
1671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(4, map.concurrencyLevel);
1691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // concurrency level
1711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(4, map.segments.length);
1721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // initial capacity / concurrency level
1731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(16 / map.segments.length, map.segments[0].table.length());
1741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(map.evictsBySize());
1761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(map.expires());
1771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(map.expiresAfterWrite());
1781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(map.expiresAfterAccess());
1791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(map.refreshes());
1801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testSetKeyEquivalence() {
1831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Equivalence<Object> testEquivalence = new Equivalence<Object>() {
1841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @Override
1851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      protected boolean doEquivalent(Object a, Object b) {
1861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        return false;
1871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
1881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @Override
1901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      protected int doHash(Object t) {
1911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        return 0;
1921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
1931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    };
1941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map =
1961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        makeLocalCache(createCacheBuilder().keyEquivalence(testEquivalence));
1971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(testEquivalence, map.keyEquivalence);
1981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(map.valueStrength.defaultEquivalence(), map.valueEquivalence);
1991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
2001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testSetValueEquivalence() {
2021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Equivalence<Object> testEquivalence = new Equivalence<Object>() {
2031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @Override
2041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      protected boolean doEquivalent(Object a, Object b) {
2051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        return false;
2061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
2071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @Override
2091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      protected int doHash(Object t) {
2101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        return 0;
2111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
2121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    };
2131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map =
2151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        makeLocalCache(createCacheBuilder().valueEquivalence(testEquivalence));
2161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(testEquivalence, map.valueEquivalence);
2171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(map.keyStrength.defaultEquivalence(), map.keyEquivalence);
2181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
2191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testSetConcurrencyLevel() {
2211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // round up to nearest power of two
2221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkConcurrencyLevel(1, 1);
2241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkConcurrencyLevel(2, 2);
2251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkConcurrencyLevel(3, 4);
2261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkConcurrencyLevel(4, 4);
2271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkConcurrencyLevel(5, 8);
2281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkConcurrencyLevel(6, 8);
2291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkConcurrencyLevel(7, 8);
2301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkConcurrencyLevel(8, 8);
2311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
2321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static void checkConcurrencyLevel(int concurrencyLevel, int segmentCount) {
2341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map =
2351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        makeLocalCache(createCacheBuilder().concurrencyLevel(concurrencyLevel));
2361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(segmentCount, map.segments.length);
2371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
2381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testSetInitialCapacity() {
2401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // share capacity over each segment, then round up to nearest power of two
2411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkInitialCapacity(1, 0, 1);
2431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkInitialCapacity(1, 1, 1);
2441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkInitialCapacity(1, 2, 2);
2451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkInitialCapacity(1, 3, 4);
2461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkInitialCapacity(1, 4, 4);
2471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkInitialCapacity(1, 5, 8);
2481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkInitialCapacity(1, 6, 8);
2491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkInitialCapacity(1, 7, 8);
2501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkInitialCapacity(1, 8, 8);
2511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkInitialCapacity(2, 0, 1);
2531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkInitialCapacity(2, 1, 1);
2541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkInitialCapacity(2, 2, 1);
2551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkInitialCapacity(2, 3, 2);
2561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkInitialCapacity(2, 4, 2);
2571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkInitialCapacity(2, 5, 4);
2581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkInitialCapacity(2, 6, 4);
2591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkInitialCapacity(2, 7, 4);
2601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkInitialCapacity(2, 8, 4);
2611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkInitialCapacity(4, 0, 1);
2631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkInitialCapacity(4, 1, 1);
2641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkInitialCapacity(4, 2, 1);
2651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkInitialCapacity(4, 3, 1);
2661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkInitialCapacity(4, 4, 1);
2671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkInitialCapacity(4, 5, 2);
2681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkInitialCapacity(4, 6, 2);
2691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkInitialCapacity(4, 7, 2);
2701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkInitialCapacity(4, 8, 2);
2711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
2721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static void checkInitialCapacity(
2741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      int concurrencyLevel, int initialCapacity, int segmentSize) {
2751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map = makeLocalCache(
2761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        createCacheBuilder().concurrencyLevel(concurrencyLevel).initialCapacity(initialCapacity));
2771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (int i = 0; i < map.segments.length; i++) {
2781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertEquals(segmentSize, map.segments[i].table.length());
2791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
2811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testSetMaximumSize() {
2831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // vary maximumSize wrt concurrencyLevel
2841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2857dd252788645e940eada959bdde927426e2531c9Paul Duffin    for (int maxSize = 1; maxSize < 100; maxSize++) {
2861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkMaximumSize(1, 8, maxSize);
2871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkMaximumSize(2, 8, maxSize);
2881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkMaximumSize(4, 8, maxSize);
2891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkMaximumSize(8, 8, maxSize);
2901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkMaximumSize(1, 8, Long.MAX_VALUE);
2931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkMaximumSize(2, 8, Long.MAX_VALUE);
2941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkMaximumSize(4, 8, Long.MAX_VALUE);
2951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkMaximumSize(8, 8, Long.MAX_VALUE);
2961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // vary initial capacity wrt maximumSize
2981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (int capacity = 0; capacity < 8; capacity++) {
3001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkMaximumSize(1, capacity, 4);
3011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkMaximumSize(2, capacity, 4);
3021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkMaximumSize(4, capacity, 4);
3031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkMaximumSize(8, capacity, 4);
3041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
3051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
3061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static void checkMaximumSize(int concurrencyLevel, int initialCapacity, long maxSize) {
3081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map = makeLocalCache(createCacheBuilder()
3091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .concurrencyLevel(concurrencyLevel)
3101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .initialCapacity(initialCapacity)
3111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .maximumSize(maxSize));
3121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    long totalCapacity = 0;
3137dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertTrue("segments=" + map.segments.length + ", maxSize=" + maxSize,
3147dd252788645e940eada959bdde927426e2531c9Paul Duffin        map.segments.length <= Math.max(1, maxSize / 10));
3151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (int i = 0; i < map.segments.length; i++) {
3161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      totalCapacity += map.segments[i].maxSegmentWeight;
3171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
3181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue("totalCapacity=" + totalCapacity + ", maxSize=" + maxSize, totalCapacity == maxSize);
3191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    map = makeLocalCache(createCacheBuilder()
3211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .concurrencyLevel(concurrencyLevel)
3221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .initialCapacity(initialCapacity)
3231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .maximumWeight(maxSize)
3241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .weigher(constantWeigher(1)));
3257dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertTrue("segments=" + map.segments.length + ", maxSize=" + maxSize,
3267dd252788645e940eada959bdde927426e2531c9Paul Duffin        map.segments.length <= Math.max(1, maxSize / 10));
3271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    totalCapacity = 0;
3281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (int i = 0; i < map.segments.length; i++) {
3291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      totalCapacity += map.segments[i].maxSegmentWeight;
3301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
3311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue("totalCapacity=" + totalCapacity + ", maxSize=" + maxSize, totalCapacity == maxSize);
3321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
3331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testSetWeigher() {
3351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Weigher<Object, Object> testWeigher = new Weigher<Object, Object>() {
3361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @Override
3371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      public int weigh(Object key, Object value) {
3381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        return 42;
3391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
3401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    };
3411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map =
3421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        makeLocalCache(createCacheBuilder().maximumWeight(1).weigher(testWeigher));
3431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(testWeigher, map.weigher);
3441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
3451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testSetWeakKeys() {
3471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map = makeLocalCache(createCacheBuilder().weakKeys());
3481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkStrength(map, Strength.WEAK, Strength.STRONG);
3491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(EntryFactory.WEAK, map.entryFactory);
3501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
3511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testSetWeakValues() {
3531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map = makeLocalCache(createCacheBuilder().weakValues());
3541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkStrength(map, Strength.STRONG, Strength.WEAK);
3551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(EntryFactory.STRONG, map.entryFactory);
3561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
3571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testSetSoftValues() {
3591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map = makeLocalCache(createCacheBuilder().softValues());
3601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkStrength(map, Strength.STRONG, Strength.SOFT);
3611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(EntryFactory.STRONG, map.entryFactory);
3621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
3631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static void checkStrength(
3651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      LocalCache<Object, Object> map, Strength keyStrength, Strength valueStrength) {
3661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(keyStrength, map.keyStrength);
3671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(valueStrength, map.valueStrength);
3681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(keyStrength.defaultEquivalence(), map.keyEquivalence);
3691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(valueStrength.defaultEquivalence(), map.valueEquivalence);
3701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
3711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testSetExpireAfterWrite() {
3731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    long duration = 42;
3741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    TimeUnit unit = TimeUnit.SECONDS;
3751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map =
3761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        makeLocalCache(createCacheBuilder().expireAfterWrite(duration, unit));
3771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(unit.toNanos(duration), map.expireAfterWriteNanos);
3781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
3791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testSetExpireAfterAccess() {
3811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    long duration = 42;
3821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    TimeUnit unit = TimeUnit.SECONDS;
3831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map =
3841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        makeLocalCache(createCacheBuilder().expireAfterAccess(duration, unit));
3851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(unit.toNanos(duration), map.expireAfterAccessNanos);
3861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
3871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testSetRefresh() {
3891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    long duration = 42;
3901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    TimeUnit unit = TimeUnit.SECONDS;
3911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map =
3921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        makeLocalCache(createCacheBuilder().refreshAfterWrite(duration, unit));
3931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(unit.toNanos(duration), map.refreshNanos);
3941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
3951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testSetRemovalListener() {
3971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    RemovalListener<Object, Object> testListener = TestingRemovalListeners.nullRemovalListener();
3981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map =
3991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        makeLocalCache(createCacheBuilder().removalListener(testListener));
4001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(testListener, map.removalListener);
4011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
4021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testSetTicker() {
4041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Ticker testTicker = new Ticker() {
4051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @Override
4061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      public long read() {
4071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        return 0;
4081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
4091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    };
4101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map = makeLocalCache(createCacheBuilder().ticker(testTicker));
4111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(testTicker, map.ticker);
4121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
4131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testEntryFactory() {
4151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(EntryFactory.STRONG,
4161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        EntryFactory.getFactory(Strength.STRONG, false, false));
4171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(EntryFactory.STRONG_ACCESS,
4181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        EntryFactory.getFactory(Strength.STRONG, true, false));
4191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(EntryFactory.STRONG_WRITE,
4201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        EntryFactory.getFactory(Strength.STRONG, false, true));
4211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(EntryFactory.STRONG_ACCESS_WRITE,
4221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        EntryFactory.getFactory(Strength.STRONG, true, true));
4231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(EntryFactory.WEAK,
4241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        EntryFactory.getFactory(Strength.WEAK, false, false));
4251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(EntryFactory.WEAK_ACCESS,
4261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        EntryFactory.getFactory(Strength.WEAK, true, false));
4271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(EntryFactory.WEAK_WRITE,
4281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        EntryFactory.getFactory(Strength.WEAK, false, true));
4291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(EntryFactory.WEAK_ACCESS_WRITE,
4301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        EntryFactory.getFactory(Strength.WEAK, true, true));
4311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
4321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  // computation tests
4341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testCompute() throws ExecutionException {
4361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    CountingLoader loader = new CountingLoader();
4371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map = makeLocalCache(createCacheBuilder());
4381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, loader.getCount());
4391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object key = new Object();
4411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object value = map.get(key, loader);
4421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, loader.getCount());
4431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(value, map.get(key, loader));
4441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, loader.getCount());
4451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
4461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testRecordReadOnCompute() throws ExecutionException {
4481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    CountingLoader loader = new CountingLoader();
4491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (CacheBuilder<Object, Object> builder : allEvictingMakers()) {
4501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      LocalCache<Object, Object> map =
4511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          makeLocalCache(builder.concurrencyLevel(1));
4521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Segment<Object, Object> segment = map.segments[0];
4531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      List<ReferenceEntry<Object, Object>> writeOrder = Lists.newLinkedList();
4541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      List<ReferenceEntry<Object, Object>> readOrder = Lists.newLinkedList();
4551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      for (int i = 0; i < SMALL_MAX_SIZE; i++) {
4561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Object key = new Object();
4571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        int hash = map.hash(key);
4581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        map.get(key, loader);
4601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        ReferenceEntry<Object, Object> entry = segment.getEntry(key, hash);
4611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        writeOrder.add(entry);
4621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        readOrder.add(entry);
4631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
4641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkEvictionQueues(map, segment, readOrder, writeOrder);
4661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkExpirationTimes(map);
4671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertTrue(segment.recencyQueue.isEmpty());
4681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      // access some of the elements
4701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Random random = new Random();
4711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      List<ReferenceEntry<Object, Object>> reads = Lists.newArrayList();
4721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Iterator<ReferenceEntry<Object, Object>> i = readOrder.iterator();
4731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      while (i.hasNext()) {
4741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        ReferenceEntry<Object, Object> entry = i.next();
4751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        if (random.nextBoolean()) {
4761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          map.get(entry.getKey(), loader);
4771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          reads.add(entry);
4781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          i.remove();
4791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          assertTrue(segment.recencyQueue.size() <= DRAIN_THRESHOLD);
4801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
4811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
4821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      int undrainedIndex = reads.size() - segment.recencyQueue.size();
4831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkAndDrainRecencyQueue(map, segment, reads.subList(undrainedIndex, reads.size()));
4841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      readOrder.addAll(reads);
4851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkEvictionQueues(map, segment, readOrder, writeOrder);
4871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkExpirationTimes(map);
4881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
4891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
4901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testComputeExistingEntry() throws ExecutionException {
4921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    CountingLoader loader = new CountingLoader();
4931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map = makeLocalCache(createCacheBuilder());
4941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, loader.getCount());
4951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object key = new Object();
4971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object value = new Object();
4981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    map.put(key, value);
4991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
5001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(value, map.get(key, loader));
5011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, loader.getCount());
5021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
5031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
5041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testComputePartiallyCollectedKey() throws ExecutionException {
5051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    CacheBuilder<Object, Object> builder = createCacheBuilder().concurrencyLevel(1);
5061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    CountingLoader loader = new CountingLoader();
5071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map = makeLocalCache(builder);
5081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Segment<Object, Object> segment = map.segments[0];
5091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    AtomicReferenceArray<ReferenceEntry<Object, Object>> table = segment.table;
5101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, loader.getCount());
5111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
5121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object key = new Object();
5131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int hash = map.hash(key);
5141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object value = new Object();
5151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int index = hash & (table.length() - 1);
5161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
5171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    DummyEntry<Object, Object> entry = DummyEntry.create(key, hash, null);
5187dd252788645e940eada959bdde927426e2531c9Paul Duffin    DummyValueReference<Object, Object> valueRef = DummyValueReference.create(value);
5191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    entry.setValueReference(valueRef);
5201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    table.set(index, entry);
5211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.count++;
5221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
5231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(value, map.get(key, loader));
5241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, loader.getCount());
5251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, segment.count);
5261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
5271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    entry.clearKey();
5281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNotSame(value, map.get(key, loader));
5291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, loader.getCount());
5301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(2, segment.count);
5311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
5321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
5331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testComputePartiallyCollectedValue() throws ExecutionException {
5341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    CacheBuilder<Object, Object> builder = createCacheBuilder().concurrencyLevel(1);
5351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    CountingLoader loader = new CountingLoader();
5361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map = makeLocalCache(builder);
5371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Segment<Object, Object> segment = map.segments[0];
5381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    AtomicReferenceArray<ReferenceEntry<Object, Object>> table = segment.table;
5391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, loader.getCount());
5401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
5411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object key = new Object();
5421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int hash = map.hash(key);
5431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object value = new Object();
5441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int index = hash & (table.length() - 1);
5451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
5461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    DummyEntry<Object, Object> entry = DummyEntry.create(key, hash, null);
5477dd252788645e940eada959bdde927426e2531c9Paul Duffin    DummyValueReference<Object, Object> valueRef = DummyValueReference.create(value);
5481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    entry.setValueReference(valueRef);
5491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    table.set(index, entry);
5501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.count++;
5511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
5521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(value, map.get(key, loader));
5531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, loader.getCount());
5541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, segment.count);
5551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
5561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    valueRef.clear();
5571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNotSame(value, map.get(key, loader));
5581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, loader.getCount());
5591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, segment.count);
5601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
5611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
5621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testComputeExpiredEntry() throws ExecutionException {
5631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    CacheBuilder<Object, Object> builder = createCacheBuilder()
5641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .expireAfterWrite(1, TimeUnit.NANOSECONDS);
5651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    CountingLoader loader = new CountingLoader();
5661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map = makeLocalCache(builder);
5671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, loader.getCount());
5681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
5691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object key = new Object();
5701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object one = map.get(key, loader);
5711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, loader.getCount());
5721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
5731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object two = map.get(key, loader);
5741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNotSame(one, two);
5751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(2, loader.getCount());
5761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
5771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
5780888a09821a98ac0680fad765217302858e70fa4Paul Duffin  public void testValues() {
5790888a09821a98ac0680fad765217302858e70fa4Paul Duffin    LocalCache<Object, Object> map = makeLocalCache(createCacheBuilder());
5800888a09821a98ac0680fad765217302858e70fa4Paul Duffin    map.put("foo", "bar");
5810888a09821a98ac0680fad765217302858e70fa4Paul Duffin    map.put("baz", "bar");
5820888a09821a98ac0680fad765217302858e70fa4Paul Duffin    map.put("quux", "quux");
5830888a09821a98ac0680fad765217302858e70fa4Paul Duffin    assertFalse(map.values() instanceof Set);
5840888a09821a98ac0680fad765217302858e70fa4Paul Duffin    assertTrue(map.values().removeAll(ImmutableSet.of("bar")));
5850888a09821a98ac0680fad765217302858e70fa4Paul Duffin    assertEquals(1, map.size());
5860888a09821a98ac0680fad765217302858e70fa4Paul Duffin  }
5870888a09821a98ac0680fad765217302858e70fa4Paul Duffin
5881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testCopyEntry_computing() {
5891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final CountDownLatch startSignal = new CountDownLatch(1);
5901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final CountDownLatch computingSignal = new CountDownLatch(1);
5911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final CountDownLatch doneSignal = new CountDownLatch(2);
5921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final Object computedObject = new Object();
5931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
5941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final CacheLoader<Object, Object> loader = new CacheLoader<Object, Object>() {
5951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @Override
5961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      public Object load(Object key) throws Exception {
5971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        computingSignal.countDown();
5981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        startSignal.await();
5991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        return computedObject;
6001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
6011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    };
6021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
6031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    QueuingRemovalListener<Object, Object> listener = queuingRemovalListener();
6041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    CacheBuilder<Object, Object> builder = createCacheBuilder()
6051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .concurrencyLevel(1)
6061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .removalListener(listener);
6071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final LocalCache<Object, Object> map = makeLocalCache(builder);
6081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Segment<Object, Object> segment = map.segments[0];
6091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    AtomicReferenceArray<ReferenceEntry<Object, Object>> table = segment.table;
6101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(listener.isEmpty());
6111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
6121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final Object one = new Object();
6131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int hash = map.hash(one);
6141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int index = hash & (table.length() - 1);
6151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
6161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    new Thread() {
6171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @Override
6181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      public void run() {
6191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        try {
6201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          map.get(one, loader);
6211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        } catch (ExecutionException e) {
6221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          throw new RuntimeException(e);
6231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
6241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        doneSignal.countDown();
6251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
6261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }.start();
6271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
6281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    try {
6291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      computingSignal.await();
6301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    } catch (InterruptedException e) {
6311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      throw new RuntimeException(e);
6321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
6331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
6341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    new Thread() {
6351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @Override
6361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      public void run() {
6371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        try {
6381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          map.get(one, loader);
6391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        } catch (ExecutionException e) {
6401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          throw new RuntimeException(e);
6411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
6421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        doneSignal.countDown();
6431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
6441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }.start();
6451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
6461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ReferenceEntry<Object, Object> entry = segment.getEntry(one, hash);
6471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ReferenceEntry<Object, Object> newEntry = segment.copyEntry(entry, null);
6481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    table.set(index, newEntry);
6491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
6501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @SuppressWarnings("unchecked")
6511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LoadingValueReference<Object, Object> valueReference =
6521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        (LoadingValueReference) newEntry.getValueReference();
6531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(valueReference.futureValue.isDone());
6541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    startSignal.countDown();
6551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
6561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    try {
6571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      doneSignal.await();
6581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    } catch (InterruptedException e) {
6591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      throw new RuntimeException(e);
6601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
6611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
6621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    map.cleanUp(); // force notifications
6631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(listener.isEmpty());
6641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(map.containsKey(one));
6651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, map.size());
6661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(computedObject, map.get(one));
6671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
6681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
6691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testRemovalListenerCheckedException() {
6701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final RuntimeException e = new RuntimeException();
6711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    RemovalListener<Object, Object> listener = new RemovalListener<Object, Object>() {
6721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @Override
6731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      public void onRemoval(RemovalNotification<Object, Object> notification) {
6741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        throw e;
6751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
6761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    };
6771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
6781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    CacheBuilder<Object, Object> builder = createCacheBuilder().removalListener(listener);
6791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final LocalCache<Object, Object> cache = makeLocalCache(builder);
6801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object key = new Object();
6811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    cache.put(key, new Object());
6821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkNothingLogged();
6831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
6841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    cache.remove(key);
6851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    checkLogged(e);
6861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
6871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
6881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testRemovalListener_replaced_computing() {
6891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final CountDownLatch startSignal = new CountDownLatch(1);
6901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final CountDownLatch computingSignal = new CountDownLatch(1);
6911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final CountDownLatch doneSignal = new CountDownLatch(1);
6921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final Object computedObject = new Object();
6931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
6941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final CacheLoader<Object, Object> loader = new CacheLoader<Object, Object>() {
6951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @Override
6961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      public Object load(Object key) throws Exception {
6971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        computingSignal.countDown();
6981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        startSignal.await();
6991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        return computedObject;
7001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
7011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    };
7021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
7031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    QueuingRemovalListener<Object, Object> listener = queuingRemovalListener();
7041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    CacheBuilder<Object, Object> builder = createCacheBuilder().removalListener(listener);
7051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final LocalCache<Object, Object> map = makeLocalCache(builder);
7061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(listener.isEmpty());
7071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
7081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final Object one = new Object();
7091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final Object two = new Object();
7101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
7111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    new Thread() {
7121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @Override
7131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      public void run() {
7141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        try {
7151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          map.get(one, loader);
7161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        } catch (ExecutionException e) {
7171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          throw new RuntimeException(e);
7181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
7191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        doneSignal.countDown();
7201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
7211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }.start();
7221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
7231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    try {
7241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      computingSignal.await();
7251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    } catch (InterruptedException e) {
7261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      throw new RuntimeException(e);
7271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
7281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
7291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    map.put(one, two);
7301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(two, map.get(one));
7311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    startSignal.countDown();
7321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
7331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    try {
7341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      doneSignal.await();
7351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    } catch (InterruptedException e) {
7361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      throw new RuntimeException(e);
7371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
7381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
7391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    map.cleanUp(); // force notifications
7401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNotified(listener, one, computedObject, RemovalCause.REPLACED);
7411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(listener.isEmpty());
7421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
7431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
7441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testSegmentRefresh_duplicate() throws ExecutionException {
7451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map = makeLocalCache(createCacheBuilder()
7461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .concurrencyLevel(1));
7471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Segment<Object, Object> segment = map.segments[0];
7481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
7491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object key = new Object();
7501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int hash = map.hash(key);
7511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    AtomicReferenceArray<ReferenceEntry<Object, Object>> table = segment.table;
7521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int index = hash & (table.length() - 1);
7531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
7541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // already loading
7551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    DummyEntry<Object, Object> entry = DummyEntry.create(key, hash, null);
7567dd252788645e940eada959bdde927426e2531c9Paul Duffin    DummyValueReference<Object, Object> valueRef = DummyValueReference.create(null);
7571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    valueRef.setLoading(true);
7581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    entry.setValueReference(valueRef);
7591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    table.set(index, entry);
7607dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertNull(segment.refresh(key, hash, identityLoader(), false));
7611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
7621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
7631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  // Removal listener tests
7641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
7651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testRemovalListener_explicit() {
7661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    QueuingRemovalListener<Object, Object> listener = queuingRemovalListener();
7671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map = makeLocalCache(createCacheBuilder()
7681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .removalListener(listener));
7691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(listener.isEmpty());
7701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
7711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object one = new Object();
7721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object two = new Object();
7731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object three = new Object();
7741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object four = new Object();
7751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object five = new Object();
7761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object six = new Object();
7771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
7781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    map.put(one, two);
7791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    map.remove(one);
7801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNotified(listener, one, two, RemovalCause.EXPLICIT);
7811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
7821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    map.put(two, three);
7831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    map.remove(two, three);
7841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNotified(listener, two, three, RemovalCause.EXPLICIT);
7851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
7861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    map.put(three, four);
7871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Iterator<?> i = map.entrySet().iterator();
7881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    i.next();
7891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    i.remove();
7901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNotified(listener, three, four, RemovalCause.EXPLICIT);
7911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
7921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    map.put(four, five);
7931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    i = map.keySet().iterator();
7941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    i.next();
7951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    i.remove();
7961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNotified(listener, four, five, RemovalCause.EXPLICIT);
7971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
7981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    map.put(five, six);
7991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    i = map.values().iterator();
8001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    i.next();
8011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    i.remove();
8021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNotified(listener, five, six, RemovalCause.EXPLICIT);
8031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
8041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(listener.isEmpty());
8051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
8061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
8071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testRemovalListener_replaced() {
8081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    QueuingRemovalListener<Object, Object> listener = queuingRemovalListener();
8091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map = makeLocalCache(createCacheBuilder()
8101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .removalListener(listener));
8111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(listener.isEmpty());
8121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
8131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object one = new Object();
8141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object two = new Object();
8151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object three = new Object();
8161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object four = new Object();
8171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object five = new Object();
8181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object six = new Object();
8191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
8201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    map.put(one, two);
8211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    map.put(one, three);
8221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNotified(listener, one, two, RemovalCause.REPLACED);
8231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
8241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Map<Object, Object> newMap = ImmutableMap.of(one, four);
8251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    map.putAll(newMap);
8261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNotified(listener, one, three, RemovalCause.REPLACED);
8271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
8281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    map.replace(one, five);
8291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNotified(listener, one, four, RemovalCause.REPLACED);
8301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
8311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    map.replace(one, five, six);
8321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNotified(listener, one, five, RemovalCause.REPLACED);
8331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
8341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
8351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testRemovalListener_collected() {
8361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    QueuingRemovalListener<Object, Object> listener = queuingRemovalListener();
8371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map = makeLocalCache(createCacheBuilder()
8381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .concurrencyLevel(1)
8391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .softValues()
8401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .removalListener(listener));
8411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Segment<Object, Object> segment = map.segments[0];
8421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(listener.isEmpty());
8431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
8441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object one = new Object();
8451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object two = new Object();
8461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object three = new Object();
8471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
8481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    map.put(one, two);
8491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    map.put(two, three);
8501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(listener.isEmpty());
8511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
8521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int hash = map.hash(one);
8531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ReferenceEntry<Object, Object> entry = segment.getEntry(one, hash);
8541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    map.reclaimValue(entry.getValueReference());
8551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNotified(listener, one, two, RemovalCause.COLLECTED);
8561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
8571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(listener.isEmpty());
8581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
8591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
8601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testRemovalListener_expired() {
8611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    FakeTicker ticker = new FakeTicker();
8621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    QueuingRemovalListener<Object, Object> listener = queuingRemovalListener();
8631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map = makeLocalCache(createCacheBuilder()
8641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .concurrencyLevel(1)
8657dd252788645e940eada959bdde927426e2531c9Paul Duffin        .expireAfterWrite(3, TimeUnit.NANOSECONDS)
8661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .ticker(ticker)
8671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .removalListener(listener));
8681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(listener.isEmpty());
8691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
8701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object one = new Object();
8711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object two = new Object();
8721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object three = new Object();
8731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object four = new Object();
8741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object five = new Object();
8751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
8761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    map.put(one, two);
8771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ticker.advance(1);
8781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    map.put(two, three);
8791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ticker.advance(1);
8801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    map.put(three, four);
8811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(listener.isEmpty());
8821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ticker.advance(1);
8831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    map.put(four, five);
8841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNotified(listener, one, two, RemovalCause.EXPIRED);
8851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
8861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(listener.isEmpty());
8871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
8881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
8891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testRemovalListener_size() {
8901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    QueuingRemovalListener<Object, Object> listener = queuingRemovalListener();
8911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map = makeLocalCache(createCacheBuilder()
8921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .concurrencyLevel(1)
8931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .maximumSize(2)
8941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .removalListener(listener));
8951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(listener.isEmpty());
8961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
8971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object one = new Object();
8981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object two = new Object();
8991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object three = new Object();
9001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object four = new Object();
9011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
9021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    map.put(one, two);
9031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    map.put(two, three);
9041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(listener.isEmpty());
9051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    map.put(three, four);
9061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNotified(listener, one, two, RemovalCause.SIZE);
9071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
9081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(listener.isEmpty());
9091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
9101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
9111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  static <K, V> void assertNotified(
9121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      QueuingRemovalListener<K, V> listener, K key, V value, RemovalCause cause) {
9131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    RemovalNotification<K, V> notification = listener.remove();
9141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(key, notification.getKey());
9151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(value, notification.getValue());
9161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(cause, notification.getCause());
9171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
9181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
9191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  // Segment core tests
9201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
9211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testNewEntry() {
9221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (CacheBuilder<Object, Object> builder : allEntryTypeMakers()) {
9231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      LocalCache<Object, Object> map = makeLocalCache(builder);
9241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
9251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Object keyOne = new Object();
9261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Object valueOne = new Object();
9271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      int hashOne = map.hash(keyOne);
9281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      ReferenceEntry<Object, Object> entryOne = map.newEntry(keyOne, hashOne, null);
9291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      ValueReference<Object, Object> valueRefOne = map.newValueReference(entryOne, valueOne, 1);
9301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertSame(valueOne, valueRefOne.get());
9311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      entryOne.setValueReference(valueRefOne);
9321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
9331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertSame(keyOne, entryOne.getKey());
9341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertEquals(hashOne, entryOne.getHash());
9351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertNull(entryOne.getNext());
9361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertSame(valueRefOne, entryOne.getValueReference());
9371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
9381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Object keyTwo = new Object();
9391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Object valueTwo = new Object();
9401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      int hashTwo = map.hash(keyTwo);
9411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      ReferenceEntry<Object, Object> entryTwo = map.newEntry(keyTwo, hashTwo, entryOne);
9421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      ValueReference<Object, Object> valueRefTwo = map.newValueReference(entryTwo, valueTwo, 1);
9431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertSame(valueTwo, valueRefTwo.get());
9441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      entryTwo.setValueReference(valueRefTwo);
9451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
9461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertSame(keyTwo, entryTwo.getKey());
9471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertEquals(hashTwo, entryTwo.getHash());
9481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertSame(entryOne, entryTwo.getNext());
9491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertSame(valueRefTwo, entryTwo.getValueReference());
9501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
9511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
9521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
9531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testCopyEntry() {
9541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (CacheBuilder<Object, Object> builder : allEntryTypeMakers()) {
9551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      LocalCache<Object, Object> map = makeLocalCache(builder);
9561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
9571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Object keyOne = new Object();
9581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Object valueOne = new Object();
9591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      int hashOne = map.hash(keyOne);
9601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      ReferenceEntry<Object, Object> entryOne = map.newEntry(keyOne, hashOne, null);
9611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      entryOne.setValueReference(map.newValueReference(entryOne, valueOne, 1));
9621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
9631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Object keyTwo = new Object();
9641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Object valueTwo = new Object();
9651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      int hashTwo = map.hash(keyTwo);
9661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      ReferenceEntry<Object, Object> entryTwo = map.newEntry(keyTwo, hashTwo, entryOne);
9671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      entryTwo.setValueReference(map.newValueReference(entryTwo, valueTwo, 1));
9681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      if (map.usesAccessQueue()) {
9691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        LocalCache.connectAccessOrder(entryOne, entryTwo);
9701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
9711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      if (map.usesWriteQueue()) {
9721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        LocalCache.connectWriteOrder(entryOne, entryTwo);
9731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
9741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertConnected(map, entryOne, entryTwo);
9751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
9761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      ReferenceEntry<Object, Object> copyOne = map.copyEntry(entryOne, null);
9771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertSame(keyOne, entryOne.getKey());
9781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertEquals(hashOne, entryOne.getHash());
9791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertNull(entryOne.getNext());
9801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertSame(valueOne, copyOne.getValueReference().get());
9811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertConnected(map, copyOne, entryTwo);
9821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
9831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      ReferenceEntry<Object, Object> copyTwo = map.copyEntry(entryTwo, copyOne);
9841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertSame(keyTwo, copyTwo.getKey());
9851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertEquals(hashTwo, copyTwo.getHash());
9861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertSame(copyOne, copyTwo.getNext());
9871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertSame(valueTwo, copyTwo.getValueReference().get());
9881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertConnected(map, copyOne, copyTwo);
9891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
9901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
9911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
9921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static <K, V> void assertConnected(
9931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      LocalCache<K, V> map, ReferenceEntry<K, V> one, ReferenceEntry<K, V> two) {
9941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    if (map.usesWriteQueue()) {
9951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertSame(two, one.getNextInWriteQueue());
9961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
9971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    if (map.usesAccessQueue()) {
9981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertSame(two, one.getNextInAccessQueue());
9991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
10001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
10011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
10021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testSegmentGetAndContains() {
10031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    FakeTicker ticker = new FakeTicker();
10041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map = makeLocalCache(createCacheBuilder()
10051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .concurrencyLevel(1)
10061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .ticker(ticker)
10071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .expireAfterAccess(1, TimeUnit.NANOSECONDS));
10081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Segment<Object, Object> segment = map.segments[0];
10091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // TODO(fry): check recency ordering
10101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
10111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object key = new Object();
10121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int hash = map.hash(key);
10131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object value = new Object();
10141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    AtomicReferenceArray<ReferenceEntry<Object, Object>> table = segment.table;
10151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int index = hash & (table.length() - 1);
10161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
10171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ReferenceEntry<Object, Object> entry = map.newEntry(key, hash, null);
10181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ValueReference<Object, Object> valueRef = map.newValueReference(entry, value, 1);
10191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    entry.setValueReference(valueRef);
10201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
10211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNull(segment.get(key, hash));
10221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
10231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // count == 0
10241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    table.set(index, entry);
10251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNull(segment.get(key, hash));
10261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(segment.containsKey(key, hash));
10271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(segment.containsValue(value));
10281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
10291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // count == 1
10301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.count++;
10311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(value, segment.get(key, hash));
10321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(segment.containsKey(key, hash));
10331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(segment.containsValue(value));
10341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // don't see absent values now that count > 0
10351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNull(segment.get(new Object(), hash));
10361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
10371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // null key
10381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    DummyEntry<Object, Object> nullEntry = DummyEntry.create(null, hash, entry);
10391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object nullValue = new Object();
10401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ValueReference<Object, Object> nullValueRef = map.newValueReference(nullEntry, nullValue, 1);
10411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    nullEntry.setValueReference(nullValueRef);
10421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    table.set(index, nullEntry);
10431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // skip the null key
10441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(value, segment.get(key, hash));
10451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(segment.containsKey(key, hash));
10461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(segment.containsValue(value));
10471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(segment.containsValue(nullValue));
10481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
10491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // hash collision
10501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    DummyEntry<Object, Object> dummy = DummyEntry.create(new Object(), hash, entry);
10511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object dummyValue = new Object();
10521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ValueReference<Object, Object> dummyValueRef = map.newValueReference(dummy, dummyValue, 1);
10531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    dummy.setValueReference(dummyValueRef);
10541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    table.set(index, dummy);
10551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(value, segment.get(key, hash));
10561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(segment.containsKey(key, hash));
10571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(segment.containsValue(value));
10581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(segment.containsValue(dummyValue));
10591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
10601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // key collision
10611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    dummy = DummyEntry.create(key, hash, entry);
10621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    dummyValue = new Object();
10631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    dummyValueRef = map.newValueReference(dummy, dummyValue, 1);
10641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    dummy.setValueReference(dummyValueRef);
10651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    table.set(index, dummy);
10661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // returns the most recent entry
10671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(dummyValue, segment.get(key, hash));
10681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(segment.containsKey(key, hash));
10691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(segment.containsValue(value));
10701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(segment.containsValue(dummyValue));
10711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
10721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // expired
10731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    dummy.setAccessTime(ticker.read() - 2);
10741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNull(segment.get(key, hash));
10751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(segment.containsKey(key, hash));
10761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(segment.containsValue(value));
10771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(segment.containsValue(dummyValue));
10781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
10791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
10801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testSegmentReplaceValue() {
10811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map =
10821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        makeLocalCache(createCacheBuilder().concurrencyLevel(1).expireAfterAccess(99999, SECONDS));
10831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Segment<Object, Object> segment = map.segments[0];
10841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // TODO(fry): check recency ordering
10851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
10861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object key = new Object();
10871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int hash = map.hash(key);
10881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object oldValue = new Object();
10891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object newValue = new Object();
10901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    AtomicReferenceArray<ReferenceEntry<Object, Object>> table = segment.table;
10911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int index = hash & (table.length() - 1);
10921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
10931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    DummyEntry<Object, Object> entry = DummyEntry.create(key, hash, null);
10947dd252788645e940eada959bdde927426e2531c9Paul Duffin    DummyValueReference<Object, Object> oldValueRef = DummyValueReference.create(oldValue);
10951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    entry.setValueReference(oldValueRef);
10961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
10971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // no entry
10981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(segment.replace(key, hash, oldValue, newValue));
10991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, segment.count);
11001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
11011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // same value
11021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    table.set(index, entry);
11031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.count++;
11041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, segment.count);
11051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(oldValue, segment.get(key, hash));
11061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(segment.replace(key, hash, oldValue, newValue));
11071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, segment.count);
11081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(newValue, segment.get(key, hash));
11091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
11101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // different value
11111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(segment.replace(key, hash, oldValue, newValue));
11121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, segment.count);
11131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(newValue, segment.get(key, hash));
11141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
11151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // cleared
11161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    entry.setValueReference(oldValueRef);
11171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(oldValue, segment.get(key, hash));
11181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    oldValueRef.clear();
11191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(segment.replace(key, hash, oldValue, newValue));
11201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, segment.count);
11211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNull(segment.get(key, hash));
11221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
11231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
11241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testSegmentReplace() {
11251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map =
11261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        makeLocalCache(createCacheBuilder().concurrencyLevel(1).expireAfterAccess(99999, SECONDS));
11271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Segment<Object, Object> segment = map.segments[0];
11281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // TODO(fry): check recency ordering
11291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
11301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object key = new Object();
11311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int hash = map.hash(key);
11321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object oldValue = new Object();
11331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object newValue = new Object();
11341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    AtomicReferenceArray<ReferenceEntry<Object, Object>> table = segment.table;
11351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int index = hash & (table.length() - 1);
11361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
11371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    DummyEntry<Object, Object> entry = DummyEntry.create(key, hash, null);
11387dd252788645e940eada959bdde927426e2531c9Paul Duffin    DummyValueReference<Object, Object> oldValueRef = DummyValueReference.create(oldValue);
11391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    entry.setValueReference(oldValueRef);
11401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
11411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // no entry
11421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNull(segment.replace(key, hash, newValue));
11431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, segment.count);
11441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
11451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // same key
11461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    table.set(index, entry);
11471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.count++;
11481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, segment.count);
11491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(oldValue, segment.get(key, hash));
11501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(oldValue, segment.replace(key, hash, newValue));
11511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, segment.count);
11521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(newValue, segment.get(key, hash));
11531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
11541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // cleared
11551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    entry.setValueReference(oldValueRef);
11561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(oldValue, segment.get(key, hash));
11571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    oldValueRef.clear();
11581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNull(segment.replace(key, hash, newValue));
11591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, segment.count);
11601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNull(segment.get(key, hash));
11611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
11621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
11631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testSegmentPut() {
11641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map =
11651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        makeLocalCache(createCacheBuilder().concurrencyLevel(1).expireAfterAccess(99999, SECONDS));
11661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Segment<Object, Object> segment = map.segments[0];
11671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // TODO(fry): check recency ordering
11681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
11691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object key = new Object();
11701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int hash = map.hash(key);
11711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object oldValue = new Object();
11721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object newValue = new Object();
11731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
11741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // no entry
11751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, segment.count);
11761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNull(segment.put(key, hash, oldValue, false));
11771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, segment.count);
11781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
11791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // same key
11801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(oldValue, segment.put(key, hash, newValue, false));
11811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, segment.count);
11821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(newValue, segment.get(key, hash));
11831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
11841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // cleared
11851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ReferenceEntry<Object, Object> entry = segment.getEntry(key, hash);
11867dd252788645e940eada959bdde927426e2531c9Paul Duffin    DummyValueReference<Object, Object> oldValueRef = DummyValueReference.create(oldValue);
11871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    entry.setValueReference(oldValueRef);
11881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(oldValue, segment.get(key, hash));
11891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    oldValueRef.clear();
11901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNull(segment.put(key, hash, newValue, false));
11911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, segment.count);
11921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(newValue, segment.get(key, hash));
11931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
11941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
11951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testSegmentPutIfAbsent() {
11961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map =
11971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        makeLocalCache(createCacheBuilder().concurrencyLevel(1).expireAfterAccess(99999, SECONDS));
11981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Segment<Object, Object> segment = map.segments[0];
11991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // TODO(fry): check recency ordering
12001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
12011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object key = new Object();
12021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int hash = map.hash(key);
12031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object oldValue = new Object();
12041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object newValue = new Object();
12051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
12061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // no entry
12071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, segment.count);
12081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNull(segment.put(key, hash, oldValue, true));
12091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, segment.count);
12101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
12111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // same key
12121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(oldValue, segment.put(key, hash, newValue, true));
12131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, segment.count);
12141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(oldValue, segment.get(key, hash));
12151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
12161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // cleared
12171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ReferenceEntry<Object, Object> entry = segment.getEntry(key, hash);
12187dd252788645e940eada959bdde927426e2531c9Paul Duffin    DummyValueReference<Object, Object> oldValueRef = DummyValueReference.create(oldValue);
12191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    entry.setValueReference(oldValueRef);
12201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(oldValue, segment.get(key, hash));
12211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    oldValueRef.clear();
12221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNull(segment.put(key, hash, newValue, true));
12231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, segment.count);
12241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(newValue, segment.get(key, hash));
12251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
12261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
12271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testSegmentPut_expand() {
12281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map =
12291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        makeLocalCache(createCacheBuilder().concurrencyLevel(1).initialCapacity(1));
12301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Segment<Object, Object> segment = map.segments[0];
12311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, segment.table.length());
12321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
12331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int count = 1024;
12341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (int i = 0; i < count; i++) {
12351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Object key = new Object();
12361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Object value = new Object();
12371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      int hash = map.hash(key);
12381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertNull(segment.put(key, hash, value, false));
12391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertTrue(segment.table.length() > i);
12401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
12411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
12421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
12431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testSegmentPut_evict() {
12441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int maxSize = 10;
12451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map =
12461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        makeLocalCache(createCacheBuilder().concurrencyLevel(1).maximumSize(maxSize));
12471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
12481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // manually add elements to avoid eviction
12491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int originalCount = 1024;
12501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LinkedHashMap<Object, Object> originalMap = Maps.newLinkedHashMap();
12511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (int i = 0; i < originalCount; i++) {
12521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Object key = new Object();
12531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Object value = new Object();
12541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      map.put(key, value);
12551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      originalMap.put(key, value);
12561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      if (i >= maxSize) {
12571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Iterator<Object> it = originalMap.keySet().iterator();
12581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        it.next();
12591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        it.remove();
12601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
12611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertEquals(originalMap, map);
12621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
12631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
12641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
12651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testSegmentStoreComputedValue() {
12661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    QueuingRemovalListener<Object, Object> listener = queuingRemovalListener();
12671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map = makeLocalCache(createCacheBuilder()
12681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .concurrencyLevel(1)
12691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .removalListener(listener));
12701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Segment<Object, Object> segment = map.segments[0];
12711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
12721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object key = new Object();
12731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int hash = map.hash(key);
12741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    AtomicReferenceArray<ReferenceEntry<Object, Object>> table = segment.table;
12751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int index = hash & (table.length() - 1);
12761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
12771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    DummyEntry<Object, Object> entry = DummyEntry.create(key, hash, null);
12781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LoadingValueReference<Object, Object> valueRef = new LoadingValueReference<Object, Object>();
12791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    entry.setValueReference(valueRef);
12801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
12811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // absent
12821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object value = new Object();
12831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(listener.isEmpty());
12841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, segment.count);
12851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNull(segment.get(key, hash));
12861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(segment.storeLoadedValue(key, hash, valueRef, value));
12871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(value, segment.get(key, hash));
12881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, segment.count);
12891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(listener.isEmpty());
12901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
12911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // clobbered
12921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object value2 = new Object();
12931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(segment.storeLoadedValue(key, hash, valueRef, value2));
12941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, segment.count);
12951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(value, segment.get(key, hash));
12961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    RemovalNotification<Object, Object> notification = listener.remove();
12971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(immutableEntry(key, value2), notification);
12981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(RemovalCause.REPLACED, notification.getCause());
12991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(listener.isEmpty());
13001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
13011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // inactive
13021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object value3 = new Object();
13031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    map.clear();
13041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    listener.clear();
13051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, segment.count);
13061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    table.set(index, entry);
13071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(segment.storeLoadedValue(key, hash, valueRef, value3));
13081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(value3, segment.get(key, hash));
13091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, segment.count);
13101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(listener.isEmpty());
13111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
13121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // replaced
13131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object value4 = new Object();
13147dd252788645e940eada959bdde927426e2531c9Paul Duffin    DummyValueReference<Object, Object> value3Ref = DummyValueReference.create(value3);
13151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    valueRef = new LoadingValueReference<Object, Object>(value3Ref);
13161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    entry.setValueReference(valueRef);
13171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    table.set(index, entry);
13181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(value3, segment.get(key, hash));
13191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, segment.count);
13201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(segment.storeLoadedValue(key, hash, valueRef, value4));
13211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(value4, segment.get(key, hash));
13221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, segment.count);
13231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    notification = listener.remove();
13241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(immutableEntry(key, value3), notification);
13251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(RemovalCause.REPLACED, notification.getCause());
13261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(listener.isEmpty());
13271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
13281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // collected
13291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    entry.setValueReference(valueRef);
13301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    table.set(index, entry);
13311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(value3, segment.get(key, hash));
13321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, segment.count);
13331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    value3Ref.clear();
13341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(segment.storeLoadedValue(key, hash, valueRef, value4));
13351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(value4, segment.get(key, hash));
13361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, segment.count);
13371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    notification = listener.remove();
13381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(immutableEntry(key, null), notification);
13391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(RemovalCause.COLLECTED, notification.getCause());
13401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(listener.isEmpty());
13411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
13421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
13431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testSegmentRemove() {
13441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map = makeLocalCache(createCacheBuilder().concurrencyLevel(1));
13451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Segment<Object, Object> segment = map.segments[0];
13461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
13471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object key = new Object();
13481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int hash = map.hash(key);
13491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object oldValue = new Object();
13501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    AtomicReferenceArray<ReferenceEntry<Object, Object>> table = segment.table;
13511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int index = hash & (table.length() - 1);
13521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
13531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    DummyEntry<Object, Object> entry = DummyEntry.create(key, hash, null);
13547dd252788645e940eada959bdde927426e2531c9Paul Duffin    DummyValueReference<Object, Object> oldValueRef = DummyValueReference.create(oldValue);
13551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    entry.setValueReference(oldValueRef);
13561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
13571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // no entry
13581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, segment.count);
13591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNull(segment.remove(key, hash));
13601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, segment.count);
13611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
13621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // same key
13631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    table.set(index, entry);
13641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.count++;
13651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, segment.count);
13661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(oldValue, segment.get(key, hash));
13671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(oldValue, segment.remove(key, hash));
13681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, segment.count);
13691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNull(segment.get(key, hash));
13701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
13711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // cleared
13721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    table.set(index, entry);
13731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.count++;
13741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, segment.count);
13751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(oldValue, segment.get(key, hash));
13761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    oldValueRef.clear();
13771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNull(segment.remove(key, hash));
13781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, segment.count);
13791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNull(segment.get(key, hash));
13801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
13811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
13821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testSegmentRemoveValue() {
13831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map = makeLocalCache(createCacheBuilder().concurrencyLevel(1));
13841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Segment<Object, Object> segment = map.segments[0];
13851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
13861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object key = new Object();
13871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int hash = map.hash(key);
13881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object oldValue = new Object();
13891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object newValue = new Object();
13901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    AtomicReferenceArray<ReferenceEntry<Object, Object>> table = segment.table;
13911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int index = hash & (table.length() - 1);
13921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
13931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    DummyEntry<Object, Object> entry = DummyEntry.create(key, hash, null);
13947dd252788645e940eada959bdde927426e2531c9Paul Duffin    DummyValueReference<Object, Object> oldValueRef = DummyValueReference.create(oldValue);
13951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    entry.setValueReference(oldValueRef);
13961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
13971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // no entry
13981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, segment.count);
13991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNull(segment.remove(key, hash));
14001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, segment.count);
14011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
14021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // same value
14031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    table.set(index, entry);
14041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.count++;
14051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, segment.count);
14061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(oldValue, segment.get(key, hash));
14071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(segment.remove(key, hash, oldValue));
14081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, segment.count);
14091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNull(segment.get(key, hash));
14101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
14111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // different value
14121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    table.set(index, entry);
14131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.count++;
14141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, segment.count);
14151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(oldValue, segment.get(key, hash));
14161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(segment.remove(key, hash, newValue));
14171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, segment.count);
14181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(oldValue, segment.get(key, hash));
14191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
14201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // cleared
14211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(oldValue, segment.get(key, hash));
14221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    oldValueRef.clear();
14231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(segment.remove(key, hash, oldValue));
14241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, segment.count);
14251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNull(segment.get(key, hash));
14261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
14271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
14281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testExpand() {
14291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map =
14301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        makeLocalCache(createCacheBuilder().concurrencyLevel(1).initialCapacity(1));
14311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Segment<Object, Object> segment = map.segments[0];
14321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, segment.table.length());
14331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
14341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // manually add elements to avoid expansion
14351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int originalCount = 1024;
14361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ReferenceEntry<Object, Object> entry = null;
14371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (int i = 0; i < originalCount; i++) {
14381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Object key = new Object();
14391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Object value = new Object();
14401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      int hash = map.hash(key);
14411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      // chain all entries together as we only have a single bucket
14421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      entry = map.newEntry(key, hash, entry);
14431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      ValueReference<Object, Object> valueRef = map.newValueReference(entry, value, 1);
14441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      entry.setValueReference(valueRef);
14451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
14461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.table.set(0, entry);
14471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.count = originalCount;
14481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ImmutableMap<Object, Object> originalMap = ImmutableMap.copyOf(map);
14491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(originalCount, originalMap.size());
14501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(originalMap, map);
14511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
14521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (int i = 1; i <= originalCount * 2; i *= 2) {
14531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      if (i > 1) {
14541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        segment.expand();
14551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
14561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertEquals(i, segment.table.length());
14571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertEquals(originalCount, countLiveEntries(map, 0));
14581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertEquals(originalCount, segment.count);
14591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertEquals(originalMap, map);
14601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
14611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
14621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
14637dd252788645e940eada959bdde927426e2531c9Paul Duffin  public void testGetCausesExpansion() throws ExecutionException {
14647dd252788645e940eada959bdde927426e2531c9Paul Duffin    for (int count = 1; count <= 100; count++) {
14657dd252788645e940eada959bdde927426e2531c9Paul Duffin      LocalCache<Object, Object> map =
14667dd252788645e940eada959bdde927426e2531c9Paul Duffin          makeLocalCache(createCacheBuilder().concurrencyLevel(1).initialCapacity(1));
14677dd252788645e940eada959bdde927426e2531c9Paul Duffin      Segment<Object, Object> segment = map.segments[0];
14687dd252788645e940eada959bdde927426e2531c9Paul Duffin      assertEquals(1, segment.table.length());
14697dd252788645e940eada959bdde927426e2531c9Paul Duffin
14707dd252788645e940eada959bdde927426e2531c9Paul Duffin      for (int i = 0; i < count; i++) {
14717dd252788645e940eada959bdde927426e2531c9Paul Duffin        Object key = new Object();
14727dd252788645e940eada959bdde927426e2531c9Paul Duffin        final Object value = new Object();
14737dd252788645e940eada959bdde927426e2531c9Paul Duffin        segment.get(key, key.hashCode(), new CacheLoader<Object, Object>() {
14747dd252788645e940eada959bdde927426e2531c9Paul Duffin          @Override
14757dd252788645e940eada959bdde927426e2531c9Paul Duffin          public Object load(Object key) {
14767dd252788645e940eada959bdde927426e2531c9Paul Duffin            return value;
14777dd252788645e940eada959bdde927426e2531c9Paul Duffin          }
14787dd252788645e940eada959bdde927426e2531c9Paul Duffin        });
14797dd252788645e940eada959bdde927426e2531c9Paul Duffin      }
14807dd252788645e940eada959bdde927426e2531c9Paul Duffin      assertEquals(count, segment.count);
14817dd252788645e940eada959bdde927426e2531c9Paul Duffin      assertTrue(count <= segment.threshold);
14827dd252788645e940eada959bdde927426e2531c9Paul Duffin      assertTrue(count <= (segment.table.length() * 3 / 4));
14837dd252788645e940eada959bdde927426e2531c9Paul Duffin      assertTrue(count > (segment.table.length() * 3 / 8));
14847dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
14857dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
14867dd252788645e940eada959bdde927426e2531c9Paul Duffin
14877dd252788645e940eada959bdde927426e2531c9Paul Duffin  public void testPutCausesExpansion() {
14887dd252788645e940eada959bdde927426e2531c9Paul Duffin    for (int count = 1; count <= 100; count++) {
14897dd252788645e940eada959bdde927426e2531c9Paul Duffin      LocalCache<Object, Object> map =
14907dd252788645e940eada959bdde927426e2531c9Paul Duffin          makeLocalCache(createCacheBuilder().concurrencyLevel(1).initialCapacity(1));
14917dd252788645e940eada959bdde927426e2531c9Paul Duffin      Segment<Object, Object> segment = map.segments[0];
14927dd252788645e940eada959bdde927426e2531c9Paul Duffin      assertEquals(1, segment.table.length());
14937dd252788645e940eada959bdde927426e2531c9Paul Duffin
14947dd252788645e940eada959bdde927426e2531c9Paul Duffin      for (int i = 0; i < count; i++) {
14957dd252788645e940eada959bdde927426e2531c9Paul Duffin        Object key = new Object();
14967dd252788645e940eada959bdde927426e2531c9Paul Duffin        Object value = new Object();
14977dd252788645e940eada959bdde927426e2531c9Paul Duffin        segment.put(key, key.hashCode(), value, true);
14987dd252788645e940eada959bdde927426e2531c9Paul Duffin      }
14997dd252788645e940eada959bdde927426e2531c9Paul Duffin      assertEquals(count, segment.count);
15007dd252788645e940eada959bdde927426e2531c9Paul Duffin      assertTrue(count <= segment.threshold);
15017dd252788645e940eada959bdde927426e2531c9Paul Duffin      assertTrue(count <= (segment.table.length() * 3 / 4));
15027dd252788645e940eada959bdde927426e2531c9Paul Duffin      assertTrue(count > (segment.table.length() * 3 / 8));
15037dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
15047dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
15057dd252788645e940eada959bdde927426e2531c9Paul Duffin
15061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testReclaimKey() {
15071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    CountingRemovalListener<Object, Object> listener = countingRemovalListener();
15081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map = makeLocalCache(createCacheBuilder()
15091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .concurrencyLevel(1)
15101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .initialCapacity(1)
15111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .maximumSize(SMALL_MAX_SIZE)
15121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .expireAfterWrite(99999, SECONDS)
15131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .removalListener(listener));
15141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Segment<Object, Object> segment = map.segments[0];
15151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    AtomicReferenceArray<ReferenceEntry<Object, Object>> table = segment.table;
15161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, table.length());
15171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
15181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // create 3 objects and chain them together
15191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object keyOne = new Object();
15201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object valueOne = new Object();
15211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int hashOne = map.hash(keyOne);
15221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    DummyEntry<Object, Object> entryOne = createDummyEntry(keyOne, hashOne, valueOne, null);
15231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object keyTwo = new Object();
15241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object valueTwo = new Object();
15251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int hashTwo = map.hash(keyTwo);
15261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    DummyEntry<Object, Object> entryTwo = createDummyEntry(keyTwo, hashTwo, valueTwo, entryOne);
15271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object keyThree = new Object();
15281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object valueThree = new Object();
15291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int hashThree = map.hash(keyThree);
15301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    DummyEntry<Object, Object> entryThree =
15311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      createDummyEntry(keyThree, hashThree, valueThree, entryTwo);
15321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
15331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // absent
15341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, listener.getCount());
15351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(segment.reclaimKey(entryOne, hashOne));
15361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, listener.getCount());
15371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    table.set(0, entryOne);
15381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(segment.reclaimKey(entryTwo, hashTwo));
15391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, listener.getCount());
15401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    table.set(0, entryTwo);
15411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(segment.reclaimKey(entryThree, hashThree));
15421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, listener.getCount());
15431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
15441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // present
15451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    table.set(0, entryOne);
15461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.count = 1;
15471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(segment.reclaimKey(entryOne, hashOne));
15481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, listener.getCount());
15491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(keyOne, listener.getLastEvictedKey());
15501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(valueOne, listener.getLastEvictedValue());
15511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(map.removalNotificationQueue.isEmpty());
15521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(segment.accessQueue.contains(entryOne));
15531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(segment.writeQueue.contains(entryOne));
15541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, segment.count);
15551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNull(table.get(0));
15561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
15571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
15581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testRemoveEntryFromChain() {
15591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map = makeLocalCache(createCacheBuilder().concurrencyLevel(1));
15601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Segment<Object, Object> segment = map.segments[0];
15611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
15621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // create 3 objects and chain them together
15631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object keyOne = new Object();
15641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object valueOne = new Object();
15651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int hashOne = map.hash(keyOne);
15661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    DummyEntry<Object, Object> entryOne = createDummyEntry(keyOne, hashOne, valueOne, null);
15671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object keyTwo = new Object();
15681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object valueTwo = new Object();
15691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int hashTwo = map.hash(keyTwo);
15701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    DummyEntry<Object, Object> entryTwo = createDummyEntry(keyTwo, hashTwo, valueTwo, entryOne);
15711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object keyThree = new Object();
15721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object valueThree = new Object();
15731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int hashThree = map.hash(keyThree);
15741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    DummyEntry<Object, Object> entryThree =
15751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      createDummyEntry(keyThree, hashThree, valueThree, entryTwo);
15761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
15771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // alone
15781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNull(segment.removeEntryFromChain(entryOne, entryOne));
15791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
15801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // head
15811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(entryOne, segment.removeEntryFromChain(entryTwo, entryTwo));
15821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
15831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // middle
15841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ReferenceEntry<Object, Object> newFirst = segment.removeEntryFromChain(entryThree, entryTwo);
15851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(keyThree, newFirst.getKey());
15861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(valueThree, newFirst.getValueReference().get());
15871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(hashThree, newFirst.getHash());
15881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(entryOne, newFirst.getNext());
15891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
15901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // tail (remaining entries are copied in reverse order)
15911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    newFirst = segment.removeEntryFromChain(entryThree, entryOne);
15921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(keyTwo, newFirst.getKey());
15931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(valueTwo, newFirst.getValueReference().get());
15941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(hashTwo, newFirst.getHash());
15951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    newFirst = newFirst.getNext();
15961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(keyThree, newFirst.getKey());
15971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(valueThree, newFirst.getValueReference().get());
15981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(hashThree, newFirst.getHash());
15991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNull(newFirst.getNext());
16001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
16011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
16021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testExpand_cleanup() {
16031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map =
16041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        makeLocalCache(createCacheBuilder().concurrencyLevel(1).initialCapacity(1));
16051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Segment<Object, Object> segment = map.segments[0];
16061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, segment.table.length());
16071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
16081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // manually add elements to avoid expansion
16091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // 1/3 null keys, 1/3 null values
16101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int originalCount = 1024;
16111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ReferenceEntry<Object, Object> entry = null;
16121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (int i = 0; i < originalCount; i++) {
16131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Object key = new Object();
16141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Object value = (i % 3 == 0) ? null : new Object();
16151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      int hash = map.hash(key);
16161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      if (i % 3 == 1) {
16171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        key = null;
16181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
16191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      // chain all entries together as we only have a single bucket
16201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      entry = DummyEntry.create(key, hash, entry);
16217dd252788645e940eada959bdde927426e2531c9Paul Duffin      ValueReference<Object, Object> valueRef = DummyValueReference.create(value);
16221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      entry.setValueReference(valueRef);
16231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
16241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.table.set(0, entry);
16251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.count = originalCount;
16261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int liveCount = originalCount / 3;
16271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, segment.table.length());
16281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(liveCount, countLiveEntries(map, 0));
16291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ImmutableMap<Object, Object> originalMap = ImmutableMap.copyOf(map);
16301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(liveCount, originalMap.size());
16311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // can't compare map contents until cleanup occurs
16321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
16331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (int i = 1; i <= originalCount * 2; i *= 2) {
16341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      if (i > 1) {
16351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        segment.expand();
16361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
16371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertEquals(i, segment.table.length());
16381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertEquals(liveCount, countLiveEntries(map, 0));
16391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      // expansion cleanup is sloppy, with a goal of avoiding unnecessary copies
16401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertTrue(segment.count >= liveCount);
16411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertTrue(segment.count <= originalCount);
16421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertEquals(originalMap, ImmutableMap.copyOf(map));
16431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
16441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
16451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
16461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static <K, V> int countLiveEntries(LocalCache<K, V> map, long now) {
16471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int result = 0;
16481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (Segment<K, V> segment : map.segments) {
16491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      AtomicReferenceArray<ReferenceEntry<K, V>> table = segment.table;
16501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      for (int i = 0; i < table.length(); i++) {
16511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        for (ReferenceEntry<K, V> e = table.get(i); e != null; e = e.getNext()) {
16521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          if (map.isLive(e, now)) {
16531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            result++;
16541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          }
16551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
16561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
16571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
16581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return result;
16591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
16601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
16611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testClear() {
16621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map = makeLocalCache(createCacheBuilder()
16631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .concurrencyLevel(1)
16641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .initialCapacity(1)
16651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .maximumSize(SMALL_MAX_SIZE)
16661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .expireAfterWrite(99999, SECONDS));
16671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Segment<Object, Object> segment = map.segments[0];
16681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    AtomicReferenceArray<ReferenceEntry<Object, Object>> table = segment.table;
16691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, table.length());
16701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
16711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object key = new Object();
16721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object value = new Object();
16731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int hash = map.hash(key);
16741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    DummyEntry<Object, Object> entry = createDummyEntry(key, hash, value, null);
16751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.recordWrite(entry, 1, map.ticker.read());
16761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.table.set(0, entry);
16771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.readCount.incrementAndGet();
16781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.count = 1;
16791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.totalWeight = 1;
16801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
16811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(entry, table.get(0));
16821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(entry, segment.accessQueue.peek());
16831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(entry, segment.writeQueue.peek());
16841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
16851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.clear();
16861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNull(table.get(0));
16871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(segment.accessQueue.isEmpty());
16881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(segment.writeQueue.isEmpty());
16891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, segment.readCount.get());
16901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, segment.count);
16911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, segment.totalWeight);
16921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
16931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
16941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testClear_notification() {
16951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    QueuingRemovalListener<Object, Object> listener = queuingRemovalListener();
16961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map = makeLocalCache(createCacheBuilder()
16971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .concurrencyLevel(1)
16981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .initialCapacity(1)
16991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .maximumSize(SMALL_MAX_SIZE)
17001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .expireAfterWrite(99999, SECONDS)
17011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .removalListener(listener));
17021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Segment<Object, Object> segment = map.segments[0];
17031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    AtomicReferenceArray<ReferenceEntry<Object, Object>> table = segment.table;
17041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, table.length());
17051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
17061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object key = new Object();
17071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object value = new Object();
17081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int hash = map.hash(key);
17091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    DummyEntry<Object, Object> entry = createDummyEntry(key, hash, value, null);
17101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.recordWrite(entry, 1, map.ticker.read());
17111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.table.set(0, entry);
17121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.readCount.incrementAndGet();
17131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.count = 1;
17141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.totalWeight = 1;
17151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
17161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(entry, table.get(0));
17171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(entry, segment.accessQueue.peek());
17181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(entry, segment.writeQueue.peek());
17191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
17201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.clear();
17211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNull(table.get(0));
17221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(segment.accessQueue.isEmpty());
17231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(segment.writeQueue.isEmpty());
17241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, segment.readCount.get());
17251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, segment.count);
17261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, segment.totalWeight);
17271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNotified(listener, key, value, RemovalCause.EXPLICIT);
17281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
17291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
17301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testRemoveEntry() {
17311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map = makeLocalCache(createCacheBuilder()
17321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .concurrencyLevel(1)
17331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .initialCapacity(1)
17341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .maximumSize(SMALL_MAX_SIZE)
17351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .expireAfterWrite(99999, SECONDS)
17361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .removalListener(countingRemovalListener()));
17371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Segment<Object, Object> segment = map.segments[0];
17381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    AtomicReferenceArray<ReferenceEntry<Object, Object>> table = segment.table;
17391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, table.length());
17401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
17411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object key = new Object();
17421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object value = new Object();
17431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int hash = map.hash(key);
17441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    DummyEntry<Object, Object> entry = createDummyEntry(key, hash, value, null);
17451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
17461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // remove absent
17471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(segment.removeEntry(entry, hash, RemovalCause.COLLECTED));
17481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
17491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // remove live
17501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.recordWrite(entry, 1, map.ticker.read());
17511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    table.set(0, entry);
17521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.count = 1;
17531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(segment.removeEntry(entry, hash, RemovalCause.COLLECTED));
17541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNotificationEnqueued(map, key, value, hash);
17551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(map.removalNotificationQueue.isEmpty());
17561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(segment.accessQueue.contains(entry));
17571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(segment.writeQueue.contains(entry));
17581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, segment.count);
17591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNull(table.get(0));
17601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
17611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
17621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testReclaimValue() {
17631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    CountingRemovalListener<Object, Object> listener =
17641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        countingRemovalListener();
17651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map = makeLocalCache(createCacheBuilder()
17661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .concurrencyLevel(1)
17671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .initialCapacity(1)
17681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .maximumSize(SMALL_MAX_SIZE)
17691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .expireAfterWrite(99999, SECONDS)
17701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .removalListener(listener));
17711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Segment<Object, Object> segment = map.segments[0];
17721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    AtomicReferenceArray<ReferenceEntry<Object, Object>> table = segment.table;
17731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, table.length());
17741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
17751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object key = new Object();
17761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object value = new Object();
17771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int hash = map.hash(key);
17781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    DummyEntry<Object, Object> entry = DummyEntry.create(key, hash, null);
17797dd252788645e940eada959bdde927426e2531c9Paul Duffin    DummyValueReference<Object, Object> valueRef = DummyValueReference.create(value);
17801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    entry.setValueReference(valueRef);
17811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
17821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // reclaim absent
17831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(segment.reclaimValue(key, hash, valueRef));
17841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
17851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // reclaim live
17861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.recordWrite(entry, 1, map.ticker.read());
17871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    table.set(0, entry);
17881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.count = 1;
17891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(segment.reclaimValue(key, hash, valueRef));
17901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, listener.getCount());
17911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(key, listener.getLastEvictedKey());
17921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(value, listener.getLastEvictedValue());
17931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(map.removalNotificationQueue.isEmpty());
17941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(segment.accessQueue.contains(entry));
17951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(segment.writeQueue.contains(entry));
17961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, segment.count);
17971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNull(table.get(0));
17981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
17991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // reclaim wrong value reference
18001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    table.set(0, entry);
18017dd252788645e940eada959bdde927426e2531c9Paul Duffin    DummyValueReference<Object, Object> otherValueRef = DummyValueReference.create(value);
18021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    entry.setValueReference(otherValueRef);
18031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(segment.reclaimValue(key, hash, valueRef));
18041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, listener.getCount());
18051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(segment.reclaimValue(key, hash, otherValueRef));
18061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(2, listener.getCount());
18071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(key, listener.getLastEvictedKey());
18081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(value, listener.getLastEvictedValue());
18091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
18101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
18111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testRemoveComputingValue() {
18121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map = makeLocalCache(createCacheBuilder()
18131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .concurrencyLevel(1)
18141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .initialCapacity(1)
18151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .maximumSize(SMALL_MAX_SIZE)
18161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .expireAfterWrite(99999, SECONDS)
18171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .removalListener(countingRemovalListener()));
18181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Segment<Object, Object> segment = map.segments[0];
18191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    AtomicReferenceArray<ReferenceEntry<Object, Object>> table = segment.table;
18201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, table.length());
18211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
18221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object key = new Object();
18231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int hash = map.hash(key);
18241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    DummyEntry<Object, Object> entry = DummyEntry.create(key, hash, null);
18251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LoadingValueReference<Object, Object> valueRef = new LoadingValueReference<Object, Object>();
18261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    entry.setValueReference(valueRef);
18271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
18281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // absent
18291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(segment.removeLoadingValue(key, hash, valueRef));
18301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
18311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // live
18321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    table.set(0, entry);
18331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // don't increment count; this is used during computation
18341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(segment.removeLoadingValue(key, hash, valueRef));
18351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // no notification sent with removeLoadingValue
18361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(map.removalNotificationQueue.isEmpty());
18371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, segment.count);
18381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNull(table.get(0));
18391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
18401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // active
18411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object value = new Object();
18427dd252788645e940eada959bdde927426e2531c9Paul Duffin    DummyValueReference<Object, Object> previousRef = DummyValueReference.create(value);
18431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    valueRef = new LoadingValueReference<Object, Object>(previousRef);
18441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    entry.setValueReference(valueRef);
18451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    table.set(0, entry);
18461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.count = 1;
18471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(segment.removeLoadingValue(key, hash, valueRef));
18481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(entry, table.get(0));
18491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(value, segment.get(key, hash));
18501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
18511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // wrong value reference
18521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    table.set(0, entry);
18537dd252788645e940eada959bdde927426e2531c9Paul Duffin    DummyValueReference<Object, Object> otherValueRef = DummyValueReference.create(value);
18541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    entry.setValueReference(otherValueRef);
18551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(segment.removeLoadingValue(key, hash, valueRef));
18561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    entry.setValueReference(valueRef);
18571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(segment.removeLoadingValue(key, hash, valueRef));
18581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
18591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
18601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static <K, V> void assertNotificationEnqueued(
18611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      LocalCache<K, V> map, K key, V value, int hash) {
18621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    RemovalNotification<K, V> notification = map.removalNotificationQueue.poll();
18631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(key, notification.getKey());
18641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(value, notification.getValue());
18651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
18661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
18671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  // Segment eviction tests
18681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
18691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testDrainRecencyQueueOnWrite() {
18701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (CacheBuilder<Object, Object> builder : allEvictingMakers()) {
18711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      LocalCache<Object, Object> map = makeLocalCache(builder.concurrencyLevel(1));
18721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Segment<Object, Object> segment = map.segments[0];
18731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
18741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      if (segment.recencyQueue != DISCARDING_QUEUE) {
18751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Object keyOne = new Object();
18761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Object valueOne = new Object();
18771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Object keyTwo = new Object();
18781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Object valueTwo = new Object();
18791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
18801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        map.put(keyOne, valueOne);
18811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        assertTrue(segment.recencyQueue.isEmpty());
18821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
18831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        for (int i = 0; i < DRAIN_THRESHOLD / 2; i++) {
18841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          map.get(keyOne);
18851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
18861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        assertFalse(segment.recencyQueue.isEmpty());
18871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
18881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        map.put(keyTwo, valueTwo);
18891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        assertTrue(segment.recencyQueue.isEmpty());
18901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
18911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
18921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
18931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
18941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testDrainRecencyQueueOnRead() {
18951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (CacheBuilder<Object, Object> builder : allEvictingMakers()) {
18961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      LocalCache<Object, Object> map = makeLocalCache(builder.concurrencyLevel(1));
18971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Segment<Object, Object> segment = map.segments[0];
18981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
18991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      if (segment.recencyQueue != DISCARDING_QUEUE) {
19001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Object keyOne = new Object();
19011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Object valueOne = new Object();
19021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
19031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        // repeated get of the same key
19041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
19051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        map.put(keyOne, valueOne);
19061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        assertTrue(segment.recencyQueue.isEmpty());
19071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
19081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        for (int i = 0; i < DRAIN_THRESHOLD / 2; i++) {
19091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          map.get(keyOne);
19101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
19111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        assertFalse(segment.recencyQueue.isEmpty());
19121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
19131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        for (int i = 0; i < DRAIN_THRESHOLD * 2; i++) {
19141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          map.get(keyOne);
19151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          assertTrue(segment.recencyQueue.size() <= DRAIN_THRESHOLD);
19161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
19171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
19181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        // get over many different keys
19191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
19201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        for (int i = 0; i < DRAIN_THRESHOLD * 2; i++) {
19211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          map.put(new Object(), new Object());
19221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
19231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        assertTrue(segment.recencyQueue.isEmpty());
19241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
19251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        for (int i = 0; i < DRAIN_THRESHOLD / 2; i++) {
19261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          map.get(keyOne);
19271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
19281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        assertFalse(segment.recencyQueue.isEmpty());
19291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
19301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        for (Object key : map.keySet()) {
19311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          map.get(key);
19321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          assertTrue(segment.recencyQueue.size() <= DRAIN_THRESHOLD);
19331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
19341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
19351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
19361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
19371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
19381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testRecordRead() {
19391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (CacheBuilder<Object, Object> builder : allEvictingMakers()) {
19401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      LocalCache<Object, Object> map = makeLocalCache(builder.concurrencyLevel(1));
19411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Segment<Object, Object> segment = map.segments[0];
19421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      List<ReferenceEntry<Object, Object>> writeOrder = Lists.newLinkedList();
19431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      List<ReferenceEntry<Object, Object>> readOrder = Lists.newLinkedList();
19441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      for (int i = 0; i < DRAIN_THRESHOLD * 2; i++) {
19451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Object key = new Object();
19461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        int hash = map.hash(key);
19471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Object value = new Object();
19481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
19491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        ReferenceEntry<Object, Object> entry = createDummyEntry(key, hash, value, null);
19501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        // must recordRead for drainRecencyQueue to believe this entry is live
19511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        segment.recordWrite(entry, 1, map.ticker.read());
19521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        writeOrder.add(entry);
19531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        readOrder.add(entry);
19541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
19551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
19561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkEvictionQueues(map, segment, readOrder, writeOrder);
19571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkExpirationTimes(map);
19581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
19591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      // access some of the elements
19601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Random random = new Random();
19611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      List<ReferenceEntry<Object, Object>> reads = Lists.newArrayList();
19621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Iterator<ReferenceEntry<Object, Object>> i = readOrder.iterator();
19631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      while (i.hasNext()) {
19641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        ReferenceEntry<Object, Object> entry = i.next();
19651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        if (random.nextBoolean()) {
19661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          segment.recordRead(entry, map.ticker.read());
19671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          reads.add(entry);
19681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          i.remove();
19691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
19701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
19711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkAndDrainRecencyQueue(map, segment, reads);
19721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      readOrder.addAll(reads);
19731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
19741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkEvictionQueues(map, segment, readOrder, writeOrder);
19751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkExpirationTimes(map);
19761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
19771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
19781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
19791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testRecordReadOnGet() {
19801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (CacheBuilder<Object, Object> builder : allEvictingMakers()) {
19811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      LocalCache<Object, Object> map = makeLocalCache(builder.concurrencyLevel(1));
19821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Segment<Object, Object> segment = map.segments[0];
19831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      List<ReferenceEntry<Object, Object>> writeOrder = Lists.newLinkedList();
19841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      List<ReferenceEntry<Object, Object>> readOrder = Lists.newLinkedList();
19851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      for (int i = 0; i < DRAIN_THRESHOLD * 2; i++) {
19861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Object key = new Object();
19871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        int hash = map.hash(key);
19881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Object value = new Object();
19891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
19901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        map.put(key, value);
19911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        ReferenceEntry<Object, Object> entry = segment.getEntry(key, hash);
19921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        writeOrder.add(entry);
19931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        readOrder.add(entry);
19941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
19951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
19961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkEvictionQueues(map, segment, readOrder, writeOrder);
19971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkExpirationTimes(map);
19981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertTrue(segment.recencyQueue.isEmpty());
19991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
20001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      // access some of the elements
20011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Random random = new Random();
20021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      List<ReferenceEntry<Object, Object>> reads = Lists.newArrayList();
20031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Iterator<ReferenceEntry<Object, Object>> i = readOrder.iterator();
20041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      while (i.hasNext()) {
20051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        ReferenceEntry<Object, Object> entry = i.next();
20061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        if (random.nextBoolean()) {
20071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          map.get(entry.getKey());
20081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          reads.add(entry);
20091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          i.remove();
20101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          assertTrue(segment.recencyQueue.size() <= DRAIN_THRESHOLD);
20111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
20121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
20131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      int undrainedIndex = reads.size() - segment.recencyQueue.size();
20141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkAndDrainRecencyQueue(map, segment, reads.subList(undrainedIndex, reads.size()));
20151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      readOrder.addAll(reads);
20161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
20171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkEvictionQueues(map, segment, readOrder, writeOrder);
20181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkExpirationTimes(map);
20191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
20201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
20211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
20221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testRecordWrite() {
20231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (CacheBuilder<Object, Object> builder : allEvictingMakers()) {
20241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      LocalCache<Object, Object> map = makeLocalCache(builder.concurrencyLevel(1));
20251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Segment<Object, Object> segment = map.segments[0];
20261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      List<ReferenceEntry<Object, Object>> writeOrder = Lists.newLinkedList();
20271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      for (int i = 0; i < DRAIN_THRESHOLD * 2; i++) {
20281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Object key = new Object();
20291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        int hash = map.hash(key);
20301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Object value = new Object();
20311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
20321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        ReferenceEntry<Object, Object> entry = createDummyEntry(key, hash, value, null);
20331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        // must recordRead for drainRecencyQueue to believe this entry is live
20341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        segment.recordWrite(entry, 1, map.ticker.read());
20351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        writeOrder.add(entry);
20361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
20371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
20381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkEvictionQueues(map, segment, writeOrder, writeOrder);
20391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkExpirationTimes(map);
20401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
20411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      // access some of the elements
20421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Random random = new Random();
20431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      List<ReferenceEntry<Object, Object>> writes = Lists.newArrayList();
20441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Iterator<ReferenceEntry<Object, Object>> i = writeOrder.iterator();
20451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      while (i.hasNext()) {
20461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        ReferenceEntry<Object, Object> entry = i.next();
20471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        if (random.nextBoolean()) {
20481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          segment.recordWrite(entry, 1, map.ticker.read());
20491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          writes.add(entry);
20501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          i.remove();
20511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
20521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
20531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      writeOrder.addAll(writes);
20541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
20551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkEvictionQueues(map, segment, writeOrder, writeOrder);
20561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkExpirationTimes(map);
20571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
20581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
20591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
20601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  static <K, V> void checkAndDrainRecencyQueue(LocalCache<K, V> map,
20611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Segment<K, V> segment, List<ReferenceEntry<K, V>> reads) {
20621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    if (map.evictsBySize() || map.expiresAfterAccess()) {
20631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertSameEntries(reads, ImmutableList.copyOf(segment.recencyQueue));
20641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
20651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.drainRecencyQueue();
20661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
20671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
20681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  static <K, V> void checkEvictionQueues(LocalCache<K, V> map,
20691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Segment<K, V> segment, List<ReferenceEntry<K, V>> readOrder,
20701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      List<ReferenceEntry<K, V>> writeOrder) {
20711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    if (map.evictsBySize() || map.expiresAfterAccess()) {
20721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertSameEntries(readOrder, ImmutableList.copyOf(segment.accessQueue));
20731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
20741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    if (map.expiresAfterWrite()) {
20751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertSameEntries(writeOrder, ImmutableList.copyOf(segment.writeQueue));
20761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
20771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
20781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
20791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static <K, V> void assertSameEntries(List<ReferenceEntry<K, V>> expectedEntries,
20801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      List<ReferenceEntry<K, V>> actualEntries) {
20811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int size = expectedEntries.size();
20821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(size, actualEntries.size());
20831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (int i = 0; i < size; i++) {
20840888a09821a98ac0680fad765217302858e70fa4Paul Duffin      ReferenceEntry<K, V> expectedEntry = expectedEntries.get(i);
20850888a09821a98ac0680fad765217302858e70fa4Paul Duffin      ReferenceEntry<K, V> actualEntry = actualEntries.get(i);
20861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertSame(expectedEntry.getKey(), actualEntry.getKey());
20871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      assertSame(expectedEntry.getValueReference().get(), actualEntry.getValueReference().get());
20881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
20891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
20901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
20911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  static <K, V> void checkExpirationTimes(LocalCache<K, V> map) {
20921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    if (!map.expires()) {
20931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return;
20941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
20951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
20961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (Segment<K, V> segment : map.segments) {
20971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      long lastAccessTime = 0;
20981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      long lastWriteTime = 0;
20991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      for (ReferenceEntry<K, V> e : segment.recencyQueue) {
21001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        long accessTime = e.getAccessTime();
21011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        assertTrue(accessTime >= lastAccessTime);
21021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        lastAccessTime = accessTime;
21031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        long writeTime = e.getWriteTime();
21041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        assertTrue(writeTime >= lastWriteTime);
21051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        lastWriteTime = writeTime;
21061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
21071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
21081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      lastAccessTime = 0;
21091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      lastWriteTime = 0;
21101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      for (ReferenceEntry<K, V> e : segment.accessQueue) {
21111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        long accessTime = e.getAccessTime();
21121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        assertTrue(accessTime >= lastAccessTime);
21131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        lastAccessTime = accessTime;
21141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
21151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      for (ReferenceEntry<K, V> e : segment.writeQueue) {
21161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        long writeTime = e.getWriteTime();
21171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        assertTrue(writeTime >= lastWriteTime);
21181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        lastWriteTime = writeTime;
21191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
21201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
21211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
21221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
21231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testExpireAfterWrite() {
21241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    FakeTicker ticker = new FakeTicker();
21251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map = makeLocalCache(createCacheBuilder()
21261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .concurrencyLevel(1)
21271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .ticker(ticker)
21287dd252788645e940eada959bdde927426e2531c9Paul Duffin        .expireAfterWrite(2, TimeUnit.NANOSECONDS));
21291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Segment<Object, Object> segment = map.segments[0];
21301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
21311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object key = new Object();
21321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object value = new Object();
21331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    map.put(key, value);
21341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ReferenceEntry<Object, Object> entry = map.getEntry(key);
21351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(map.isLive(entry, ticker.read()));
21361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
21371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.writeQueue.add(entry);
21381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(value, map.get(key));
21391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(entry, segment.writeQueue.peek());
21401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, segment.writeQueue.size());
21411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
21421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.recordRead(entry, ticker.read());
21431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.expireEntries(ticker.read());
21441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(value, map.get(key));
21451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(entry, segment.writeQueue.peek());
21461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, segment.writeQueue.size());
21471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
21481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ticker.advance(1);
21491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.recordRead(entry, ticker.read());
21501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.expireEntries(ticker.read());
21511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(value, map.get(key));
21521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(entry, segment.writeQueue.peek());
21531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, segment.writeQueue.size());
21541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
21551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ticker.advance(1);
21561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNull(map.get(key));
21571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.expireEntries(ticker.read());
21581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNull(map.get(key));
21591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(segment.writeQueue.isEmpty());
21601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
21611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
21621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testExpireAfterAccess() {
21631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    FakeTicker ticker = new FakeTicker();
21641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map = makeLocalCache(createCacheBuilder()
21651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .concurrencyLevel(1)
21661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .ticker(ticker)
21677dd252788645e940eada959bdde927426e2531c9Paul Duffin        .expireAfterAccess(2, TimeUnit.NANOSECONDS));
21681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Segment<Object, Object> segment = map.segments[0];
21691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
21701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object key = new Object();
21711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object value = new Object();
21721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    map.put(key, value);
21731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ReferenceEntry<Object, Object> entry = map.getEntry(key);
21741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(map.isLive(entry, ticker.read()));
21751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
21761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.accessQueue.add(entry);
21771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(value, map.get(key));
21781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(entry, segment.accessQueue.peek());
21791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, segment.accessQueue.size());
21801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
21811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.recordRead(entry, ticker.read());
21821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.expireEntries(ticker.read());
21831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(map.containsKey(key));
21841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(entry, segment.accessQueue.peek());
21851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, segment.accessQueue.size());
21861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
21871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ticker.advance(1);
21881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.recordRead(entry, ticker.read());
21891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.expireEntries(ticker.read());
21901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(map.containsKey(key));
21911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(entry, segment.accessQueue.peek());
21921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, segment.accessQueue.size());
21931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
21941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ticker.advance(1);
21951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.recordRead(entry, ticker.read());
21961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.expireEntries(ticker.read());
21971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(map.containsKey(key));
21981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(entry, segment.accessQueue.peek());
21991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, segment.accessQueue.size());
22001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
22011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ticker.advance(1);
22021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.expireEntries(ticker.read());
22031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(map.containsKey(key));
22041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertSame(entry, segment.accessQueue.peek());
22051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, segment.accessQueue.size());
22061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
22071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ticker.advance(1);
22081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(map.containsKey(key));
22091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNull(map.get(key));
22101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.expireEntries(ticker.read());
22111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(map.containsKey(key));
22121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertNull(map.get(key));
22131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(segment.accessQueue.isEmpty());
22141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
22151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
22161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testEvictEntries() {
22171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int maxSize = 10;
22181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> map =
22191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        makeLocalCache(createCacheBuilder().concurrencyLevel(1).maximumSize(maxSize));
22201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Segment<Object, Object> segment = map.segments[0];
22211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
22221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // manually add elements to avoid eviction
22231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int originalCount = 1024;
22241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ReferenceEntry<Object, Object> entry = null;
22251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LinkedHashMap<Object, Object> originalMap = Maps.newLinkedHashMap();
22261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (int i = 0; i < originalCount; i++) {
22271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Object key = new Object();
22281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Object value = new Object();
22291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      AtomicReferenceArray<ReferenceEntry<Object, Object>> table = segment.table;
22301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      int hash = map.hash(key);
22311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      int index = hash & (table.length() - 1);
22321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      ReferenceEntry<Object, Object> first = table.get(index);
22331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      entry = map.newEntry(key, hash, first);
22341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      ValueReference<Object, Object> valueRef = map.newValueReference(entry, value, 1);
22351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      entry.setValueReference(valueRef);
22361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      segment.recordWrite(entry, 1, map.ticker.read());
22371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      table.set(index, entry);
22381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      originalMap.put(key, value);
22391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
22401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.count = originalCount;
22411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.totalWeight = originalCount;
22421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(originalCount, map.size());
22431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(originalMap, map);
22441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
22451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Iterator<Object> it = originalMap.keySet().iterator();
22461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (int i = 0; i < originalCount - maxSize; i++) {
22471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      it.next();
22481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      it.remove();
22491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
22501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    segment.evictEntries();
22511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(maxSize, map.size());
22521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(originalMap, map);
22531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
22541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
22551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  // reference queues
22561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
22571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testDrainKeyReferenceQueueOnWrite() {
22581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (CacheBuilder<Object, Object> builder : allKeyValueStrengthMakers()) {
22591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      LocalCache<Object, Object> map =
22601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          makeLocalCache(builder.concurrencyLevel(1));
22611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      if (map.usesKeyReferences()) {
22621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Segment<Object, Object> segment = map.segments[0];
22631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
22641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Object keyOne = new Object();
22651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        int hashOne = map.hash(keyOne);
22661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Object valueOne = new Object();
22671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Object keyTwo = new Object();
22681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Object valueTwo = new Object();
22691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
22701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        map.put(keyOne, valueOne);
22711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        ReferenceEntry<Object, Object> entry = segment.getEntry(keyOne, hashOne);
22721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
22731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        @SuppressWarnings("unchecked")
22741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Reference<Object> reference = (Reference) entry;
22751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        reference.enqueue();
22761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
22771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        map.put(keyTwo, valueTwo);
22781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        assertFalse(map.containsKey(keyOne));
22791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        assertFalse(map.containsValue(valueOne));
22801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        assertNull(map.get(keyOne));
22811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        assertEquals(1, map.size());
22821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        assertNull(segment.keyReferenceQueue.poll());
22831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
22841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
22851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
22861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
22871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testDrainValueReferenceQueueOnWrite() {
22881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (CacheBuilder<Object, Object> builder : allKeyValueStrengthMakers()) {
22891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      LocalCache<Object, Object> map =
22901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          makeLocalCache(builder.concurrencyLevel(1));
22911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      if (map.usesValueReferences()) {
22921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Segment<Object, Object> segment = map.segments[0];
22931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
22941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Object keyOne = new Object();
22951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        int hashOne = map.hash(keyOne);
22961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Object valueOne = new Object();
22971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Object keyTwo = new Object();
22981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Object valueTwo = new Object();
22991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
23001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        map.put(keyOne, valueOne);
23011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        ReferenceEntry<Object, Object> entry = segment.getEntry(keyOne, hashOne);
23021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        ValueReference<Object, Object> valueReference = entry.getValueReference();
23031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
23041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        @SuppressWarnings("unchecked")
23051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Reference<Object> reference = (Reference) valueReference;
23061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        reference.enqueue();
23071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
23081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        map.put(keyTwo, valueTwo);
23091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        assertFalse(map.containsKey(keyOne));
23101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        assertFalse(map.containsValue(valueOne));
23111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        assertNull(map.get(keyOne));
23121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        assertEquals(1, map.size());
23131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        assertNull(segment.valueReferenceQueue.poll());
23141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
23151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
23161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
23171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
23181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testDrainKeyReferenceQueueOnRead() {
23191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (CacheBuilder<Object, Object> builder : allKeyValueStrengthMakers()) {
23201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      LocalCache<Object, Object> map =
23211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          makeLocalCache(builder.concurrencyLevel(1));
23221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      if (map.usesKeyReferences()) {
23231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Segment<Object, Object> segment = map.segments[0];
23241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
23251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Object keyOne = new Object();
23261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        int hashOne = map.hash(keyOne);
23271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Object valueOne = new Object();
23281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Object keyTwo = new Object();
23291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
23301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        map.put(keyOne, valueOne);
23311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        ReferenceEntry<Object, Object> entry = segment.getEntry(keyOne, hashOne);
23321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
23331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        @SuppressWarnings("unchecked")
23341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Reference<Object> reference = (Reference) entry;
23351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        reference.enqueue();
23361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
23371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        for (int i = 0; i < SMALL_MAX_SIZE; i++) {
23381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          map.get(keyTwo);
23391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
23401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        assertFalse(map.containsKey(keyOne));
23411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        assertFalse(map.containsValue(valueOne));
23421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        assertNull(map.get(keyOne));
23431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        assertEquals(0, map.size());
23441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        assertNull(segment.keyReferenceQueue.poll());
23451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
23461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
23471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
23481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
23491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testDrainValueReferenceQueueOnRead() {
23501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (CacheBuilder<Object, Object> builder : allKeyValueStrengthMakers()) {
23511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      LocalCache<Object, Object> map =
23521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          makeLocalCache(builder.concurrencyLevel(1));
23531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      if (map.usesValueReferences()) {
23541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Segment<Object, Object> segment = map.segments[0];
23551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
23561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Object keyOne = new Object();
23571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        int hashOne = map.hash(keyOne);
23581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Object valueOne = new Object();
23591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Object keyTwo = new Object();
23601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
23611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        map.put(keyOne, valueOne);
23621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        ReferenceEntry<Object, Object> entry = segment.getEntry(keyOne, hashOne);
23631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        ValueReference<Object, Object> valueReference = entry.getValueReference();
23641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
23651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        @SuppressWarnings("unchecked")
23661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Reference<Object> reference = (Reference) valueReference;
23671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        reference.enqueue();
23681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
23691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        for (int i = 0; i < SMALL_MAX_SIZE; i++) {
23701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          map.get(keyTwo);
23711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
23721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        assertFalse(map.containsKey(keyOne));
23731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        assertFalse(map.containsValue(valueOne));
23741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        assertNull(map.get(keyOne));
23751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        assertEquals(0, map.size());
23761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        assertNull(segment.valueReferenceQueue.poll());
23771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
23781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
23791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
23801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
23811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testNullParameters() throws Exception {
23821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    NullPointerTester tester = new NullPointerTester();
23831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    tester.testAllPublicInstanceMethods(makeLocalCache(createCacheBuilder()));
23841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    CacheLoader<Object, Object> loader = identityLoader();
23851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    tester.testAllPublicInstanceMethods(makeLocalCache(createCacheBuilder()));
23861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
23871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
23881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testSerializationProxyLoading() {
23891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    CacheLoader<Object, Object> loader = new SerializableCacheLoader();
23901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    RemovalListener<Object, Object> listener = new SerializableRemovalListener<Object, Object>();
23911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    SerializableWeigher<Object, Object> weigher = new SerializableWeigher<Object, Object>();
23921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Ticker ticker = new SerializableTicker();
23931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @SuppressWarnings("unchecked") // createMock
23941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalLoadingCache<Object, Object> one = (LocalLoadingCache) CacheBuilder.newBuilder()
23951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .weakKeys()
23961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .softValues()
23971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .expireAfterAccess(123, SECONDS)
23987dd252788645e940eada959bdde927426e2531c9Paul Duffin        .expireAfterWrite(60 * 456, SECONDS) // 456 minutes
23991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .maximumWeight(789)
24001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .weigher(weigher)
24011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .concurrencyLevel(12)
24021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .removalListener(listener)
24031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .ticker(ticker)
24041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .build(loader);
24051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // add a non-serializable entry
24061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    one.getUnchecked(new Object());
24071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, one.size());
24081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(one.asMap().isEmpty());
24091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalLoadingCache<Object, Object> two = SerializableTester.reserialize(one);
24101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, two.size());
24111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(two.asMap().isEmpty());
24121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
24131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> localCacheOne = one.localCache;
24141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> localCacheTwo = two.localCache;
24151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
24161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheOne.keyStrength, localCacheTwo.keyStrength);
24171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheOne.keyStrength, localCacheTwo.keyStrength);
24181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheOne.valueEquivalence, localCacheTwo.valueEquivalence);
24191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheOne.valueEquivalence, localCacheTwo.valueEquivalence);
24201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheOne.maxWeight, localCacheTwo.maxWeight);
24211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheOne.weigher, localCacheTwo.weigher);
24221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheOne.expireAfterAccessNanos, localCacheTwo.expireAfterAccessNanos);
24231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheOne.expireAfterWriteNanos, localCacheTwo.expireAfterWriteNanos);
24241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheOne.refreshNanos, localCacheTwo.refreshNanos);
24251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheOne.removalListener, localCacheTwo.removalListener);
24261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheOne.ticker, localCacheTwo.ticker);
24271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
24281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // serialize the reconstituted version to be sure we haven't lost the ability to reserialize
24291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalLoadingCache<Object, Object> three = SerializableTester.reserialize(two);
24301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> localCacheThree = three.localCache;
24311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
24321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheTwo.defaultLoader, localCacheThree.defaultLoader);
24331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheTwo.keyStrength, localCacheThree.keyStrength);
24341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheTwo.keyStrength, localCacheThree.keyStrength);
24351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheTwo.valueEquivalence, localCacheThree.valueEquivalence);
24361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheTwo.valueEquivalence, localCacheThree.valueEquivalence);
24371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheTwo.maxWeight, localCacheThree.maxWeight);
24381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheTwo.weigher, localCacheThree.weigher);
24391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheTwo.expireAfterAccessNanos, localCacheThree.expireAfterAccessNanos);
24401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheTwo.expireAfterWriteNanos, localCacheThree.expireAfterWriteNanos);
24411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheTwo.removalListener, localCacheThree.removalListener);
24421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheTwo.ticker, localCacheThree.ticker);
24431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
24441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
24451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testSerializationProxyManual() {
24461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    RemovalListener<Object, Object> listener = new SerializableRemovalListener<Object, Object>();
24471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    SerializableWeigher<Object, Object> weigher = new SerializableWeigher<Object, Object>();
24481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Ticker ticker = new SerializableTicker();
24491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @SuppressWarnings("unchecked") // createMock
24501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalManualCache<Object, Object> one = (LocalManualCache) CacheBuilder.newBuilder()
24511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .weakKeys()
24521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .softValues()
24531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .expireAfterAccess(123, NANOSECONDS)
24541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .maximumWeight(789)
24551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .weigher(weigher)
24561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .concurrencyLevel(12)
24571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .removalListener(listener)
24581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .ticker(ticker)
24591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        .build();
24601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // add a non-serializable entry
24611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    one.put(new Object(), new Object());
24621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(1, one.size());
24631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertFalse(one.asMap().isEmpty());
24641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalManualCache<Object, Object> two = SerializableTester.reserialize(one);
24651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(0, two.size());
24661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(two.asMap().isEmpty());
24671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
24681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> localCacheOne = one.localCache;
24691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> localCacheTwo = two.localCache;
24701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
24711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheOne.keyStrength, localCacheTwo.keyStrength);
24721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheOne.keyStrength, localCacheTwo.keyStrength);
24731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheOne.valueEquivalence, localCacheTwo.valueEquivalence);
24741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheOne.valueEquivalence, localCacheTwo.valueEquivalence);
24751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheOne.maxWeight, localCacheTwo.maxWeight);
24761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheOne.weigher, localCacheTwo.weigher);
24771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheOne.expireAfterAccessNanos, localCacheTwo.expireAfterAccessNanos);
24781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheOne.expireAfterWriteNanos, localCacheTwo.expireAfterWriteNanos);
24791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheOne.removalListener, localCacheTwo.removalListener);
24801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheOne.ticker, localCacheTwo.ticker);
24811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
24821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // serialize the reconstituted version to be sure we haven't lost the ability to reserialize
24831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalManualCache<Object, Object> three = SerializableTester.reserialize(two);
24841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    LocalCache<Object, Object> localCacheThree = three.localCache;
24851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
24861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheTwo.keyStrength, localCacheThree.keyStrength);
24871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheTwo.keyStrength, localCacheThree.keyStrength);
24881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheTwo.valueEquivalence, localCacheThree.valueEquivalence);
24891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheTwo.valueEquivalence, localCacheThree.valueEquivalence);
24901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheTwo.maxWeight, localCacheThree.maxWeight);
24911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheTwo.weigher, localCacheThree.weigher);
24921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheTwo.expireAfterAccessNanos, localCacheThree.expireAfterAccessNanos);
24931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheTwo.expireAfterWriteNanos, localCacheThree.expireAfterWriteNanos);
24941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheTwo.removalListener, localCacheThree.removalListener);
24951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(localCacheTwo.ticker, localCacheThree.ticker);
24961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
24971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
24981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  // utility methods
24991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
25001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /**
25011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Returns an iterable containing all combinations of maximumSize, expireAfterAccess/Write,
25021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * weakKeys and weak/softValues.
25031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
25041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  @SuppressWarnings("unchecked") // varargs
25051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static Iterable<CacheBuilder<Object, Object>> allEntryTypeMakers() {
25061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    List<CacheBuilder<Object, Object>> result =
25071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        newArrayList(allKeyValueStrengthMakers());
25081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (CacheBuilder<Object, Object> builder : allKeyValueStrengthMakers()) {
25091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      result.add(builder.maximumSize(SMALL_MAX_SIZE));
25101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
25111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (CacheBuilder<Object, Object> builder : allKeyValueStrengthMakers()) {
25121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      result.add(builder.expireAfterAccess(99999, SECONDS));
25131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
25141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (CacheBuilder<Object, Object> builder : allKeyValueStrengthMakers()) {
25151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      result.add(builder.expireAfterWrite(99999, SECONDS));
25161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
25171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (CacheBuilder<Object, Object> builder : allKeyValueStrengthMakers()) {
25181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      result.add(builder.maximumSize(SMALL_MAX_SIZE).expireAfterAccess(99999, SECONDS));
25191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
25201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    for (CacheBuilder<Object, Object> builder : allKeyValueStrengthMakers()) {
25211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      result.add(builder.maximumSize(SMALL_MAX_SIZE).expireAfterWrite(99999, SECONDS));
25221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
25231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return result;
25241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
25251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
25261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /**
25271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Returns an iterable containing all combinations of maximumSize and expireAfterAccess/Write.
25281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
25291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  @SuppressWarnings("unchecked") // varargs
25301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  static Iterable<CacheBuilder<Object, Object>> allEvictingMakers() {
25311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return ImmutableList.of(createCacheBuilder().maximumSize(SMALL_MAX_SIZE),
25321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        createCacheBuilder().expireAfterAccess(99999, SECONDS),
25331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        createCacheBuilder().expireAfterWrite(99999, SECONDS),
25341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        createCacheBuilder()
25351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            .maximumSize(SMALL_MAX_SIZE)
25361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            .expireAfterAccess(SMALL_MAX_SIZE, TimeUnit.SECONDS),
25371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        createCacheBuilder()
25381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            .maximumSize(SMALL_MAX_SIZE)
25391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            .expireAfterWrite(SMALL_MAX_SIZE, TimeUnit.SECONDS));
25401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
25411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
25421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /**
25431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Returns an iterable containing all combinations weakKeys and weak/softValues.
25441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
25451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  @SuppressWarnings("unchecked") // varargs
25461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static Iterable<CacheBuilder<Object, Object>> allKeyValueStrengthMakers() {
25471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return ImmutableList.of(createCacheBuilder(),
25481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        createCacheBuilder().weakValues(),
25491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        createCacheBuilder().softValues(),
25501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        createCacheBuilder().weakKeys(),
25511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        createCacheBuilder().weakKeys().weakValues(),
25521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        createCacheBuilder().weakKeys().softValues());
25531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
25541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
25551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  // entries and values
25561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
25571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static <K, V> DummyEntry<K, V> createDummyEntry(
25581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      K key, int hash, V value, ReferenceEntry<K, V> next) {
25591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    DummyEntry<K, V> entry = DummyEntry.create(key, hash, next);
25607dd252788645e940eada959bdde927426e2531c9Paul Duffin    DummyValueReference<K, V> valueRef = DummyValueReference.create(value);
25611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    entry.setValueReference(valueRef);
25621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return entry;
25631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
25641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
25651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  static class DummyEntry<K, V> implements ReferenceEntry<K, V> {
25661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private K key;
25671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private final int hash;
25681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private final ReferenceEntry<K, V> next;
25691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
25701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public DummyEntry(K key, int hash, ReferenceEntry<K, V> next) {
25711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      this.key = key;
25721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      this.hash = hash;
25731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      this.next = next;
25741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
25751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
25761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public static <K, V> DummyEntry<K, V> create(K key, int hash, ReferenceEntry<K, V> next) {
25771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return new DummyEntry<K, V>(key, hash, next);
25781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
25791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
25801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public void clearKey() {
25811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      this.key = null;
25821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
25831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
25841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private ValueReference<K, V> valueReference = unset();
25851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
25861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
25871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public ValueReference<K, V> getValueReference() {
25881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return valueReference;
25891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
25901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
25911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
25921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public void setValueReference(ValueReference<K, V> valueReference) {
25931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      this.valueReference = valueReference;
25941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
25951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
25961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
25971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public ReferenceEntry<K, V> getNext() {
25981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return next;
25991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
26001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
26011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
26021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public int getHash() {
26031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return hash;
26041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
26051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
26061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
26071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public K getKey() {
26081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return key;
26091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
26101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
26111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private long accessTime = Long.MAX_VALUE;
26121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
26131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
26141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public long getAccessTime() {
26151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return accessTime;
26161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
26171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
26181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
26191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public void setAccessTime(long time) {
26201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      this.accessTime = time;
26211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
26221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
26231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private ReferenceEntry<K, V> nextAccess = nullEntry();
26241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
26251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
26261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public ReferenceEntry<K, V> getNextInAccessQueue() {
26271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return nextAccess;
26281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
26291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
26301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
26311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public void setNextInAccessQueue(ReferenceEntry<K, V> next) {
26321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      this.nextAccess = next;
26331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
26341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
26351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private ReferenceEntry<K, V> previousAccess = nullEntry();
26361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
26371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
26381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public ReferenceEntry<K, V> getPreviousInAccessQueue() {
26391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return previousAccess;
26401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
26411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
26421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
26431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public void setPreviousInAccessQueue(ReferenceEntry<K, V> previous) {
26441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      this.previousAccess = previous;
26451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
26461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
26471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private long writeTime = Long.MAX_VALUE;
26481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
26491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
26501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public long getWriteTime() {
26511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return writeTime;
26521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
26531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
26541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
26551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public void setWriteTime(long time) {
26561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      this.writeTime = time;
26571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
26581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
26591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private ReferenceEntry<K, V> nextWrite = nullEntry();
26601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
26611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
26621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public ReferenceEntry<K, V> getNextInWriteQueue() {
26631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return nextWrite;
26641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
26651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
26661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
26671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public void setNextInWriteQueue(ReferenceEntry<K, V> next) {
26681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      this.nextWrite = next;
26691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
26701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
26711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private ReferenceEntry<K, V> previousWrite = nullEntry();
26721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
26731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
26741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public ReferenceEntry<K, V> getPreviousInWriteQueue() {
26751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return previousWrite;
26761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
26771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
26781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
26791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public void setPreviousInWriteQueue(ReferenceEntry<K, V> previous) {
26801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      this.previousWrite = previous;
26811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
26821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
26831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
26841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  static class DummyValueReference<K, V> implements ValueReference<K, V> {
26851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private V value;
26861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    boolean loading = false;
26871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
26887dd252788645e940eada959bdde927426e2531c9Paul Duffin    public DummyValueReference() {
26891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      this.loading = true;
26901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
26911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
26927dd252788645e940eada959bdde927426e2531c9Paul Duffin    public DummyValueReference(V value) {
26931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      this.value = value;
26941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
26951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
26967dd252788645e940eada959bdde927426e2531c9Paul Duffin    public static <K, V> DummyValueReference<K, V> create(V value) {
26977dd252788645e940eada959bdde927426e2531c9Paul Duffin      return new DummyValueReference<K, V>(value);
26981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
26991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
27007dd252788645e940eada959bdde927426e2531c9Paul Duffin    public static <K, V> DummyValueReference<K, V> createLoading() {
27017dd252788645e940eada959bdde927426e2531c9Paul Duffin      return new DummyValueReference<K, V>();
27021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
27031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
27041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
27051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public V get() {
27061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return value;
27071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
27081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
27091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
27101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public int getWeight() {
27111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return 1;
27121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
27131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
27141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
27151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public ReferenceEntry<K, V> getEntry() {
27167dd252788645e940eada959bdde927426e2531c9Paul Duffin      return null;
27171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
27181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
27191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
27207dd252788645e940eada959bdde927426e2531c9Paul Duffin    public ValueReference<K, V> copyFor(
27217dd252788645e940eada959bdde927426e2531c9Paul Duffin        ReferenceQueue<V> queue, V value, ReferenceEntry<K, V> entry) {
27227dd252788645e940eada959bdde927426e2531c9Paul Duffin      return this;
27231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
27241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
27251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public void setLoading(boolean loading) {
27261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      this.loading = loading;
27271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
27281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
27291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
27301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public boolean isLoading() {
27311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return loading;
27321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
27331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
27341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
27351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public boolean isActive() {
27361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return !loading;
27371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
27381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
27391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
27401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public V waitForValue() {
27411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return get();
27421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
27431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
27441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
27451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public void notifyNewValue(V newValue) {}
27461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
27471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public void clear() {
27481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      value = null;
27491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
27501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
27511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
27521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static class SerializableCacheLoader
27531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      extends CacheLoader<Object, Object> implements Serializable {
27541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
27551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public Object load(Object key) {
27561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return new Object();
27571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
27581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
27591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
27601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public int hashCode() {
27611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return 42;
27621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
27631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
27641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
27651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public boolean equals(Object o) {
27661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return (o instanceof SerializableCacheLoader);
27671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
27681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
27691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
27701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static class SerializableRemovalListener<K, V>
27711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      implements RemovalListener<K, V>, Serializable {
27721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
27731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public void onRemoval(RemovalNotification<K, V> notification) {}
27741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
27751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
27761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public int hashCode() {
27771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return 42;
27781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
27791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
27801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
27811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public boolean equals(Object o) {
27821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return (o instanceof SerializableRemovalListener);
27831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
27841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
27851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
27861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static class SerializableTicker extends Ticker implements Serializable {
27871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
27881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public long read() {
27891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return 42;
27901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
27911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
27921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
27931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public int hashCode() {
27941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return 42;
27951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
27961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
27971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
27981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public boolean equals(Object o) {
27991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return (o instanceof SerializableTicker);
28001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
28011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
28021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
28031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static class SerializableWeigher<K, V> implements Weigher<K, V>, Serializable {
28041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
28051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public int weigh(K key, V value) {
28061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return 42;
28071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
28081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
28091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
28101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public int hashCode() {
28111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return 42;
28121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
28131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
28141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
28151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public boolean equals(Object o) {
28161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return (o instanceof SerializableWeigher);
28171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
28181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
28191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
28201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert}
2821