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.LocalCache.Strength.STRONG; 181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static com.google.common.collect.Maps.immutableEntry; 193ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffinimport static com.google.common.truth.Truth.assertThat; 201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.base.Function; 221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.cache.LocalCache.Strength; 231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.cache.TestingRemovalListeners.CountingRemovalListener; 241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.collect.ImmutableSet; 251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.collect.Iterables; 261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 277dd252788645e940eada959bdde927426e2531c9Paul Duffinimport junit.framework.TestCase; 281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 290888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport java.lang.ref.WeakReference; 300888a09821a98ac0680fad765217302858e70fa4Paul Duffin 311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/** 321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Tests of basic {@link LoadingCache} operations with all possible combinations of key & value 331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * strengths. 341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author mike nonemacher 361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpublic class CacheReferencesTest extends TestCase { 381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private static final CacheLoader<Key,String> KEY_TO_STRING_LOADER = 401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert new CacheLoader<Key, String>() { 411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public String load(Key key) { 421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return key.toString(); 431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert }; 451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private CacheBuilderFactory factoryWithAllKeyStrengths() { 471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return new CacheBuilderFactory() 481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert .withKeyStrengths(ImmutableSet.of(STRONG, Strength.WEAK)) 491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert .withValueStrengths(ImmutableSet.of(STRONG, Strength.WEAK, Strength.SOFT)); 501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private Iterable<LoadingCache<Key, String>> caches() { 531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert CacheBuilderFactory factory = factoryWithAllKeyStrengths(); 541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return Iterables.transform(factory.buildAllPermutations(), 551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert new Function<CacheBuilder<Object, Object>, LoadingCache<Key, String>>() { 561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public LoadingCache<Key, String> apply(CacheBuilder<Object, Object> builder) { 571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return builder.build(KEY_TO_STRING_LOADER); 581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert }); 601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testContainsKeyAndValue() { 631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (LoadingCache<Key, String> cache : caches()) { 641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // maintain strong refs so these won't be collected, regardless of cache's key/value strength 651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Key key = new Key(1); 661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert String value = key.toString(); 671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertSame(value, cache.getUnchecked(key)); 681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertTrue(cache.asMap().containsKey(key)); 691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertTrue(cache.asMap().containsValue(value)); 701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(1, cache.size()); 711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testClear() { 751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (LoadingCache<Key, String> cache : caches()) { 761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Key key = new Key(1); 771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert String value = key.toString(); 781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertSame(value, cache.getUnchecked(key)); 791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(cache.asMap().isEmpty()); 801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert cache.invalidateAll(); 811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(0, cache.size()); 821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertTrue(cache.asMap().isEmpty()); 831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(cache.asMap().containsKey(key)); 841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(cache.asMap().containsValue(value)); 851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testKeySetEntrySetValues() { 891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (LoadingCache<Key, String> cache : caches()) { 901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Key key1 = new Key(1); 911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert String value1 = key1.toString(); 921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Key key2 = new Key(2); 931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert String value2 = key2.toString(); 941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertSame(value1, cache.getUnchecked(key1)); 951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertSame(value2, cache.getUnchecked(key2)); 961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(ImmutableSet.of(key1, key2), cache.asMap().keySet()); 973ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin assertThat(cache.asMap().values()).has().exactly(value1, value2); 981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(ImmutableSet.of(immutableEntry(key1, value1), immutableEntry(key2, value2)), 991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert cache.asMap().entrySet()); 1001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public void testInvalidate() { 1041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (LoadingCache<Key, String> cache : caches()) { 1051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Key key1 = new Key(1); 1061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert String value1 = key1.toString(); 1071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Key key2 = new Key(2); 1081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert String value2 = key2.toString(); 1091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertSame(value1, cache.getUnchecked(key1)); 1101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertSame(value2, cache.getUnchecked(key2)); 1111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert cache.invalidate(key1); 1121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertFalse(cache.asMap().containsKey(key1)); 1131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertTrue(cache.asMap().containsKey(key2)); 1141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(1, cache.size()); 1151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(ImmutableSet.of(key2), cache.asMap().keySet()); 1163ecfa412eddc4b084663f38d562537b86b9734d5Paul Duffin assertThat(cache.asMap().values()).has().item(value2); 1171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(ImmutableSet.of(immutableEntry(key2, value2)), cache.asMap().entrySet()); 1181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1210888a09821a98ac0680fad765217302858e70fa4Paul Duffin // fails in Maven with 64-bit JDK: http://code.google.com/p/guava-libraries/issues/detail?id=1568 1221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private void assertCleanup(LoadingCache<Integer, String> cache, 1241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert CountingRemovalListener<Integer, String> removalListener) { 1251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // initialSize will most likely be 2, but it's possible for the GC to have already run, so we'll 1271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // observe a size of 1 1281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert long initialSize = cache.size(); 1291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertTrue(initialSize == 1 || initialSize == 2); 1301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // wait up to 5s 1321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert byte[] filler = new byte[1024]; 1331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (int i = 0; i < 500; i++) { 1341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert System.gc(); 1351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert CacheTesting.drainReferenceQueues(cache); 1371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (cache.size() == 1) { 1381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert break; 1391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert try { 1411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Thread.sleep(10); 1421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } catch (InterruptedException e) { /* ignore */} 1431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert try { 1441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // Fill up heap so soft references get cleared. 1451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert filler = new byte[Math.max(filler.length, filler.length * 2)]; 1461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } catch (OutOfMemoryError e) {} 1471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert CacheTesting.processPendingNotifications(cache); 1501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(1, cache.size()); 1511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert assertEquals(1, removalListener.getCount()); 1521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // A simple type whose .toString() will return the same value each time, but without maintaining 1551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert // a strong reference to that value. 1561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert static class Key { 1571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private final int value; 1581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private WeakReference<String> toString; 1591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Key(int value) { 1611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert this.value = value; 1621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public synchronized String toString() { 1651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert String s; 1661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (toString != null) { 1671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert s = toString.get(); 1681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (s != null) { 1691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return s; 1701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert s = Integer.toString(value); 1731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert toString = new WeakReference<String>(s); 1741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return s; 1751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert} 178