KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > quadcap > sql > lock > LockManager


1 package com.quadcap.sql.lock;
2
3 /* Copyright 1999 - 2003 Quadcap Software. All rights reserved.
4  *
5  * This software is distributed under the Quadcap Free Software License.
6  * This software may be used or modified for any purpose, personal or
7  * commercial. Open Source redistributions are permitted. Commercial
8  * redistribution of larger works derived from, or works which bundle
9  * this software requires a "Commercial Redistribution License"; see
10  * http://www.quadcap.com/purchase.
11  *
12  * Redistributions qualify as "Open Source" under one of the following terms:
13  *
14  * Redistributions are made at no charge beyond the reasonable cost of
15  * materials and delivery.
16  *
17  * Redistributions are accompanied by a copy of the Source Code or by an
18  * irrevocable offer to provide a copy of the Source Code for up to three
19  * years at the cost of materials and delivery. Such redistributions
20  * must allow further use, modification, and redistribution of the Source
21  * Code under substantially the same terms as this license.
22  *
23  * Redistributions of source code must retain the copyright notices as they
24  * appear in each source code file, these license terms, and the
25  * disclaimer/limitation of liability set forth as paragraph 6 below.
26  *
27  * Redistributions in binary form must reproduce this Copyright Notice,
28  * these license terms, and the disclaimer/limitation of liability set
29  * forth as paragraph 6 below, in the documentation and/or other materials
30  * provided with the distribution.
31  *
32  * The Software is provided on an "AS IS" basis. No warranty is
33  * provided that the Software is free of defects, or fit for a
34  * particular purpose.
35  *
36  * Limitation of Liability. Quadcap Software shall not be liable
37  * for any damages suffered by the Licensee or any third party resulting
38  * from use of the Software.
39  */

40
41 import java.util.ArrayList JavaDoc;
42 import java.util.HashMap JavaDoc;
43 import java.util.Iterator JavaDoc;
44
45 import java.util.Comparator JavaDoc;
46
47 import java.sql.SQLException JavaDoc;
48
49 import javax.concurrent.Sync;
50
51 import com.quadcap.util.Debug;
52 import com.quadcap.util.Util;
53
54 import com.quadcap.util.ConfigNumber;
55
56
57 /**
58  * Manage a hierarchical set of read/write/intention locks.
59  *
60  * @author Stan Bailes
61  */

62 public class LockManager {
63     //#ifdef TRACE
64
/*{com.quadcap.qed.Trace-vars.xml-1064}
65      * <config-var>
66      * <config-name>qed.trace.locks</config-name>
67      * <config-dflt>0</config-dflt>
68      * <config-desc>
69      * <pre>
70      * bit 0: verbose lock tracing
71      * bit 1: lock tracing
72      * bit 2: really verbose lock tracing
73      * bit 3: transactions
74      * bit 4: dump locktable every 30 seconds
75      * </pre>
76      * </config-desc>
77      * </config-var>
78      */

79     protected static final
80     ConfigNumber trace = ConfigNumber.find("qed.trace.locks", "0");
81     //#endif
82

83     protected static final
84     ConfigNumber lockTimeout = ConfigNumber.find("qed.lock.Timeout", "60");
85
86     private long transCount = 1;
87
88     final Object JavaDoc locksLock = new Object JavaDoc();
89
90     /** Pool of lock objects */
91     LockPool locks = new LockPool();
92
93     /** Pool of 'held' locks */
94     HeldLockPool held = new HeldLockPool();
95
96     /** Temp held lock object used for searching */
97     HeldLock tmpHeld = null;
98
99     /** Pool of transaction objects. */
100     TransactionPool transactions =new TransactionPool();
101
102     /** held locks sorted by transaction */
103     SortedArray byTrans;
104     SortedArrayIterator byTransIter;
105     
106     /**
107      * Constructor
108      */

109     public LockManager() {
110         Comparator JavaDoc compare = new Comparator JavaDoc() {
111             public int compare(Object JavaDoc a, Object JavaDoc b) {
112                 return HeldLock.compare((HeldLock)a, (HeldLock)b);
113             }
114         };
115         byTrans = new SortedArray(compare);
116         byTransIter = new SortedArrayIterator(byTrans);
117         tmpHeld = held.get(null, null, LockMode.IX);
118         final LockManager lockMgr = this;
119
120         //#ifdef DEBUG
121
if (trace.bit(4)) {
122             Thread JavaDoc t = new Thread JavaDoc() {
123                 public void run() {
124                     setName("LockManager Debug");
125                     Debug.println("Lock dump thread running");
126                     while (lockMgr != null) {
127                         try {
128                             Thread.sleep(10000);
129                             synchronized (lockMgr.locksLock) {
130                                 if (lockMgr.byTrans.size() > 0) {
131                                     Debug.println("DUMP: " +
132                                                   lockMgr.toString());
133                                 }
134                             }
135                         } catch (Throwable JavaDoc e) {
136                             Debug.print(e);
137                         }
138                     }
139                 }
140                 };
141             t.setDaemon(true);
142             t.start();
143         }
144         //#endif
145
}
146     
147     /**
148      * Allocate a new Transaction. All lock operations are performed
149      * on behalf of a Transaction.
150      */

151     public final Transaction getTransaction(long transId) {
152     synchronized (locksLock) {
153             Transaction t = (Transaction)transactions.get(transId);
154             //#ifdef DEBUG
155
if (trace.bit(3)) {
156                 Debug.println("getTransaction() = " + t);
157                 if (trace.bit(2)) {
158                     Debug.println("this = " + this);
159                 }
160             }
161             //#endif
162
return t;
163         }
164     }
165
166     /**
167      * Find an existing transaction. Return null if the specified
168      * transaction doesn't exist.
169      */

170     public Transaction findTransaction(long transId) {
171         return transactions.find(transId);
172     }
173
174     /**
175      * End a transaction, releasing all of its locks
176      */

177     public void releaseTransaction(Transaction t) {
178         //#ifdef DEBUG
179
if (trace.bit(3)) {
180             Debug.println("releaseTransaction(" + t + ")");
181             if (trace.bit(2)) {
182                 Debug.println("this = " + this);
183             }
184         }
185         //#endif
186
synchronized (locksLock) {
187             try {
188                 // for each lock held by the transaction
189
Iterator JavaDoc tlocks = locksForTransaction(t);
190                 //#ifdef TRACE
191
if (trace.bit(1)) {
192                     Debug.println("releaseTransaction(" + t + ") [1]");
193                 }
194                 //#endif
195
//Debug.println("releaseTransaction(" + t + "), held locks = " + byTrans);
196
while (tlocks.hasNext()) {
197                     HeldLock h = (HeldLock)tlocks.next();
198                     boolean saveMe = false;
199                     if (h.trans.getTransactionId() < t.getTransactionId()) continue;
200                     if (h.trans.getTransactionId() > t.getTransactionId()) break;
201                     //Debug.println(" Releasing: " + h);
202
Lock lock = h.lock;
203                     int mode = h.mode;
204                     tlocks.remove();
205                     if (h.mode == LockMode.NL) continue;
206                     //#ifdef TRACE
207
if (trace.bit(1)) {
208                         Debug.println("[release] lock(" + t + ", " + lock + " in " +
209                             LockMode.toString(mode));
210                     }
211                     //#endif
212
lock.decrHeldCount(mode);
213                     Transaction w = lock.headWaitQueue();
214                     while (w != null && w.getWaitMode() == LockMode.NL) {
215                         lock.popWaitQueue();
216                         w = lock.headWaitQueue();
217                     }
218                     if (w != null && !w.equals(t)) {
219                         if (lock.couldLock(w.getWaitMode())) {
220                             lock.popWaitQueue();
221                             HeldLock wl = w.getWait();
222                             //#ifdef TRACE
223
if (trace.bit(1)) {
224                                 Debug.println("" + t + " releasing " + lock +
225                                               ", waking " + wl);
226                             }
227                             //#endif
228

229                             wl.mode = wl.waitMode;
230                             acquireLock(wl);
231                             w.clearWait();
232                             try {
233                                 Sync c = w.getSync();
234                                 c.release();
235                             } catch (InterruptedException JavaDoc ex) {
236                             }
237                         }
238                     }
239                     held.release(h);
240                 }
241             } finally {
242                 transactions.release(t);
243             }
244             //#ifdef TRACE
245
if (trace.bit(1)) {
246                 Debug.println("releaseTransaction(" + t + ") done");
247                 if (trace.bit(2)) {
248                     Debug.println("this = " + this);
249                 }
250             }
251             //#endif
252
}
253     }
254
255     /**
256      * Return an iterator over all active transactions
257      */

258     public Iterator JavaDoc transactions() {
259         return transactions.iterator();
260     }
261
262     /**
263      * Return an Iterator over the held locks positioned at the first
264      * lock owned by transaction 't'.
265      */

266     final Iterator JavaDoc locksForTransaction(Transaction t) {
267         tmpHeld.trans = t;
268         tmpHeld.lock = null;
269         byTransIter.position(tmpHeld);
270         return byTransIter;
271     }
272
273     final HeldLock getLockForTransaction(Transaction t, Lock lock) {
274         tmpHeld.trans = t;
275         tmpHeld.lock = lock;
276         tmpHeld.mode = LockMode.NL;
277         byTransIter.position(tmpHeld);
278         while (byTransIter.hasNext()) {
279             HeldLock h = (HeldLock)byTransIter.next();
280             if (t.getTransactionId() > h.trans.getTransactionId()) {
281                 return null;
282             }
283             if (t.getTransactionId() == h.trans.getTransactionId() &&
284                 lock.hashCode() == h.lock.hashCode()) {
285                 return h;
286             }
287         }
288         return null;
289     }
290     
291     /**
292      * Instantiate the specified lock on behalf of transaction 't',
293      * which may or may not already have this lock.
294      */

295     public final Lock getLock(Transaction t, Lock parent, String JavaDoc name,
296                               int mode)
297         throws SQLException JavaDoc
298     {
299     HeldLock h = null;
300         boolean newLock = false;
301         Sync s = null;
302         //#ifdef TRACE
303
if (trace.bit(1)) {
304             Debug.println("---- getLock(" + t + ", " + parent + ", " +
305                           name + ", " + LockMode.toString(mode) + ")");
306         }
307         //#endif
308
try {
309             synchronized (locksLock) {
310                 Lock lock = locks.get(parent, name);
311                 checkParentsLockMode(t, lock, mode);
312
313                 h = getLockForTransaction(t, lock);
314                 if (h != null) {
315                     //Debug.println(" holding: " + h);
316
// 't' already has 'lock'; check the mode.
317
if (LockMode.implies(h.mode, mode)) {
318                         //Debug.println(" Already have: " + h);
319
return h.lock;
320                     }
321                     if (LockMode.implies(mode, h.mode)) {
322                         if (lock.couldPromote(h.mode, mode)) {
323                             promoteLock(h, mode);
324                             //Debug.println(" Promoted: " + h);
325
return h.lock;
326                         } else {
327                             //Debug.println(" Can't promote: " + h + ": " + lock.dump());
328
}
329                     } else {
330                         throw new RuntimeException JavaDoc("Transaction " + t +
331                                                    " has lock " + lock +
332                                                    " in mode " +
333                                                    LockMode.toString(h.mode) +
334                                                    ", trying to lock now in mode "+
335                                                    LockMode.toString(mode));
336                     }
337                 } else {
338                     newLock = true;
339                     //Debug.println(" Don't have it yet");
340
// 't' does not have 'lock' in any way
341
h = held.get(t, lock, mode);
342                     if (lock.couldLock(mode) && !lock.hasWaiters()) {
343                         acquireLock(h);
344                         //Debug.println(" Got lock: " + h);
345
return h.lock;
346                     }
347                 }
348                 h.setWaitMode(mode);
349                 try {
350                     s = waitForLock(h);
351                 } catch (InterruptedException JavaDoc ex) {
352                     throw new SQLException JavaDoc("Interrupted trying to get lock: " +
353                                            name);
354                 }
355                     
356             }
357             //#ifdef DEBUG
358
if (trace.bit(0)) {
359                 Debug.println(" Waiting for: " + h);
360                 if (trace.bit(2)) {
361                     Debug.println(byTrans.toString());
362                 }
363             }
364             //#endif
365
boolean got = false;
366             try {
367                 got = s.attempt(lockTimeout.longValue() * 1000);
368             } catch (InterruptedException JavaDoc ex) { }
369             if (!got) {
370                 Debug.println("Lock timed out: " + name + " after " +
371                               lockTimeout.longValue() +
372                               " seconds");
373                 Debug.println("LockManager: " + this);
374 // try {
375
// got = s.attempt(lockTimeout.longValue() * 1000);
376
// } catch (InterruptedException ex) {}
377
if (!got) {
378                     t.setWait(null);
379                     if (newLock) {
380                         held.release(h);
381                         newLock = false;
382                     }
383                     throw new SQLException JavaDoc("Timed out trying to get lock: " +
384                                            name + " for [T:" + t + "]");
385                 }
386             }
387             //#ifdef DEBUG
388
if (trace.bit(0)) {
389                 Debug.println(" Wait done for: " + h);
390             }
391             //#endif
392
return h.lock;
393         } finally {
394             //#ifdef TRACE
395
if (trace.bit(1)) {
396                 Debug.println("getLock(" + name + ") done");
397             }
398             //#endif
399
}
400     }
401         
402     /**
403      * We're in the critical section still
404      */

405     final Sync waitForLock(HeldLock h) throws InterruptedException JavaDoc {
406         final Transaction t = h.trans;
407         //#ifdef PARANOID
408
//- if (t.getWait() != null)
409
//- throw new RuntimeException("Transaction already waiting");
410
//#endif
411
h.lock.addWaitQueue(t);
412     t.setWait(h);
413     return t.getSync();
414     }
415
416     /**
417      * Ensure that the lock's parent(s) are properly locked, to enable
418      * locking <code>lock</code> in the specified mode.
419      */

420     final void checkParentsLockMode(Transaction t, Lock lock, int mode) {
421     Lock p = lock.getParent();
422         if (p != null) {
423             HeldLock h = getLockForTransaction(t, p);
424             if (h == null) {
425                 //#ifdef DEBUG
426
Debug.println("Held: " + byTrans + ", lock = " + lock);
427                 Debug.println("LockManager: " + this);
428                 //#endif
429
throw new RuntimeException JavaDoc("no lock on parent " + p);
430             }
431             if (!couldLockWithParentMode(h.mode, mode)) {
432                 //#ifdef DEBUG
433
Debug.println("lock = " + lock + ", p = " + p + ", h = " + h);
434                 Debug.println("LockManager: " + this);
435                 //#endif
436
throw new RuntimeException JavaDoc("parent not properly locked: " + h);
437             }
438             checkParentsLockMode(t, p, mode);
439         }
440     }
441
442     final boolean couldLockWithParentMode(int pmode, int mode) {
443     switch (mode) {
444     case LockMode.S:
445     case LockMode.IS:
446         return pmode == LockMode.X || pmode == LockMode.S
447                 || pmode == LockMode.IX || pmode == LockMode.IS;
448     case LockMode.X:
449     case LockMode.IX:
450     case LockMode.SIX:
451         return pmode == LockMode.X
452                 || pmode == LockMode.IX || pmode == LockMode.SIX;
453     default:
454         throw new RuntimeException JavaDoc("bad lock mode: " +
455                        LockMode.toString(mode));
456     }
457     }
458
459     void promoteLock(HeldLock h, int mode) {
460         h.lock.decrHeldCount(h.mode);
461         h.lock.incrHeldCount(mode);
462         h.mode = mode;
463     }
464
465     void acquireLock(HeldLock h) {
466         h.lock.incrHeldCount(h.mode);
467         byTrans.add(h);
468     }
469
470     //#ifdef DEBUG
471
public String JavaDoc toString() {
472         synchronized (locksLock) {
473             StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
474             sb.append("\nTransactions:\n------------\n");
475             sb.append(transactions);
476             sb.append("\nHeld:\n----\n");
477             sb.append(byTrans);
478             sb.append("\nLocks:\n-----\n");
479             sb.append(locks);
480             sb.append("\n");
481             return sb.toString();
482         }
483     }
484     //#endif
485
}
486
487
Popular Tags