KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > ozoneDB > core > storage > GcListeningDelayCache


1 // You can redistribute this software and/or modify it under the terms of
2
// the Ozone Core License version 1 published by ozone-db.org.
3
//
4
// Copyright (C) 2003-@year@, Leo Mekenkamp. All rights reserved.
5
//
6
// $Id: GcListeningDelayCache.java,v 1.3.2.1 2004/03/28 16:40:04 per_nyfelt Exp $
7

8 package org.ozoneDB.core.storage;
9
10 import java.lang.ref.ReferenceQueue JavaDoc;
11 import java.lang.ref.WeakReference JavaDoc;
12 import java.util.Properties JavaDoc;
13 import java.util.logging.Level JavaDoc;
14 import java.util.logging.Logger JavaDoc;
15 import org.ozoneDB.core.ConfigurationException;
16 import org.ozoneDB.core.storage.DelayCache.TimedEntry;
17
18 /**
19
20  * @author <a HREF="mailto:leoATmekenkampD0Tcom">Leo Mekenkamp (mind the anti sp@m)</a>
21  * @version $Id: GcListeningDelayCache.java,v 1.3.2.1 2004/03/28 16:40:04 per_nyfelt Exp $
22  */

23 public class GcListeningDelayCache extends DelayCache {
24     
25     private static Logger JavaDoc log = Logger.getLogger(GcListeningDelayCache.class.getName());
26     
27     public static final PropertyInfo HIGHTHRESHOLD = new PropertyInfo(
28         ".highThreshold",
29         "int",
30         "10000000",
31         "when free memory falls below this threshold this cache will start throwing out elements",
32         new String JavaDoc[] {"10000", "50000000"}
33     );
34
35     public static final PropertyInfo LOWTHRESHOLD = new PropertyInfo(
36         ".lowThreshold",
37         "int",
38         "-1000000",
39         "when free memory falls below this threshold this cache will throw out all elements (may be < 0)",
40         new String JavaDoc[] {"1000", "-500000"}
41     );
42
43     /**
44      * gets cleared every time the jvm gc runs
45      */

46     private WeakReference JavaDoc gcIndicator;
47     
48     private ReferenceQueue JavaDoc gcQueue = new ReferenceQueue JavaDoc();
49     private Thread JavaDoc gcIndicatorThread = new GcIndicatorThread();
50     
51     private long lowThreshold;
52     private long highThreshold;
53     
54     public GcListeningDelayCache(Properties JavaDoc properties, String JavaDoc prefix) {
55         super(properties, prefix);
56         gcIndicatorThread.start();
57         try {
58             lowThreshold = Integer.parseInt(properties.getProperty(prefix + LOWTHRESHOLD.getKey(), LOWTHRESHOLD.getDefaultValue()));
59             log.config(getPrefix() + " using a low threshold of " + lowThreshold);
60             highThreshold = Integer.parseInt(properties.getProperty(prefix + HIGHTHRESHOLD.getKey(), HIGHTHRESHOLD.getDefaultValue()));
61             log.config(getPrefix() + " using a high threshold of " + highThreshold);
62         } catch (NumberFormatException JavaDoc e) {
63             throw new ConfigurationException(e);
64         }
65     }
66     
67     /**
68      * Creates an object that is only weakly referenced. There is a 1 on 1
69      * correspondance between this weak reference getting enqueued and a
70      * jvm gc run
71      */

72     private final void resetGcIndicator() {
73         gcIndicator = new WeakReference JavaDoc(new Object JavaDoc(), gcQueue);
74     }
75     
76     private void ourGC() {
77         synchronized(getSynchronizer()) {
78             if (size() > 0) {
79                 long freeMemory = Runtime.getRuntime().freeMemory();
80                 if (freeMemory < getHighThreshold()) {
81                     // y == ax + b
82
// 1 == a * low + b
83
// 0 == a * high + b
84
//
85
// b == -a * high
86
//
87
// 1 == a * low - a * high
88
//
89
// a == 1 / (low - high)
90
//
91
// b == -high / (low - high)
92
//
93
// y == x / (low - high) - high / (low - high)
94
// y == (x - high) / (low - high)
95

96                     float clearRatio = (float) (freeMemory - getHighThreshold()) / (float) (getLowThreshold() - getHighThreshold());
97                     if (clearRatio > 0) {
98                         if (clearRatio > 1) {
99                             clearRatio = 1;
100                         }
101                         if (log.isLoggable(Level.FINE)) log.fine("removing " + clearRatio + " from cache");
102                         int numToClear = (int) (size() * clearRatio);
103                         if (numToClear < 1) {
104                             numToClear = 1;
105                         }
106                         for (;numToClear > 0; numToClear--) {
107                             TimedEntry last = (TimedEntry) getEntries().last();
108                             if (getTrimHandler() != null) {
109                                 getTrimHandler().trimming(last.key, last.value);
110                             }
111                             getEntries().remove(last);
112                             getKeysToEntries().remove(last.key);
113                         }
114                     }
115                 }
116             }
117         }
118     }
119     
120     /**
121      * value in range <max(0,lowThreshold), 1] indicating when caches should
122      * start throwing away entries.
123      */

124     public void setHighThreshold(long highThreshold) {
125         synchronized(getSynchronizer()) {
126             if (highThreshold <= getLowThreshold()) {
127                 String JavaDoc msg = "could not set highThreshold to " + highThreshold + "; must be > lowThreshold (" + getLowThreshold() + ")";
128                 log.severe(msg);
129                 throw new IllegalArgumentException JavaDoc(msg);
130             }
131             this.highThreshold = highThreshold;
132         }
133     }
134     
135     /**
136      * value in range <0, min(1,highThreshold)] indicating when cache should
137      * throw away all its entries.
138      */

139     public void setLowThreshold(long lowThreshold) {
140         synchronized(getSynchronizer()) {
141             if (lowThreshold < 0 || lowThreshold >= getHighThreshold()) {
142                 String JavaDoc msg = "could not set lowThreshold to " + lowThreshold + "; must be >= 0 and <= highThreshold (" + getHighThreshold() + ")";
143                 log.severe(msg);
144                 throw new IllegalArgumentException JavaDoc(msg);
145             }
146             this.lowThreshold = lowThreshold;
147         }
148     }
149     
150     public long getHighThreshold() {
151         synchronized(getSynchronizer()) {
152             return highThreshold;
153         }
154     }
155     
156     public synchronized long getLowThreshold() {
157         synchronized(getSynchronizer()) {
158             return lowThreshold;
159         }
160     }
161     
162     /**
163      * Is woken up every time the gc has completed a run, or is in the process
164      * of a run. The javadocs are a bit sketchy on this. Empirical data seems
165      * to suggest the first.
166      */

167     private class GcIndicatorThread extends Thread JavaDoc {
168         
169         GcIndicatorThread() {
170             super(Thread.currentThread().getThreadGroup(), "gc indicator");
171             setDaemon(true);
172             // setting priority to high to lessen the chance that another
173
// thread does a lot of object creating during our run()
174
setPriority(Thread.MAX_PRIORITY - 1);
175         }
176         
177         public void run() {
178             for (;;) {
179                 try {
180                     resetGcIndicator();
181                     
182                     // only interested in 'when', not 'what', no 'Reference ref ='
183
gcQueue.remove();
184                     if (log.isLoggable(Level.FINE)) {
185                         Runtime JavaDoc runtime = Runtime.getRuntime();
186                         log.fine("gc has kicked in (free mem: " + runtime.freeMemory() + ", total mem: " + runtime.totalMemory());
187                     }
188                     ourGC();
189                 } catch (InterruptedException JavaDoc ignore) {
190                 }
191             }
192         }
193         
194     }
195         
196     // DEBUG AND BUGTEST CODE ONLY FOLLOWING; not needed for normal operation
197

198     static class Item {
199         byte[] filling = new byte[100];
200         private Object JavaDoc key;
201         
202         Item(Object JavaDoc key) {
203             this.key = key;
204         }
205         
206         public String JavaDoc toString() {
207             return key.toString();
208         }
209         
210     }
211     
212     public static void main(String JavaDoc[] args) {
213         Properties JavaDoc properties = new Properties JavaDoc();
214         String JavaDoc prefix = "dbg";
215         properties.setProperty(prefix + LOWTHRESHOLD.getKey(), "-32000000");
216         properties.setProperty(prefix + HIGHTHRESHOLD.getKey(), "1000000");
217         properties.setProperty(prefix + DELAY.getKey(), "2000");
218         GcListeningDelayCache cache = new GcListeningDelayCache(properties, prefix);
219         
220         for (int i = 0; ; i++ ) {
221             Object JavaDoc key = new Integer JavaDoc(i);
222             Item item = new Item(key);
223             // System.out.println("creating " + key + ", free: " + Runtime.getRuntime().freeMemory());
224
cache.put(key, item);
225             if (i > 10) {
226                 // System.out.println("get(10): " + cache.get(new Integer(10)));
227
}
228             
229             if (cache.size() % 100 == 0) {
230                 System.out.println("references in map: " + cache.size() + ", free: " + Runtime.getRuntime().freeMemory());
231             }
232         }
233         // System.out.println("completed sucessfully");
234
}
235     
236 }
237
Popular Tags