1 package org.apache.commons.jcs.engine.memory.soft;
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.lang.ref.SoftReference;
24 import java.util.HashSet;
25 import java.util.Iterator;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Set;
29 import java.util.concurrent.ConcurrentHashMap;
30 import java.util.concurrent.ConcurrentMap;
31 import java.util.concurrent.LinkedBlockingQueue;
32
33 import org.apache.commons.jcs.engine.CacheConstants;
34 import org.apache.commons.jcs.engine.behavior.ICacheElement;
35 import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes;
36 import org.apache.commons.jcs.engine.control.CompositeCache;
37 import org.apache.commons.jcs.engine.control.group.GroupAttrName;
38 import org.apache.commons.jcs.engine.memory.AbstractMemoryCache;
39 import org.apache.commons.jcs.engine.memory.util.MemoryElementDescriptor;
40 import org.apache.commons.jcs.engine.memory.util.SoftReferenceElementDescriptor;
41 import org.apache.commons.jcs.engine.stats.StatElement;
42 import org.apache.commons.jcs.engine.stats.behavior.IStatElement;
43 import org.apache.commons.jcs.engine.stats.behavior.IStats;
44 import org.apache.commons.logging.Log;
45 import org.apache.commons.logging.LogFactory;
46
47
48
49
50
51
52
53
54
55
56
57 public class SoftReferenceMemoryCache<K, V> extends AbstractMemoryCache<K, V>
58 {
59
60 private static final Log log = LogFactory.getLog(SoftReferenceMemoryCache.class);
61
62
63
64
65
66
67
68
69 private LinkedBlockingQueue<ICacheElement<K, V>> strongReferences;
70
71
72
73
74
75
76 @Override
77 public synchronized void initialize( CompositeCache<K, V> hub )
78 {
79 super.initialize( hub );
80 strongReferences = new LinkedBlockingQueue<ICacheElement<K, V>>();
81 log.info( "initialized Soft Reference Memory Cache for " + getCacheName() );
82 }
83
84
85
86
87 @Override
88 public ConcurrentMap<K, MemoryElementDescriptor<K, V>> createMap()
89 {
90 return new ConcurrentHashMap<K, MemoryElementDescriptor<K, V>>();
91 }
92
93
94
95
96 @Override
97 public Set<K> getKeySet()
98 {
99 Set<K> keys = new HashSet<K>();
100 for (Map.Entry<K, MemoryElementDescriptor<K, V>> e : map.entrySet())
101 {
102 SoftReferenceElementDescriptor<K, V> sred = (SoftReferenceElementDescriptor<K, V>) e.getValue();
103 if (sred.getCacheElement() != null)
104 {
105 keys.add(e.getKey());
106 }
107 }
108
109 return keys;
110 }
111
112
113
114
115
116
117 @Override
118 public int getSize()
119 {
120 int size = 0;
121 for (MemoryElementDescriptor<K, V> me : map.values())
122 {
123 SoftReferenceElementDescriptor<K, V> sred = (SoftReferenceElementDescriptor<K, V>) me;
124 if (sred.getCacheElement() != null)
125 {
126 size++;
127 }
128 }
129 return size;
130 }
131
132
133
134
135 @Override
136 public IStats getStatistics()
137 {
138 IStats stats = super.getStatistics();
139 stats.setTypeName("Soft Reference Memory Cache");
140
141 List<IStatElement<?>> elems = stats.getStatElements();
142 int emptyrefs = map.size() - getSize();
143 elems.add(new StatElement<Integer>("Empty References", Integer.valueOf(emptyrefs)));
144 elems.add(new StatElement<Integer>("Strong References", Integer.valueOf(strongReferences.size())));
145
146 return stats;
147 }
148
149
150
151
152
153
154
155
156
157
158
159 @Override
160 public boolean remove(K key) throws IOException
161 {
162 if (log.isDebugEnabled())
163 {
164 log.debug("removing item for key: " + key);
165 }
166
167 boolean removed = false;
168
169
170 if (key instanceof String && ((String) key).endsWith(CacheConstants.NAME_COMPONENT_DELIMITER))
171 {
172
173 for (Iterator<Map.Entry<K, MemoryElementDescriptor<K, V>>> itr = map.entrySet().iterator();
174 itr.hasNext();)
175 {
176 Map.Entry<K, MemoryElementDescriptor<K, V>> entry = itr.next();
177 K k = entry.getKey();
178
179 if (k instanceof String && ((String) k).startsWith(key.toString()))
180 {
181 lock.lock();
182 try
183 {
184 strongReferences.remove(entry.getValue().getCacheElement());
185 itr.remove();
186 removed = true;
187 }
188 finally
189 {
190 lock.unlock();
191 }
192 }
193 }
194 }
195 else if (key instanceof GroupAttrName && ((GroupAttrName<?>) key).attrName == null)
196 {
197
198 for (Iterator<Map.Entry<K, MemoryElementDescriptor<K, V>>> itr = map.entrySet().iterator();
199 itr.hasNext();)
200 {
201 Map.Entry<K, MemoryElementDescriptor<K, V>> entry = itr.next();
202 K k = entry.getKey();
203
204 if (k instanceof GroupAttrName && ((GroupAttrName<?>) k).groupId.equals(((GroupAttrName<?>) key).groupId))
205 {
206 lock.lock();
207 try
208 {
209 strongReferences.remove(entry.getValue().getCacheElement());
210 itr.remove();
211 removed = true;
212 }
213 finally
214 {
215 lock.unlock();
216 }
217 }
218 }
219 }
220 else
221 {
222
223 lock.lock();
224 try
225 {
226 MemoryElementDescriptor<K, V> me = map.remove(key);
227 if (me != null)
228 {
229 strongReferences.remove(me.getCacheElement());
230 removed = true;
231 }
232 }
233 finally
234 {
235 lock.unlock();
236 }
237 }
238
239 return removed;
240 }
241
242
243
244
245
246
247 @Override
248 public void removeAll() throws IOException
249 {
250 super.removeAll();
251 strongReferences.clear();
252 }
253
254
255
256
257
258
259
260 @Override
261 public void update(ICacheElement<K, V> ce) throws IOException
262 {
263 putCnt.incrementAndGet();
264 ce.getElementAttributes().setLastAccessTimeNow();
265
266 lock.lock();
267
268 try
269 {
270 map.put(ce.getKey(), new SoftReferenceElementDescriptor<K, V>(ce));
271 strongReferences.add(ce);
272 trimStrongReferences();
273 }
274 finally
275 {
276 lock.unlock();
277 }
278 }
279
280
281
282
283
284 private void trimStrongReferences()
285 {
286 int max = getCacheAttributes().getMaxObjects();
287 int startsize = strongReferences.size();
288
289 for (int cursize = startsize; cursize > max; cursize--)
290 {
291 ICacheElement<K, V> ce = strongReferences.poll();
292 waterfal(ce);
293 }
294 }
295
296
297
298
299
300
301
302
303 @Override
304 public ICacheElement<K, V> get(K key) throws IOException
305 {
306 ICacheElement<K, V> val = null;
307 lock.lock();
308
309 try
310 {
311 val = getQuiet(key);
312 if (val != null)
313 {
314 val.getElementAttributes().setLastAccessTimeNow();
315
316
317 strongReferences.add(val);
318 trimStrongReferences();
319 }
320 }
321 finally
322 {
323 lock.unlock();
324 }
325
326 if (val == null)
327 {
328 missCnt.incrementAndGet();
329 }
330 else
331 {
332 hitCnt.incrementAndGet();
333 }
334
335 return val;
336 }
337
338
339
340
341
342
343
344
345 @Override
346 public int freeElements(int numberToFree) throws IOException
347 {
348 return 0;
349 }
350 }