1 package org.apache.jcs.auxiliary.disk.block;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.BufferedInputStream;
23 import java.io.BufferedOutputStream;
24 import java.io.EOFException;
25 import java.io.File;
26 import java.io.FileInputStream;
27 import java.io.FileOutputStream;
28 import java.io.IOException;
29 import java.io.ObjectInputStream;
30 import java.io.ObjectOutputStream;
31 import java.io.Serializable;
32 import java.util.HashMap;
33 import java.util.Map;
34 import java.util.Set;
35
36 import org.apache.commons.logging.Log;
37 import org.apache.commons.logging.LogFactory;
38 import org.apache.jcs.auxiliary.disk.LRUMapJCS;
39 import org.apache.jcs.utils.timing.ElapsedTimer;
40
41
42
43
44
45
46 public class BlockDiskKeyStore<K extends Serializable>
47 {
48
49 protected static final Log log = LogFactory.getLog( BlockDiskKeyStore.class );
50
51
52 private final BlockDiskCacheAttributes blockDiskCacheAttributes;
53
54
55 private Map<K, int[]> keyHash;
56
57
58 private final File keyFile;
59
60
61 protected final String logCacheName;
62
63
64 private final String fileName;
65
66
67 private final int maxKeySize;
68
69
70 protected final BlockDiskCache<K, ?> blockDiskCache;
71
72
73
74
75
76
77
78 public BlockDiskKeyStore( BlockDiskCacheAttributes cacheAttributes,
79 BlockDiskCache<K, ?> blockDiskCache)
80 {
81 this.blockDiskCacheAttributes = cacheAttributes;
82 this.logCacheName = "Region [" + this.blockDiskCacheAttributes.getCacheName() + "] ";
83 this.fileName = this.blockDiskCacheAttributes.getCacheName();
84 this.maxKeySize = cacheAttributes.getMaxKeySize();
85 this.blockDiskCache = blockDiskCache;
86
87 String rootDirName = cacheAttributes.getDiskPath();
88 File rootDirectory = new File( rootDirName );
89 rootDirectory.mkdirs();
90
91 if ( log.isInfoEnabled() )
92 {
93 log.info( logCacheName + "Cache file root directory [" + rootDirName + "]" );
94 }
95
96 this.keyFile = new File( rootDirectory, fileName + ".key" );
97
98 if ( log.isInfoEnabled() )
99 {
100 log.info( logCacheName + "Key File [" + this.keyFile.getAbsolutePath() + "]" );
101 }
102
103 if ( keyFile.length() > 0 )
104 {
105 loadKeys();
106
107 }
108 else
109 {
110 initKeyMap();
111 }
112 }
113
114
115
116
117
118 protected void saveKeys()
119 {
120 try
121 {
122 ElapsedTimer timer = new ElapsedTimer();
123 int numKeys = keyHash.size();
124 if ( log.isInfoEnabled() )
125 {
126 log.info( logCacheName + "Saving keys to [" + this.keyFile.getAbsolutePath() + "], key count ["
127 + numKeys + "]" );
128 }
129
130 synchronized (keyFile)
131 {
132 FileOutputStream fos = new FileOutputStream( keyFile );
133 BufferedOutputStream bos = new BufferedOutputStream( fos, 65536 );
134 ObjectOutputStream oos = new ObjectOutputStream( bos );
135 try
136 {
137
138 for (Map.Entry<K, int[]> entry : keyHash.entrySet())
139 {
140 BlockDiskElementDescriptor<K> descriptor = new BlockDiskElementDescriptor<K>();
141 descriptor.setKey( entry.getKey() );
142 descriptor.setBlocks( entry.getValue() );
143
144 oos.writeObject( descriptor );
145 }
146 }
147 finally
148 {
149 oos.flush();
150 oos.close();
151 }
152 }
153
154 if ( log.isInfoEnabled() )
155 {
156 log.info( logCacheName + "Finished saving keys. It took " + timer.getElapsedTimeString() + " to store "
157 + numKeys + " keys. Key file length [" + keyFile.length() + "]" );
158 }
159 }
160 catch ( IOException e )
161 {
162 log.error( logCacheName + "Problem storing keys.", e );
163 }
164 }
165
166
167
168
169 protected void reset()
170 {
171 synchronized (keyFile)
172 {
173 clearMemoryMap();
174 saveKeys();
175 }
176
177 }
178
179
180
181
182 protected void clearMemoryMap()
183 {
184 this.keyHash.clear();
185 }
186
187
188
189
190 private void initKeyMap()
191 {
192 keyHash = null;
193 if ( maxKeySize >= 0 )
194 {
195 keyHash = new LRUMap( maxKeySize );
196 if ( log.isInfoEnabled() )
197 {
198 log.info( logCacheName + "Set maxKeySize to: '" + maxKeySize + "'" );
199 }
200 }
201 else
202 {
203
204 keyHash = new HashMap<K, int[]>();
205
206 if ( log.isInfoEnabled() )
207 {
208 log.info( logCacheName + "Set maxKeySize to unlimited'" );
209 }
210 }
211 }
212
213
214
215
216
217 protected void loadKeys()
218 {
219 if ( log.isInfoEnabled() )
220 {
221 log.info( logCacheName + "Loading keys for " + keyFile.toString() );
222 }
223
224 try
225 {
226
227 initKeyMap();
228
229 HashMap<K, int[]> keys = new HashMap<K, int[]>();
230
231 synchronized (keyFile)
232 {
233 FileInputStream fis = new FileInputStream( keyFile );
234 BufferedInputStream bis = new BufferedInputStream( fis );
235 ObjectInputStream ois = new ObjectInputStream( bis );
236 try
237 {
238 while ( true )
239 {
240 @SuppressWarnings("unchecked")
241 BlockDiskElementDescriptor<K> descriptor = (BlockDiskElementDescriptor<K>) ois.readObject();
242 if ( descriptor != null )
243 {
244 keys.put( descriptor.getKey(), descriptor.getBlocks() );
245 }
246 }
247 }
248 catch ( EOFException eof )
249 {
250
251 }
252 finally
253 {
254 ois.close();
255 }
256 }
257
258 if ( !keys.isEmpty() )
259 {
260 keyHash.putAll( keys );
261
262 if ( log.isDebugEnabled() )
263 {
264 log.debug( logCacheName + "Found " + keys.size() + " in keys file." );
265 }
266
267 if ( log.isInfoEnabled() )
268 {
269 log.info( logCacheName + "Loaded keys from [" + fileName + "], key count: " + keyHash.size()
270 + "; up to " + maxKeySize + " will be available." );
271 }
272 }
273 }
274 catch ( Exception e )
275 {
276 log.error( logCacheName + "Problem loading keys for file " + fileName, e );
277 }
278 }
279
280
281
282
283
284
285 public Set<Map.Entry<K, int[]>> entrySet()
286 {
287 return this.keyHash.entrySet();
288 }
289
290
291
292
293
294
295 public Set<K> keySet()
296 {
297 return this.keyHash.keySet();
298 }
299
300
301
302
303
304
305 public int size()
306 {
307 return this.keyHash.size();
308 }
309
310
311
312
313
314
315
316 public int[] get( K key )
317 {
318 return this.keyHash.get( key );
319 }
320
321
322
323
324
325
326
327 public void put( K key, int[] value )
328 {
329 this.keyHash.put( key, value );
330 }
331
332
333
334
335
336
337
338 public int[] remove( K key )
339 {
340 return this.keyHash.remove( key );
341 }
342
343
344
345
346
347 public class LRUMap
348 extends LRUMapJCS<K, int[]>
349 {
350
351 private static final long serialVersionUID = 4955079991472142198L;
352
353
354
355
356 public String tag = "orig";
357
358
359
360
361 public LRUMap()
362 {
363 super();
364 }
365
366
367
368
369 public LRUMap( int maxKeySize )
370 {
371 super( maxKeySize );
372 }
373
374
375
376
377
378
379
380
381 @Override
382 protected void processRemovedLRU( K key, int[] value )
383 {
384 blockDiskCache.freeBlocks( value );
385 if ( log.isDebugEnabled() )
386 {
387 log.debug( logCacheName + "Removing key: [" + key + "] from key store." );
388 log.debug( logCacheName + "Key store size: [" + super.size() + "]." );
389 }
390 }
391 }
392 }