1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.commons.cache;
17
18 import java.util.HashMap;
19 import java.util.ArrayList;
20 import java.util.NoSuchElementException;
21 import java.io.Serializable;
22 import java.io.ObjectInputStream;
23 import java.io.IOException;
24 import java.io.NotActiveException;
25 import org.apache.commons.cache.adt.Listable;
26 import org.apache.commons.cache.adt.WListableObject;
27
28
29
30
31
32
33 public class LRUEvictionPolicy implements EvictionPolicy, StorageListener, RetrievalListener, CachedObjectIterator {
34 transient protected HashMap _hash = new HashMap();
35 transient protected WListableObject _leastRecent = null;
36 transient protected WListableObject _mostRecent = null;
37 transient protected WListableObject _current = null;
38
39 protected boolean _canRemove = false;
40 public Cache _cache = null;
41 protected int _objsbetweennaps;
42 protected long _sleeptimemillis;
43
44 public LRUEvictionPolicy() {
45 this(StaleObjectEvictor.DEFAULT_OBJECTS_BETWEEN_NAPS,StaleObjectEvictor.DEFAULT_SLEEP_TIME_MILLIS);
46 }
47
48 public LRUEvictionPolicy(int objsbetweennaps, long sleeptimemillis) {
49 _objsbetweennaps = objsbetweennaps;
50 _sleeptimemillis = sleeptimemillis;
51 Thread t = new Thread(new StaleObjectEvictor(this,_objsbetweennaps,_sleeptimemillis));
52 t.setDaemon(true);
53 t.start();
54 }
55
56 private void writeObject(java.io.ObjectOutputStream out) throws IOException {
57 out.defaultWriteObject();
58 WListableObject cur = _leastRecent;
59 while(null != cur) {
60 out.writeObject(cur.getValue());
61 cur =(WListableObject)(cur.getNext());
62 }
63 out.writeObject(null);
64 }
65
66 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
67 try {
68 in.defaultReadObject();
69 _hash = new HashMap();
70 for(;;) {
71 Object obj = in.readObject();
72 if(null == obj) {
73 break;
74 } else {
75 WListableObject temp = new WListableObject(obj,_mostRecent,null);
76 if(null == _leastRecent) {
77 _leastRecent = temp;
78 _current = temp;
79 }
80 if(null != _mostRecent) {
81 _mostRecent.setNext(temp);
82 }
83 _mostRecent = temp;
84 _hash.put(((CachedObjectInfo)obj).getKey(),_mostRecent);
85 }
86 }
87
88 Thread t = new Thread(new StaleObjectEvictor(this,_objsbetweennaps,_sleeptimemillis));
89 t.setDaemon(true);
90 t.start();
91 } catch(NotActiveException e) {
92 e.printStackTrace();
93 }
94 }
95
96 protected synchronized void addToList(WListableObject cur) {
97 if(null == _mostRecent) {
98 _mostRecent = cur;
99 _leastRecent = cur;
100 } else {
101 _mostRecent.setNext(cur);
102 cur.setPrev(_mostRecent);
103 _mostRecent = cur;
104 }
105 }
106
107 protected synchronized void removeFromList(WListableObject cur) {
108
109 if(_current == cur) {
110 _current = (WListableObject)(_current.getPrev());
111 _canRemove = false;
112 }
113 if(cur.hasPrev()) {
114 if(cur.hasNext()) {
115 cur.getPrev().setNext(cur.getNext());
116 cur.getNext().setPrev(cur.getPrev());
117 cur.setNext(null);
118 cur.setPrev(null);
119 } else {
120
121 _mostRecent = (WListableObject)(cur.getPrev());
122 cur.getPrev().setNext(null);
123 cur.setPrev(null);
124 }
125 } else {
126
127 _leastRecent = (WListableObject)(cur.getNext());
128 if(cur.hasNext()) {
129 cur.getNext().setPrev(null);
130 cur.setNext(null);
131 } else {
132
133
134 _leastRecent = null;
135 _mostRecent = null;
136 }
137 }
138 }
139
140
141 public synchronized boolean hasNext() {
142 return (null != _mostRecent);
143 }
144
145 public synchronized CachedObjectInfo getNext() throws NoSuchElementException {
146 if(null != _current) {
147 _current = (WListableObject)(_current.getNext());
148 }
149 if(null == _current) { _current = _leastRecent; }
150 if(null == _current) {
151 throw new NoSuchElementException();
152 } else {
153 _canRemove = true;
154 return (CachedObjectInfo)(_current.getValue());
155 }
156 }
157
158 public synchronized Object next() throws NoSuchElementException {
159 return getNext();
160 }
161
162 public void remove() throws NoSuchElementException, IllegalStateException {
163
164 synchronized(_cache) {
165 synchronized(this) {
166 if(null == _current) {
167 throw new IllegalStateException();
168 }
169 if(_canRemove) {
170 _cache.clear( ((CachedObjectInfo)(_current.getValue())).getKey() );
171 } else {
172 throw new IllegalStateException();
173 }
174 }
175 }
176 }
177
178
179
180 public void setCache(Cache c) {
181 if(null != _cache) {
182 Object mutex = _cache;
183 synchronized(mutex) {
184 synchronized(c) {
185 synchronized(this) {
186 unsetCache();
187 _cache = c;
188 _cache.registerRetrievalListener(this);
189 _cache.registerStorageListener(this);
190 }
191 }
192 }
193 } else {
194 synchronized(c) {
195 synchronized(this) {
196 _cache = c;
197 _cache.registerRetrievalListener(this);
198 _cache.registerStorageListener(this);
199 }
200 }
201 }
202 }
203
204
205 public void unsetCache() {
206 if(null != _cache) {
207 Object mutex = _cache;
208 synchronized(mutex) {
209 synchronized(this) {
210 _cache.unregisterRetrievalListener(this);
211 _cache.unregisterStorageListener(this);
212 _cache = null;
213 }
214 }
215 }
216 }
217
218 public void storeRequested(Serializable key, Serializable val, Long expiresAt, Long cost, Serializable group) { }
219
220 public void notStored(Serializable key, Serializable val, Long expiresAt, Long cost, Serializable group) { }
221
222 public synchronized void stored(Serializable key, Serializable val, Long expiresAt, Long cost, Serializable group) {
223 WListableObject cur = (WListableObject)(_hash.get(key));
224 if(null == cur) {
225 cur = new WListableObject(new CachedObjectInfoImpl(key,expiresAt,cost));
226 addToList(cur);
227 _hash.put(key,cur);
228 } else {
229 removeFromList(cur);
230 addToList(cur);
231 }
232 }
233
234 public synchronized void cleared(Serializable key) {
235 WListableObject cur = (WListableObject)(_hash.get(key));
236 if(cur != null) {
237 removeFromList(cur);
238 _hash.remove(key);
239 }
240 }
241
242 public synchronized void cleared() {
243 _hash.clear();
244 _mostRecent = null;
245 _leastRecent = null;
246 _current = null;
247 }
248
249 public void retrieveRequested(Serializable key) {
250 }
251
252 public synchronized void retrieved(Serializable key) {
253 WListableObject cur = (WListableObject)(_hash.get(key));
254 if(null == cur) {
255 cur = new WListableObject(new CachedObjectInfoImpl(key,null,null));
256 addToList(cur);
257 _hash.put(key,cur);
258 } else {
259 removeFromList(cur);
260 addToList(cur);
261 }
262 }
263
264 public void notRetrieved(Serializable key) {
265 }
266
267 public synchronized Serializable getEvictionCandidate() {
268 try {
269 return ((CachedObjectInfoImpl)(_leastRecent.getValue())).getKey();
270 } catch(NullPointerException e) {
271 return null;
272 }
273 }
274
275 public synchronized Serializable[] getEvictionCandidates(int n) {
276 ArrayList v = new ArrayList(n);
277 WListableObject c = _leastRecent;
278 while(n-- > 0) {
279 if(null != c) {
280 v.add(((CachedObjectInfoImpl)(c.getValue())).getKey());
281 c = (WListableObject)(c.getNext());
282 } else {
283 break;
284 }
285 }
286 return (Serializable[])(v.toArray(new Serializable[0]));
287 }
288
289 public synchronized String toString() {
290 StringBuffer buf = new StringBuffer();
291 WListableObject c = _leastRecent;
292 while(c != null) {
293 if(c.hasPrev()) {
294 buf.append(", ");
295 }
296 buf.append(c.getValue());
297 c = (WListableObject)(c.getNext());
298 }
299 return buf.toString();
300 }
301 }