1
2
3
4
5
6
7 package ca.uhn.cache.internal.impl;
8
9 import org.apache.commons.logging.Log;
10 import org.apache.commons.logging.LogFactory;
11
12 import ca.uhn.cache.internal.ICacheCleaner;
13 import ca.uhn.cache.internal.IChunk;
14 import ca.uhn.cache.internal.IChunkIterator;
15 import ca.uhn.cache.internal.IChunkPurger;
16 import ca.uhn.cache.internal.IChunkStore;
17 import ca.uhn.cache.internal.IQueryResultStore;
18 import ca.uhn.cache.internal.exception.QueryResultStoreException;
19
20 /***
21 * Default implementation of ICacheCleaner.
22 *
23 * @author <a href="mailto:bryan.tripp@uhn.on.ca">Bryan Tripp</a>
24 * @version $Revision: 1.1 $ updated on $Date: 2005/01/24 22:54:03 $ by $Author: bryan_tripp $
25 */
26 public class CacheCleaner implements ICacheCleaner {
27
28 private static final Log ourLog = LogFactory.getLog( CacheCleaner.class );
29
30 private IChunkStore myChunkStore;
31 private IChunkPurger myPurger;
32 private int myTargetSize;
33 private IQueryResultStore myItemStore;
34 private float myAgeDecrement;
35
36 /***
37 * @param theChunkStore chunk store cleaned by this cleaner
38 * @param thePurger a specialized interface to the same store
39 * @param theTargetSize as in getTargetSize()
40 * @param theItemStore query result store that corresponds to the chunk store
41 * @param theAgeDecrement unused chunks are evicted in blocks according to the age of last usage,
42 * and this param is the size of each block as a proportion of greatest age in the cache
43 * (.01 = 1%, i.e. chunks divided into 100 blocks)
44 */
45 public CacheCleaner(IChunkStore theChunkStore, IChunkPurger thePurger, int theTargetSize,
46 IQueryResultStore theItemStore, float theAgeDecrement) {
47 myChunkStore = theChunkStore;
48 myPurger = thePurger;
49 myTargetSize = theTargetSize;
50 myItemStore = theItemStore;
51
52 if (theAgeDecrement > 1 || theAgeDecrement < 0) {
53 throw new IllegalArgumentException("theAgeDecrement must be between 0 and 1");
54 }
55 myAgeDecrement = theAgeDecrement;
56 }
57
58 /***
59 * @see ca.uhn.cache.internal.ICacheCleaner#getTargetSize()
60 */
61 public long getTargetSize() {
62 return myTargetSize;
63 }
64
65 /***
66 * @see ca.uhn.cache.internal.ICacheCleaner#evictStaleChunks()
67 */
68 public void evictStaleChunks() {
69 IChunkIterator stale = myPurger.getStaleChunks();
70 evict(stale);
71 }
72
73 /***
74 * @see ca.uhn.cache.internal.ICacheCleaner#evictUnusedChunks()
75 */
76 public void evictUnusedChunks() {
77 long now = System.currentTimeMillis();
78 long cutoffAge = now - myPurger.getLowestVogueness();
79
80 int decrement = Math.round( ((float) cutoffAge) * myAgeDecrement);
81
82
83 while (myPurger.getNumCachedItems() > getTargetSize()) {
84 cutoffAge = cutoffAge - decrement;
85 IChunkIterator unused = myPurger.getUnusedChunks(now - cutoffAge);
86 evict(unused);
87 }
88 }
89
90 private void evict(IChunkIterator theIterator) {
91 IChunk currentChunk = null;
92 try {
93 while (theIterator.hasNext()) {
94 currentChunk = theIterator.next();
95 evict(currentChunk);
96 }
97 } catch (QueryResultStoreException e) {
98 ourLog.error("Error evicting chunk " + currentChunk, e);
99 theIterator.close();
100 }
101 }
102
103
104
105 private void evict(IChunk theChunk) throws QueryResultStoreException {
106 myChunkStore.remove(theChunk.getBoundaries());
107 myItemStore.delete(theChunk.getBoundaries());
108 }
109
110 }