KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > impl > services > locks > SinglePool


1 /*
2
3    Derby - Class org.apache.derby.impl.services.locks.SinglePool
4
5    Licensed to the Apache Software Foundation (ASF) under one or more
6    contributor license agreements. See the NOTICE file distributed with
7    this work for additional information regarding copyright ownership.
8    The ASF licenses this file to you under the Apache License, Version 2.0
9    (the "License"); you may not use this file except in compliance with
10    the License. You may obtain a copy of the License at
11
12       http://www.apache.org/licenses/LICENSE-2.0
13
14    Unless required by applicable law or agreed to in writing, software
15    distributed under the License is distributed on an "AS IS" BASIS,
16    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17    See the License for the specific language governing permissions and
18    limitations under the License.
19
20  */

21
22 package org.apache.derby.impl.services.locks;
23
24 import org.apache.derby.iapi.services.monitor.Monitor;
25
26 import org.apache.derby.iapi.services.locks.LockFactory;
27 import org.apache.derby.iapi.services.locks.C_LockFactory;
28 import org.apache.derby.iapi.services.locks.Lockable;
29 import org.apache.derby.iapi.services.locks.Latch;
30 import org.apache.derby.iapi.services.locks.Limit;
31
32 import org.apache.derby.iapi.error.StandardException;
33
34 import org.apache.derby.iapi.services.property.PropertyUtil;
35 import org.apache.derby.iapi.services.daemon.Serviceable;
36
37 import org.apache.derby.iapi.services.sanity.SanityManager;
38 import org.apache.derby.iapi.util.Matchable;
39 import org.apache.derby.iapi.reference.Property;
40
41 import java.util.Hashtable JavaDoc;
42 import java.util.Properties JavaDoc;
43 import java.io.Serializable JavaDoc;
44 import java.util.Dictionary JavaDoc;
45 import java.util.Enumeration JavaDoc;
46
47 // debugging
48
import org.apache.derby.iapi.services.stream.HeaderPrintWriter;
49
50 /**
51     An implementation of LockFactory that uses a single pool
52     for the locks, i.e. all lock requests go through a single
53     point of synchronisation.
54     <p>
55     The default concrete class "SinglePool.java", prints nothing and thus
56     incurs no overhead associated with the code to dump lock information. An
57     alternate concrete class "LockDebug/TracingSinglePool.java", attempts to
58     output only lock information that "makes sense" to a user - for instance it
59     doesn't print latch locks.
60
61     <BR>
62     MT - Mutable - Container Object : Thread Aware
63 */

64
65 public class SinglePool extends Hashtable JavaDoc
66     implements LockFactory
67 {
68     /**
69         The complete set of locks in the system
70
71         <BR>
72         MT - immutable - content dynamic : LockSet is ThreadSafe
73     */

74     protected final LockSet lockTable;
75
76     /**
77         This is now in this object, it now extends Hashtable.
78         A hash table of all compatability spaces. Key is the object
79         representing the compatability space, value is a LockSpace object.
80         Addition and removal from the Hashtable is performed under the
81         Hashtable's monitor. This requires holding this monitor while making
82         calls to the thread safe methods of LockSpace. This is to ensure
83         that it is guaranteed that a LockSpace is only removed when it is
84         empty and no-one is in the process of adding to it. No deadlocks are
85         possible because the spaces reference is not visible outside this
86         class and the LockSpace class does not call back into this class.
87
88         <BR>
89         MT - immutable - content dynamic : Java synchronized(spaces)
90
91         This class creates a LockSet and LockSpaces, both classes are thread
92         safe.
93         
94     */

95
96     /**
97         True if all deadlocks errors should be logged.
98     */

99     int deadlockMonitor;
100
101     public SinglePool() {
102         lockTable = new LockSet(this);
103     }
104
105     /*
106     ** Methods of LockFactory
107     */

108
109     /**
110         Latch a specific object with a timeout.
111
112         <BR>
113         MT - thread safe
114
115         @exception StandardException Standard Cloudscape error policy
116
117         @see LockFactory#latchObject
118     */

119     public boolean latchObject(Object JavaDoc compatabilitySpace, Lockable ref, Object JavaDoc qualifier, int timeout)
120         throws StandardException {
121
122         Lock latch = lockTable.lockObject(compatabilitySpace, ref, qualifier, timeout, (Latch) null);
123
124         if (SanityManager.DEBUG) {
125             if (latch == null)
126                 SanityManager.ASSERT(timeout == C_LockFactory.NO_WAIT, "timeout not NO_WAIT");
127         }
128         return latch != null;
129     }
130
131     /**
132         Unlatch an object.
133
134         <BR>
135         MT - thread safe
136
137         @see LockFactory#unlatch
138     */

139     public void unlatch(Latch heldLatch) {
140         lockTable.unlock(heldLatch, 1);
141     }
142
143     /**
144         Lock a specific object with a timeout.
145
146         <BR>
147         MT - thread safe
148
149         @exception StandardException Standard Cloudscape error policy
150
151         @see LockFactory#lockObject
152     */

153     protected Lock lockAnObject(Object JavaDoc compatabilitySpace, Object JavaDoc group, Lockable ref, Object JavaDoc qualifier, int timeout, Latch heldLatch)
154             throws StandardException
155     {
156         if (SanityManager.DEBUG) {
157             if (SanityManager.DEBUG_ON(Constants.LOCK_TRACE)) {
158
159                 D_LockControl.debugLock("Lock Request before Grant: ",
160                     compatabilitySpace, group, ref, qualifier, timeout);
161
162                 if (SanityManager.DEBUG_ON(Constants.LOCK_STACK_TRACE))
163                 {
164                     // The following will print the stack trace of the lock
165
// request to the log.
166
Throwable JavaDoc t = new Throwable JavaDoc();
167                    java.io.PrintWriter JavaDoc istream = SanityManager.GET_DEBUG_STREAM();
168
169                     istream.println("Stack trace of lock request:");
170                     t.printStackTrace(istream);
171                 }
172             }
173         }
174
175         Lock lock =
176             lockTable.lockObject(compatabilitySpace, ref, qualifier, timeout, heldLatch);
177
178         // See if NO_WAIT was passed in and the lock could not be granted.
179
if (lock == null) {
180             if (SanityManager.DEBUG) {
181                 SanityManager.ASSERT(timeout == C_LockFactory.NO_WAIT, "timeout not NO_WAIT");
182             }
183             return null;
184         }
185
186         if (SanityManager.DEBUG) {
187             if (SanityManager.DEBUG_ON(Constants.LOCK_TRACE)) {
188                 D_LockControl.debugLock(
189                     "Lock Request Granted: ",
190                     compatabilitySpace, group, ref, qualifier, timeout);
191             }
192         }
193
194         // find the space and atomically add lock to required group
195
synchronized (this) {
196
197             LockSpace ls = (LockSpace) get(compatabilitySpace);
198             if (ls == null) {
199                  ls = new LockSpace(this, compatabilitySpace);
200                  put(compatabilitySpace, ls);
201             }
202
203             // we hold the spaces monitor while adding the lock to close
204
// the window between finding the LockSpace and adding a lock
205
// to it, thus ensuring the LockSpace is not removed from the
206
// spaces Hashtable underneath us.
207

208             ls.addLock(group, lock);
209         }
210
211         return lock;
212     }
213
214     /**
215         Lock a specific object
216
217         <BR>
218         MT - thread safe
219
220         @exception StandardException Standard Cloudscape error policy
221
222         @see LockFactory#lockObject
223     */

224     public boolean lockObject(Object JavaDoc compatabilitySpace, Object JavaDoc group, Lockable ref, Object JavaDoc qualifier, int timeout)
225         throws StandardException {
226
227         return lockAnObject(compatabilitySpace, group, ref, qualifier, timeout, (Latch) null) != null;
228     }
229
230     /**
231         Lock a specific object while holding a latch
232
233         <BR>
234         MT - thread safe
235
236         @exception StandardException Standard Cloudscape error policy
237
238         @see LockFactory#lockObject
239     */

240     public boolean lockObject(Object JavaDoc group, Lockable ref, Object JavaDoc qualifier, int timeout, Latch latch)
241         throws StandardException {
242
243         if (SanityManager.DEBUG) {
244             if (timeout == C_LockFactory.NO_WAIT)
245                 SanityManager.THROWASSERT("no wait lock requested in lockObject() with latch");
246         }
247
248         Lock lock = lockAnObject(latch.getCompatabilitySpace(), group, ref, qualifier, timeout, latch);
249         return lock instanceof ActiveLock;
250     }
251
252     /**
253         Unlock a specific object
254
255         <BR>
256         MT - thread safe
257
258         @see LockFactory#unlock
259     */

260
261     public int unlock(Object JavaDoc compatabilitySpace, Object JavaDoc group, Lockable ref, Object JavaDoc qualifier)
262     {
263         if (SanityManager.DEBUG) {
264             if (SanityManager.DEBUG_ON(Constants.LOCK_TRACE)) {
265                 D_LockControl.debugLock("Lock Unlock: ",
266                     compatabilitySpace, group, ref, qualifier, -1);
267             }
268         }
269
270         LockSpace ls = (LockSpace) get(compatabilitySpace);
271         if (ls == null)
272             return 0;
273
274         int count = ls.unlockReference(lockTable, ref, qualifier, group);
275
276         if (SanityManager.DEBUG) {
277             SanityManager.ASSERT(
278                 (count == 0) || (count == 1), "count = " + count);
279         }
280
281         return count;
282     }
283
284     /**
285         Unlock a group of objects.
286
287         <BR>
288         MT - thread safe
289
290         @param group handle of group that objects were locked with.
291         If group is null then this call is equivilent to unlockAll().
292
293         @see LockFactory#unlockGroup
294     */

295     public void unlockGroup(Object JavaDoc compatabilitySpace, Object JavaDoc group) {
296
297         if (SanityManager.DEBUG) {
298             if (SanityManager.DEBUG_ON(Constants.LOCK_TRACE)) {
299                 D_LockControl.debugLock("Lock Unlock Group: ", compatabilitySpace, group);
300             }
301         }
302
303         LockSpace ls = (LockSpace) get(compatabilitySpace);
304         if (ls == null)
305             return;
306
307         ls.unlockGroup(lockTable, group);
308     }
309
310     public void unlockGroup(Object JavaDoc compatabilitySpace, Object JavaDoc group, Matchable key) {
311
312         if (SanityManager.DEBUG) {
313             if (SanityManager.DEBUG_ON(Constants.LOCK_TRACE)) {
314                 D_LockControl.debugLock("Lock Unlock Group: ", compatabilitySpace, group);
315             }
316         }
317
318         LockSpace ls = (LockSpace) get(compatabilitySpace);
319         if (ls == null)
320             return;
321
322         ls.unlockGroup(lockTable, group, key);
323
324
325     }
326
327     /**
328         Transfer a set of locks from one group to another.
329
330         <BR>
331         MT - thread safe
332
333         @see LockFactory#transfer
334     */

335     public void transfer(Object JavaDoc compatabilitySpace, Object JavaDoc oldGroup, Object JavaDoc newGroup) {
336
337         if (SanityManager.DEBUG) {
338             if (SanityManager.DEBUG_ON(Constants.LOCK_TRACE)) {
339                 StringBuffer JavaDoc sb = new StringBuffer JavaDoc("Lock Transfer:");
340
341                 D_LockControl.debugAppendObject(
342                     sb, " CompatabilitySpace=", compatabilitySpace);
343                 D_LockControl.debugAppendObject(sb, " Old Group=", oldGroup);
344                 D_LockControl.debugAppendObject(sb, " New Group=", newGroup);
345
346                 D_LockControl.debugAddThreadInfo(sb);
347
348                 SanityManager.DEBUG(Constants.LOCK_TRACE, sb.toString());
349             }
350         }
351
352         LockSpace ls = (LockSpace) get(compatabilitySpace);
353         if (ls == null)
354             return;
355
356         // there is a window where someone could remove the LockSpace from the
357
// spaces Hashtable, since we do not hold the spaces' monitor. This is
358
// Ok as the LockSpace will have no locks and this method
359
// will correctly do nothing.
360

361         ls.transfer(oldGroup, newGroup);
362     }
363
364     /**
365         Returns true if locks by anyone are blocking anyone else
366     */

367     public boolean anyoneBlocked() {
368         return lockTable.anyoneBlocked();
369     }
370
371     /**
372         Return true if locks are held in this group and this space.
373
374         <BR>
375         MT - thread safe
376
377         @param group handle of group that objects were locked with.
378
379         @see LockFactory#areLocksHeld
380     */

381     public boolean areLocksHeld(Object JavaDoc compatabilitySpace, Object JavaDoc group) {
382
383         LockSpace ls = (LockSpace) get(compatabilitySpace);
384         if (ls == null)
385             return false;
386
387         // there is a window where someone could remove the LockSpace from the
388
// spaces Hashtable, since we do not hold the spaces' monitor. This is
389
// Ok as the LockSpace will have no locks and this method will
390
// correctly return false.
391

392         return ls.areLocksHeld(group);
393     }
394
395     /**
396         Return true if locks are held in this space
397         
398         <BR>
399         MT - thread safe
400
401         @see LockFactory#areLocksHeld
402     */

403     public boolean areLocksHeld(Object JavaDoc compatabilitySpace) {
404         LockSpace ls = (LockSpace) get(compatabilitySpace);
405         if (ls == null)
406             return false;
407         return !ls.isEmpty();
408     }
409
410     public boolean zeroDurationlockObject(Object JavaDoc compatabilitySpace, Lockable ref, Object JavaDoc qualifier, int timeout)
411         throws StandardException {
412
413         if (SanityManager.DEBUG) {
414             if (SanityManager.DEBUG_ON(Constants.LOCK_TRACE)) {
415
416                 D_LockControl.debugLock("Zero Duration Lock Request before Grant: ",
417                     compatabilitySpace, (Object JavaDoc) null, ref, qualifier, timeout);
418
419                 if (SanityManager.DEBUG_ON(Constants.LOCK_STACK_TRACE))
420                 {
421                     // The following will print the stack trace of the lock
422
// request to the log.
423
Throwable JavaDoc t = new Throwable JavaDoc();
424                    java.io.PrintWriter JavaDoc istream = SanityManager.GET_DEBUG_STREAM();
425
426                     istream.println("Stack trace of lock request:");
427                     t.printStackTrace(istream);
428                 }
429             }
430         }
431
432         // Very fast zeroDurationlockObject() for unlocked objects.
433
// If no entry exists in the lock manager for this reference
434
// then it must be unlocked.
435
// If the object is locked then we perform a grantable
436
// check, skipping over any waiters.
437
// If the caller wants to wait and the lock cannot
438
// be granted then we do the slow join the queue and
439
// release the lock method.
440
synchronized (lockTable) {
441
442             Control control = (Control) lockTable.get(ref);
443             if (control == null) {
444                 return true;
445             }
446
447             // If we are grantable, ignoring waiting locks then
448
// we can also grant this request now, as skipping
449
// over the waiters won't block them as we release
450
// the lock rightway.
451
if (control.isGrantable(true, compatabilitySpace, qualifier))
452                 return true;
453
454             // can't be granted and are not willing to wait.
455
if (timeout == C_LockFactory.NO_WAIT)
456                 return false;
457         }
458
459         Lock lock =
460             lockTable.lockObject(compatabilitySpace, ref, qualifier, timeout, (Latch) null);
461
462         if (SanityManager.DEBUG) {
463             if (SanityManager.DEBUG_ON(Constants.LOCK_TRACE)) {
464                 D_LockControl.debugLock(
465                     "Zero Lock Request Granted: ",
466                     compatabilitySpace, (Object JavaDoc) null, ref, qualifier, timeout);
467             }
468         }
469
470         // and simply unlock it once
471
lockTable.unlock(lock, 1);
472
473         return true;
474     }
475
476     public boolean isLockHeld(Object JavaDoc compatabilitySpace, Object JavaDoc group, Lockable ref, Object JavaDoc qualifier) {
477
478         LockSpace ls = (LockSpace) get(compatabilitySpace);
479         if (ls == null)
480             return false;
481
482         return ls.isLockHeld(group, ref, qualifier);
483     }
484
485     public synchronized void setLimit(Object JavaDoc compatabilitySpace, Object JavaDoc group, int limit, Limit callback) {
486
487         LockSpace ls = (LockSpace) get(compatabilitySpace);
488         if (ls == null) {
489              ls = new LockSpace(this, compatabilitySpace);
490              put(compatabilitySpace, ls);
491         }
492
493         ls.setLimit(group, limit, callback);
494         
495     }
496
497     /**
498         Clear a limit set by setLimit.
499     */

500     public void clearLimit(Object JavaDoc compatabilitySpace, Object JavaDoc group) {
501         LockSpace ls = (LockSpace) get(compatabilitySpace);
502         if (ls == null)
503             return;
504
505         ls.clearLimit(group);
506     }
507
508 //EXCLUDE-START-lockdiag-
509

510     /**
511         Routines to support lock diagnostics VTIs for the benefit of VirtualLockTable
512      */

513     /* package */
514     public Enumeration JavaDoc makeVirtualLockTable()
515     {
516         // make a shallow copy of the locktable.
517
LockTableVTI myclone = new LockTableVTI(lockTable.shallowClone());
518
519         return myclone;
520     }
521 //EXCLUDE-END-lockdiag-
522

523
524     /*
525     ** Non-public methods
526     */

527
528 //EXCLUDE-START-debug-
529

530     public String JavaDoc toDebugString()
531     {
532         return(lockTable.toDebugString());
533     }
534
535 //EXCLUDE-END-debug-
536

537     /*
538     ** Methods of PropertySetCallback
539     */

540
541     public void init(boolean dbOnly, Dictionary JavaDoc p) {
542
543         getAndApply(dbOnly, p, Property.DEADLOCK_TIMEOUT);
544         getAndApply(dbOnly, p, Property.LOCKWAIT_TIMEOUT);
545         getAndApply(dbOnly, p, Property.DEADLOCK_MONITOR);
546 //EXCLUDE-START-lockdiag-
547
getAndApply(dbOnly, p, Property.DEADLOCK_TRACE);
548 //EXCLUDE-END-lockdiag-
549
}
550
551     private void getAndApply(boolean dbOnly, Dictionary JavaDoc p, String JavaDoc key) {
552
553         try {
554
555             Serializable JavaDoc value = (String JavaDoc) PropertyUtil.getPropertyFromSet(dbOnly, p, key);
556             if (value != null) {
557                 validate(key, value, p);
558                 apply(key, value, p);
559             }
560         } catch (StandardException se) {
561             // just ignore value at bootup.
562
}
563     }
564
565     
566     public boolean validate(String JavaDoc key, Serializable JavaDoc value, Dictionary JavaDoc p)
567         throws StandardException {
568
569         if (!key.startsWith(Property.LOCKS_INTRO))
570             return false;
571
572         if (value != null) {
573
574             if (key.equals(Property.DEADLOCK_TIMEOUT))
575                 getWaitValue((String JavaDoc) value, Property.DEADLOCK_TIMEOUT_DEFAULT);
576             else if (key.equals(Property.LOCKWAIT_TIMEOUT))
577                 getWaitValue((String JavaDoc) value, Property.WAIT_TIMEOUT_DEFAULT);
578             else if (key.equals(Property.DEADLOCK_MONITOR))
579                 PropertyUtil.booleanProperty(Property.DEADLOCK_MONITOR, value, false);
580             else if (key.equals(Property.DEADLOCK_TRACE))
581                 PropertyUtil.booleanProperty(Property.DEADLOCK_TRACE, value, false);
582         }
583
584         return true;
585     }
586
587     public Serviceable apply(String JavaDoc key, Serializable JavaDoc value, Dictionary JavaDoc p)
588         throws StandardException {
589
590         if (value == null) {
591             // a delete, fill in the new value
592
value = PropertyUtil.getPropertyFromSet(p, key);
593         }
594
595         String JavaDoc svalue = (String JavaDoc) value;
596
597         if (key.equals(Property.DEADLOCK_TIMEOUT))
598             lockTable.deadlockTimeout = getWaitValue(svalue, Property.DEADLOCK_TIMEOUT_DEFAULT);
599         else if (key.equals(Property.LOCKWAIT_TIMEOUT))
600             lockTable.waitTimeout = getWaitValue(svalue, Property.WAIT_TIMEOUT_DEFAULT);
601         else if (key.equals(Property.DEADLOCK_MONITOR)) {
602             deadlockMonitor = PropertyUtil.booleanProperty(Property.DEADLOCK_MONITOR, svalue, false) ?
603                 StandardException.REPORT_ALWAYS : StandardException.REPORT_DEFAULT;
604         }
605 //EXCLUDE-START-lockdiag-
606
else if (key.equals(Property.DEADLOCK_TRACE))
607             lockTable.setDeadlockTrace(PropertyUtil.booleanProperty(Property.DEADLOCK_TRACE, svalue, false));
608 //EXCLUDE-END-lockdiag-
609

610         return null;
611     }
612     
613     public Serializable JavaDoc map(String JavaDoc key, Serializable JavaDoc value, Dictionary JavaDoc p) {
614         return null;
615     }
616
617     /*
618     ** Property related methods
619     */

620     
621     private static int getWaitValue(String JavaDoc value, int defaultValue ) {
622
623         // properties are defined in seconds
624
int wait = PropertyUtil.handleInt(value, Integer.MIN_VALUE, Integer.MAX_VALUE / 1000, defaultValue);
625
626         if (wait < 0)
627             wait = C_LockFactory.WAIT_FOREVER;
628         else
629             // convert to milliseconds
630
wait *= 1000;
631
632         return wait;
633     }
634 }
635
Popular Tags