151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski/* 2d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. 351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * This code is free software; you can redistribute it and/or modify it 651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * under the terms of the GNU General Public License version 2 only, as 751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * published by the Free Software Foundation. Oracle designates this 851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * particular file as subject to the "Classpath" exception as provided 951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * by Oracle in the LICENSE file that accompanied this code. 1051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 1151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * This code is distributed in the hope that it will be useful, but WITHOUT 1251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * version 2 for more details (a copy is included in the LICENSE file that 1551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * accompanied this code). 1651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 1751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * You should have received a copy of the GNU General Public License version 1851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 2 along with this work; if not, write to the Free Software Foundation, 1951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 2151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * or visit www.oracle.com if you need additional information or have any 2351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * questions. 2451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 2551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 2651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskipackage sun.security.util; 2751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 2851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.*; 2951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.lang.ref.*; 3051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 3151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski/** 3251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Abstract base class and factory for caches. A cache is a key-value mapping. 3351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * It has properties that make it more suitable for caching than a Map. 3451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 3551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * The factory methods can be used to obtain two different implementations. 3651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * They have the following properties: 3751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 3851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * . keys and values reside in memory 3951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 4051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * . keys and values must be non-null 4151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 4251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * . maximum size. Replacements are made in LRU order. 4351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 4451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * . optional lifetime, specified in seconds. 4551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 46d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root * . safe for concurrent use by multiple threads 4751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 4851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * . values are held by either standard references or via SoftReferences. 4951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * SoftReferences have the advantage that they are automatically cleared 5051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * by the garbage collector in response to memory demand. This makes it 5151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * possible to simple set the maximum size to a very large value and let 5251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * the GC automatically size the cache dynamically depending on the 5351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * amount of available memory. 5451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 5551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * However, note that because of the way SoftReferences are implemented in 5651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * HotSpot at the moment, this may not work perfectly as it clears them fairly 5751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * eagerly. Performance may be improved if the Java heap size is set to larger 5851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * value using e.g. java -ms64M -mx128M foo.Test 5951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 6051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Cache sizing: the memory cache is implemented on top of a LinkedHashMap. 6151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * In its current implementation, the number of buckets (NOT entries) in 6251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * (Linked)HashMaps is always a power of two. It is recommended to set the 6351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * maximum cache size to value that uses those buckets fully. For example, 6451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * if a cache with somewhere between 500 and 1000 entries is desired, a 6551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * maximum size of 750 would be a good choice: try 1024 buckets, with a 6651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * load factor of 0.75f, the number of entries can be calculated as 6751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * buckets / 4 * 3. As mentioned above, with a SoftReference cache, it is 6851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * generally reasonable to set the size to a fairly large value. 6951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 7051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @author Andreas Sterbenz 7151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 72d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Rootpublic abstract class Cache<K,V> { 7351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 7451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski protected Cache() { 7551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // empty 7651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 7751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 7851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 7951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Return the number of currently valid entries in the cache. 8051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 8151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public abstract int size(); 8251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 8351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 8451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Remove all entries from the cache. 8551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 8651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public abstract void clear(); 8751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 8851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 8951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Add an entry to the cache. 9051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 91d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root public abstract void put(K key, V value); 9251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 9351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 9451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Get a value from the cache. 9551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 96d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root public abstract V get(Object key); 9751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 9851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 9951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Remove an entry from the cache. 10051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 10151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public abstract void remove(Object key); 10251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 10351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 10451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Set the maximum size. 10551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 10651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public abstract void setCapacity(int size); 10751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 10851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 10951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Set the timeout(in seconds). 11051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 11151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public abstract void setTimeout(int timeout); 11251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 11351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 11451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * accept a visitor 11551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 116d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root public abstract void accept(CacheVisitor<K,V> visitor); 11751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 11851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 11951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Return a new memory cache with the specified maximum size, unlimited 12051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * lifetime for entries, with the values held by SoftReferences. 12151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 122d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root public static <K,V> Cache<K,V> newSoftMemoryCache(int size) { 123d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root return new MemoryCache<>(true, size); 12451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 12551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 12651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 12751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Return a new memory cache with the specified maximum size, the 12851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * specified maximum lifetime (in seconds), with the values held 12951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * by SoftReferences. 13051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 131d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root public static <K,V> Cache<K,V> newSoftMemoryCache(int size, int timeout) { 132d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root return new MemoryCache<>(true, size, timeout); 13351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 13451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 13551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 13651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Return a new memory cache with the specified maximum size, unlimited 13751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * lifetime for entries, with the values held by standard references. 13851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 139d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root public static <K,V> Cache<K,V> newHardMemoryCache(int size) { 140d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root return new MemoryCache<>(false, size); 14151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 14251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 14351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 14451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Return a dummy cache that does nothing. 14551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 146d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root @SuppressWarnings("unchecked") 147d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root public static <K,V> Cache<K,V> newNullCache() { 148d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root return (Cache<K,V>) NullCache.INSTANCE; 14951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 15051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 15151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 15251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Return a new memory cache with the specified maximum size, the 15351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * specified maximum lifetime (in seconds), with the values held 15451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * by standard references. 15551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 156d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root public static <K,V> Cache<K,V> newHardMemoryCache(int size, int timeout) { 157d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root return new MemoryCache<>(false, size, timeout); 15851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 15951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 16051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 16151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Utility class that wraps a byte array and implements the equals() 16251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * and hashCode() contract in a way suitable for Maps and caches. 16351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 16451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public static class EqualByteArray { 16551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 16651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private final byte[] b; 16751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private volatile int hash; 16851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 16951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public EqualByteArray(byte[] b) { 17051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski this.b = b; 17151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 17251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 17351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public int hashCode() { 17451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int h = hash; 17551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (h == 0) { 17651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski h = b.length + 1; 17751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski for (int i = 0; i < b.length; i++) { 17851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski h += (b[i] & 0xff) * 37; 17951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 18051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski hash = h; 18151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 18251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return h; 18351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 18451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 18551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public boolean equals(Object obj) { 18651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (this == obj) { 18751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return true; 18851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 18951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (obj instanceof EqualByteArray == false) { 19051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return false; 19151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 19251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski EqualByteArray other = (EqualByteArray)obj; 19351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return Arrays.equals(this.b, other.b); 19451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 19551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 19651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 197d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root public interface CacheVisitor<K,V> { 198d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root public void visit(Map<K,V> map); 19951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 20051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 20151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski} 20251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 203d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Rootclass NullCache<K,V> extends Cache<K,V> { 20451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 205d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root final static Cache<Object,Object> INSTANCE = new NullCache<>(); 20651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 20751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private NullCache() { 20851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // empty 20951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 21051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 21151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public int size() { 21251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return 0; 21351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 21451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 21551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public void clear() { 21651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // empty 21751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 21851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 219d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root public void put(K key, V value) { 22051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // empty 22151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 22251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 223d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root public V get(Object key) { 22451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return null; 22551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 22651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 22751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public void remove(Object key) { 22851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // empty 22951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 23051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 23151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public void setCapacity(int size) { 23251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // empty 23351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 23451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 23551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public void setTimeout(int timeout) { 23651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // empty 23751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 23851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 239d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root public void accept(CacheVisitor<K,V> visitor) { 24051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // empty 24151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 24251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 24351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski} 24451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 245d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Rootclass MemoryCache<K,V> extends Cache<K,V> { 24651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 24751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private final static float LOAD_FACTOR = 0.75f; 24851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 24951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // XXXX 25051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private final static boolean DEBUG = false; 25151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 252d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root private final Map<K, CacheEntry<K,V>> cacheMap; 25351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private int maxSize; 25451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private long lifetime; 255d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root 256d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root // ReferenceQueue is of type V instead of Cache<K,V> 257d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root // to allow SoftCacheEntry to extend SoftReference<V> 258d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root private final ReferenceQueue<V> queue; 25951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 26051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public MemoryCache(boolean soft, int maxSize) { 26151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski this(soft, maxSize, 0); 26251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 26351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 26451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public MemoryCache(boolean soft, int maxSize, int lifetime) { 26551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski this.maxSize = maxSize; 26651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski this.lifetime = lifetime * 1000; 267d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root if (soft) 268d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root this.queue = new ReferenceQueue<>(); 269d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root else 270d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root this.queue = null; 271d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root 27251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int buckets = (int)(maxSize / LOAD_FACTOR) + 1; 273d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root cacheMap = new LinkedHashMap<>(buckets, LOAD_FACTOR, true); 27451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 27551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 27651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 27751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Empty the reference queue and remove all corresponding entries 27851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * from the cache. 27951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 28051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * This method should be called at the beginning of each public 28151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * method. 28251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 28351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private void emptyQueue() { 28451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (queue == null) { 28551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return; 28651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 28751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int startSize = cacheMap.size(); 28851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski while (true) { 289d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root @SuppressWarnings("unchecked") 290d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root CacheEntry<K,V> entry = (CacheEntry<K,V>)queue.poll(); 29151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (entry == null) { 29251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski break; 29351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 294d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root K key = entry.getKey(); 29551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (key == null) { 29651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // key is null, entry has already been removed 29751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski continue; 29851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 299d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root CacheEntry<K,V> currentEntry = cacheMap.remove(key); 30051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // check if the entry in the map corresponds to the expired 30151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // entry. If not, readd the entry 30251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if ((currentEntry != null) && (entry != currentEntry)) { 30351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski cacheMap.put(key, currentEntry); 30451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 30551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 30651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (DEBUG) { 30751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int endSize = cacheMap.size(); 30851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (startSize != endSize) { 30951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski System.out.println("*** Expunged " + (startSize - endSize) 31051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski + " entries, " + endSize + " entries left"); 31151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 31251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 31351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 31451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 31551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /** 31651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Scan all entries and remove all expired ones. 31751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 31851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private void expungeExpiredEntries() { 31951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski emptyQueue(); 32051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (lifetime == 0) { 32151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return; 32251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 32351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int cnt = 0; 32451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski long time = System.currentTimeMillis(); 325d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root for (Iterator<CacheEntry<K,V>> t = cacheMap.values().iterator(); 32651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski t.hasNext(); ) { 327d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root CacheEntry<K,V> entry = t.next(); 32851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (entry.isValid(time) == false) { 32951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski t.remove(); 33051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski cnt++; 33151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 33251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 33351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (DEBUG) { 33451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (cnt != 0) { 33551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski System.out.println("Removed " + cnt 33651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski + " expired entries, remaining " + cacheMap.size()); 33751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 33851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 33951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 34051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 34151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public synchronized int size() { 34251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski expungeExpiredEntries(); 34351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return cacheMap.size(); 34451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 34551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 34651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public synchronized void clear() { 34751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (queue != null) { 34851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // if this is a SoftReference cache, first invalidate() all 34951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // entries so that GC does not have to enqueue them 350d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root for (CacheEntry<K,V> entry : cacheMap.values()) { 35151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski entry.invalidate(); 35251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 35351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski while (queue.poll() != null) { 35451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // empty 35551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 35651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 35751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski cacheMap.clear(); 35851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 35951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 360d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root public synchronized void put(K key, V value) { 36151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski emptyQueue(); 36251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski long expirationTime = (lifetime == 0) ? 0 : 36351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski System.currentTimeMillis() + lifetime; 364d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root CacheEntry<K,V> newEntry = newEntry(key, value, expirationTime, queue); 365d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root CacheEntry<K,V> oldEntry = cacheMap.put(key, newEntry); 36651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (oldEntry != null) { 36751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski oldEntry.invalidate(); 36851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return; 36951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 37051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (maxSize > 0 && cacheMap.size() > maxSize) { 37151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski expungeExpiredEntries(); 37251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (cacheMap.size() > maxSize) { // still too large? 373d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root Iterator<CacheEntry<K,V>> t = cacheMap.values().iterator(); 374d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root CacheEntry<K,V> lruEntry = t.next(); 37551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (DEBUG) { 37651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski System.out.println("** Overflow removal " 37751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski + lruEntry.getKey() + " | " + lruEntry.getValue()); 37851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 37951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski t.remove(); 38051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski lruEntry.invalidate(); 38151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 38251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 38351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 38451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 385d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root public synchronized V get(Object key) { 38651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski emptyQueue(); 387d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root CacheEntry<K,V> entry = cacheMap.get(key); 38851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (entry == null) { 38951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return null; 39051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 39151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski long time = (lifetime == 0) ? 0 : System.currentTimeMillis(); 39251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (entry.isValid(time) == false) { 39351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (DEBUG) { 39451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski System.out.println("Ignoring expired entry"); 39551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 39651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski cacheMap.remove(key); 39751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return null; 39851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 39951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return entry.getValue(); 40051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 40151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 40251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public synchronized void remove(Object key) { 40351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski emptyQueue(); 404d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root CacheEntry<K,V> entry = cacheMap.remove(key); 40551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (entry != null) { 40651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski entry.invalidate(); 40751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 40851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 40951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 41051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public synchronized void setCapacity(int size) { 41151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski expungeExpiredEntries(); 41251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (size > 0 && cacheMap.size() > size) { 413d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root Iterator<CacheEntry<K,V>> t = cacheMap.values().iterator(); 41451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski for (int i = cacheMap.size() - size; i > 0; i--) { 415d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root CacheEntry<K,V> lruEntry = t.next(); 41651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (DEBUG) { 41751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski System.out.println("** capacity reset removal " 41851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski + lruEntry.getKey() + " | " + lruEntry.getValue()); 41951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 42051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski t.remove(); 42151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski lruEntry.invalidate(); 42251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 42351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 42451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 42551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski maxSize = size > 0 ? size : 0; 42651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 42751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (DEBUG) { 42851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski System.out.println("** capacity reset to " + size); 42951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 43051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 43151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 43251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public synchronized void setTimeout(int timeout) { 43351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski emptyQueue(); 43451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski lifetime = timeout > 0 ? timeout * 1000L : 0L; 43551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 43651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (DEBUG) { 43751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski System.out.println("** lifetime reset to " + timeout); 43851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 43951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 44051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 44151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // it is a heavyweight method. 442d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root public synchronized void accept(CacheVisitor<K,V> visitor) { 44351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski expungeExpiredEntries(); 444d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root Map<K,V> cached = getCachedEntries(); 44551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 44651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski visitor.visit(cached); 44751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 44851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 449d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root private Map<K,V> getCachedEntries() { 450d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root Map<K,V> kvmap = new HashMap<>(cacheMap.size()); 45151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 452d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root for (CacheEntry<K,V> entry : cacheMap.values()) { 45351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski kvmap.put(entry.getKey(), entry.getValue()); 45451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 45551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 45651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return kvmap; 45751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 45851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 459d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root protected CacheEntry<K,V> newEntry(K key, V value, 460d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root long expirationTime, ReferenceQueue<V> queue) { 46151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (queue != null) { 462d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root return new SoftCacheEntry<>(key, value, expirationTime, queue); 46351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } else { 464d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root return new HardCacheEntry<>(key, value, expirationTime); 46551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 46651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 46751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 468d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root private static interface CacheEntry<K,V> { 46951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 47051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski boolean isValid(long currentTime); 47151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 47251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski void invalidate(); 47351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 474d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root K getKey(); 47551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 476d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root V getValue(); 47751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 47851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 47951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 480d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root private static class HardCacheEntry<K,V> implements CacheEntry<K,V> { 48151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 482d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root private K key; 483d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root private V value; 48451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private long expirationTime; 48551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 486d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root HardCacheEntry(K key, V value, long expirationTime) { 48751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski this.key = key; 48851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski this.value = value; 48951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski this.expirationTime = expirationTime; 49051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 49151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 492d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root public K getKey() { 49351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return key; 49451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 49551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 496d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root public V getValue() { 49751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return value; 49851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 49951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 50051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public boolean isValid(long currentTime) { 50151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski boolean valid = (currentTime <= expirationTime); 50251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (valid == false) { 50351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski invalidate(); 50451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 50551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return valid; 50651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 50751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 50851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public void invalidate() { 50951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski key = null; 51051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski value = null; 51151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski expirationTime = -1; 51251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 51351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 51451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 515d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root private static class SoftCacheEntry<K,V> 516d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root extends SoftReference<V> 517d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root implements CacheEntry<K,V> { 51851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 519d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root private K key; 52051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private long expirationTime; 52151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 522d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root SoftCacheEntry(K key, V value, long expirationTime, 523d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root ReferenceQueue<V> queue) { 52451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski super(value, queue); 52551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski this.key = key; 52651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski this.expirationTime = expirationTime; 52751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 52851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 529d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root public K getKey() { 53051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return key; 53151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 53251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 533d7819a81f8b1b8d1a6b26329e4aa5f046afbf1f6Kenny Root public V getValue() { 53451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return get(); 53551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 53651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 53751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public boolean isValid(long currentTime) { 53851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski boolean valid = (currentTime <= expirationTime) && (get() != null); 53951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (valid == false) { 54051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski invalidate(); 54151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 54251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return valid; 54351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 54451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 54551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public void invalidate() { 54651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski clear(); 54751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski key = null; 54851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski expirationTime = -1; 54951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 55051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 55151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 55251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski} 553