Mercurial > hg > blitz_condensed
comparison src/org/dancres/blitz/EntryLeaseHandlerImpl.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; | |
2 | |
3 import java.io.IOException; | |
4 | |
5 import java.util.logging.Level; | |
6 | |
7 import net.jini.core.lease.UnknownLeaseException; | |
8 import net.jini.core.lease.LeaseDeniedException; | |
9 | |
10 import net.jini.core.transaction.TransactionException; | |
11 | |
12 import org.dancres.blitz.disk.DiskTxn; | |
13 | |
14 import org.dancres.blitz.lease.SpaceUID; | |
15 import org.dancres.blitz.lease.LeaseHandler; | |
16 import org.dancres.blitz.lease.LeaseBounds; | |
17 | |
18 import org.dancres.blitz.entry.EntryRepositoryFactory; | |
19 import org.dancres.blitz.entry.EntryRepository; | |
20 | |
21 import org.dancres.blitz.txn.TxnId; | |
22 import org.dancres.blitz.txn.TxnOp; | |
23 import org.dancres.blitz.txn.TxnState; | |
24 import org.dancres.blitz.txn.TxnManager; | |
25 | |
26 import org.dancres.blitz.txnlock.*; | |
27 | |
28 import org.dancres.blitz.task.Task; | |
29 | |
30 import org.dancres.blitz.oid.OID; | |
31 | |
32 import org.dancres.blitz.util.Time; | |
33 | |
34 public class EntryLeaseHandlerImpl implements LeaseHandler { | |
35 public boolean recognizes(SpaceUID aUID) { | |
36 return (aUID instanceof SpaceEntryUID); | |
37 } | |
38 | |
39 public long renew(SpaceUID aUID, long aLeaseDuration) | |
40 throws UnknownLeaseException, LeaseDeniedException, IOException { | |
41 | |
42 long myDuration = LeaseBounds.boundWrite(aLeaseDuration); | |
43 long myExpiry = Time.getAbsoluteTime(myDuration); | |
44 | |
45 boolean myResult; | |
46 | |
47 String myType = ((SpaceEntryUID) aUID).getType(); | |
48 OID myOID = ((SpaceEntryUID) aUID).getOID(); | |
49 | |
50 DiskTxn myTxn = DiskTxn.newTxn(); | |
51 | |
52 try { | |
53 myResult = | |
54 EntryRepositoryFactory.get().find(myType).renew(myOID, | |
55 myExpiry); | |
56 } finally { | |
57 myTxn.commit(); | |
58 } | |
59 | |
60 if (!myResult) | |
61 throw new UnknownLeaseException(); | |
62 | |
63 LeaseRenewal myRenewal = new LeaseRenewal(myType, myOID, myExpiry); | |
64 | |
65 // Now figure out when we're gonna log this change | |
66 LockMgr myMgr = TxnLocks.getLockMgr(myType); | |
67 TxnLock myLock = myMgr.getLock(myOID); | |
68 TxnId myWriter = null; | |
69 | |
70 synchronized(myLock) { | |
71 myWriter = myLock.getWriter(); | |
72 } | |
73 | |
74 /* | |
75 If there is a writer present, the lease renewal should only be issued | |
76 on completion of the associated transaction. | |
77 | |
78 This ordering is critical for correct recovery. If we immediately | |
79 write the lease renewal it will appear in the logs before the | |
80 transaction that write's the Entry. Thus, if the Entry was never | |
81 flushed to disk, it won't be present in the cache and the lease | |
82 renewal will fail whilst apparently having succeeded from the user's | |
83 perspective. | |
84 */ | |
85 if (myWriter == null) { | |
86 log(myRenewal); | |
87 } else { | |
88 TxnState myState = null; | |
89 | |
90 try { | |
91 myState = TxnManager.get().getTxnFor(myWriter); | |
92 } catch (Exception anE) { | |
93 /* | |
94 It's either UnknownTransaction or Remote - in this case | |
95 as there's a writer, it can't be Remote so it can only be | |
96 UnknownTransaction which means the transaction completed | |
97 before we tag the lease renewal onto it. | |
98 */ | |
99 } | |
100 | |
101 if (myState == null) { | |
102 // Too late, transaction is gone | |
103 log(myRenewal); | |
104 } else { | |
105 try { | |
106 myState.add(myRenewal); | |
107 } catch (TransactionException aTE) { | |
108 // Couldn't tag it onto the transaction - must have | |
109 // resolved | |
110 log(myRenewal); | |
111 } | |
112 } | |
113 } | |
114 | |
115 return myDuration; | |
116 } | |
117 | |
118 public void cancel(SpaceUID aUID) | |
119 throws UnknownLeaseException, IOException { | |
120 | |
121 boolean myResult; | |
122 | |
123 String myType = ((SpaceEntryUID) aUID).getType(); | |
124 OID myOID = ((SpaceEntryUID) aUID).getOID(); | |
125 | |
126 DiskTxn myTxn = DiskTxn.newTxn(); | |
127 | |
128 try { | |
129 myResult = | |
130 EntryRepositoryFactory.get().find(myType).cancel(myOID); | |
131 } finally { | |
132 myTxn.commit(); | |
133 } | |
134 | |
135 if (!myResult) | |
136 throw new UnknownLeaseException(); | |
137 | |
138 LeaseCancel myCancel = new LeaseCancel(myType, myOID); | |
139 | |
140 // Now figure out when we're gonna log this change | |
141 LockMgr myMgr = TxnLocks.getLockMgr(myType); | |
142 TxnLock myLock = myMgr.getLock(myOID); | |
143 TxnId myWriter = null; | |
144 | |
145 synchronized(myLock) { | |
146 myWriter = myLock.getWriter(); | |
147 } | |
148 | |
149 /* | |
150 If there is a writer present, the lease cancel should only be issued | |
151 on completion of the associated transaction. | |
152 | |
153 This ordering is critical for correct recovery. If we immediately | |
154 write the lease cancel it will appear in the logs before the | |
155 transaction that write's the Entry. Thus, if the Entry was never | |
156 flushed to disk, it won't be present in the cache and the lease | |
157 cancel will fail whilst apparently having succeeded from the user's | |
158 perspective. | |
159 */ | |
160 if (myWriter == null) { | |
161 log(myCancel); | |
162 } else { | |
163 TxnState myState = null; | |
164 | |
165 try { | |
166 myState = TxnManager.get().getTxnFor(myWriter); | |
167 } catch (Exception anE) { | |
168 /* | |
169 It's either UnknownTransaction or Remote - in this case | |
170 as there's a writer, it can't be Remote so it can only be | |
171 UnknownTransaction which means the transaction completed | |
172 before we tag the lease cancel onto it. | |
173 */ | |
174 } | |
175 | |
176 if (myState == null) { | |
177 // Too late, transaction is gone | |
178 log(myCancel); | |
179 } else { | |
180 try { | |
181 myState.add(myCancel); | |
182 } catch (TransactionException aTE) { | |
183 // Couldn't tag it onto the transaction - must have | |
184 // resolved | |
185 log(myCancel); | |
186 } | |
187 } | |
188 } | |
189 } | |
190 | |
191 private void log(TxnOp anAction) throws IOException { | |
192 try { | |
193 TxnManager.get().log(anAction); | |
194 } catch (TransactionException aTE) { | |
195 throw new IOException("Failed to log action"); | |
196 } | |
197 } | |
198 | |
199 private static final class LeaseRenewal implements TxnOp { | |
200 | |
201 private String theType; | |
202 private OID theOID; | |
203 private long theExpiry; | |
204 | |
205 LeaseRenewal(String aType, OID aOID, long anExpiry) { | |
206 theType = aType; | |
207 theOID = aOID; | |
208 theExpiry = anExpiry; | |
209 } | |
210 | |
211 public void restore(TxnState aState) throws IOException { | |
212 EntryRepository myRepos = | |
213 EntryRepositoryFactory.get().get(theType); | |
214 | |
215 DiskTxn myTxn = DiskTxn.newTxn(); | |
216 | |
217 try { | |
218 myRepos.renew(theOID, theExpiry); | |
219 } catch (IOException anIOE) { | |
220 } finally { | |
221 myTxn.commit(); | |
222 } | |
223 } | |
224 | |
225 public void commit(TxnState aState) throws IOException { | |
226 // Nothing to do - already applied | |
227 } | |
228 | |
229 public void abort(TxnState aState) throws IOException { | |
230 // Never called | |
231 } | |
232 | |
233 public String toString() { | |
234 return " ER : " + theType + " : " + theOID + " : " + theExpiry; | |
235 } | |
236 } | |
237 | |
238 private static final class LeaseCancel implements TxnOp { | |
239 private String theType; | |
240 private OID theOID; | |
241 | |
242 LeaseCancel(String aType, OID aOID) { | |
243 theType = aType; | |
244 theOID = aOID; | |
245 } | |
246 | |
247 public void restore(TxnState aState) throws IOException { | |
248 EntryRepository myRepos = | |
249 EntryRepositoryFactory.get().get(theType); | |
250 | |
251 DiskTxn myTxn = DiskTxn.newTxn(); | |
252 | |
253 try { | |
254 myRepos.cancel(theOID); | |
255 } catch (IOException anIOE) { | |
256 } finally { | |
257 myTxn.commit(); | |
258 } | |
259 } | |
260 | |
261 public void commit(TxnState aState) throws IOException { | |
262 // Nothing to do - already applied | |
263 } | |
264 | |
265 public void abort(TxnState aState) throws IOException { | |
266 // Never called | |
267 } | |
268 | |
269 public String toString() { | |
270 return " EC : " + theType + " : " + theOID; | |
271 } | |
272 } | |
273 | |
274 private static final class LogTask implements Task { | |
275 private TxnOp theAction; | |
276 | |
277 LogTask(TxnOp anAction) { | |
278 theAction = anAction; | |
279 } | |
280 | |
281 public void run() { | |
282 try { | |
283 TxnManager.get().log(theAction); | |
284 } catch (Exception anException) { | |
285 SpaceImpl.theLogger.log(Level.SEVERE, | |
286 "Failed to log lease action", | |
287 anException); | |
288 } | |
289 } | |
290 } | |
291 } |