1 package org.gffs.cache;
16 import java.util.ArrayList;
17 import java.util.Date;
18 import java.util.HashMap;
19 import java.util.HashSet;
20 import java.util.List;
23 import org.apache.commons.logging.Log;
24 import org.apache.commons.logging.LogFactory;
43 private HashMap<KeyType, RoleBasedCacheNode<KeyType, DataType>> _map;
44 private LRUList<KeyType, DataType> _lruList;
45 private TimeoutList<KeyType, DataType> _timeoutList;
47 private int _maxElements;
48 private long _defaultTimeoutMS;
49 private Thread _activeTimeoutThread =
null;
50 private boolean _logCacheEjection =
false;
56 throw new IllegalArgumentException(
"\"maxElements\" must be greater than 0.");
59 throw new IllegalArgumentException(
"must provide a non-null cache name");
61 _maxElements = maxElements;
62 _defaultTimeoutMS = defaultTimeoutMS;
63 _map =
new HashMap<KeyType, RoleBasedCacheNode<KeyType, DataType>>(_maxElements);
64 _lruList =
new LRUList<KeyType, DataType>();
65 _timeoutList =
new TimeoutList<KeyType, DataType>();
81 _logCacheEjection = logRemovals;
87 if (_activeTimeoutThread ==
null) {
102 public void put(KeyType key, DataType data,
long timeoutMS)
104 RoleBasedCacheNode<KeyType, DataType> newNode =
105 new RoleBasedCacheNode<KeyType, DataType>(key, data,
new Date(System.currentTimeMillis() + timeoutMS));
107 synchronized (_map) {
108 RoleBasedCacheNode<KeyType, DataType> oldNode = _map.remove(key);
109 if (oldNode !=
null) {
110 _lruList.remove(oldNode);
111 _timeoutList.remove(oldNode);
114 if (_map.size() >= _maxElements)
117 while (_map.size() >= _maxElements) {
118 RoleBasedCacheNode<KeyType, DataType> node = _lruList.removeFirst();
119 if (_logCacheEjection && _logger.isDebugEnabled())
120 _logger.debug(
debugPrefix() +
"overloaded cache: removing cached item with key: " + node.getKey());
121 _timeoutList.remove(node);
122 _map.remove(node.getKey());
125 _map.put(key, newNode);
126 _lruList.insert(newNode);
127 _timeoutList.insert(newNode);
133 public void put(KeyType key, DataType data)
135 put(key, data, _defaultTimeoutMS);
149 synchronized (_map) {
150 RoleBasedCacheNode<KeyType, DataType> node = _map.get(key);
153 _lruList.remove(node);
154 node.setInvalidationDate(_defaultTimeoutMS);
156 _lruList.insert(node);
158 _timeoutList.remove(node);
159 _timeoutList.insert(node);
166 private final long CHECK_INTERVAL = 1000 * 10;
168 private Date _nextDeepSizeCheck =
new Date((
new Date().getTime()) + CHECK_INTERVAL);
170 public DataType
get(KeyType key)
172 Date
now =
new Date();
174 if (
now.after(_nextDeepSizeCheck)) {
191 _nextDeepSizeCheck =
new Date((
new Date().getTime()) + CHECK_INTERVAL);
194 synchronized (_map) {
195 RoleBasedCacheNode<KeyType, DataType> node = _map.get(key);
198 _lruList.remove(node);
199 if (node.getInvalidationDate().before(
now)) {
201 if (_logCacheEjection && _logger.isDebugEnabled())
202 _logger.debug(
debugPrefix() +
"timed-out entry in get: removing cached item with key: " + node.getKey());
204 _timeoutList.remove(node);
208 _lruList.insert(node);
209 return node.getData();
215 ArrayList<DataType> toReturn =
new ArrayList<DataType>();
216 synchronized (_map) {
217 for (KeyType key : _map.keySet()) {
218 toReturn.add(_map.get(key).getData());
226 ArrayList<DataType> toReturn =
new ArrayList<DataType>();
227 synchronized (_map) {
228 for (KeyType key : references) {
230 if (_map.containsKey(key)) {
231 toReturn.add(_map.get(key).getData());
233 _logger.error(
debugPrefix() +
"failed to locate referenced object in cache: " + key);
242 Date
now =
new Date();
244 synchronized (_map) {
246 RoleBasedCacheNode<KeyType, DataType> node = _timeoutList.peekFirst();
250 if (node.getInvalidationDate().compareTo(
now) <= 0) {
251 if (_logCacheEjection && _logger.isDebugEnabled())
252 _logger.debug(
debugPrefix() +
"removing timed-out node: " + node.getKey());
253 _map.remove(node.getKey());
254 _timeoutList.removeFirst();
255 _lruList.remove(node);
263 public void remove(KeyType key)
265 synchronized (_map) {
266 RoleBasedCacheNode<KeyType, DataType> node = _map.remove(key);
268 _lruList.remove(node);
269 _timeoutList.remove(node);
276 synchronized (_map) {
277 return new HashSet<KeyType>(_map.keySet());
283 synchronized (_map) {
286 _timeoutList.clear();
292 _activeTimeoutThread =
new Thread(
new ActiveTimeoutWorker(),
"Active Cache Timeout Thread");
293 _activeTimeoutThread.setDaemon(
true);
294 _activeTimeoutThread.start();
299 Thread tmp = _activeTimeoutThread;
300 _activeTimeoutThread =
null;
301 synchronized (_map) {
307 }
catch (InterruptedException cause) {
311 private class ActiveTimeoutWorker
implements Runnable
315 synchronized (_map) {
316 while (_activeTimeoutThread !=
null) {
319 RoleBasedCacheNode<KeyType, DataType> firstNode = _timeoutList.peekFirst();
320 if (firstNode ==
null) {
323 Date nextStale = firstNode.getInvalidationDate();
324 long timeout = nextStale.getTime() - System.currentTimeMillis();
329 }
catch (InterruptedException ie) {
void put(KeyType key, DataType data, long timeoutMS)
void activelyTimeoutElements(boolean activelyTimeout)
boolean refresh(KeyType key)
void put(KeyType key, DataType data)
List< DataType > getAll()
void setCacheEjectionLogging(boolean logRemovals)
List< DataType > getAllReferenced(List< KeyType > references)
TimedOutLRUCache(int maxElements, long defaultTimeoutMS, String cacheName)
void startActiveTimeout()
time_locus now()
returns our current locus in the time continuum.