1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 package jdbm.recman;
50
51 import jdbm.RecordManager;
52 import jdbm.helper.CacheEvictionException;
53 import jdbm.helper.CachePolicy;
54 import jdbm.helper.CachePolicyListener;
55 import jdbm.helper.DefaultSerializer;
56 import jdbm.helper.Serializer;
57 import jdbm.helper.WrappedRuntimeException;
58
59 import java.io.IOException;
60 import java.util.Enumeration;
61
62
63
64
65
66
67
68
69 public class CacheRecordManager
70 implements RecordManager
71 {
72
73
74
75
76 protected RecordManager _recman;
77
78
79
80
81
82 protected CachePolicy _cache;
83
84
85
86
87
88
89
90
91
92 public CacheRecordManager( RecordManager recman, CachePolicy cache )
93 {
94 if ( recman == null ) {
95 throw new IllegalArgumentException( "Argument 'recman' is null" );
96 }
97 if ( cache == null ) {
98 throw new IllegalArgumentException( "Argument 'cache' is null" );
99 }
100 _recman = recman;
101 _cache = cache;
102
103 _cache.addListener( new CacheListener() );
104 }
105
106
107
108
109
110
111
112
113 public RecordManager getRecordManager()
114 {
115 return _recman;
116 }
117
118
119
120
121
122
123
124
125 public CachePolicy getCachePolicy()
126 {
127 return _cache;
128 }
129
130
131
132
133
134
135
136
137
138 public long insert( Object obj )
139 throws IOException
140 {
141 return insert( obj, DefaultSerializer.INSTANCE );
142 }
143
144
145
146
147
148
149
150
151
152
153 public synchronized long insert( Object obj, Serializer serializer )
154 throws IOException
155 {
156 checkIfClosed();
157
158 long recid = _recman.insert( obj, serializer );
159 try {
160 _cache.put( new Long( recid ), new CacheEntry( recid, obj, serializer, false ) );
161 } catch ( CacheEvictionException except ) {
162 throw new WrappedRuntimeException( except );
163 }
164 return recid;
165 }
166
167
168
169
170
171
172
173
174 public synchronized void delete( long recid )
175 throws IOException
176 {
177 checkIfClosed();
178
179 _recman.delete( recid );
180 _cache.remove( new Long( recid ) );
181 }
182
183
184
185
186
187
188
189
190
191 public void update( long recid, Object obj )
192 throws IOException
193 {
194 update( recid, obj, DefaultSerializer.INSTANCE );
195 }
196
197
198
199
200
201
202
203
204
205
206 public synchronized void update( long recid, Object obj,
207 Serializer serializer )
208 throws IOException
209 {
210 CacheEntry entry;
211 Long id;
212
213 checkIfClosed();
214
215 id = new Long( recid );
216 try {
217 entry = (CacheEntry) _cache.get( id );
218 if ( entry != null ) {
219
220 entry._obj = obj;
221 entry._serializer = serializer;
222 entry._isDirty = true;
223 } else {
224 _cache.put( id, new CacheEntry( recid, obj, serializer, true ) );
225 }
226 } catch ( CacheEvictionException except ) {
227 throw new IOException( except.getMessage() );
228 }
229 }
230
231
232
233
234
235
236
237
238
239 public Object fetch( long recid )
240 throws IOException
241 {
242 return fetch( recid, DefaultSerializer.INSTANCE );
243 }
244
245
246
247
248
249
250
251
252
253
254 public synchronized Object fetch( long recid, Serializer serializer )
255 throws IOException
256 {
257 checkIfClosed();
258
259 Long id = new Long( recid );
260 CacheEntry entry = (CacheEntry) _cache.get( id );
261 if ( entry == null ) {
262 entry = new CacheEntry( recid, null, serializer, false );
263 entry._obj = _recman.fetch( recid, serializer );
264 try {
265 _cache.put( id, entry );
266 } catch ( CacheEvictionException except ) {
267 throw new WrappedRuntimeException( except );
268 }
269 }
270 return entry._obj;
271 }
272
273
274
275
276
277
278
279 public synchronized void close()
280 throws IOException
281 {
282 checkIfClosed();
283
284 updateCacheEntries();
285 _recman.close();
286 _recman = null;
287 _cache = null;
288 }
289
290
291
292
293
294
295
296
297 public synchronized int getRootCount()
298 {
299 checkIfClosed();
300
301 return _recman.getRootCount();
302 }
303
304
305
306
307
308
309
310 public synchronized long getRoot( int id )
311 throws IOException
312 {
313 checkIfClosed();
314
315 return _recman.getRoot( id );
316 }
317
318
319
320
321
322
323
324 public synchronized void setRoot( int id, long rowid )
325 throws IOException
326 {
327 checkIfClosed();
328
329 _recman.setRoot( id, rowid );
330 }
331
332
333
334
335
336 public synchronized void commit()
337 throws IOException
338 {
339 checkIfClosed();
340 updateCacheEntries();
341 _recman.commit();
342 }
343
344
345
346
347
348 public synchronized void rollback()
349 throws IOException
350 {
351 checkIfClosed();
352
353 _recman.rollback();
354
355
356
357 _cache.removeAll();
358 }
359
360
361
362
363
364
365 public synchronized long getNamedObject( String name )
366 throws IOException
367 {
368 checkIfClosed();
369
370 return _recman.getNamedObject( name );
371 }
372
373
374
375
376
377 public synchronized void setNamedObject( String name, long recid )
378 throws IOException
379 {
380 checkIfClosed();
381
382 _recman.setNamedObject( name, recid );
383 }
384
385
386
387
388
389
390 private void checkIfClosed()
391 throws IllegalStateException
392 {
393 if ( _recman == null ) {
394 throw new IllegalStateException( "RecordManager has been closed" );
395 }
396 }
397
398
399
400
401
402 protected void updateCacheEntries()
403 throws IOException
404 {
405 Enumeration enume = _cache.elements();
406 while ( enume.hasMoreElements() ) {
407 CacheEntry entry = (CacheEntry) enume.nextElement();
408 if ( entry._isDirty ) {
409 _recman.update( entry._recid, entry._obj, entry._serializer );
410 entry._isDirty = false;
411 }
412 }
413 }
414
415
416 private class CacheEntry
417 {
418
419 long _recid;
420 Object _obj;
421 Serializer _serializer;
422 boolean _isDirty;
423
424 CacheEntry( long recid, Object obj, Serializer serializer, boolean isDirty )
425 {
426 _recid = recid;
427 _obj = obj;
428 _serializer = serializer;
429 _isDirty = isDirty;
430 }
431
432 }
433
434 private class CacheListener
435 implements CachePolicyListener
436 {
437
438
439
440
441
442
443 public void cacheObjectEvicted( Object obj )
444 throws CacheEvictionException
445 {
446 CacheEntry entry = (CacheEntry) obj;
447 if ( entry._isDirty ) {
448 try {
449 _recman.update( entry._recid, entry._obj, entry._serializer );
450 } catch ( IOException except ) {
451 throw new CacheEvictionException( except );
452 }
453 }
454 }
455
456 }
457 }