1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.fjank.jcache.persistence;
20
21 import java.io.File;
22 import java.io.Serializable;
23 import java.util.HashMap;
24 import java.util.Iterator;
25 import javax.util.jcache.CacheAttributes;
26 import javax.util.jcache.DiskCacheException;
27 import org.fjank.jcache.CacheObject;
28 import org.fjank.jcache.DiskCacheObject;
29 import EDU.oswego.cs.dl.util.concurrent.ReadWriteLock;
30 import EDU.oswego.cs.dl.util.concurrent.WriterPreferenceReadWriteLock;
31
32
33
34
35
36
37 public class DiskCache implements Serializable {
38
39
40
41
42 private boolean alive;
43
44
45
46
47 private final String cacheName;
48
49
50
51
52 private final CacheAttributes cattr;
53
54
55 private transient CacheFileAdapter dataFile;
56
57
58 private final String fileName;
59
60
61 private transient CacheFileAdapter keyFile;
62
63
64 private HashMap keyHash;
65
66
67 private final File rafDir;
68
69
70
71
72
73 private final ReadWriteLock storageLock = new WriterPreferenceReadWriteLock();
74
75
76
77 private int currentSize;
78
79
80
81
82
83
84
85
86
87 public DiskCache(final CacheAttributes attributes) throws DiskCacheException {
88 this.cacheName = "Fjanks FKache";
89 String rootDirName = attributes.getDiskPath();
90 this.cattr = attributes;
91 this.fileName = cacheName;
92 rafDir = new File(rootDirName);
93 rafDir.mkdirs();
94 dataFile = new CacheFileAdapter(new File(rafDir, fileName + ".data"));
95 keyFile = new CacheFileAdapter(new File(rafDir, fileName + ".key"));
96 if (keyFile.length() > 0) {
97 loadKeysFromFile();
98 if (keyHash.size() == 0) {
99 dataFile.reset();
100 }
101 } else {
102 keyHash = new HashMap();
103 if (dataFile.length() > 0) {
104 dataFile.reset();
105 }
106 }
107 alive = true;
108 }
109
110
111
112
113
114
115
116
117
118
119 private CacheObject doGet(Serializable key) throws DiskCacheException {
120 try {
121 storageLock.readLock().acquire();
122 if (!alive) {
123 return null;
124 }
125 return readElement(key);
126 } catch (InterruptedException e) {
127 throw new DiskCacheException("The read was interrupted.");
128 } finally {
129 storageLock.readLock().release();
130 }
131 }
132
133
134
135
136
137
138
139
140 private void doUpdate(Object key, byte[] data) {
141 try {
142 DiskElementDescriptor ded = new DiskElementDescriptor();
143 ded.init(dataFile.length(), data);
144 storageLock.writeLock().acquire();
145 if (!alive) {
146 return;
147 }
148 DiskElementDescriptor old =
149 (DiskElementDescriptor) keyHash.put(key, ded);
150 if ((old != null) && (ded.len <= old.len)) {
151 ded.pos = old.pos;
152 }
153 dataFile.write(data, ded.pos);
154 } catch (InterruptedException e) {
155 ;
156 } finally {
157 storageLock.writeLock().release();
158 }
159 }
160
161
162
163
164
165
166
167
168
169
170 public final CacheObject getObject(final Serializable key)
171 throws DiskCacheException {
172 if (!alive) {
173 return null;
174 }
175 return doGet(key);
176 }
177
178
179
180
181
182
183
184 private void loadKeysFromFile() throws DiskCacheException {
185 try {
186 storageLock.readLock().acquire();
187 keyHash = (HashMap) keyFile.readObject(0);
188 if (keyHash == null) {
189 keyHash = new HashMap();
190 }
191 } catch (InterruptedException e) {
192 ;
193 } finally {
194 storageLock.readLock().release();
195 }
196 }
197
198
199
200
201 public void close() {
202 try {
203 storageLock.writeLock().acquire();
204 if (!alive) {
205 return;
206 }
207 optimizeFile();
208 dataFile.close();
209 dataFile = null;
210 keyFile.close();
211 keyFile = null;
212 } catch (DiskCacheException e) {
213
214
215 } catch (InterruptedException e) {
216 ;
217 } finally {
218 alive = false;
219 storageLock.writeLock().release();
220
221 }
222 }
223
224
225
226
227
228
229 private void optimizeFile() throws DiskCacheException {
230 HashMap keyHashTemp = new HashMap();
231 CacheFileAdapter dataFileTemp =
232 new CacheFileAdapter(new File(rafDir, fileName + "Temp.data"));
233 Iterator itr = keyHash.keySet().iterator();
234 while (itr.hasNext()) {
235 Serializable key = (Serializable) itr.next();
236 CacheObject tempDe = readElement(key);
237 DiskElementDescriptor de = dataFileTemp.appendObject(tempDe);
238 keyHashTemp.put(key, de);
239 }
240 dataFileTemp.close();
241 dataFile.close();
242 File oldData = new File(rafDir, fileName + ".data");
243 if (oldData.exists()) {
244 oldData.delete();
245 }
246 File newData = new File(rafDir, fileName + "Temp.data");
247 File newFileName = new File(rafDir, fileName + ".data");
248 if (newData.exists()) {
249 newData.renameTo(newFileName);
250 }
251 keyHash = keyHashTemp;
252 keyFile.reset();
253 if (keyHash.size() > 0) {
254 keyFile.writeObject(keyHash, 0);
255 }
256 }
257
258
259
260
261
262
263
264
265
266
267 CacheObject readElement(final Serializable key)
268 throws DiskCacheException {
269 DiskElementDescriptor ded = (DiskElementDescriptor) keyHash.get(key);
270 if (ded != null) {
271 Serializable readObject = dataFile.readObject(ded.pos);
272 return ((DiskCacheObject) readObject).getCacheObject();
273 }
274 throw new DiskCacheException("The object " + key
275 + " was not found in the diskCache.");
276 }
277
278
279
280
281
282
283 public final boolean update(final CacheObject cacheElement) {
284 byte[] data = CacheFileAdapter.serialize(new DiskCacheObject(cacheElement));
285 int newSize = currentSize+data.length;
286 int maxSize = cattr.getDiskSize()*1024*1024;
287 if(newSize>maxSize) {
288 return false;
289 }
290 doUpdate(cacheElement.getKey(), data);
291 currentSize=newSize;
292 return true;
293 }
294
295
296
297
298
299
300
301
302
303 public void removeAll() throws DiskCacheException {
304 try {
305 storageLock.writeLock().acquire();
306 } catch (InterruptedException e) {
307 ;
308 }
309 try {
310 if(dataFile!=null)dataFile.reset();
311 if(keyFile!=null)keyFile.reset();
312 currentSize=0;
313 } finally {
314 storageLock.writeLock().release();
315 }
316 }
317 }