KickJava   Java API By Example, From Geeks To Geeks.

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


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: DelayCache.java,v 1.1.2.2 2004/04/10 10:06:51 per_nyfelt Exp $
7

8 package org.ozoneDB.core.storage;
9
10 import java.util.Collection JavaDoc;
11 import java.util.Comparator JavaDoc;
12 import java.util.HashMap JavaDoc;
13 import java.util.Iterator JavaDoc;
14 import java.util.LinkedHashMap JavaDoc;
15 import java.util.LinkedHashSet JavaDoc;
16 import java.util.LinkedList JavaDoc;
17 import java.util.List JavaDoc;
18 import java.util.Map JavaDoc;
19 import java.util.Properties JavaDoc;
20 import java.util.Set JavaDoc;
21 import java.util.Map.Entry;
22 import java.util.SortedSet JavaDoc;
23 import java.util.TreeMap JavaDoc;
24 import java.util.TreeSet JavaDoc;
25 import java.util.logging.Level JavaDoc;
26 import java.util.logging.Logger JavaDoc;
27 import org.ozoneDB.OzoneInternalException;
28 import org.ozoneDB.core.ConfigurationException;
29
30
31 /**
32  * <p>A cache with a fixed maximum number of objects in it. This cache grows
33  * until it has reached its maximum, which can be set by maxCapacity. Once that
34  * maximum has been reached, the least recently used object is thrown away when
35  * a new object is put in the cache. This cache has, next to that maximum number
36  * of elements, also a maximum time an element will remain in this cache. If
37  * that time has expired the element will be removed from this cache also.
38  * Reinserting an element (using the same key) causes the time for that element
39  * to be reset.</p>
40  *
41  * <p>Note: every instance creates its own thread for asynchronous removal of
42  * items past their 'best before' time. The trimmed() method on the TrimHandler
43  * is often but not always called asynchronously from that thread.</p>
44  *
45  * @author <a HREF="mailto:leoATmekenkampD0Tcom">Leo Mekenkamp (mind the anti sp@m)</a>
46  * @version $Id: DelayCache.java,v 1.1.2.2 2004/04/10 10:06:51 per_nyfelt Exp $
47  */

48 public class DelayCache extends AbstractTrimmingCache implements PropertyConfigurable {
49     
50     private static final Logger JavaDoc log = Logger.getLogger(DelayCache.class.getName());
51
52     public static final PropertyInfo DELAY = new PropertyInfo(
53         ".delay",
54         "int",
55         "1000",
56         "time (in ms) that an object can stay in this cache before may be thrown out",
57         new String JavaDoc[] {"100", "10000"}
58     );
59
60     public static final PropertyInfo MINSLEEPTIME = new PropertyInfo(
61         ".minSleepTime",
62         "int",
63         "100",
64         "time (in ms) that the thread that does the actual removing will wait at least",
65         new String JavaDoc[] {"100", "10000"}
66     );
67
68     public static final PropertyInfo INITIALCAPACITY = new PropertyInfo(
69         ".initialCapacity",
70         "int",
71         "1",
72         "number of objects that this cache reserves space for initially",
73         new String JavaDoc[] {"100", "100000"}
74     );
75
76     public static final PropertyInfo LOADFACTOR = new PropertyInfo(
77         ".loadFactor",
78         "float, in range <0, 1>",
79         "0.75",
80         "load factor for this cache; see java.util.LinkedHashMap(int initialCapacity, float loadFactor)",
81         new String JavaDoc[] {"0.5", "0.95"}
82     );
83
84     private int delay;
85     private int minSleepTime;
86     private Map JavaDoc keysToEntries;
87     private SortedSet JavaDoc entries;
88     private TrimThread trimThread;
89     
90     private volatile long sleepUntil;
91     private volatile long wakingUpAt;
92     
93     public DelayCache(Properties JavaDoc properties, String JavaDoc prefix) {
94         super(properties, prefix);
95         entries = new TreeSet JavaDoc();
96         try {
97             float loadFactor = Float.parseFloat(properties.getProperty(prefix + LOADFACTOR.getKey(), LOADFACTOR.getDefaultValue()));
98             log.config(getPrefix() + " using a load factory of " + loadFactor);
99             int initialCapacity = Integer.parseInt(properties.getProperty(prefix + INITIALCAPACITY.getKey(), INITIALCAPACITY.getDefaultValue()));
100             log.config(getPrefix() + " using an initial capacity of " + initialCapacity);
101             keysToEntries = new LinkedHashMap JavaDoc(initialCapacity, loadFactor);
102             setDelay(Integer.parseInt(properties.getProperty(getPrefix() + DELAY.getKey(), DELAY.getDefaultValue())));
103             log.config(getPrefix() + " using a delay of " + getDelay());
104             setMinSleepTime(Integer.parseInt(properties.getProperty(getPrefix() + MINSLEEPTIME.getKey(), MINSLEEPTIME.getDefaultValue())));
105             log.config(getPrefix() + " using a minimum sleep time of " + getMinSleepTime());
106         } catch (NumberFormatException JavaDoc e) {
107             throw new ConfigurationException(e);
108         }
109         trimThread = new TrimThread();
110         trimThread.start();
111     }
112
113     protected final Map JavaDoc getKeysToEntries() {
114         return keysToEntries;
115     }
116     
117     protected final SortedSet JavaDoc getEntries() {
118         return entries;
119     }
120
121     public Collection JavaDoc getPropertyInfos() {
122         Collection JavaDoc result = new LinkedList JavaDoc();
123         result.add(INITIALCAPACITY);
124         result.add(DELAY);
125         result.add(LOADFACTOR);
126         result.add(MINSLEEPTIME);
127         return result;
128     }
129     
130     public Object JavaDoc get(Object JavaDoc key) {
131         synchronized(getSynchronizer()) {
132             TimedEntry entry = (TimedEntry) getKeysToEntries().get(key);
133             return entry == null ? null : entry.value;
134         }
135     }
136     
137     public void put(Object JavaDoc key, Object JavaDoc value) {
138         synchronized(getSynchronizer()) {
139             TimedEntry entry = (TimedEntry) getKeysToEntries().get(key);
140             if (entry != null) {
141                 getEntries().remove(entry);
142                 entry.touch();
143             } else {
144                 entry = new TimedEntry((Comparable JavaDoc) key, value);
145                 getKeysToEntries().put(key, entry);
146             }
147             getEntries().add(entry);
148         }
149     }
150
151     public Object JavaDoc remove(Object JavaDoc key) {
152         synchronized(getSynchronizer()) {
153             TimedEntry entry = (TimedEntry) getKeysToEntries().remove(key);
154             getEntries().remove(entry);
155             return entry == null ? null : entry.value;
156         }
157     }
158     
159     private void trim() {
160         long now = System.currentTimeMillis();
161         while (size() > 0) {
162             TimedEntry first = (TimedEntry) getEntries().first();
163             if (now > first.time + getDelay()) {
164 //System.out.println("TRIMMING! " + (first.time + getDelay() - now));
165
getEntries().remove(first);
166                 if (getTrimHandler() != null) {
167                     getTrimHandler().trimming(first.key, first.value);
168                 }
169                 getKeysToEntries().remove(first.key);
170             } else {
171 //System.out.println("LEAVING! " + (first.time + getDelay() - now));
172
if (first.time + getDelay() > sleepUntil) {
173                     sleepUntil = first.time + getDelay();
174                 } else {
175                     sleepUntil = 0;
176                 }
177                 break;
178             }
179         }
180     }
181     
182     public int size() {
183         synchronized(getSynchronizer()) {
184             return getKeysToEntries().size();
185         }
186     }
187     
188     public Map JavaDoc copyToMap() {
189         synchronized(getSynchronizer()) {
190             HashMap JavaDoc result = new HashMap JavaDoc(size());
191             for (Iterator JavaDoc i = getEntries().iterator(); i.hasNext(); ) {
192                 TimedEntry entry = (TimedEntry) i.next();
193                 result.put(entry.key, entry.value);
194             }
195             return result;
196         }
197     }
198     
199     public final int getDelay() {
200         // delay is an int, so synchronization is not needed
201
return delay;
202     }
203     
204     public final void setDelay(int delay) {
205         synchronized(getSynchronizer()) {
206             this.delay = delay;
207             trim();
208         }
209     }
210     
211     public final int getMinSleepTime() {
212         // delay is an int, so synchronization is not needed
213
return minSleepTime;
214     }
215     
216     public final void setMinSleepTime(int minSleepTime) {
217         synchronized(getSynchronizer()) {
218             this.minSleepTime = minSleepTime;
219             trim();
220         }
221     }
222     
223     protected final class TimedEntry implements Comparable JavaDoc {
224         
225         public long time;
226         public Comparable JavaDoc key;
227         public Object JavaDoc value;
228         
229         public TimedEntry(Comparable JavaDoc key, Object JavaDoc value) {
230             this.key = key;
231             this.value = value;
232             touch();
233         }
234         
235         public int compareTo(Object JavaDoc o) {
236             TimedEntry other = (TimedEntry) o;
237             int result = (int) (time - other.time);
238             return result != 0 ? result : key.compareTo(other.key);
239         }
240         
241         public boolean equals(Object JavaDoc o) {
242             return compareTo(o) == 0;
243         }
244         
245         public void touch() {
246             time = System.currentTimeMillis();
247         }
248     }
249     
250     private class TrimThread extends Thread JavaDoc {
251         
252         public TrimThread() {
253             super("delayed trimmer");
254             setDaemon(true);
255         }
256         
257         public void run() {
258             synchronized(getSynchronizer()) {
259                 for (;;) {
260                     long now = System.currentTimeMillis();
261                     try {
262                         getSynchronizer().wait(Math.max(sleepUntil - now, getMinSleepTime()));
263                     } catch (InterruptedException JavaDoc ignore) {
264                     }
265                     trim();
266                 }
267             }
268         }
269     }
270     
271 }
272
Popular Tags