KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > fjank > jcache > CacheSweeper


1
2 /* Open Source Java Caching Service
3 * Copyright (C) 2002 Frank Karlstrøm
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 * The author can be contacted by email: fjankk@users.sourceforge.net
19 */

20 package org.fjank.jcache;
21
22 import java.lang.ref.ReferenceQueue JavaDoc;
23 import java.util.Iterator JavaDoc;
24 import javax.util.jcache.Attributes;
25 import javax.util.jcache.CacheAttributes;
26 import javax.util.jcache.CacheException;
27 import javax.util.jcache.CacheNotAvailableException;
28 import javax.util.jcache.NullObjectException;
29
30
31
32
33 /**
34  * A Runnable class for Sweeping the cache for expired objects. Either they are
35  * serialized to disk, or they are removed from the cache depending on the
36  * attributes of the object.
37  *
38  * @author Frank Karlstrøm
39  */

40 public class CacheSweeper implements Runnable JavaDoc {
41     /** the singleton sweeper */
42     private static CacheSweeper _singleton;
43     /** a boolean indication wether this sweeper is active or not. */
44     //2004-09-FB
45
private boolean active = false;
46
47     /**
48      * Creates new CacheSweeper
49      */

50     private CacheSweeper() {
51     }
52
53     /**
54      * sweeps the cache and removes invalid objects, waits for cleanInterval
55      * seconds, then sweeps again etc.
56      */

57     public void run() {
58         CacheImpl cache = CacheImpl.getCache(true);
59         CacheAttributes attribs = cache.getAttributes();
60
61         while (active) {
62             try {
63                 Thread.sleep(attribs.getCleanInterval() * 1000);
64             } catch (InterruptedException JavaDoc e) {
65                 //normal
66
}
67             sweepCache();
68         }
69     }
70
71     /**
72      * checks the size of the objects in the cache, and if the memory limit
73      * is nearing its capacity, somoe objects are saved to disk. The
74      * algorithm for choosing these is in the method writeToDisk(). Then the
75      * ReferenceQueue is checked, and all objects in this queue have been
76      * swept by the GC. if they have expired, they are deleted from the cache.
77      * If not, they are retained to the next cachesweep.
78      */

79     private void sweepCache() {
80         CacheImpl cache = null;
81         try {
82             cache = CacheImpl.getCache(true);
83
84             int maxSize = cache.getAttributes().getMemoryCacheSize();
85             long maxBytes = maxSize * 1024 * 1024;
86             if (getMemoryCacheSize() >= maxBytes) {
87                 writeToDisk();
88             }
89             /**sweeps the entire cache, and de-references the expired objects.
90              * This will add them to the appropiate ReferenceQueue
91              * when their referenceCount is zero. If no one uses the objects,
92              * this will happen immediantely.
93              * We also attempt to stimulate the gc to run. (Not neccessary perhaps?)
94              *
95              */

96
97             CacheRegion reg = cache.getRegion();
98             sweepGroup(reg);
99             Iterator JavaDoc iter = cache.userRegionNames();
100             while(iter.hasNext()) {
101                 Object JavaDoc key = iter.next();
102                 CacheRegion userReg = cache.getRegion(key);
103                 sweepGroup(userReg);
104             }
105             for(int i=0; i<3; i++) {
106                 System.runFinalization();
107                 System.gc();
108                 try {
109                     Thread.sleep(500);
110                 } catch (InterruptedException JavaDoc e1) {;}
111             }
112
113             /**now its up to the referencequeue to remove the
114              * appropiate obects.
115              */

116             CacheObject cacheObj = null;
117             ReferenceQueue JavaDoc q = cache.getReferenceQueue();
118             while ((cacheObj = (CacheObject) q.poll()) != null) {
119                 cacheObj.resetRefCount();
120                 tryRemoval(cacheObj);
121             }
122
123         } catch (CacheException e) {
124             e.printStackTrace();
125             stopSweeper();
126         } catch (java.lang.IncompatibleClassChangeError JavaDoc e) {
127             //the cache has probably been reloaded/redeployed.
128
//restart ourselves.
129
if (cache != null) {
130                 cache.close();
131                 try {
132                     cache.open();
133                 } catch (CacheNotAvailableException ee) {
134                     stopSweeper();
135                 }
136             }
137         }
138     }
139     /**
140      * Will sweep a group in search for an object which has expired.
141      * any groups encountered will use this method as a recursive method
142      * to further search for expired objects.
143      * @todo there's no failsafe for groups containing themselves.
144      * @param group the group to sweep.
145      * @throws NullObjectException if a nullobject is encountered.
146      */

147     private void sweepGroup(CacheGroup group) throws NullObjectException {
148         Iterator JavaDoc iter = group.weakReferenceObjects.keySet().iterator();
149         while(iter.hasNext()) {
150             Object JavaDoc key = iter.next();
151             Object JavaDoc obj = group.weakReferenceObjects.get(key);
152             if(obj instanceof CacheObject) {
153                 if(hasExpired((CacheObject) obj)) {
154                     group.removeObjectReference(key);
155                 }
156             }else if(obj instanceof CacheGroup) {
157                 sweepGroup((CacheGroup) obj);
158             }else {
159                 System.out.println("An unknown object ("+obj.getClass().getName()+") was discovered in the cache.");
160                 break;
161             }
162         }
163     }
164
165     /**
166      * the actual remove routine. if the object has been alive longer than the
167      * timeToLive , its invalidated.
168      * @todo Some of the code here is duplicated in tryRemoveHardReference.
169      * @todo return value is never used.
170      * @param cacheObj the CacheObject to try to remove.
171      * @return an boolean indication wether the object was removed or not.
172      */

173
174     private boolean tryRemoval(final CacheObject cacheObj) throws NullObjectException {
175         if (hasExpired(cacheObj)) {
176             cacheObj.invalidate();
177             return true;
178         }
179         return false;
180     }
181     private boolean hasExpired(CacheObject obj) throws NullObjectException {
182         Attributes attributes = obj.getAttributes();
183         if(attributes==null) throw new NullObjectException("A null attributes was detected.");
184         /*-1 is the default for attributes, and the default is
185          * non invalidation, so if the ttl is -1, the objects remains in the cache.
186          */

187
188         if(attributes.getTimeToLive()==-1) {
189             return false;
190         }
191         if(attributes.getLoader()!=null) return false;
192         long now = System.currentTimeMillis();
193         long timealive = (now - attributes.getCreateTime()) / 1000;
194
195         //only ttl is support for now. the rest of the params can be implemented later.
196
if (timealive >= attributes.getTimeToLive()) {
197             return true;
198         }
199         return false;
200     }
201     /**
202      * Finds all objects wich are not in use, and determines wich one of them
203      * is the best to flush to disk. LFU is a caching strategy that stands for
204      * "least frequently used". In this strategy, elements are evicted based
205      * when they were added, when they were last used, and how many times they
206      * have been used. Other strategies may be implemented later. Gets the
207      * diskFile, fins an available position in the file, converts the
208      * CacheObject to a CacheObjectDisk, and writes it to the disk file.
209      *
210      *@todo NOT IMPLEMENTED.
211      */

212     private void writeToDisk() {
213     }
214
215     /**
216      * Gets the current size of all objects in the cache. Return the size of
217      * the actuall object, not regarding the size of the attributes, or the
218      * wrapper objects.
219      *
220      * @return long the current size of all objects in the cache.
221      *
222      *@todo NOT IMPLEMENTED.
223      */

224     private long getMemoryCacheSize() {
225         return 0;
226     }
227
228     /**
229      * activates this sweeper.
230      */

231     synchronized void startSweeper() {
232         //2004/09-FB
233
if (!_singleton.active){
234             active=true;
235             CacheThreadFactory fact = CacheThreadFactory.getInstance();
236             fact.setName("Fjanks FKache - CacheSweeper");
237             fact.setDaemon(true);
238             fact.newThread(this).start();
239             
240         }
241     }
242
243     /**
244      * deactivates this sweeper.
245      */

246     //2004/09-FB
247
synchronized void stopSweeper() {
248         active = false;
249         
250     }
251
252     /**
253      * create this sweeper instance.
254      */

255     public static synchronized CacheSweeper getInstance() {
256         if (_singleton == null) {
257             _singleton = new CacheSweeper();
258             //2004/09-FB
259
//_singleton.startSweeper();
260

261         }
262         return _singleton;
263     }
264
265     //2004/09-FB
266
/**
267      * remove this sweeper instance.
268      */

269     static synchronized void removeInstance() {
270         if (_singleton != null) {
271              if (_singleton.active){
272                 _singleton.stopSweeper();
273              }
274             _singleton = null;
275             
276         }
277     }
278 }
279
Popular Tags