KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sleepycat > je > txn > Lock


1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 2002,2006 Oracle. All rights reserved.
5  *
6  * $Id: Lock.java,v 1.60 2006/10/30 21:14:27 bostic Exp $
7  */

8
9 package com.sleepycat.je.txn;
10
11 import java.util.ArrayList JavaDoc;
12 import java.util.Collections JavaDoc;
13 import java.util.HashSet JavaDoc;
14 import java.util.Iterator JavaDoc;
15 import java.util.List JavaDoc;
16 import java.util.Set JavaDoc;
17
18 import com.sleepycat.je.DatabaseException;
19 import com.sleepycat.je.dbi.MemoryBudget;
20
21 /**
22  * A Lock embodies the lock state of a NodeId. It includes a set of owners and
23  * a list of waiters.
24  */

25 public class Lock {
26     private static final int REMOVE_LOCKINFO_OVERHEAD =
27         0 - MemoryBudget.LOCKINFO_OVERHEAD;
28
29     /**
30      * A single locker always appears only once in the logical set of owners.
31      * The owners set is always in one of the following states.
32      *
33      * 1- Empty
34      * 2- A single writer
35      * 3- One or more readers
36      * 4- Multiple writers or a mix of readers and writers, all for
37      * txns which share locks (all ThreadLocker instances for the same
38      * thread)
39      *
40      * Both ownerSet and waiterList are a collection of LockInfo. Since the
41      * common case is that there is only one owner or waiter, we have added an
42      * optimization to avoid the cost of collections. FirstOwner and
43      * firstWaiter are used for the first owner or waiter of the lock, and the
44      * corresponding collection is instantiated and used only if more owners
45      * arrive.
46      *
47      * In terms of memory accounting, we count up the cost of each added or
48      * removed LockInfo, but not the cost of the HashSet/List entry
49      * overhead. We could do the latter for more precise accounting.
50      */

51     private LockInfo firstOwner;
52     private Set JavaDoc ownerSet;
53     private LockInfo firstWaiter;
54     private List JavaDoc waiterList;
55     private Long JavaDoc nodeId;
56
57     /**
58      * Create a Lock.
59      */

60     Lock(Long JavaDoc nodeId) {
61         this.nodeId = nodeId;
62     }
63
64     /* For the Sizeof program. */
65     public Lock() {
66     }
67
68     Long JavaDoc getNodeId() {
69         return nodeId;
70     }
71
72     /**
73      * The first waiter goes into the firstWaiter member variable. Once the
74      * waiterList is made, all appended waiters go into waiterList, even after
75      * the firstWaiter goes away and leaves that field null, so as to leave the
76      * list ordered.
77      */

78     private void addWaiterToEndOfList(LockInfo waiter,
79                       MemoryBudget mb,
80                       int lockTableIndex) {
81         /* Careful: order important! */
82         if (waiterList == null) {
83             if (firstWaiter == null) {
84                 firstWaiter = waiter;
85             } else {
86                 waiterList = new ArrayList JavaDoc();
87                 waiterList.add(waiter);
88             }
89         } else {
90             waiterList.add(waiter);
91         }
92         mb.updateLockMemoryUsage
93         (MemoryBudget.LOCKINFO_OVERHEAD, lockTableIndex);
94     }
95
96     /**
97      * Add this waiter to the front of the list.
98      */

99     private void addWaiterToHeadOfList(LockInfo waiter,
100                        MemoryBudget mb,
101                        int lockTableIndex) {
102         /* Shuffle the current first waiter down a slot. */
103         if (firstWaiter != null) {
104             if (waiterList == null) {
105                 waiterList = new ArrayList JavaDoc();
106             }
107             waiterList.add(0, firstWaiter);
108         }
109
110         firstWaiter = waiter;
111         mb.updateLockMemoryUsage
112         (MemoryBudget.LOCKINFO_OVERHEAD, lockTableIndex);
113     }
114
115     /**
116      * Get a list of waiters for debugging and error messages.
117      */

118     List JavaDoc getWaitersListClone() {
119         List JavaDoc dumpWaiters = new ArrayList JavaDoc();
120         if (firstWaiter != null) {
121             dumpWaiters.add(firstWaiter);
122         }
123
124         if (waiterList != null) {
125             dumpWaiters.addAll(waiterList);
126         }
127
128         return dumpWaiters;
129     }
130
131     /**
132      * Remove this locker from the waiter list.
133      */

134     void flushWaiter(Locker locker, MemoryBudget mb, int lockTableIndex) {
135         if ((firstWaiter != null) && (firstWaiter.getLocker() == locker)) {
136             firstWaiter = null;
137             mb.updateLockMemoryUsage
138         (REMOVE_LOCKINFO_OVERHEAD, lockTableIndex);
139         } else if (waiterList != null) {
140             Iterator JavaDoc iter = waiterList.iterator();
141             while (iter.hasNext()) {
142                 LockInfo info = (LockInfo) iter.next();
143                 if (info.getLocker() == locker) {
144                     iter.remove();
145                     mb.updateLockMemoryUsage
146             (REMOVE_LOCKINFO_OVERHEAD, lockTableIndex);
147                     return;
148                 }
149             }
150         }
151     }
152
153     private void addOwner(LockInfo newLock,
154               MemoryBudget mb,
155               int lockTableIndex) {
156         if (firstOwner == null) {
157             firstOwner = newLock;
158         } else {
159             if (ownerSet == null) {
160                 ownerSet = new HashSet JavaDoc();
161             }
162             ownerSet.add(newLock);
163         }
164         mb.updateLockMemoryUsage
165         (MemoryBudget.LOCKINFO_OVERHEAD, lockTableIndex);
166     }
167
168     /**
169      * Get a new Set of the owners.
170      */

171     Set JavaDoc getOwnersClone() {
172
173         /* No need to update memory usage, the returned Set is transient. */
174         Set JavaDoc owners;
175         if (ownerSet != null) {
176             owners = new HashSet JavaDoc(ownerSet);
177         } else {
178             owners = new HashSet JavaDoc();
179         }
180         if (firstOwner != null) {
181             owners.add(firstOwner);
182         }
183         return owners;
184     }
185
186     /**
187      * Remove this LockInfo from the owner set.
188      */

189     private boolean flushOwner(LockInfo oldOwner,
190                    MemoryBudget mb,
191                    int lockTableIndex) {
192         boolean removed = false;
193         if (oldOwner != null) {
194             if (firstOwner == oldOwner) {
195                 firstOwner = null;
196                 return true;
197             }
198
199             if (ownerSet != null) {
200                 removed = ownerSet.remove(oldOwner);
201             }
202         }
203         
204         if (removed) {
205             mb.updateLockMemoryUsage(REMOVE_LOCKINFO_OVERHEAD, lockTableIndex);
206         }
207         return removed;
208     }
209
210     /**
211      * Remove this locker from the owner set.
212      */

213     private LockInfo flushOwner(Locker locker,
214                 MemoryBudget mb,
215                 int lockTableIndex) {
216         LockInfo flushedInfo = null;
217         if ((firstOwner != null) &&
218         (firstOwner.getLocker() == locker)) {
219             flushedInfo = firstOwner;
220             firstOwner = null;
221         } else if (ownerSet != null) {
222             Iterator JavaDoc iter = ownerSet.iterator();
223             while (iter.hasNext()) {
224                 LockInfo o = (LockInfo) iter.next();
225                 if (o.getLocker() == locker) {
226                     iter.remove();
227                     flushedInfo = o;
228                 }
229             }
230         }
231         if (flushedInfo != null) {
232             mb.updateLockMemoryUsage(REMOVE_LOCKINFO_OVERHEAD, lockTableIndex);
233         }
234             
235         return flushedInfo;
236     }
237
238     /**
239      * Returns the owner LockInfo for a locker, or null if locker is not an
240      * owner.
241      */

242     private LockInfo getOwnerLockInfo(Locker locker) {
243         if ((firstOwner != null) && (firstOwner.getLocker() == locker)) {
244             return firstOwner;
245         }
246
247         if (ownerSet != null) {
248             Iterator JavaDoc iter = ownerSet.iterator();
249             while (iter.hasNext()) {
250                 LockInfo o = (LockInfo) iter.next();
251                 if (o.getLocker() == locker) {
252                     return o;
253                 }
254             }
255         }
256
257         return null;
258     }
259
260     /**
261      * Return true if locker is an owner of this Lock for lockType,
262      * false otherwise.
263      *
264      * This method is only used by unit tests.
265      */

266     boolean isOwner(Locker locker, LockType lockType) {
267         LockInfo o = getOwnerLockInfo(locker);
268         if (o != null) {
269             LockType ownedLockType = o.getLockType();
270             if (lockType == ownedLockType) {
271                 return true;
272             }
273             LockUpgrade upgrade = ownedLockType.getUpgrade(lockType);
274             if (!upgrade.getPromotion()) {
275                 return true;
276             }
277         }
278         return false;
279     }
280
281     /**
282      * Return true if locker is an owner of this Lock and this is a write
283      * lock.
284      */

285     boolean isOwnedWriteLock(Locker locker) {
286         LockInfo o = getOwnerLockInfo(locker);
287         return o != null && o.getLockType().isWriteLock();
288     }
289
290     /**
291      * Return true if locker is a waiter on this Lock.
292      *
293      * This method is only used by unit tests.
294      */

295     boolean isWaiter(Locker locker) {
296
297         if (firstWaiter != null) {
298             if (firstWaiter.getLocker() == locker) {
299                 return true;
300             }
301         }
302
303         if (waiterList != null) {
304             Iterator JavaDoc iter = waiterList.iterator();
305             while (iter.hasNext()) {
306                 LockInfo info = (LockInfo) iter.next();
307                 if (info.getLocker() == locker) {
308                     return true;
309                 }
310             }
311         }
312         return false;
313     }
314
315     int nWaiters() {
316         int count = 0;
317         if (firstWaiter != null) {
318             count++;
319         }
320         if (waiterList != null) {
321             count += waiterList.size();
322         }
323         return count;
324     }
325
326     int nOwners() {
327         int count = 0;
328         if (firstOwner != null) {
329             count++;
330         }
331
332         if (ownerSet != null) {
333             count += ownerSet.size();
334         }
335         return count;
336     }
337
338     /**
339      * Attempts to acquire the lock and returns the LockGrantType.
340      *
341      * Assumes we hold the lockTableLatch when entering this method.
342      */

343     LockGrantType lock(LockType requestType,
344                        Locker locker,
345                        boolean nonBlockingRequest,
346                        MemoryBudget mb,
347                int lockTableIndex) {
348
349         assert validateRequest(locker); // intentional side effect
350

351         /* Request an ordinary lock by checking the owners list. */
352         LockInfo newLock = new LockInfo(locker, requestType);
353         LockGrantType grant =
354         tryLock(newLock, nWaiters() == 0, mb, lockTableIndex);
355
356         /* Do we have to wait for this lock? */
357         if (grant == LockGrantType.WAIT_NEW ||
358             grant == LockGrantType.WAIT_PROMOTION ||
359             grant == LockGrantType.WAIT_RESTART) {
360
361             /*
362              * If the request type can cause a restart and a restart conflict
363              * does not already exist, then we have to check the waiters list
364              * for restart conflicts. A restart conflict must take precedence
365              * or it may be missed.
366              */

367             if (requestType.getCausesRestart() &&
368                 grant != LockGrantType.WAIT_RESTART) {
369                 LockInfo waiter = null;
370                 Iterator JavaDoc iter = null;
371
372                 if (waiterList != null) {
373                     iter = waiterList.iterator();
374                 }
375
376                 if (firstWaiter != null) {
377                     waiter = firstWaiter;
378                 } else if ((iter != null) && (iter.hasNext())) {
379                     waiter = (LockInfo) iter.next();
380                 }
381                 
382                 while (waiter != null) {
383
384                     /*
385                      * Check for a restart conflict. Ignore LockType.RESTART
386                      * in the waiter list when checking for conflicts.
387                      */

388                     Locker waiterLocker = waiter.getLocker();
389                     LockType waiterType = waiter.getLockType();
390                     if (waiterType != LockType.RESTART &&
391                         locker != waiterLocker &&
392                         !locker.sharesLocksWith(waiterLocker)) {
393                         LockConflict conflict =
394                             waiterType.getConflict(requestType);
395                         if (conflict.getRestart()) {
396                             grant = LockGrantType.WAIT_RESTART;
397                             break;
398                         }
399                     }
400
401                     /* Move to the next waiter, if it's in the list. */
402                     if ((iter != null) && (iter.hasNext())) {
403                         waiter = (LockInfo) iter.next();
404                     } else {
405                         waiter = null;
406                     }
407                 }
408             }
409
410             /* Add the waiter or deny the lock as appropriate. */
411             if (nonBlockingRequest) {
412                 grant = LockGrantType.DENIED;
413             } else {
414                 if (grant == LockGrantType.WAIT_PROMOTION) {
415                     addWaiterToHeadOfList(newLock, mb, lockTableIndex);
416                 } else {
417                     assert grant == LockGrantType.WAIT_NEW ||
418                            grant == LockGrantType.WAIT_RESTART;
419
420                     /*
421                      * If waiting to restart, change the lock type to RESTART
422                      * to avoid granting the lock later. We wait until the
423                      * RESTART waiter moves to the head of waiter list to
424                      * prevent the requester from spinning performing repeated
425                      * restarts, but we don't grant the lock.
426                      */

427                     if (grant == LockGrantType.WAIT_RESTART) {
428                         newLock.setLockType(LockType.RESTART);
429                     }
430
431                     addWaiterToEndOfList(newLock, mb, lockTableIndex);
432                 }
433             }
434         }
435
436         return grant;
437     }
438
439     /**
440      * Releases a lock and moves the next waiter(s) to the owners.
441      * @return
442      * null if we were not the owner,
443      * a non-empty set if owners should be notified after releasing,
444      * an empty set if no notification is required.
445      */

446     Set JavaDoc release(Locker locker, MemoryBudget mb, int lockTableIndex) {
447
448         LockInfo removedLock = flushOwner(locker, mb, lockTableIndex);
449         if (removedLock == null) {
450             /* Not owner. */
451             return null;
452         }
453
454         Set JavaDoc lockersToNotify = Collections.EMPTY_SET;
455
456         if (nWaiters() == 0) {
457             /* No more waiters, so no one to notify. */
458             return lockersToNotify;
459         }
460
461         /*
462          * Move the next set of waiters to the owners set. Iterate through the
463          * firstWaiter field, then the waiterList.
464          */

465         LockInfo waiter = null;
466         Iterator JavaDoc iter = null;
467         boolean isFirstWaiter = false;
468
469         if (waiterList != null) {
470             iter = waiterList.iterator();
471         }
472
473         if (firstWaiter != null) {
474             waiter = firstWaiter;
475             isFirstWaiter = true;
476         } else if ((iter != null) && (iter.hasNext())) {
477             waiter = (LockInfo) iter.next();
478         }
479         
480         while (waiter != null) {
481             /* Make the waiter an owner if the lock can be acquired. */
482             LockType waiterType = waiter.getLockType();
483             Locker waiterLocker = waiter.getLocker();
484             LockGrantType grant;
485             if (waiterType == LockType.RESTART) {
486                 /* Special case for restarts: see rangeInsertConflict. */
487                 grant = rangeInsertConflict(waiterLocker) ?
488                     LockGrantType.WAIT_NEW : LockGrantType.NEW;
489             } else {
490                 /* Try locking. */
491                 grant = tryLock(waiter, true, mb, lockTableIndex);
492             }
493             /* Check if granted. */
494             if (grant == LockGrantType.NEW ||
495                 grant == LockGrantType.EXISTING ||
496                 grant == LockGrantType.PROMOTION) {
497                 /* Remove it from the waiters list. */
498                 if (isFirstWaiter) {
499                     firstWaiter = null;
500                 } else {
501                     iter.remove();
502                 }
503                 if (lockersToNotify == Collections.EMPTY_SET) {
504                     lockersToNotify = new HashSet JavaDoc();
505                 }
506                 lockersToNotify.add(waiterLocker);
507                 mb.updateLockMemoryUsage
508             (REMOVE_LOCKINFO_OVERHEAD, lockTableIndex);
509             } else {
510                 assert grant == LockGrantType.WAIT_NEW ||
511                        grant == LockGrantType.WAIT_PROMOTION ||
512                        grant == LockGrantType.WAIT_RESTART;
513                 /* Stop on first waiter that cannot be an owner. */
514                 break;
515             }
516
517             /* Move to the next waiter, if it's in the list. */
518             if ((iter != null) && (iter.hasNext())) {
519                 waiter = (LockInfo) iter.next();
520                 isFirstWaiter = false;
521             } else {
522                 waiter = null;
523             }
524         }
525         return lockersToNotify;
526     }
527
528     /**
529      * Called from lock() to try locking a new request, and from release() to
530      * try locking a waiting request.
531      *
532      * @param newLock is the lock that is requested.
533      *
534      * @param firstWaiterInLine determines whether to grant the lock when a
535      * NEW lock can be granted, but other non-conflicting owners exist; for
536      * example, when a new READ lock is requested but READ locks are held by
537      * other owners. This parameter should be true if the requestor is the
538      * first waiter in line (or if there are no waiters), and false otherwise.
539      *
540      * @param mb is the current memory budget.
541      *
542      * @return LockGrantType.EXISTING, NEW, PROMOTION, WAIT_RESTART, WAIT_NEW
543      * or WAIT_PROMOTION.
544      */

545     private LockGrantType tryLock(LockInfo newLock,
546                                   boolean firstWaiterInLine,
547                                   MemoryBudget mb,
548                   int lockTableIndex) {
549
550         /* If no one owns this right now, just grab it. */
551         if (nOwners() == 0) {
552             addOwner(newLock, mb, lockTableIndex);
553             return LockGrantType.NEW;
554         }
555
556         Locker locker = newLock.getLocker();
557         LockType requestType = newLock.getLockType();
558         LockUpgrade upgrade = null;
559         LockInfo lockToUpgrade = null;
560         boolean ownerExists = false;
561         boolean ownerConflicts = false;
562
563         /*
564          * Iterate through the current owners. See if there is a current owner
565          * who has to be upgraded from read to write. Also track whether there
566          * is a conflict with another owner.
567          */

568         LockInfo owner = null;
569         Iterator JavaDoc iter = null;
570         
571         if (ownerSet != null) {
572             iter = ownerSet.iterator();
573         }
574
575         if (firstOwner != null) {
576             owner = firstOwner;
577         } else if ((iter != null) && (iter.hasNext())) {
578             owner = (LockInfo) iter.next();
579         }
580
581         while (owner != null) {
582             Locker ownerLocker = owner.getLocker();
583             LockType ownerType = owner.getLockType();
584             if (locker == ownerLocker) {
585
586                 /*
587                  * Requestor currently holds this lock: check for upgrades.
588                  * If no type change is needed, return EXISTING now to avoid
589                  * iterating further; otherwise, we need to check for conflicts
590                  * before granting the upgrade.
591                  */

592                 assert (upgrade == null); // An owner should appear only once
593
upgrade = ownerType.getUpgrade(requestType);
594                 if (upgrade.getUpgrade() == null) {
595                     return LockGrantType.EXISTING;
596                 } else {
597                     lockToUpgrade = owner;
598                 }
599             } else {
600
601                 /*
602                  * Requestor does not hold this lock: check for conflicts.
603                  * If the owner shares locks with the requestor, ignore it;
604                  * otherwise, if a restart conflict exists, return it now;
605                  * otherwise, save the conflict information.
606                  */

607                 if (!locker.sharesLocksWith(ownerLocker)) {
608                     LockConflict conflict = ownerType.getConflict(requestType);
609                     if (conflict.getRestart()) {
610                         return LockGrantType.WAIT_RESTART;
611                     } else {
612                         if (!conflict.getAllowed()) {
613                             ownerConflicts = true;
614                         }
615                         ownerExists = true;
616                     }
617                 }
618             }
619
620             /* Move on to the next owner. */
621             if ((iter != null) && (iter.hasNext())) {
622                 owner = (LockInfo) iter.next();
623             } else {
624                 owner = null;
625             }
626         }
627
628         /* Now handle the upgrade or conflict as appropriate. */
629         if (upgrade != null) {
630             /* The requestor holds this lock. */
631             LockType upgradeType = upgrade.getUpgrade();
632             assert upgradeType != null;
633             if (!ownerConflicts) {
634                 /* No conflict: grant the upgrade. */
635                 lockToUpgrade.setLockType(upgradeType);
636                 return upgrade.getPromotion() ?
637                     LockGrantType.PROMOTION : LockGrantType.EXISTING;
638             } else {
639                 /* Upgrade cannot be granted at this time. */
640                 return LockGrantType.WAIT_PROMOTION;
641             }
642         } else {
643             /* The requestor doesn't hold this lock. */
644             if (!ownerConflicts && (!ownerExists || firstWaiterInLine)) {
645                 /* No conflict: grant the lock. */
646                 addOwner(newLock, mb, lockTableIndex);
647                 return LockGrantType.NEW;
648             } else {
649                 /* Lock cannot be granted at this time. */
650                 return LockGrantType.WAIT_NEW;
651             }
652         }
653     }
654
655     /**
656      * Called from release() when a RESTART request is waiting to determine if
657      * any RANGE_INSERT owners exist. We can't call tryLock for a RESTART
658      * lock because it must never be granted.
659      */

660     private boolean rangeInsertConflict(Locker waiterLocker) {
661
662         LockInfo owner = null;
663         Iterator JavaDoc iter = null;
664         
665         if (ownerSet != null) {
666             iter = ownerSet.iterator();
667         }
668
669         if (firstOwner != null) {
670             owner = firstOwner;
671         } else if ((iter != null) && (iter.hasNext())) {
672             owner = (LockInfo) iter.next();
673         }
674
675         while (owner != null) {
676             Locker ownerLocker = owner.getLocker();
677             if (ownerLocker != waiterLocker &&
678                 !ownerLocker.sharesLocksWith(waiterLocker) &&
679                 owner.getLockType() == LockType.RANGE_INSERT) {
680                 return true;
681             }
682
683             /* Move on to the next owner. */
684             if ((iter != null) && (iter.hasNext())) {
685                 owner = (LockInfo) iter.next();
686             } else {
687                 owner = null;
688             }
689         }
690
691         return false;
692     }
693
694     /**
695      * Downgrade a write lock to a read lock.
696      */

697     void demote(Locker locker) {
698         LockInfo owner = getOwnerLockInfo(locker);
699         if (owner != null) {
700             LockType type = owner.getLockType();
701             if (type.isWriteLock()) {
702                 owner.setLockType((type == LockType.RANGE_WRITE) ?
703                                   LockType.RANGE_READ : LockType.READ);
704             }
705         }
706     }
707
708     /**
709      * Transfer a lock from one transaction to another. Make sure that this
710      * destination locker is only present as a single reader or writer.
711      */

712     LockType transfer(Locker currentLocker,
713                       Locker destLocker,
714                       MemoryBudget mb,
715               int lockTableIndex)
716         throws DatabaseException {
717
718         /*
719          * Remove all the old owners held by the dest locker. Take all the
720          * owners held by currentLocker and make them dest lockers.
721          */

722         LockType lockType = null;
723         int numRemovedLockInfos = 0;
724         
725         if (firstOwner != null) {
726             if (firstOwner.getLocker() == destLocker) {
727                 firstOwner = null;
728                 numRemovedLockInfos++;
729             } else if (firstOwner.getLocker() == currentLocker) {
730                 lockType = setNewLocker(firstOwner, destLocker);
731             }
732         }
733
734         if (ownerSet != null) {
735             Iterator JavaDoc iter = ownerSet.iterator();
736             while (iter.hasNext()) {
737                 LockInfo owner = (LockInfo) iter.next();
738                 if (owner.getLocker() == destLocker) {
739                     iter.remove();
740                     numRemovedLockInfos++;
741                 } else if (owner.getLocker() == currentLocker) {
742                     lockType = setNewLocker(owner, destLocker);
743                 }
744             }
745         }
746
747         /* Check the waiters, remove any that belonged to the dest locker. */
748         if ((firstWaiter != null) && (firstWaiter.getLocker() == destLocker)) {
749             firstWaiter = null;
750             numRemovedLockInfos++;
751         }
752         if (waiterList != null) {
753             Iterator JavaDoc iter = waiterList.iterator();
754             while (iter.hasNext()) {
755                 LockInfo info = (LockInfo) iter.next();
756                 if (info.getLocker() == destLocker) {
757                     iter.remove();
758                     numRemovedLockInfos++;
759                 }
760             }
761         }
762
763         mb.updateLockMemoryUsage(0 - (numRemovedLockInfos *
764                       MemoryBudget.LOCKINFO_OVERHEAD),
765                  lockTableIndex);
766         return lockType;
767     }
768
769     private LockType setNewLocker(LockInfo owner, Locker destLocker)
770         throws DatabaseException {
771             
772         owner.setLocker(destLocker);
773         destLocker.addLock(nodeId, this, owner.getLockType(),
774                            LockGrantType.NEW);
775         return owner.getLockType();
776     }
777
778     /**
779      * Transfer a lock from one transaction to many others. Only really needed
780      * for case where a write handle lock is being transferred to multiple read
781      * handles.
782      */

783     LockType transferMultiple(Locker currentLocker,
784                               Locker[] destLockers,
785                               MemoryBudget mb,
786                   int lockTableIndex)
787         throws DatabaseException {
788         
789         LockType lockType = null;
790         LockInfo oldOwner = null;
791
792         if (destLockers.length == 1) {
793             return transfer(currentLocker, destLockers[0], mb, lockTableIndex);
794         } else {
795
796             /*
797              * First remove any ownership of the dest txns
798              */

799             if (firstOwner != null) {
800                 for (int i = 0; i < destLockers.length; i++) {
801                     if (firstOwner.getLocker() == destLockers[i]) {
802                         firstOwner = null;
803                         break;
804                     }
805                 }
806             }
807                  
808             if (ownerSet != null) {
809                 Iterator JavaDoc ownersIter = ownerSet.iterator();
810                 while (ownersIter.hasNext()) {
811                     LockInfo o = (LockInfo) ownersIter.next();
812                     for (int i = 0; i < destLockers.length; i++) {
813                         if (o.getLocker() == destLockers[i]) {
814                             ownersIter.remove();
815                             break;
816                         }
817                     }
818                 }
819             }
820
821             /*
822              * Create the clones
823              */

824             if (firstOwner != null) {
825                 oldOwner = cloneLockInfo(firstOwner,
826                                          currentLocker,
827                                          destLockers,
828                                          mb,
829                      lockTableIndex);
830             }
831
832             if ((ownerSet != null) && (oldOwner == null)) {
833                 Iterator JavaDoc ownersIter = ownerSet.iterator();
834                 while (ownersIter.hasNext()) {
835                     LockInfo o = (LockInfo) ownersIter.next();
836                     oldOwner = cloneLockInfo(o,
837                                              currentLocker,
838                                              destLockers,
839                                              mb,
840                          lockTableIndex);
841                     if (oldOwner != null) {
842                         break;
843                     }
844                 }
845             }
846
847             /*
848              * Check the waiters, remove any that belonged to the dest locker.
849              */

850             if (firstWaiter != null) {
851                 for (int i = 0; i < destLockers.length; i++) {
852                     if (firstWaiter.getLocker() == destLockers[i]) {
853                         firstWaiter = null;
854                         break;
855                     }
856                 }
857             }
858                         
859             if (waiterList != null) {
860                 Iterator JavaDoc iter = waiterList.iterator();
861                 while (iter.hasNext()) {
862                     LockInfo o = (LockInfo) iter.next();
863                     for (int i = 0; i < destLockers.length; i++) {
864                         if (o.getLocker() == destLockers[i]) {
865                             iter.remove();
866                             break;
867                         }
868                     }
869                 }
870             }
871         }
872             
873         boolean removed = flushOwner(oldOwner, mb, lockTableIndex);
874         assert removed;
875         return lockType;
876     }
877
878     /**
879      * If oldOwner is the current owner, clone it and transform it into a dest
880      * locker.
881      */

882     private LockInfo cloneLockInfo(LockInfo oldOwner,
883                                    Locker currentLocker,
884                                    Locker[] destLockers,
885                                    MemoryBudget mb,
886                    int lockTableIndex)
887            throws DatabaseException {
888
889         if (oldOwner.getLocker() == currentLocker) {
890             try {
891                 LockType lockType = oldOwner.getLockType();
892                 for (int i = 0; i < destLockers.length; i++) {
893                     LockInfo clonedLockInfo = (LockInfo) oldOwner.clone();
894                     clonedLockInfo.setLocker(destLockers[i]);
895                     destLockers[i].addLock(nodeId, this, lockType,
896                                            LockGrantType.NEW);
897                     addOwner(clonedLockInfo, mb, lockTableIndex);
898                 }
899                 return oldOwner;
900             } catch (CloneNotSupportedException JavaDoc e) {
901                 throw new DatabaseException(e);
902             }
903         } else {
904             return null;
905         }
906     }
907
908     /**
909      * Return the locker that has a write ownership on this lock. If no
910      * write owner exists, return null.
911      */

912     Locker getWriteOwnerLocker() {
913
914         LockInfo owner = null;
915         Iterator JavaDoc iter = null;
916         
917         if (ownerSet != null) {
918             iter = ownerSet.iterator();
919         }
920
921         if (firstOwner != null) {
922             owner = firstOwner;
923         } else if ((iter != null) && (iter.hasNext())) {
924             owner = (LockInfo) iter.next();
925         }
926
927         while (owner != null) {
928             /* Return locker if it owns a write lock. */
929             if (owner.getLockType().isWriteLock()) {
930                 return owner.getLocker();
931             }
932
933             /* Move on to the next owner. */
934             if ((iter != null) && (iter.hasNext())) {
935                 owner = (LockInfo) iter.next();
936             } else {
937                 owner = null;
938             }
939         }
940
941         return null;
942     }
943
944     /**
945      * Debugging aid, validation before a lock request.
946      */

947     private boolean validateRequest(Locker locker) {
948         if (firstWaiter != null) {
949             if (firstWaiter.getLocker() == locker) {
950                 assert false : "locker " + locker +
951                                 " is already on waiters list.";
952             }
953         }
954          
955         if (waiterList != null) {
956             Iterator JavaDoc iter = waiterList.iterator();
957             while (iter.hasNext()) {
958                 LockInfo o = (LockInfo) iter.next();
959                 if (o.getLocker() == locker) {
960                     assert false : "locker " + locker +
961                         " is already on waiters list.";
962                 }
963             }
964         }
965         return true;
966     }
967
968     /**
969      * Debug dumper.
970      */

971     public String JavaDoc toString() {
972         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
973         sb.append(" NodeId:").append(nodeId);
974         sb.append(" Owners:");
975         if (nOwners() == 0) {
976             sb.append(" (none)");
977         } else {
978             if (firstOwner != null) {
979                 sb.append(firstOwner);
980             }
981
982             if (ownerSet != null) {
983                 Iterator JavaDoc iter = ownerSet.iterator();
984                 while (iter.hasNext()) {
985                     LockInfo info = (LockInfo) iter.next();
986                     sb.append(info);
987                 }
988             }
989         }
990
991         sb.append(" Waiters:");
992         if (nWaiters() == 0) {
993             sb.append(" (none)");
994         } else {
995             sb.append(getWaitersListClone());
996         }
997         return sb.toString();
998     }
999 }
1000
Popular Tags