KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mmbase > cache > Cache


1 /*
2
3 This software is OSI Certified Open Source Software.
4 OSI Certified is a certification mark of the Open Source Initiative.
5
6 The license (Mozilla version 1.0) can be read at the MMBase site.
7 See http://www.MMBase.org/license
8
9 */

10 package org.mmbase.cache;
11
12 import java.util.*;
13
14 import org.mmbase.util.*;
15 import org.mmbase.util.logging.Logger;
16 import org.mmbase.util.logging.Logging;
17 import org.mmbase.bridge.Cacheable;
18
19 /**
20  * A base class for all Caches. Extend this class for other caches.
21  *
22  * @author Michiel Meeuwissen
23  * @version $Id: Cache.java,v 1.36 2006/07/31 13:33:05 michiel Exp $
24  */

25 abstract public class Cache implements SizeMeasurable, Map {
26
27     private static final Logger log = Logging.getLoggerInstance(Cache.class);
28
29     private boolean active = true;
30     protected int maxEntrySize = -1; // no maximum/ implementation does not support;
31

32     /**
33      * @since MMBase-1.8
34      */

35     private CacheImplementationInterface implementation;
36
37     /**
38      * The number of times an element was succesfully retrieved from this cache.
39      */

40     private int hits = 0;
41
42     /**
43      * The number of times an element could not be retrieved from this cache.
44      */

45     private int misses = 0;
46
47     /**
48      * The number of times an element was committed to this cache.
49      */

50     private int puts = 0;
51
52     public Cache(int size) {
53         implementation = new LRUHashtable(size);
54         log.service("Creating cache " + getName() + ": " + getDescription());
55     }
56
57     void setImplementation(String JavaDoc clazz, Map configValues) {
58         try {
59             Class JavaDoc clas = Class.forName(clazz);
60             if (implementation == null || (! clas.equals(implementation.getClass()))) {
61                 implementation = (CacheImplementationInterface) clas.newInstance();
62                 implementation.config(configValues);
63             }
64         } catch (ClassNotFoundException JavaDoc cnfe) {
65             log.error("For cache " + this + " " + cnfe.getClass().getName() + ": " + cnfe.getMessage());
66         } catch (InstantiationException JavaDoc ie) {
67             log.error("For cache " + this + " " + ie.getClass().getName() + ": " + ie.getMessage());
68         } catch (IllegalAccessException JavaDoc iae) {
69             log.error("For cache " + this + " " + iae.getClass().getName() + ": " + iae.getMessage());
70         }
71     }
72
73     /**
74      * Returns a name for this cache type. Default it is the class
75      * name, but this normally will be overriden.
76      */

77     public String JavaDoc getName() {
78         return getClass().getName();
79     }
80
81     /**
82      * Gives a description for this cache type. This can be used in
83      * cache overviews.
84      */

85     public String JavaDoc getDescription() {
86         return "An all purpose Cache";
87     }
88
89
90
91     /**
92      * Return the maximum entry size for the cache in bytes. If the
93      * cache-type supports it (default no), then no values bigger then
94      * this will be stored in the cache.
95      */

96     public int getMaxEntrySize() {
97         if (getDefaultMaxEntrySize() > 0) {
98             return maxEntrySize;
99         } else {
100             return -1;
101         }
102     }
103
104     /**
105      * This has to be overridden by Caches which support max entry size.
106      */

107
108     protected int getDefaultMaxEntrySize() {
109         return -1;
110     }
111
112     public Set entrySet() {
113         if (! active) return new HashSet();
114         return implementation.entrySet();
115     }
116
117     /**
118      * Checks whether the key object should be cached.
119      * This method returns <code>false</code> if either the current cache is inactive, or the object to cache
120      * has a cache policy associated that prohibits caching of the object.
121      * @param key the object to be cached
122      * @return <code>true</code> if the object can be cached
123      * @since MMBase-1.8
124      */

125     protected boolean checkCachePolicy(Object JavaDoc key) {
126         CachePolicy policy = null;
127         if (active) {
128             if (key instanceof Cacheable) {
129                 policy = ((Cacheable)key).getCachePolicy();
130                 if (policy != null) {
131                     return policy.checkPolicy(key);
132                 }
133             }
134             return true;
135         }
136         return false;
137     }
138
139     /**
140      * Like 'get' of Maps but considers if the cache is active or not, and the cache policy of the key.
141      */

142     public Object JavaDoc get(Object JavaDoc key) {
143         if (!checkCachePolicy(key)) {
144             return null;
145         }
146         Object JavaDoc res = implementation.get(key);
147         if (res != null) {
148             hits++;
149         } else {
150             misses++;
151         }
152         return res;
153     }
154
155     /**
156      * Like 'put' of LRUHashtable but considers if the cache is active or not.
157      *
158      */

159     public Object JavaDoc put(Object JavaDoc key, Object JavaDoc value) {
160         if (!checkCachePolicy(key)) {
161             return null;
162         }
163         puts++;
164         return implementation.put(key, value);
165     }
166
167     /**
168      * Returns the number of times an element was succesfully retrieved
169      * from the table.
170      */

171     public int getHits() {
172         return hits;
173     }
174
175     /**
176      * Returns the number of times an element cpould not be retrieved
177      * from the table.
178      */

179     public int getMisses() {
180         return misses;
181     }
182
183     /**
184      * Returns the number of times an element was committed to the table.
185      */

186     public int getPuts() {
187         return puts;
188     }
189
190     public void setMaxSize(int size) {
191         implementation.setMaxSize(size);
192     }
193     public int maxSize() {
194         return implementation.maxSize();
195     }
196
197     /**
198      * @see java.util.Map#size()
199      */

200     public int size() {
201         return implementation.size();
202     }
203     public boolean contains(Object JavaDoc key) {
204         return implementation.containsKey(key);
205     }
206
207     public int getCount(Object JavaDoc key) {
208         return implementation.getCount(key);
209     }
210
211     /**
212      * Returns the ratio of hits and misses.
213      * The higher the ratio, the more succesfull the table retrieval is.
214      * A value of 1 means every attempt to retrieve data is succesfull,
215      * while a value nearing 0 means most times the object requested it is
216      * not available.
217      * Generally a high ratio means the table can be shrunk, while a low ratio
218      * means its size needs to be increased.
219      *
220      * @return A double between 0 and 1 or NaN.
221      */

222     public double getRatio() {
223         return ((double) hits) / ( hits + misses );
224     }
225
226
227     /**
228      * Returns statistics on this table.
229      * The information shown includes number of accesses, ratio of misses and hits,
230      * current size, and number of puts.
231      */

232     public String JavaDoc getStats() {
233         return "Access "+ (hits + misses) + " Ratio " + getRatio() + " Size " + size() + " Puts " + puts;
234     }
235
236
237     /**
238      * Sets this cache to active or passive.
239      * TODO: Writing back to caches.xml if necessary (if this call was nog caused by change of caches.xml itself)
240      */

241     public void setActive(boolean a) {
242         active = a;
243         if (! active) {
244             implementation.clear();
245         }
246         // inactive caches cannot contain anything
247
// another option would be to override also the 'contains' methods (which you problable should not use any way)
248
}
249
250     public String JavaDoc toString() {
251         return "Cache " + getName() + ", Ratio: " + getRatio() + " " + implementation;
252     }
253
254     /**
255      * Wether this cache is active or not.
256      */

257     public final boolean isActive() {
258         return active;
259     }
260
261     public int getByteSize() {
262         return getByteSize(new SizeOf());
263     }
264
265     public int getByteSize(SizeOf sizeof) {
266         int size = 26;
267         if (implementation instanceof SizeMeasurable) {
268             size += ((SizeMeasurable) implementation).getByteSize(sizeof);
269         } else {
270             // sizeof.sizeof(implementation) does not work because this.equals(implementation)
271
Iterator i = implementation.entrySet().iterator();
272             while(i.hasNext()) {
273                 Map.Entry entry = (Map.Entry) i.next();
274                 size += sizeof.sizeof(entry.getKey());
275                 size += sizeof.sizeof(entry.getValue());
276             }
277         }
278         return size;
279     }
280
281     /**
282      * Returns the sum of bytesizes of every key and value. This may count too much, because objects
283      * (like Nodes) may occur in more then one value, but this is considerably cheaper then {@link
284      * #getByteSize()}, which has to keep a Collection of every counted object.
285      * @since MMBase-1.8
286      */

287     public int getCheapByteSize() {
288         int size = 0;
289         SizeOf sizeof = new SizeOf();
290         Iterator i = implementation.entrySet().iterator();
291         while(i.hasNext()) {
292             Map.Entry entry = (Map.Entry) i.next();
293             size += sizeof.sizeof(entry.getKey());
294             size += sizeof.sizeof(entry.getValue());
295             sizeof.clear();
296         }
297         return size;
298     }
299
300
301     /**
302      * @see java.util.Map#clear()
303      */

304     public void clear() {
305         implementation.clear();
306     }
307
308
309     /**
310      * @see java.util.Map#containsKey(java.lang.Object)
311      */

312     public boolean containsKey(Object JavaDoc key) {
313         return implementation.containsKey(key);
314     }
315
316
317     /**
318      * @see java.util.Map#containsValue(java.lang.Object)
319      */

320     public boolean containsValue(Object JavaDoc value) {
321         return implementation.containsValue(value);
322     }
323
324
325     /**
326      * @see java.util.Map#equals(java.lang.Object)
327      */

328     public boolean equals(Object JavaDoc o) {
329         // odd, but this is accordinding to javadoc of Map.
330
return implementation.equals(o);
331     }
332
333
334     /**
335      * @see java.util.Map#hashCode()
336      */

337     public int hashCode() {
338         return implementation.hashCode();
339     }
340
341
342     /**
343      * @see java.util.Map#isEmpty()
344      */

345     public boolean isEmpty() {
346         return implementation.isEmpty();
347     }
348
349
350     /**
351      * @see java.util.Map#keySet()
352      */

353     public Set keySet() {
354         return implementation.keySet();
355     }
356
357
358     /**
359      * @see java.util.Map#putAll(java.util.Map)
360      */

361     public void putAll(Map t) {
362         implementation.putAll(t);
363     }
364
365
366     /**
367      * @see java.util.Map#remove(java.lang.Object)
368      */

369     public Object JavaDoc remove(Object JavaDoc key) {
370         return implementation.remove(key);
371     }
372
373
374     /**
375      * @see java.util.Map#values()
376      */

377     public Collection values() {
378         return implementation.values();
379     }
380
381
382     /**
383      * Puts this cache in the caches repository.
384      * @see CacheManager#putCache(Cache)
385      */

386
387     public Cache putCache() {
388         return CacheManager.putCache(this);
389     }
390
391     /**
392      * @see CacheManager#getCache(String)
393      */

394     protected static Cache putCache(Cache cache) {
395         return CacheManager.putCache(cache);
396     }
397
398     /**
399      * @see CacheManager#getCache(String)
400      */

401     public static Cache getCache(String JavaDoc name) {
402         return CacheManager.getCache(name);
403     }
404
405     /**
406      * @see CacheManager#getCaches
407      */

408     public static Set getCaches() {
409         return CacheManager.getCaches();
410     }
411
412     /**
413      * @see CacheManager#getTotalByteSize
414      */

415     public static int getTotalByteSize() {
416         return CacheManager.getTotalByteSize();
417     }
418
419
420     public static void main(String JavaDoc args[]) {
421         Cache mycache = new Cache(20000000) {
422                 public String JavaDoc getName() { return "test cache"; }
423                 public String JavaDoc getDescription() { return ""; }
424             };
425         Runtime JavaDoc rt = Runtime.getRuntime();
426         rt.gc();
427         long usedBefore = rt.totalMemory() - rt.freeMemory();
428
429         System.out.println("putting some strings in cache");
430         mycache.put("aaa", "AAA"); // 6 bytes
431
mycache.put("bbb", "BBB"); // 6 bytes
432

433         System.out.println("putting an hashmap in cache");
434         Map m = new HashMap();
435         m.put("ccc", "CCCCCC"); // 9
436
m.put("ddd", "DDD"); // 6
437
m.put("abc", "EEE"); // 6
438
mycache.put("eee", m); // 3
439

440
441         //String[] list = new String[1000000];
442
//ArrayList list = new ArrayList();
443
// should cause 16M of char
444
for (int i = 1000000; i < 2000000; i++) {
445             mycache.put("a" + 1000000 + i, "b" + 1000000 + i);
446             //list[i - 1000000] = "a" + i + "b" + i;
447
//list.add("a" + i + "b" + i);
448
//list.add(new String( new byte[] {}).intern());
449
}
450         rt.gc();
451
452         long usedAfter = rt.totalMemory() - rt.freeMemory();
453
454         System.out.println("1M of String costs " + (usedAfter - usedBefore) + " bytes");
455         System.out.println("Sizeof reports " + SizeOf.getByteSize(mycache));
456         System.out.println("size of cache: " + mycache.getByteSize() + " ");
457
458     }
459
460 }
461
Popular Tags