comparison src/org/dancres/blitz/entry/WriteScheduler.java @ 0:3dc0c5604566

Initial checkin of blitz 2.0 fcs - no installer yet.
author Dan Creswell <dan.creswell@gmail.com>
date Sat, 21 Mar 2009 11:00:06 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:3dc0c5604566
1 package org.dancres.blitz.entry;
2
3 import java.io.IOException;
4
5 import java.util.HashMap;
6
7 import java.util.logging.Level;
8
9 import org.dancres.blitz.oid.OID;
10 import org.dancres.blitz.entry.ci.CacheIndexer;
11
12 /**
13 <p> Transactional writes add a further complication to the caching process
14 because, whilst they can be flushed from SleeveCache, they can't necessarily
15 be written to disk. Consider the case where a transaction starts and
16 writes an entry, other activity causes that entry to be flushed from
17 SleeveCache into the asynchronous write queue and then saved to disk.
18 The system now crashes prior to the original writing transaction issuing
19 a successful prepare. At recovery, we will have an additional entry on
20 disk unprotected by transactional locks and it would be valid for matching.
21 </p>
22
23 <p> WriteScheduler helps solve this problem by supporting "Transient"
24 EntrySleeveImpls. EntrySleeveImpls marked as transient are held in
25 WriteScheduler but not schedule to be written to disk. WriteScheduler
26 maintains an index of all Entry's to assist in searching so these
27 Transient's are available for matching. When a transaction commits, the
28 Transient mark is removed from EntrySleeveImpls (these sleeves must be
29 reloaded into SleeveCache for this to happen) and they are re-submitted to
30 WriteScheduler at which point they are scheduled for writing. </p>
31
32 <p> Thus, until a transaction is commited/aborted, any EntrySleeveImpls
33 written are marked Transient. During commit/abort, these Sleeves have the
34 mark removed and are thus eligible for writing to disk. </p>
35 */
36 class WriteScheduler {
37 private HashMap theTransients = new HashMap();
38
39 private WriteBuffer theBuffer;
40 private String theType;
41
42 WriteScheduler(EntryEditor anEditor) {
43 theType = anEditor.getType();
44 theBuffer = new WriteBuffer(anEditor);
45 }
46
47 public int getSize() {
48 throw new org.dancres.util.NotImplementedException();
49 }
50
51 void add(EntrySleeveImpl aSleeve) throws IOException {
52 /*
53 Cache has no concept of dirty, it flushes content out of a block
54 whenever it wishes to use the block for something else. So,
55 it's possible we'll be asked to flush an empty block.
56 */
57 if (aSleeve == null)
58 return;
59
60 /*
61 Whether the sleeve is dirty or not, if it's pinned we remember it.
62 Pinned implies some entity will do more with this sleeve later
63 including potentially dirtying state which might be clean at
64 this stage. Thus we must remember the state clean or dirty until
65 the pin is released.
66 */
67 SleeveState myState = aSleeve.getState();
68
69 if (myState.test(SleeveState.PINNED)) {
70 synchronized(theTransients) {
71 theTransients.put(aSleeve.getOID(), aSleeve);
72 }
73
74 return;
75 }
76
77 /*
78 Cache flushed the entry - do we need to save it?
79 */
80 if (!aSleeve.isDirty())
81 return;
82
83 boolean dontWrite = myState.test(SleeveState.NOT_ON_DISK) &&
84 myState.test(SleeveState.DELETED);
85
86 /*
87 If we're not writing this entry, clear it from the indexer now
88 otherwise leave it to the write buffer to do when it's pushed
89 the entry to disk
90 if (dontWrite) {
91 CacheIndexer.getIndexer(theType).flushed(aSleeve);
92 }
93 */
94
95 synchronized(theTransients) {
96 theTransients.remove(aSleeve.getOID());
97
98 if (!dontWrite)
99 theBuffer.add(aSleeve);
100 }
101
102 /*
103 Note we do not manage NOT_ON_DISK - this is dealt with in the
104 WriteBuffer as it's vital state it needs to determine whether or
105 not to actually update disk.
106 */
107 aSleeve.clearDirty();
108 }
109
110 EntrySleeveImpl dirtyRead(OID aUID) {
111 EntrySleeveImpl mySleeve = null;
112
113 synchronized(theTransients) {
114 mySleeve = (EntrySleeveImpl) theTransients.get(aUID);
115 }
116
117 if (mySleeve == null)
118 mySleeve = theBuffer.dirtyRead(aUID);
119
120 return mySleeve;
121 }
122 }