001: /*
002: * Cache.java February 2001
003: *
004: * Copyright (C) 2001, Niall Gallagher <niallg@users.sf.net>
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013: * GNU Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General
016: * Public License along with this library; if not, write to the
017: * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
018: * Boston, MA 02111-1307 USA
019: */
020:
021: package simple.util.cache;
022:
023: /**
024: * This is a LRU, Least Recently Used, <code>Cache</code> used to store
025: * objects. This ensures that the <code>Cache</code> does not allow
026: * too many objects to be cached. This does not account for anything
027: * other than the number of lockable regions, i.e. synchronized Least
028: * Recently Used lists, and the maximum number of items a region can
029: * have before it removes the least recently used objects.
030: *
031: * @author Niall Gallagher
032: */
033: public class Cache {
034:
035: /**
036: * This is the default number of regions for the cache.
037: */
038: private static final int DEFAULT_LOCKS = 20;
039:
040: /**
041: * This is the default number of elements per lock.
042: */
043: private static final int DEFAULT_LIMIT = 100;
044:
045: /**
046: * Used to store the lists that store objects.
047: */
048: private CacheList[] list;
049:
050: /**
051: * This is used to create a <code>Cache</code> object for storing
052: * objects. This <code>Cache</code> is an LRU <code>Cache</code>
053: * meaning that the Least Recently Used items are removed if the
054: * size of a region grows to large, the default is two thousand.
055: */
056: public Cache() {
057: this (DEFAULT_LOCKS, DEFAULT_LIMIT);
058: }
059:
060: /**
061: * This is used to create a <code>Cache</code> object for storing
062: * objects. This <code>Cache</code> is an LRU <code>Cache</code>
063: * meaning that the Least Recently Used items are removed if the
064: * size if the region grows to large. This constructor configures
065: * the <code>Cache</code> as specified.
066: *
067: * @param regions number of regions that are synchronized
068: * @param limit the maximum amount of objects per region
069: */
070: public Cache(int regions, int limit) {
071: this .init(regions, limit);
072: }
073:
074: /**
075: * In this <code>Cache</code> a region is considered to be an area
076: * within the <code>Cache</code> that is synchronized independantly.
077: * This means that if there are two threads accessing the
078: * <code>Cache</code>, they can access objects that hash to a different
079: * regions concurrently. This <code>Cache</code> maintains an array of
080: * <code>CacheList</code> objects. These are Least Recently Used
081: * lists in the sense that if they reach there maximum capacity they
082: * will drop the most unused items. The limit defines the maximum
083: * capacity of a region i.e. list.
084: *
085: * @param regions number of regions that are synchronized
086: * @param limit the maximum amount of objects per region
087: */
088: private void init(int regions, int limit) {
089: list = new CacheList[regions];
090:
091: for (int i = 0; i < regions; i++) {
092: list[i] = new CacheList(limit);
093: }
094: }
095:
096: /**
097: * This will store the object given in the <code>Cache</code>
098: * under the reference specified. The object may exist in the
099: * <code>Cache</code> if it remains an actively used object.
100: *
101: * @param key this is the key that references the object
102: * @param obj this is the object that is to be stored
103: */
104: public void cache(Object key, Object obj) {
105: int pos = translate(key);
106: list[pos].insert(key, obj);
107: }
108:
109: /**
110: * This is a simple function that maps an objects hash
111: * code using <code>Object.hashCode</code> into an array
112: * subscript. This is used to index into a specific list.
113: *
114: * @param key the object that is to be translated
115: *
116: * @return an array subscript into the list
117: */
118: private int translate(Object key) {
119: int hash = key.hashCode();
120: if (hash < 0)
121: hash *= -1;
122: return hash % list.length;
123: }
124:
125: /**
126: * This will search the <code>Cache</code> to see if the item
127: * in the cache. If it is in the cache this will return it.
128: * This provides a very concurrent lookup mechanism, where threads
129: * have less contention for locks, as the key decides which list
130: * to use based on the value of the key hash code.
131: *
132: * @param key this is the key that references the object
133: *
134: * @return the object that is referenced by the key
135: */
136: public Object lookup(Object key) {
137: int pos = translate(key);
138: return list[pos].lookup(key);
139: }
140:
141: /**
142: * This will check to see if an object exists within the
143: * <code>Cache</code>. If it exists this returns true else
144: * false.
145: *
146: * @param key this is the key that references the object
147: *
148: * @return a boolean indicating the status of the object
149: */
150: public boolean contains(Object key) {
151: int pos = translate(key);
152: return list[pos].contains(key);
153: }
154:
155: /**
156: * This will remove the object cached using the specified
157: * key. If the object is not stored this does nothing.
158: * This ensures that no reference fot the object is left.
159: *
160: * @param key this is the key that references the object
161: */
162: public Object remove(Object key) {
163: int pos = translate(key);
164: return list[pos].remove(key);
165: }
166:
167: /**
168: * This will remove all items from the <code>Cache</code>.
169: * This is used to synchronize the cached objects.
170: */
171: public void clear() {
172: for (int i = 0; i < list.length; i++) {
173: list[i].clear();
174: }
175: }
176: }
|