LRU Cache
/* * XAPool: Open Source XA JDBC Pool * Copyright (C) 2003 Objectweb.org * Initial Developer: Lutris Technologies Inc. * Contact: xapool-public@lists.debian-sf.objectweb.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA */ import java.util.Hashtable; import java.util.LinkedList; import java.util.ArrayList; import java.util.List; import java.util.Iterator; import java.util.Enumeration; /** * Simple implementation of a cache, using Least Recently Used algorithm * for discarding members when the cache fills up */ public class LRUCache { /** The cache */ private Hashtable cache = new Hashtable(); /** The linked list to keep track of least/most recently used */ private LinkedList lru = new LinkedList(); /** The maximum size of the cache */ private int maxSize; /** * Constructor */ public LRUCache(int maxSize) { this.maxSize = maxSize; } public int LRUSize() { return lru.size(); } public int cacheSize() { return cache.size(); } /** * Puts a new object in the cache. If the cache is full, it removes * the least recently used object. The new object becomes the most * recently used object. */ public void put(Object key, Object value) { List removed = new ArrayList(); synchronized (this) { // make room if needed while (cache.size() + 1 > maxSize) { removed.add(removeLRU()); } // remove the key from the list if it's in the cache already Object cacheValue = cache.get(key); if (cacheValue != null) { if (cacheValue != value) removed.add(cacheValue); lru.remove(key); } // the last item in the list is the most recently used lru.addLast(key); // put it in the actual cache cache.put(key, value); } cleanupAll(removed); } /** * Gets an object from the cache. This object is set to be the * most recenty used */ public synchronized Object get(Object key) { // check for existence in cache if (!cache.containsKey(key)) { return null; } // set to most recently used lru.remove(key); lru.addLast(key); // return the object return cache.get(key); } /** * Removes the object from the cache and the lru list */ public synchronized Object remove(Object key) { // check for existence in cache if (!cache.containsKey(key)) { return null; } // remove from lru list lru.remove(key); // remove from cache Object obj = cache.remove(key); return obj; } private synchronized Object removeLRU() { Object obj = cache.remove(lru.getFirst()); lru.removeFirst(); return obj; } /** * Resize the cache */ public void resize(int newSize) { if (newSize <= 0) { return; } List removed = new ArrayList(); synchronized (this) { maxSize = newSize; while (cache.size() > maxSize) { removed.add(removeLRU()); } } cleanupAll(removed); } private void cleanupAll(List removed) { Iterator it = removed.iterator(); while (it.hasNext()) { cleanupObject(it.next()); } } /** * Override this method to do special cleanup on an object, * such as closing a statement or a connection */ protected void cleanupObject(Object o) {} public void cleanupAll() { for (Enumeration enumeration = cache.keys();enumeration.hasMoreElements();) { Object o = remove(enumeration.nextElement()); cleanupObject(o); } } }