1 package org.apache.jcs.engine.memory.lru;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.IOException;
23 import java.io.Serializable;
24 import java.util.ArrayList;
25 import java.util.Collections;
26 import java.util.Iterator;
27 import java.util.LinkedHashSet;
28 import java.util.Map;
29 import java.util.Set;
30
31 import org.apache.commons.logging.Log;
32 import org.apache.commons.logging.LogFactory;
33 import org.apache.jcs.engine.CacheConstants;
34 import org.apache.jcs.engine.behavior.ICacheElement;
35 import org.apache.jcs.engine.control.CompositeCache;
36 import org.apache.jcs.engine.control.group.GroupAttrName;
37 import org.apache.jcs.engine.memory.AbstractMemoryCache;
38 import org.apache.jcs.engine.memory.util.MemoryElementDescriptor;
39 import org.apache.jcs.engine.stats.StatElement;
40 import org.apache.jcs.engine.stats.Stats;
41 import org.apache.jcs.engine.stats.behavior.IStatElement;
42 import org.apache.jcs.engine.stats.behavior.IStats;
43
44
45
46
47 public class LHMLRUMemoryCache<K extends Serializable, V extends Serializable>
48 extends AbstractMemoryCache<K, V>
49 {
50
51 private static final long serialVersionUID = 6403738094136424101L;
52
53
54 protected final static Log log = LogFactory.getLog( LRUMemoryCache.class );
55
56
57 protected int hitCnt = 0;
58
59
60 protected int missCnt = 0;
61
62
63 protected int putCnt = 0;
64
65
66
67
68
69
70 @Override
71 public synchronized void initialize( CompositeCache<K, V> hub )
72 {
73 super.initialize( hub );
74 log.info( "initialized LHMLRUMemoryCache for " + cacheName );
75 }
76
77
78
79
80
81
82 @Override
83 public Map<K, MemoryElementDescriptor<K, V>> createMap()
84 {
85 return Collections.synchronizedMap( new LHMSpooler() );
86 }
87
88
89
90
91
92
93
94 @Override
95 public void update( ICacheElement<K, V> ce )
96 throws IOException
97 {
98 putCnt++;
99 ce.getElementAttributes().setLastAccessTimeNow();
100 map.put( ce.getKey(), new MemoryElementDescriptor<K, V>(ce) );
101 }
102
103
104
105
106
107
108
109
110
111 @Override
112 public ICacheElement<K, V> getQuiet( K key )
113 throws IOException
114 {
115 return map.get( key ).ce;
116 }
117
118
119
120
121
122
123
124
125 @Override
126 public synchronized ICacheElement<K, V> get( K key )
127 throws IOException
128 {
129 MemoryElementDescriptor<K, V> me = null;
130
131 if ( log.isDebugEnabled() )
132 {
133 log.debug( "getting item from cache " + cacheName + " for key " + key );
134 }
135
136 me = map.get( key );
137
138 if ( me != null )
139 {
140 hitCnt++;
141 me.ce.getElementAttributes().setLastAccessTimeNow();
142 if ( log.isDebugEnabled() )
143 {
144 log.debug( cacheName + ": LRUMemoryCache hit for " + key );
145 }
146 return me.ce;
147 }
148 else
149 {
150 missCnt++;
151 log.debug( cacheName + ": LRUMemoryCache miss for " + key );
152 }
153
154 return null;
155 }
156
157
158
159
160
161
162
163
164
165
166 @Override
167 public synchronized boolean remove( K key )
168 throws IOException
169 {
170 if ( log.isDebugEnabled() )
171 {
172 log.debug( "removing item for key: " + key );
173 }
174
175 boolean removed = false;
176
177
178 if ( key instanceof String && ( (String) key ).endsWith( CacheConstants.NAME_COMPONENT_DELIMITER ) )
179 {
180
181 synchronized ( map )
182 {
183 for (Iterator<Map.Entry<K, MemoryElementDescriptor<K, V>>> itr = map.entrySet().iterator(); itr.hasNext(); )
184 {
185 Map.Entry<K, MemoryElementDescriptor<K, V>> entry = itr.next();
186 K k = entry.getKey();
187
188 if ( k instanceof String && ( (String) k ).startsWith( key.toString() ) )
189 {
190 itr.remove();
191 removed = true;
192 }
193 }
194 }
195 }
196 else if ( key instanceof GroupAttrName && ((GroupAttrName<?>)key).attrName == null )
197 {
198
199 synchronized ( map )
200 {
201 for (Iterator<Map.Entry<K, MemoryElementDescriptor<K, V>>> itr = map.entrySet().iterator(); itr.hasNext(); )
202 {
203 Map.Entry<K, MemoryElementDescriptor<K, V>> entry = itr.next();
204 K k = entry.getKey();
205
206 if ( k instanceof GroupAttrName &&
207 ((GroupAttrName<?>)k).groupId.equals(((GroupAttrName<?>)key).groupId) )
208 {
209 itr.remove();
210 removed = true;
211 }
212 }
213 }
214 }
215 else
216 {
217
218 MemoryElementDescriptor<K, V> me = map.remove( key );
219 if ( me != null )
220 {
221 removed = true;
222 }
223 }
224
225 return removed;
226 }
227
228
229
230
231
232
233 @Override
234 public Set<K> getKeySet()
235 {
236
237 synchronized ( this )
238 {
239
240 return new LinkedHashSet<K>(map.keySet());
241 }
242 }
243
244
245
246
247
248
249
250 @Override
251 public synchronized IStats getStatistics()
252 {
253 IStats stats = new Stats();
254 stats.setTypeName( "LHMLRU Memory Cache" );
255
256 ArrayList<IStatElement> elems = new ArrayList<IStatElement>();
257
258 IStatElement se = null;
259
260 se = new StatElement();
261 se.setName( "Map Size" );
262 se.setData( "" + map.size() );
263 elems.add( se );
264
265 se = new StatElement();
266 se.setName( "Put Count" );
267 se.setData( "" + putCnt );
268 elems.add( se );
269
270 se = new StatElement();
271 se.setName( "Hit Count" );
272 se.setData( "" + hitCnt );
273 elems.add( se );
274
275 se = new StatElement();
276 se.setName( "Miss Count" );
277 se.setData( "" + missCnt );
278 elems.add( se );
279
280
281 IStatElement[] ses = elems.toArray( new StatElement[0] );
282 stats.setStatElements( ses );
283
284
285
286
287 return stats;
288 }
289
290
291
292
293
294
295 public void dumpCacheEntries()
296 {
297 dumpMap();
298 }
299
300
301
302
303
304
305
306
307 public int freeElements( int numberToFree )
308 throws IOException
309 {
310
311 return 0;
312 }
313
314
315
316
317
318
319 public class LHMSpooler
320 extends java.util.LinkedHashMap<K, MemoryElementDescriptor<K, V>>
321 {
322
323 private static final long serialVersionUID = -1255907868906762484L;
324
325
326
327
328
329 public LHMSpooler()
330 {
331 super( (int) ( cache.getCacheAttributes().getMaxObjects() * .5 ), .75F, true );
332 }
333
334
335
336
337
338
339
340 @Override
341 protected boolean removeEldestEntry( Map.Entry<K, MemoryElementDescriptor<K, V>> eldest )
342 {
343 ICacheElement<K, V> element = eldest.getValue().ce;
344
345 if ( size() <= cache.getCacheAttributes().getMaxObjects() )
346 {
347 return false;
348 }
349 else
350 {
351
352 if ( log.isDebugEnabled() )
353 {
354 log.debug( "LHMLRU max size: " + cache.getCacheAttributes().getMaxObjects()
355 + ". Spooling element, key: " + element.getKey() );
356 }
357 spoolToDisk( element );
358
359 if ( log.isDebugEnabled() )
360 {
361 log.debug( "LHMLRU size: " + map.size() );
362 }
363 }
364 return true;
365 }
366
367
368
369
370
371
372 private void spoolToDisk( ICacheElement<K, V> element )
373 {
374 cache.spoolToDisk( element );
375
376 if ( log.isDebugEnabled() )
377 {
378 log.debug( cache.getCacheName() + "Spooled element to disk: " + element.getKey() );
379 }
380 }
381 }
382 }