Mercurial > hg > blitz_condensed
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 } |