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 }