11d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/* 21d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Copyright (C) 2011 The Guava Authors 31d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 41d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 51d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * in compliance with the License. You may obtain a copy of the License at 61d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 71d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * http://www.apache.org/licenses/LICENSE-2.0 81d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 91d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Unless required by applicable law or agreed to in writing, software distributed under the License 101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * or implied. See the License for the specific language governing permissions and limitations under 121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * the License. 131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpackage com.google.common.cache; 161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static com.google.common.cache.TestingCacheLoaders.identityLoader; 181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static com.google.common.cache.TestingRemovalListeners.countingRemovalListener; 191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static java.util.Arrays.asList; 201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static java.util.concurrent.TimeUnit.MILLISECONDS; 217dd252788645e940eada959bdde927426e2531c9Paul Duffinimport static org.truth0.Truth.ASSERT; 221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.cache.TestingCacheLoaders.IdentityLoader; 241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.cache.TestingRemovalListeners.CountingRemovalListener; 251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.collect.Iterators; 261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.testing.FakeTicker; 271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.util.concurrent.Callables; 281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 290888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport junit.framework.TestCase; 300888a09821a98ac0680fad765217302858e70fa4Paul Duffin 311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.List; 321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.Set; 331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.ExecutionException; 341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.atomic.AtomicInteger; 351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/** 371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Tests relating to cache expiration: make sure entries expire at the right times, make sure 381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * expired entries don't show up, etc. 391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author mike nonemacher 411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 420888a09821a98ac0680fad765217302858e70fa4Paul Duffin@SuppressWarnings("deprecation") // tests of deprecated method 431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpublic class CacheExpirationTest extends TestCase { 441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private static final long EXPIRING_TIME = 1000; 461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private static final int VALUE_PREFIX = 12345; 471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private static final String KEY_PREFIX = "key prefix:"; 481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testExpiration_expireAfterWrite() { 501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert FakeTicker ticker = new FakeTicker(); 511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert CountingRemovalListener<String, Integer> removalListener = countingRemovalListener(); 521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert WatchedCreatorLoader loader = new WatchedCreatorLoader(); 531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert LoadingCache<String, Integer> cache = CacheBuilder.newBuilder() 540888a09821a98ac0680fad765217302858e70fa4Paul Duffin .expireAfterWrite(EXPIRING_TIME, MILLISECONDS) 550888a09821a98ac0680fad765217302858e70fa4Paul Duffin .removalListener(removalListener) 560888a09821a98ac0680fad765217302858e70fa4Paul Duffin .ticker(ticker) 570888a09821a98ac0680fad765217302858e70fa4Paul Duffin .build(loader); 581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert checkExpiration(cache, loader, ticker, removalListener); 591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testExpiration_expireAfterAccess() { 621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert FakeTicker ticker = new FakeTicker(); 631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert CountingRemovalListener<String, Integer> removalListener = countingRemovalListener(); 641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert WatchedCreatorLoader loader = new WatchedCreatorLoader(); 651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert LoadingCache<String, Integer> cache = CacheBuilder.newBuilder() 660888a09821a98ac0680fad765217302858e70fa4Paul Duffin .expireAfterAccess(EXPIRING_TIME, MILLISECONDS) 670888a09821a98ac0680fad765217302858e70fa4Paul Duffin .removalListener(removalListener) 680888a09821a98ac0680fad765217302858e70fa4Paul Duffin .ticker(ticker) 690888a09821a98ac0680fad765217302858e70fa4Paul Duffin .build(loader); 701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert checkExpiration(cache, loader, ticker, removalListener); 711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private void checkExpiration(LoadingCache<String, Integer> cache, WatchedCreatorLoader loader, 741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert FakeTicker ticker, CountingRemovalListener<String, Integer> removalListener) { 751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int i = 0; i < 10; i++) { 771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(Integer.valueOf(VALUE_PREFIX + i), cache.getUnchecked(KEY_PREFIX + i)); 781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int i = 0; i < 10; i++) { 811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert loader.reset(); 821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(Integer.valueOf(VALUE_PREFIX + i), cache.getUnchecked(KEY_PREFIX + i)); 831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse("Creator should not have been called @#" + i, loader.wasCalled()); 841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 860888a09821a98ac0680fad765217302858e70fa4Paul Duffin CacheTesting.expireEntries((LoadingCache<?, ?>) cache, EXPIRING_TIME, ticker); 871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals("Map must be empty by now", 0, cache.size()); 890888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals("Eviction notifications must be received", 10, 900888a09821a98ac0680fad765217302858e70fa4Paul Duffin removalListener.getCount()); 911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 920888a09821a98ac0680fad765217302858e70fa4Paul Duffin CacheTesting.expireEntries((LoadingCache<?, ?>) cache, EXPIRING_TIME, ticker); 931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // ensure that no new notifications are sent 940888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals("Eviction notifications must be received", 10, 950888a09821a98ac0680fad765217302858e70fa4Paul Duffin removalListener.getCount()); 961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testExpiringGet_expireAfterWrite() { 991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert FakeTicker ticker = new FakeTicker(); 1001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert CountingRemovalListener<String, Integer> removalListener = countingRemovalListener(); 1011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert WatchedCreatorLoader loader = new WatchedCreatorLoader(); 1021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert LoadingCache<String, Integer> cache = CacheBuilder.newBuilder() 1030888a09821a98ac0680fad765217302858e70fa4Paul Duffin .expireAfterWrite(EXPIRING_TIME, MILLISECONDS) 1040888a09821a98ac0680fad765217302858e70fa4Paul Duffin .removalListener(removalListener) 1050888a09821a98ac0680fad765217302858e70fa4Paul Duffin .ticker(ticker) 1060888a09821a98ac0680fad765217302858e70fa4Paul Duffin .build(loader); 1071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert runExpirationTest(cache, loader, ticker, removalListener); 1081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testExpiringGet_expireAfterAccess() { 1111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert FakeTicker ticker = new FakeTicker(); 1121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert CountingRemovalListener<String, Integer> removalListener = countingRemovalListener(); 1131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert WatchedCreatorLoader loader = new WatchedCreatorLoader(); 1141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert LoadingCache<String, Integer> cache = CacheBuilder.newBuilder() 1150888a09821a98ac0680fad765217302858e70fa4Paul Duffin .expireAfterAccess(EXPIRING_TIME, MILLISECONDS) 1160888a09821a98ac0680fad765217302858e70fa4Paul Duffin .removalListener(removalListener) 1170888a09821a98ac0680fad765217302858e70fa4Paul Duffin .ticker(ticker) 1180888a09821a98ac0680fad765217302858e70fa4Paul Duffin .build(loader); 1191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert runExpirationTest(cache, loader, ticker, removalListener); 1201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private void runExpirationTest(LoadingCache<String, Integer> cache, WatchedCreatorLoader loader, 1231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert FakeTicker ticker, CountingRemovalListener<String, Integer> removalListener) { 1241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int i = 0; i < 10; i++) { 1261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(Integer.valueOf(VALUE_PREFIX + i), cache.getUnchecked(KEY_PREFIX + i)); 1271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int i = 0; i < 10; i++) { 1301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert loader.reset(); 1311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(Integer.valueOf(VALUE_PREFIX + i), cache.getUnchecked(KEY_PREFIX + i)); 1321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse("Loader should NOT have been called @#" + i, loader.wasCalled()); 1331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // wait for entries to expire, but don't call expireEntries 1361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ticker.advance(EXPIRING_TIME * 10, MILLISECONDS); 1371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // add a single unexpired entry 1391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert cache.getUnchecked(KEY_PREFIX + 11); 1401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // collections views shouldn't expose expired entries 1421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(1, Iterators.size(cache.asMap().entrySet().iterator())); 1431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(1, Iterators.size(cache.asMap().keySet().iterator())); 1441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(1, Iterators.size(cache.asMap().values().iterator())); 1451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1460888a09821a98ac0680fad765217302858e70fa4Paul Duffin CacheTesting.expireEntries((LoadingCache<?, ?>) cache, EXPIRING_TIME, ticker); 1471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int i = 0; i < 11; i++) { 1491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(cache.asMap().containsKey(KEY_PREFIX + i)); 1501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(11, removalListener.getCount()); 1521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int i = 0; i < 10; i++) { 1541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(cache.asMap().containsKey(KEY_PREFIX + i)); 1551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert loader.reset(); 1561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(Integer.valueOf(VALUE_PREFIX + i), cache.getUnchecked(KEY_PREFIX + i)); 1571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertTrue("Creator should have been called @#" + i, loader.wasCalled()); 1581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // expire new values we just created 1610888a09821a98ac0680fad765217302858e70fa4Paul Duffin CacheTesting.expireEntries((LoadingCache<?, ?>) cache, EXPIRING_TIME, ticker); 1620888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals("Eviction notifications must be received", 21, 1630888a09821a98ac0680fad765217302858e70fa4Paul Duffin removalListener.getCount()); 1641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1650888a09821a98ac0680fad765217302858e70fa4Paul Duffin CacheTesting.expireEntries((LoadingCache<?, ?>) cache, EXPIRING_TIME, ticker); 1661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // ensure that no new notifications are sent 1670888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals("Eviction notifications must be received", 21, 1680888a09821a98ac0680fad765217302858e70fa4Paul Duffin removalListener.getCount()); 1691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testRemovalListener_expireAfterWrite() { 1721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert FakeTicker ticker = new FakeTicker(); 1731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert final AtomicInteger evictionCount = new AtomicInteger(); 1741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert final AtomicInteger applyCount = new AtomicInteger(); 1751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert final AtomicInteger totalSum = new AtomicInteger(); 1761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1770888a09821a98ac0680fad765217302858e70fa4Paul Duffin RemovalListener<Integer, AtomicInteger> removalListener = 1780888a09821a98ac0680fad765217302858e70fa4Paul Duffin new RemovalListener<Integer, AtomicInteger>() { 1790888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override 1800888a09821a98ac0680fad765217302858e70fa4Paul Duffin public void onRemoval(RemovalNotification<Integer, AtomicInteger> notification) { 1810888a09821a98ac0680fad765217302858e70fa4Paul Duffin if (notification.wasEvicted()) { 1820888a09821a98ac0680fad765217302858e70fa4Paul Duffin evictionCount.incrementAndGet(); 1830888a09821a98ac0680fad765217302858e70fa4Paul Duffin totalSum.addAndGet(notification.getValue().get()); 1840888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 1850888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 1860888a09821a98ac0680fad765217302858e70fa4Paul Duffin }; 1871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert CacheLoader<Integer, AtomicInteger> loader = new CacheLoader<Integer, AtomicInteger>() { 1890888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public AtomicInteger load(Integer key) { 1901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert applyCount.incrementAndGet(); 1911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return new AtomicInteger(); 1921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert }; 1941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert LoadingCache<Integer, AtomicInteger> cache = CacheBuilder.newBuilder() 1960888a09821a98ac0680fad765217302858e70fa4Paul Duffin .removalListener(removalListener) 1970888a09821a98ac0680fad765217302858e70fa4Paul Duffin .expireAfterWrite(10, MILLISECONDS) 1980888a09821a98ac0680fad765217302858e70fa4Paul Duffin .ticker(ticker) 1991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert .build(loader); 2001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // Increment 100 times 2021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int i = 0; i < 100; ++i) { 2031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert cache.getUnchecked(10).incrementAndGet(); 2041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ticker.advance(1, MILLISECONDS); 2051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(evictionCount.get() + 1, applyCount.get()); 2081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert int remaining = cache.getUnchecked(10).get(); 2091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(100, totalSum.get() + remaining); 2101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testRemovalScheduler_expireAfterWrite() { 2131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert FakeTicker ticker = new FakeTicker(); 2141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert CountingRemovalListener<String, Integer> removalListener = countingRemovalListener(); 2151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert WatchedCreatorLoader loader = new WatchedCreatorLoader(); 2161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert LoadingCache<String, Integer> cache = CacheBuilder.newBuilder() 2170888a09821a98ac0680fad765217302858e70fa4Paul Duffin .expireAfterWrite(EXPIRING_TIME, MILLISECONDS) 2180888a09821a98ac0680fad765217302858e70fa4Paul Duffin .removalListener(removalListener) 2190888a09821a98ac0680fad765217302858e70fa4Paul Duffin .ticker(ticker) 2200888a09821a98ac0680fad765217302858e70fa4Paul Duffin .build(loader); 2211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert runRemovalScheduler(cache, removalListener, loader, ticker, KEY_PREFIX, EXPIRING_TIME); 2221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testRemovalScheduler_expireAfterAccess() { 2251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert FakeTicker ticker = new FakeTicker(); 2261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert CountingRemovalListener<String, Integer> removalListener = countingRemovalListener(); 2271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert WatchedCreatorLoader loader = new WatchedCreatorLoader(); 2281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert LoadingCache<String, Integer> cache = CacheBuilder.newBuilder() 2290888a09821a98ac0680fad765217302858e70fa4Paul Duffin .expireAfterAccess(EXPIRING_TIME, MILLISECONDS) 2300888a09821a98ac0680fad765217302858e70fa4Paul Duffin .removalListener(removalListener) 2310888a09821a98ac0680fad765217302858e70fa4Paul Duffin .ticker(ticker) 2320888a09821a98ac0680fad765217302858e70fa4Paul Duffin .build(loader); 2331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert runRemovalScheduler(cache, removalListener, loader, ticker, KEY_PREFIX, EXPIRING_TIME); 2341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testRemovalScheduler_expireAfterBoth() { 2371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert FakeTicker ticker = new FakeTicker(); 2381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert CountingRemovalListener<String, Integer> removalListener = countingRemovalListener(); 2391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert WatchedCreatorLoader loader = new WatchedCreatorLoader(); 2401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert LoadingCache<String, Integer> cache = CacheBuilder.newBuilder() 2411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert .expireAfterAccess(EXPIRING_TIME, MILLISECONDS) 2420888a09821a98ac0680fad765217302858e70fa4Paul Duffin .expireAfterWrite(EXPIRING_TIME, MILLISECONDS) 2430888a09821a98ac0680fad765217302858e70fa4Paul Duffin .removalListener(removalListener) 2440888a09821a98ac0680fad765217302858e70fa4Paul Duffin .ticker(ticker) 2450888a09821a98ac0680fad765217302858e70fa4Paul Duffin .build(loader); 2461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert runRemovalScheduler(cache, removalListener, loader, ticker, KEY_PREFIX, EXPIRING_TIME); 2471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testExpirationOrder_access() { 2501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // test lru within a single segment 2511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert FakeTicker ticker = new FakeTicker(); 2521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert IdentityLoader<Integer> loader = identityLoader(); 2530888a09821a98ac0680fad765217302858e70fa4Paul Duffin LoadingCache<Integer, Integer> cache = CacheBuilder.newBuilder() 2540888a09821a98ac0680fad765217302858e70fa4Paul Duffin .concurrencyLevel(1) 2550888a09821a98ac0680fad765217302858e70fa4Paul Duffin .expireAfterAccess(11, MILLISECONDS) 2560888a09821a98ac0680fad765217302858e70fa4Paul Duffin .ticker(ticker) 2570888a09821a98ac0680fad765217302858e70fa4Paul Duffin .build(loader); 2581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int i = 0; i < 10; i++) { 2591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert cache.getUnchecked(i); 2601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ticker.advance(1, MILLISECONDS); 2611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 2621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Set<Integer> keySet = cache.asMap().keySet(); 2630888a09821a98ac0680fad765217302858e70fa4Paul Duffin ASSERT.that(keySet).has().exactly(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); 2641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // 0 expires 2661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ticker.advance(1, MILLISECONDS); 2670888a09821a98ac0680fad765217302858e70fa4Paul Duffin ASSERT.that(keySet).has().exactly(1, 2, 3, 4, 5, 6, 7, 8, 9); 2681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // reorder 2701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert getAll(cache, asList(0, 1, 2)); 2711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert CacheTesting.drainRecencyQueues(cache); 2721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ticker.advance(2, MILLISECONDS); 2730888a09821a98ac0680fad765217302858e70fa4Paul Duffin ASSERT.that(keySet).has().exactly(3, 4, 5, 6, 7, 8, 9, 0, 1, 2); 2741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // 3 expires 2761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ticker.advance(1, MILLISECONDS); 2770888a09821a98ac0680fad765217302858e70fa4Paul Duffin ASSERT.that(keySet).has().exactly(4, 5, 6, 7, 8, 9, 0, 1, 2); 2781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // reorder 2801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert getAll(cache, asList(5, 7, 9)); 2811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert CacheTesting.drainRecencyQueues(cache); 2820888a09821a98ac0680fad765217302858e70fa4Paul Duffin ASSERT.that(keySet).has().exactly(4, 6, 8, 0, 1, 2, 5, 7, 9); 2831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // 4 expires 2851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ticker.advance(1, MILLISECONDS); 2860888a09821a98ac0680fad765217302858e70fa4Paul Duffin ASSERT.that(keySet).has().exactly(6, 8, 0, 1, 2, 5, 7, 9); 2871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ticker.advance(1, MILLISECONDS); 2880888a09821a98ac0680fad765217302858e70fa4Paul Duffin ASSERT.that(keySet).has().exactly(6, 8, 0, 1, 2, 5, 7, 9); 2891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // 6 expires 2911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ticker.advance(1, MILLISECONDS); 2920888a09821a98ac0680fad765217302858e70fa4Paul Duffin ASSERT.that(keySet).has().exactly(8, 0, 1, 2, 5, 7, 9); 2931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ticker.advance(1, MILLISECONDS); 2940888a09821a98ac0680fad765217302858e70fa4Paul Duffin ASSERT.that(keySet).has().exactly(8, 0, 1, 2, 5, 7, 9); 2951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 2961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // 8 expires 2971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ticker.advance(1, MILLISECONDS); 2980888a09821a98ac0680fad765217302858e70fa4Paul Duffin ASSERT.that(keySet).has().exactly(0, 1, 2, 5, 7, 9); 2991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testExpirationOrder_write() throws ExecutionException { 3021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // test lru within a single segment 3031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert FakeTicker ticker = new FakeTicker(); 3041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert IdentityLoader<Integer> loader = identityLoader(); 3050888a09821a98ac0680fad765217302858e70fa4Paul Duffin LoadingCache<Integer, Integer> cache = CacheBuilder.newBuilder() 3060888a09821a98ac0680fad765217302858e70fa4Paul Duffin .concurrencyLevel(1) 3070888a09821a98ac0680fad765217302858e70fa4Paul Duffin .expireAfterWrite(11, MILLISECONDS) 3080888a09821a98ac0680fad765217302858e70fa4Paul Duffin .ticker(ticker) 3090888a09821a98ac0680fad765217302858e70fa4Paul Duffin .build(loader); 3101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int i = 0; i < 10; i++) { 3111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert cache.getUnchecked(i); 3121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ticker.advance(1, MILLISECONDS); 3131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Set<Integer> keySet = cache.asMap().keySet(); 3150888a09821a98ac0680fad765217302858e70fa4Paul Duffin ASSERT.that(keySet).has().exactly(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); 3161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // 0 expires 3181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ticker.advance(1, MILLISECONDS); 3190888a09821a98ac0680fad765217302858e70fa4Paul Duffin ASSERT.that(keySet).has().exactly(1, 2, 3, 4, 5, 6, 7, 8, 9); 3201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // get doesn't stop 1 from expiring 3221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert getAll(cache, asList(0, 1, 2)); 3231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert CacheTesting.drainRecencyQueues(cache); 3241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ticker.advance(1, MILLISECONDS); 3250888a09821a98ac0680fad765217302858e70fa4Paul Duffin ASSERT.that(keySet).has().exactly(2, 3, 4, 5, 6, 7, 8, 9, 0); 3261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // get(K, Callable) doesn't stop 2 from expiring 3281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert cache.get(2, Callables.returning(-2)); 3291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert CacheTesting.drainRecencyQueues(cache); 3301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ticker.advance(1, MILLISECONDS); 3310888a09821a98ac0680fad765217302858e70fa4Paul Duffin ASSERT.that(keySet).has().exactly(3, 4, 5, 6, 7, 8, 9, 0); 3321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // asMap.put saves 3 3341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert cache.asMap().put(3, -3); 3351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ticker.advance(1, MILLISECONDS); 3360888a09821a98ac0680fad765217302858e70fa4Paul Duffin ASSERT.that(keySet).has().exactly(4, 5, 6, 7, 8, 9, 0, 3); 3371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // asMap.replace saves 4 3391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert cache.asMap().replace(4, -4); 3401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ticker.advance(1, MILLISECONDS); 3410888a09821a98ac0680fad765217302858e70fa4Paul Duffin ASSERT.that(keySet).has().exactly(5, 6, 7, 8, 9, 0, 3, 4); 3421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // 5 expires 3441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ticker.advance(1, MILLISECONDS); 3450888a09821a98ac0680fad765217302858e70fa4Paul Duffin ASSERT.that(keySet).has().exactly(6, 7, 8, 9, 0, 3, 4); 3461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testExpirationOrder_writeAccess() throws ExecutionException { 3491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // test lru within a single segment 3501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert FakeTicker ticker = new FakeTicker(); 3511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert IdentityLoader<Integer> loader = identityLoader(); 3520888a09821a98ac0680fad765217302858e70fa4Paul Duffin LoadingCache<Integer, Integer> cache = CacheBuilder.newBuilder() 3530888a09821a98ac0680fad765217302858e70fa4Paul Duffin .concurrencyLevel(1) 3540888a09821a98ac0680fad765217302858e70fa4Paul Duffin .expireAfterWrite(5, MILLISECONDS) 3550888a09821a98ac0680fad765217302858e70fa4Paul Duffin .expireAfterAccess(3, MILLISECONDS) 3560888a09821a98ac0680fad765217302858e70fa4Paul Duffin .ticker(ticker) 3571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert .build(loader); 3581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int i = 0; i < 5; i++) { 3591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert cache.getUnchecked(i); 3601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ticker.advance(1, MILLISECONDS); 3621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int i = 5; i < 10; i++) { 3631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert cache.getUnchecked(i); 3641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ticker.advance(1, MILLISECONDS); 3661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Set<Integer> keySet = cache.asMap().keySet(); 3680888a09821a98ac0680fad765217302858e70fa4Paul Duffin ASSERT.that(keySet).has().exactly(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); 3691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // get saves 1, 3; 0, 2, 4 expire 3711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert getAll(cache, asList(1, 3)); 3721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert CacheTesting.drainRecencyQueues(cache); 3731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ticker.advance(1, MILLISECONDS); 3740888a09821a98ac0680fad765217302858e70fa4Paul Duffin ASSERT.that(keySet).has().exactly(5, 6, 7, 8, 9, 1, 3); 3751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // get saves 6, 8; 5, 7, 9 expire 3771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert getAll(cache, asList(6, 8)); 3781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert CacheTesting.drainRecencyQueues(cache); 3791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ticker.advance(1, MILLISECONDS); 3800888a09821a98ac0680fad765217302858e70fa4Paul Duffin ASSERT.that(keySet).has().exactly(1, 3, 6, 8); 3811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // get fails to save 1, put saves 3 3831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert cache.asMap().put(3, -3); 3841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert getAll(cache, asList(1)); 3851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert CacheTesting.drainRecencyQueues(cache); 3861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ticker.advance(1, MILLISECONDS); 3870888a09821a98ac0680fad765217302858e70fa4Paul Duffin ASSERT.that(keySet).has().exactly(6, 8, 3); 3881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // get(K, Callable) fails to save 8, replace saves 6 3901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert cache.asMap().replace(6, -6); 3911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert cache.get(8, Callables.returning(-8)); 3921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert CacheTesting.drainRecencyQueues(cache); 3931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ticker.advance(1, MILLISECONDS); 3940888a09821a98ac0680fad765217302858e70fa4Paul Duffin ASSERT.that(keySet).has().exactly(3, 6); 3951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 3961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 3971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private void runRemovalScheduler(LoadingCache<String, Integer> cache, 3980888a09821a98ac0680fad765217302858e70fa4Paul Duffin CountingRemovalListener<String, Integer> removalListener, 3990888a09821a98ac0680fad765217302858e70fa4Paul Duffin WatchedCreatorLoader loader, 4001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert FakeTicker ticker, String keyPrefix, long ttl) { 4011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert int shift1 = 10 + VALUE_PREFIX; 4031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert loader.setValuePrefix(shift1); 4041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // fill with initial data 4051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int i = 0; i < 10; i++) { 4061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(Integer.valueOf(i + shift1), cache.getUnchecked(keyPrefix + i)); 4071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(10, CacheTesting.expirationQueueSize(cache)); 4091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(0, removalListener.getCount()); 4101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // wait, so that entries have just 10 ms to live 4121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ticker.advance(ttl * 2 / 3, MILLISECONDS); 4131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(10, CacheTesting.expirationQueueSize(cache)); 4151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(0, removalListener.getCount()); 4161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert int shift2 = shift1 + 10; 4181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert loader.setValuePrefix(shift2); 4191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // fill with new data - has to live for 20 ms more 4201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int i = 0; i < 10; i++) { 4211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert cache.invalidate(keyPrefix + i); 4220888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals("key: " + keyPrefix + i, 4230888a09821a98ac0680fad765217302858e70fa4Paul Duffin Integer.valueOf(i + shift2), cache.getUnchecked(keyPrefix + i)); 4241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(10, CacheTesting.expirationQueueSize(cache)); 4260888a09821a98ac0680fad765217302858e70fa4Paul Duffin assertEquals(10, removalListener.getCount()); // these are the invalidated ones 4271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // old timeouts must expire after this wait 4291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ticker.advance(ttl * 2 / 3, MILLISECONDS); 4301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(10, CacheTesting.expirationQueueSize(cache)); 4321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(10, removalListener.getCount()); 4331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // check that new values are still there - they still have 10 ms to live 4351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int i = 0; i < 10; i++) { 4361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert loader.reset(); 4371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(Integer.valueOf(i + shift2), cache.getUnchecked(keyPrefix + i)); 4381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse("Creator should NOT have been called @#" + i, loader.wasCalled()); 4391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(10, removalListener.getCount()); 4411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private void getAll(LoadingCache<Integer, Integer> cache, List<Integer> keys) { 4441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int i : keys) { 4451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert cache.getUnchecked(i); 4461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private static class WatchedCreatorLoader extends CacheLoader<String, Integer> { 4501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert boolean wasCalled = false; // must be set in load() 4511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert String keyPrefix = KEY_PREFIX; 4521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert int valuePrefix = VALUE_PREFIX; 4531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4540888a09821a98ac0680fad765217302858e70fa4Paul Duffin public WatchedCreatorLoader() { 4550888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 4561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void reset() { 4581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert wasCalled = false; 4591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public boolean wasCalled() { 4621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return wasCalled; 4631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void setKeyPrefix(String keyPrefix) { 4661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert this.keyPrefix = keyPrefix; 4671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void setValuePrefix(int valuePrefix) { 4701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert this.valuePrefix = valuePrefix; 4711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 4730888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override public Integer load(String key) { 4741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert wasCalled = true; 4751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return valuePrefix + Integer.parseInt(key.substring(keyPrefix.length())); 4761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 4781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert} 479