1 package org.apache.commons.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.util.Collections;
24 import java.util.Iterator;
25 import java.util.LinkedHashSet;
26 import java.util.Map;
27 import java.util.Set;
28
29 import org.apache.commons.jcs.engine.CacheConstants;
30 import org.apache.commons.jcs.engine.behavior.ICacheElement;
31 import org.apache.commons.jcs.engine.control.CompositeCache;
32 import org.apache.commons.jcs.engine.control.group.GroupAttrName;
33 import org.apache.commons.jcs.engine.memory.AbstractMemoryCache;
34 import org.apache.commons.jcs.engine.memory.util.MemoryElementDescriptor;
35 import org.apache.commons.jcs.engine.stats.behavior.IStats;
36 import org.apache.commons.logging.Log;
37 import org.apache.commons.logging.LogFactory;
38
39
40
41
42 public class LHMLRUMemoryCache<K, V>
43 extends AbstractMemoryCache<K, V>
44 {
45
46 private static final Log log = LogFactory.getLog( LRUMemoryCache.class );
47
48
49
50
51
52
53 @Override
54 public void initialize( CompositeCache<K, V> hub )
55 {
56 super.initialize( hub );
57 log.info( "initialized LHMLRUMemoryCache for " + getCacheName() );
58 }
59
60
61
62
63
64
65 @Override
66 public Map<K, MemoryElementDescriptor<K, V>> createMap()
67 {
68 return Collections.synchronizedMap( new LHMSpooler() );
69 }
70
71
72
73
74
75
76
77 @Override
78 public void update( ICacheElement<K, V> ce )
79 throws IOException
80 {
81 putCnt.incrementAndGet();
82 map.put( ce.getKey(), new MemoryElementDescriptor<K, V>(ce) );
83 }
84
85
86
87
88
89
90
91
92 @Override
93 public ICacheElement<K, V> get( K key )
94 throws IOException
95 {
96 if ( log.isDebugEnabled() )
97 {
98 log.debug( "getting item from cache " + getCacheName() + " for key " + key );
99 }
100
101 MemoryElementDescriptor<K, V> me = map.get( key );
102
103 if ( me != null )
104 {
105 hitCnt.incrementAndGet();
106 if ( log.isDebugEnabled() )
107 {
108 log.debug( getCacheName() + ": LHMLRUMemoryCache hit for " + key );
109 }
110 return me.getCacheElement();
111 }
112 else
113 {
114 missCnt.incrementAndGet();
115 if ( log.isDebugEnabled() )
116 {
117 log.debug( getCacheName() + ": LHMLRUMemoryCache miss for " + key );
118 }
119 }
120
121 return null;
122 }
123
124
125
126
127
128
129
130
131
132
133 @Override
134 public boolean remove( K key )
135 throws IOException
136 {
137 if ( log.isDebugEnabled() )
138 {
139 log.debug( "removing item for key: " + key );
140 }
141
142 boolean removed = false;
143
144
145 if ( key instanceof String && ( (String) key ).endsWith( CacheConstants.NAME_COMPONENT_DELIMITER ) )
146 {
147
148 synchronized ( map )
149 {
150 for (Iterator<Map.Entry<K, MemoryElementDescriptor<K, V>>> itr = map.entrySet().iterator(); itr.hasNext(); )
151 {
152 Map.Entry<K, MemoryElementDescriptor<K, V>> entry = itr.next();
153 K k = entry.getKey();
154
155 if ( k instanceof String && ( (String) k ).startsWith( key.toString() ) )
156 {
157 itr.remove();
158 removed = true;
159 }
160 }
161 }
162 }
163 else if ( key instanceof GroupAttrName && ((GroupAttrName<?>)key).attrName == null )
164 {
165
166 synchronized ( map )
167 {
168 for (Iterator<Map.Entry<K, MemoryElementDescriptor<K, V>>> itr = map.entrySet().iterator(); itr.hasNext(); )
169 {
170 Map.Entry<K, MemoryElementDescriptor<K, V>> entry = itr.next();
171 K k = entry.getKey();
172
173 if ( k instanceof GroupAttrName &&
174 ((GroupAttrName<?>)k).groupId.equals(((GroupAttrName<?>)key).groupId) )
175 {
176 itr.remove();
177 removed = true;
178 }
179 }
180 }
181 }
182 else
183 {
184
185 MemoryElementDescriptor<K, V> me = map.remove( key );
186 if ( me != null )
187 {
188 removed = true;
189 }
190 }
191
192 return removed;
193 }
194
195
196
197
198
199
200 @Override
201 public Set<K> getKeySet()
202 {
203 return new LinkedHashSet<K>(map.keySet());
204 }
205
206
207
208
209
210
211
212 @Override
213 public IStats getStatistics()
214 {
215 IStats stats = super.getStatistics();
216 stats.setTypeName( "LHMLRU Memory Cache" );
217
218 return stats;
219 }
220
221
222
223
224
225
226 public void dumpCacheEntries()
227 {
228 dumpMap();
229 }
230
231
232
233
234
235
236
237
238 @Override
239 public int freeElements( int numberToFree )
240 throws IOException
241 {
242
243 return 0;
244 }
245
246
247
248
249
250
251 protected class LHMSpooler
252 extends java.util.LinkedHashMap<K, MemoryElementDescriptor<K, V>>
253 {
254
255 private static final long serialVersionUID = -1255907868906762484L;
256
257
258
259
260
261 public LHMSpooler()
262 {
263 super( (int) ( getCacheAttributes().getMaxObjects() * .5 ), .75F, true );
264 }
265
266
267
268
269
270
271
272 @SuppressWarnings("synthetic-access")
273 @Override
274 protected boolean removeEldestEntry( Map.Entry<K, MemoryElementDescriptor<K, V>> eldest )
275 {
276 ICacheElement<K, V> element = eldest.getValue().getCacheElement();
277
278 if ( size() <= getCacheAttributes().getMaxObjects() )
279 {
280 return false;
281 }
282 else
283 {
284
285 if ( log.isDebugEnabled() )
286 {
287 log.debug( "LHMLRU max size: " + getCacheAttributes().getMaxObjects()
288 + ". Spooling element, key: " + element.getKey() );
289 }
290
291 waterfal( element );
292
293 if ( log.isDebugEnabled() )
294 {
295 log.debug( "LHMLRU size: " + map.size() );
296 }
297 }
298 return true;
299 }
300 }
301 }