001: /*-
002: * See the file LICENSE for redistribution information.
003: *
004: * Copyright (c) 2002,2008 Oracle. All rights reserved.
005: *
006: * $Id: Lock.java,v 1.60.2.6 2008/02/06 12:52:30 cwl Exp $
007: */
008:
009: package com.sleepycat.je.txn;
010:
011: import java.util.ArrayList;
012: import java.util.Collections;
013: import java.util.HashSet;
014: import java.util.Iterator;
015: import java.util.List;
016: import java.util.Set;
017:
018: import com.sleepycat.je.DatabaseException;
019: import com.sleepycat.je.dbi.MemoryBudget;
020:
021: /**
022: * A Lock embodies the lock state of a NodeId. It includes a set of owners and
023: * a list of waiters.
024: */
025: public// for Sizeof
026: class Lock {
027: private static final int REMOVE_LOCKINFO_OVERHEAD = 0 - MemoryBudget.LOCKINFO_OVERHEAD;
028:
029: /**
030: * A single locker always appears only once in the logical set of owners.
031: * The owners set is always in one of the following states.
032: *
033: * 1- Empty
034: * 2- A single writer
035: * 3- One or more readers
036: * 4- Multiple writers or a mix of readers and writers, all for
037: * txns which share locks (all ThreadLocker instances for the same
038: * thread)
039: *
040: * Both ownerSet and waiterList are a collection of LockInfo. Since the
041: * common case is that there is only one owner or waiter, we have added an
042: * optimization to avoid the cost of collections. FirstOwner and
043: * firstWaiter are used for the first owner or waiter of the lock, and the
044: * corresponding collection is instantiated and used only if more owners
045: * arrive.
046: *
047: * In terms of memory accounting, we count up the cost of each added or
048: * removed LockInfo, but not the cost of the HashSet/List entry
049: * overhead. We could do the latter for more precise accounting.
050: */
051: private LockInfo firstOwner;
052: private Set ownerSet;
053: private LockInfo firstWaiter;
054: private List waiterList;
055:
056: /**
057: * Create a Lock. public for Sizeof
058: */
059: public Lock() {
060: }
061:
062: /**
063: * The first waiter goes into the firstWaiter member variable. Once the
064: * waiterList is made, all appended waiters go into waiterList, even after
065: * the firstWaiter goes away and leaves that field null, so as to leave the
066: * list ordered.
067: */
068: private void addWaiterToEndOfList(LockInfo waiter, MemoryBudget mb,
069: int lockTableIndex) {
070: /* Careful: order important! */
071: if (waiterList == null) {
072: if (firstWaiter == null) {
073: firstWaiter = waiter;
074: } else {
075: waiterList = new ArrayList();
076: waiterList.add(waiter);
077: }
078: } else {
079: waiterList.add(waiter);
080: }
081: mb.updateLockMemoryUsage(MemoryBudget.LOCKINFO_OVERHEAD,
082: lockTableIndex);
083: }
084:
085: /**
086: * Add this waiter to the front of the list.
087: */
088: private void addWaiterToHeadOfList(LockInfo waiter,
089: MemoryBudget mb, int lockTableIndex) {
090: /* Shuffle the current first waiter down a slot. */
091: if (firstWaiter != null) {
092: if (waiterList == null) {
093: waiterList = new ArrayList();
094: }
095: waiterList.add(0, firstWaiter);
096: }
097:
098: firstWaiter = waiter;
099: mb.updateLockMemoryUsage(MemoryBudget.LOCKINFO_OVERHEAD,
100: lockTableIndex);
101: }
102:
103: /**
104: * Get a list of waiters for debugging and error messages.
105: */
106: List getWaitersListClone() {
107: List dumpWaiters = new ArrayList();
108: if (firstWaiter != null) {
109: dumpWaiters.add(firstWaiter);
110: }
111:
112: if (waiterList != null) {
113: dumpWaiters.addAll(waiterList);
114: }
115:
116: return dumpWaiters;
117: }
118:
119: /**
120: * Remove this locker from the waiter list.
121: */
122: void flushWaiter(Locker locker, MemoryBudget mb, int lockTableIndex) {
123: if ((firstWaiter != null)
124: && (firstWaiter.getLocker() == locker)) {
125: firstWaiter = null;
126: mb.updateLockMemoryUsage(REMOVE_LOCKINFO_OVERHEAD,
127: lockTableIndex);
128: } else if (waiterList != null) {
129: Iterator iter = waiterList.iterator();
130: while (iter.hasNext()) {
131: LockInfo info = (LockInfo) iter.next();
132: if (info.getLocker() == locker) {
133: iter.remove();
134: mb.updateLockMemoryUsage(REMOVE_LOCKINFO_OVERHEAD,
135: lockTableIndex);
136: return;
137: }
138: }
139: }
140: }
141:
142: private void addOwner(LockInfo newLock, MemoryBudget mb,
143: int lockTableIndex) {
144: if (firstOwner == null) {
145: firstOwner = newLock;
146: } else {
147: if (ownerSet == null) {
148: ownerSet = new HashSet();
149: }
150: ownerSet.add(newLock);
151: }
152: mb.updateLockMemoryUsage(MemoryBudget.LOCKINFO_OVERHEAD,
153: lockTableIndex);
154: }
155:
156: /**
157: * Get a new Set of the owners.
158: */
159: Set getOwnersClone() {
160:
161: /* No need to update memory usage, the returned Set is transient. */
162: Set owners;
163: if (ownerSet != null) {
164: owners = new HashSet(ownerSet);
165: } else {
166: owners = new HashSet();
167: }
168: if (firstOwner != null) {
169: owners.add(firstOwner);
170: }
171: return owners;
172: }
173:
174: /**
175: * Remove this LockInfo from the owner set.
176: */
177: private boolean flushOwner(LockInfo oldOwner, MemoryBudget mb,
178: int lockTableIndex) {
179: boolean removed = false;
180: if (oldOwner != null) {
181: if (firstOwner == oldOwner) {
182: firstOwner = null;
183: return true;
184: }
185:
186: if (ownerSet != null) {
187: removed = ownerSet.remove(oldOwner);
188: }
189: }
190:
191: if (removed) {
192: mb.updateLockMemoryUsage(REMOVE_LOCKINFO_OVERHEAD,
193: lockTableIndex);
194: }
195: return removed;
196: }
197:
198: /**
199: * Remove this locker from the owner set.
200: */
201: private LockInfo flushOwner(Locker locker, MemoryBudget mb,
202: int lockTableIndex) {
203: LockInfo flushedInfo = null;
204: if ((firstOwner != null) && (firstOwner.getLocker() == locker)) {
205: flushedInfo = firstOwner;
206: firstOwner = null;
207: } else if (ownerSet != null) {
208: Iterator iter = ownerSet.iterator();
209: while (iter.hasNext()) {
210: LockInfo o = (LockInfo) iter.next();
211: if (o.getLocker() == locker) {
212: iter.remove();
213: flushedInfo = o;
214: }
215: }
216: }
217: if (flushedInfo != null) {
218: mb.updateLockMemoryUsage(REMOVE_LOCKINFO_OVERHEAD,
219: lockTableIndex);
220: }
221:
222: return flushedInfo;
223: }
224:
225: /**
226: * Returns the owner LockInfo for a locker, or null if locker is not an
227: * owner.
228: */
229: private LockInfo getOwnerLockInfo(Locker locker) {
230: if ((firstOwner != null) && (firstOwner.getLocker() == locker)) {
231: return firstOwner;
232: }
233:
234: if (ownerSet != null) {
235: Iterator iter = ownerSet.iterator();
236: while (iter.hasNext()) {
237: LockInfo o = (LockInfo) iter.next();
238: if (o.getLocker() == locker) {
239: return o;
240: }
241: }
242: }
243:
244: return null;
245: }
246:
247: /**
248: * Return true if locker is an owner of this Lock for lockType,
249: * false otherwise.
250: *
251: * This method is only used by unit tests.
252: */
253: boolean isOwner(Locker locker, LockType lockType) {
254: LockInfo o = getOwnerLockInfo(locker);
255: if (o != null) {
256: LockType ownedLockType = o.getLockType();
257: if (lockType == ownedLockType) {
258: return true;
259: }
260: LockUpgrade upgrade = ownedLockType.getUpgrade(lockType);
261: if (!upgrade.getPromotion()) {
262: return true;
263: }
264: }
265: return false;
266: }
267:
268: /**
269: * Return true if locker is an owner of this Lock and this is a write
270: * lock.
271: */
272: boolean isOwnedWriteLock(Locker locker) {
273: LockInfo o = getOwnerLockInfo(locker);
274: return o != null && o.getLockType().isWriteLock();
275: }
276:
277: /**
278: * Return true if locker is a waiter on this Lock.
279: *
280: * This method is only used by unit tests.
281: */
282: boolean isWaiter(Locker locker) {
283:
284: if (firstWaiter != null) {
285: if (firstWaiter.getLocker() == locker) {
286: return true;
287: }
288: }
289:
290: if (waiterList != null) {
291: Iterator iter = waiterList.iterator();
292: while (iter.hasNext()) {
293: LockInfo info = (LockInfo) iter.next();
294: if (info.getLocker() == locker) {
295: return true;
296: }
297: }
298: }
299: return false;
300: }
301:
302: int nWaiters() {
303: int count = 0;
304: if (firstWaiter != null) {
305: count++;
306: }
307: if (waiterList != null) {
308: count += waiterList.size();
309: }
310: return count;
311: }
312:
313: int nOwners() {
314: int count = 0;
315: if (firstOwner != null) {
316: count++;
317: }
318:
319: if (ownerSet != null) {
320: count += ownerSet.size();
321: }
322: return count;
323: }
324:
325: /**
326: * Attempts to acquire the lock and returns the LockGrantType.
327: *
328: * Assumes we hold the lockTableLatch when entering this method.
329: */
330: LockGrantType lock(LockType requestType, Locker locker,
331: boolean nonBlockingRequest, MemoryBudget mb,
332: int lockTableIndex) {
333:
334: assert validateRequest(locker); // intentional side effect
335:
336: /* Request an ordinary lock by checking the owners list. */
337: LockInfo newLock = new LockInfo(locker, requestType);
338: LockGrantType grant = tryLock(newLock, nWaiters() == 0, mb,
339: lockTableIndex);
340:
341: /* Do we have to wait for this lock? */
342: if (grant == LockGrantType.WAIT_NEW
343: || grant == LockGrantType.WAIT_PROMOTION
344: || grant == LockGrantType.WAIT_RESTART) {
345:
346: /*
347: * If the request type can cause a restart and a restart conflict
348: * does not already exist, then we have to check the waiters list
349: * for restart conflicts. A restart conflict must take precedence
350: * or it may be missed.
351: */
352: if (requestType.getCausesRestart()
353: && grant != LockGrantType.WAIT_RESTART) {
354: LockInfo waiter = null;
355: Iterator iter = null;
356:
357: if (waiterList != null) {
358: iter = waiterList.iterator();
359: }
360:
361: if (firstWaiter != null) {
362: waiter = firstWaiter;
363: } else if ((iter != null) && (iter.hasNext())) {
364: waiter = (LockInfo) iter.next();
365: }
366:
367: while (waiter != null) {
368:
369: /*
370: * Check for a restart conflict. Ignore LockType.RESTART
371: * in the waiter list when checking for conflicts.
372: */
373: Locker waiterLocker = waiter.getLocker();
374: LockType waiterType = waiter.getLockType();
375: if (waiterType != LockType.RESTART
376: && locker != waiterLocker
377: && !locker.sharesLocksWith(waiterLocker)) {
378: LockConflict conflict = waiterType
379: .getConflict(requestType);
380: if (conflict.getRestart()) {
381: grant = LockGrantType.WAIT_RESTART;
382: break;
383: }
384: }
385:
386: /* Move to the next waiter, if it's in the list. */
387: if ((iter != null) && (iter.hasNext())) {
388: waiter = (LockInfo) iter.next();
389: } else {
390: waiter = null;
391: }
392: }
393: }
394:
395: /* Add the waiter or deny the lock as appropriate. */
396: if (nonBlockingRequest) {
397: grant = LockGrantType.DENIED;
398: } else {
399: if (grant == LockGrantType.WAIT_PROMOTION) {
400: addWaiterToHeadOfList(newLock, mb, lockTableIndex);
401: } else {
402: assert grant == LockGrantType.WAIT_NEW
403: || grant == LockGrantType.WAIT_RESTART;
404:
405: /*
406: * If waiting to restart, change the lock type to RESTART
407: * to avoid granting the lock later. We wait until the
408: * RESTART waiter moves to the head of waiter list to
409: * prevent the requester from spinning performing repeated
410: * restarts, but we don't grant the lock.
411: */
412: if (grant == LockGrantType.WAIT_RESTART) {
413: newLock.setLockType(LockType.RESTART);
414: }
415:
416: addWaiterToEndOfList(newLock, mb, lockTableIndex);
417: }
418: }
419: }
420:
421: return grant;
422: }
423:
424: /**
425: * Releases a lock and moves the next waiter(s) to the owners.
426: * @return
427: * null if we were not the owner,
428: * a non-empty set if owners should be notified after releasing,
429: * an empty set if no notification is required.
430: */
431: Set release(Locker locker, MemoryBudget mb, int lockTableIndex) {
432:
433: LockInfo removedLock = flushOwner(locker, mb, lockTableIndex);
434: if (removedLock == null) {
435: /* Not owner. */
436: return null;
437: }
438:
439: Set lockersToNotify = Collections.EMPTY_SET;
440:
441: if (nWaiters() == 0) {
442: /* No more waiters, so no one to notify. */
443: return lockersToNotify;
444: }
445:
446: /*
447: * Move the next set of waiters to the owners set. Iterate through the
448: * firstWaiter field, then the waiterList.
449: */
450: LockInfo waiter = null;
451: Iterator iter = null;
452: boolean isFirstWaiter = false;
453:
454: if (waiterList != null) {
455: iter = waiterList.iterator();
456: }
457:
458: if (firstWaiter != null) {
459: waiter = firstWaiter;
460: isFirstWaiter = true;
461: } else if ((iter != null) && (iter.hasNext())) {
462: waiter = (LockInfo) iter.next();
463: }
464:
465: while (waiter != null) {
466: /* Make the waiter an owner if the lock can be acquired. */
467: LockType waiterType = waiter.getLockType();
468: Locker waiterLocker = waiter.getLocker();
469: LockGrantType grant;
470: if (waiterType == LockType.RESTART) {
471: /* Special case for restarts: see rangeInsertConflict. */
472: grant = rangeInsertConflict(waiterLocker) ? LockGrantType.WAIT_NEW
473: : LockGrantType.NEW;
474: } else {
475: /* Try locking. */
476: grant = tryLock(waiter, true, mb, lockTableIndex);
477: }
478: /* Check if granted. */
479: if (grant == LockGrantType.NEW
480: || grant == LockGrantType.EXISTING
481: || grant == LockGrantType.PROMOTION) {
482: /* Remove it from the waiters list. */
483: if (isFirstWaiter) {
484: firstWaiter = null;
485: } else {
486: iter.remove();
487: }
488: if (lockersToNotify == Collections.EMPTY_SET) {
489: lockersToNotify = new HashSet();
490: }
491: lockersToNotify.add(waiterLocker);
492: mb.updateLockMemoryUsage(REMOVE_LOCKINFO_OVERHEAD,
493: lockTableIndex);
494: } else {
495: assert grant == LockGrantType.WAIT_NEW
496: || grant == LockGrantType.WAIT_PROMOTION
497: || grant == LockGrantType.WAIT_RESTART;
498: /* Stop on first waiter that cannot be an owner. */
499: break;
500: }
501:
502: /* Move to the next waiter, if it's in the list. */
503: if ((iter != null) && (iter.hasNext())) {
504: waiter = (LockInfo) iter.next();
505: isFirstWaiter = false;
506: } else {
507: waiter = null;
508: }
509: }
510: return lockersToNotify;
511: }
512:
513: /**
514: * Called from lock() to try locking a new request, and from release() to
515: * try locking a waiting request.
516: *
517: * @param newLock is the lock that is requested.
518: *
519: * @param firstWaiterInLine determines whether to grant the lock when a
520: * NEW lock can be granted, but other non-conflicting owners exist; for
521: * example, when a new READ lock is requested but READ locks are held by
522: * other owners. This parameter should be true if the requestor is the
523: * first waiter in line (or if there are no waiters), and false otherwise.
524: *
525: * @param mb is the current memory budget.
526: *
527: * @return LockGrantType.EXISTING, NEW, PROMOTION, WAIT_RESTART, WAIT_NEW
528: * or WAIT_PROMOTION.
529: */
530: private LockGrantType tryLock(LockInfo newLock,
531: boolean firstWaiterInLine, MemoryBudget mb,
532: int lockTableIndex) {
533:
534: /* If no one owns this right now, just grab it. */
535: if (nOwners() == 0) {
536: addOwner(newLock, mb, lockTableIndex);
537: return LockGrantType.NEW;
538: }
539:
540: Locker locker = newLock.getLocker();
541: LockType requestType = newLock.getLockType();
542: LockUpgrade upgrade = null;
543: LockInfo lockToUpgrade = null;
544: boolean ownerExists = false;
545: boolean ownerConflicts = false;
546:
547: /*
548: * Iterate through the current owners. See if there is a current owner
549: * who has to be upgraded from read to write. Also track whether there
550: * is a conflict with another owner.
551: */
552: LockInfo owner = null;
553: Iterator iter = null;
554:
555: if (ownerSet != null) {
556: iter = ownerSet.iterator();
557: }
558:
559: if (firstOwner != null) {
560: owner = firstOwner;
561: } else if ((iter != null) && (iter.hasNext())) {
562: owner = (LockInfo) iter.next();
563: }
564:
565: while (owner != null) {
566: Locker ownerLocker = owner.getLocker();
567: LockType ownerType = owner.getLockType();
568: if (locker == ownerLocker) {
569:
570: /*
571: * Requestor currently holds this lock: check for upgrades.
572: * If no type change is needed, return EXISTING now to avoid
573: * iterating further; otherwise, we need to check for conflicts
574: * before granting the upgrade.
575: */
576: assert (upgrade == null); // An owner should appear only once
577: upgrade = ownerType.getUpgrade(requestType);
578: if (upgrade.getUpgrade() == null) {
579: return LockGrantType.EXISTING;
580: } else {
581: lockToUpgrade = owner;
582: }
583: } else {
584:
585: /*
586: * Requestor does not hold this lock: check for conflicts.
587: * If the owner shares locks with the requestor, ignore it;
588: * otherwise, if a restart conflict exists, return it now;
589: * otherwise, save the conflict information.
590: */
591: if (!locker.sharesLocksWith(ownerLocker)) {
592: LockConflict conflict = ownerType
593: .getConflict(requestType);
594: if (conflict.getRestart()) {
595: return LockGrantType.WAIT_RESTART;
596: } else {
597: if (!conflict.getAllowed()) {
598: ownerConflicts = true;
599: }
600: ownerExists = true;
601: }
602: }
603: }
604:
605: /* Move on to the next owner. */
606: if ((iter != null) && (iter.hasNext())) {
607: owner = (LockInfo) iter.next();
608: } else {
609: owner = null;
610: }
611: }
612:
613: /* Now handle the upgrade or conflict as appropriate. */
614: if (upgrade != null) {
615: /* The requestor holds this lock. */
616: LockType upgradeType = upgrade.getUpgrade();
617: assert upgradeType != null;
618: if (!ownerConflicts) {
619: /* No conflict: grant the upgrade. */
620: lockToUpgrade.setLockType(upgradeType);
621: return upgrade.getPromotion() ? LockGrantType.PROMOTION
622: : LockGrantType.EXISTING;
623: } else {
624: /* Upgrade cannot be granted at this time. */
625: return LockGrantType.WAIT_PROMOTION;
626: }
627: } else {
628: /* The requestor doesn't hold this lock. */
629: if (!ownerConflicts && (!ownerExists || firstWaiterInLine)) {
630: /* No conflict: grant the lock. */
631: addOwner(newLock, mb, lockTableIndex);
632: return LockGrantType.NEW;
633: } else {
634: /* Lock cannot be granted at this time. */
635: return LockGrantType.WAIT_NEW;
636: }
637: }
638: }
639:
640: /**
641: * Called from release() when a RESTART request is waiting to determine if
642: * any RANGE_INSERT owners exist. We can't call tryLock for a RESTART
643: * lock because it must never be granted.
644: */
645: private boolean rangeInsertConflict(Locker waiterLocker) {
646:
647: LockInfo owner = null;
648: Iterator iter = null;
649:
650: if (ownerSet != null) {
651: iter = ownerSet.iterator();
652: }
653:
654: if (firstOwner != null) {
655: owner = firstOwner;
656: } else if ((iter != null) && (iter.hasNext())) {
657: owner = (LockInfo) iter.next();
658: }
659:
660: while (owner != null) {
661: Locker ownerLocker = owner.getLocker();
662: if (ownerLocker != waiterLocker
663: && !ownerLocker.sharesLocksWith(waiterLocker)
664: && owner.getLockType() == LockType.RANGE_INSERT) {
665: return true;
666: }
667:
668: /* Move on to the next owner. */
669: if ((iter != null) && (iter.hasNext())) {
670: owner = (LockInfo) iter.next();
671: } else {
672: owner = null;
673: }
674: }
675:
676: return false;
677: }
678:
679: /**
680: * Downgrade a write lock to a read lock.
681: */
682: void demote(Locker locker) {
683: LockInfo owner = getOwnerLockInfo(locker);
684: if (owner != null) {
685: LockType type = owner.getLockType();
686: if (type.isWriteLock()) {
687: owner
688: .setLockType((type == LockType.RANGE_WRITE) ? LockType.RANGE_READ
689: : LockType.READ);
690: }
691: }
692: }
693:
694: /**
695: * Transfer a lock from one transaction to another. Make sure that this
696: * destination locker is only present as a single reader or writer.
697: */
698: LockType transfer(Long nodeId, Locker currentLocker,
699: Locker destLocker, MemoryBudget mb, int lockTableIndex)
700: throws DatabaseException {
701:
702: /*
703: * Remove all the old owners held by the dest locker. Take all the
704: * owners held by currentLocker and make them dest lockers.
705: */
706: LockType lockType = null;
707: int numRemovedLockInfos = 0;
708:
709: if (firstOwner != null) {
710: if (firstOwner.getLocker() == destLocker) {
711: firstOwner = null;
712: numRemovedLockInfos++;
713: } else if (firstOwner.getLocker() == currentLocker) {
714: lockType = setNewLocker(nodeId, firstOwner, destLocker);
715: }
716: }
717:
718: if (ownerSet != null) {
719: Iterator iter = ownerSet.iterator();
720: while (iter.hasNext()) {
721: LockInfo owner = (LockInfo) iter.next();
722: if (owner.getLocker() == destLocker) {
723: iter.remove();
724: numRemovedLockInfos++;
725: } else if (owner.getLocker() == currentLocker) {
726: lockType = setNewLocker(nodeId, owner, destLocker);
727: }
728: }
729: }
730:
731: /* Check the waiters, remove any that belonged to the dest locker. */
732: if ((firstWaiter != null)
733: && (firstWaiter.getLocker() == destLocker)) {
734: firstWaiter = null;
735: numRemovedLockInfos++;
736: }
737: if (waiterList != null) {
738: Iterator iter = waiterList.iterator();
739: while (iter.hasNext()) {
740: LockInfo info = (LockInfo) iter.next();
741: if (info.getLocker() == destLocker) {
742: iter.remove();
743: numRemovedLockInfos++;
744: }
745: }
746: }
747:
748: mb
749: .updateLockMemoryUsage(
750: 0 - (numRemovedLockInfos * MemoryBudget.LOCKINFO_OVERHEAD),
751: lockTableIndex);
752: return lockType;
753: }
754:
755: private LockType setNewLocker(Long nodeId, LockInfo owner,
756: Locker destLocker) throws DatabaseException {
757:
758: owner.setLocker(destLocker);
759: destLocker.addLock(nodeId, owner.getLockType(),
760: LockGrantType.NEW);
761: return owner.getLockType();
762: }
763:
764: /**
765: * Transfer a lock from one transaction to many others. Only really needed
766: * for case where a write handle lock is being transferred to multiple read
767: * handles.
768: */
769: LockType transferMultiple(Long nodeId, Locker currentLocker,
770: Locker[] destLockers, MemoryBudget mb, int lockTableIndex)
771: throws DatabaseException {
772:
773: LockType lockType = null;
774: LockInfo oldOwner = null;
775:
776: if (destLockers.length == 1) {
777: return transfer(nodeId, currentLocker, destLockers[0], mb,
778: lockTableIndex);
779: } else {
780:
781: /*
782: * First remove any ownership of the dest txns
783: */
784: if (firstOwner != null) {
785: for (int i = 0; i < destLockers.length; i++) {
786: if (firstOwner.getLocker() == destLockers[i]) {
787: firstOwner = null;
788: break;
789: }
790: }
791: }
792:
793: if (ownerSet != null) {
794: Iterator ownersIter = ownerSet.iterator();
795: while (ownersIter.hasNext()) {
796: LockInfo o = (LockInfo) ownersIter.next();
797: for (int i = 0; i < destLockers.length; i++) {
798: if (o.getLocker() == destLockers[i]) {
799: ownersIter.remove();
800: break;
801: }
802: }
803: }
804: }
805:
806: /*
807: * Create the clones
808: */
809: if (firstOwner != null) {
810: oldOwner = cloneLockInfo(nodeId, firstOwner,
811: currentLocker, destLockers, mb, lockTableIndex);
812: }
813:
814: if ((ownerSet != null) && (oldOwner == null)) {
815: Iterator ownersIter = ownerSet.iterator();
816: while (ownersIter.hasNext()) {
817: LockInfo o = (LockInfo) ownersIter.next();
818: oldOwner = cloneLockInfo(nodeId, o, currentLocker,
819: destLockers, mb, lockTableIndex);
820: if (oldOwner != null) {
821: break;
822: }
823: }
824: }
825:
826: /*
827: * Check the waiters, remove any that belonged to the dest locker.
828: */
829: if (firstWaiter != null) {
830: for (int i = 0; i < destLockers.length; i++) {
831: if (firstWaiter.getLocker() == destLockers[i]) {
832: firstWaiter = null;
833: break;
834: }
835: }
836: }
837:
838: if (waiterList != null) {
839: Iterator iter = waiterList.iterator();
840: while (iter.hasNext()) {
841: LockInfo o = (LockInfo) iter.next();
842: for (int i = 0; i < destLockers.length; i++) {
843: if (o.getLocker() == destLockers[i]) {
844: iter.remove();
845: break;
846: }
847: }
848: }
849: }
850: }
851:
852: boolean removed = flushOwner(oldOwner, mb, lockTableIndex);
853: assert removed;
854: return lockType;
855: }
856:
857: /**
858: * If oldOwner is the current owner, clone it and transform it into a dest
859: * locker.
860: */
861: private LockInfo cloneLockInfo(Long nodeId, LockInfo oldOwner,
862: Locker currentLocker, Locker[] destLockers,
863: MemoryBudget mb, int lockTableIndex)
864: throws DatabaseException {
865:
866: if (oldOwner.getLocker() == currentLocker) {
867: try {
868: LockType lockType = oldOwner.getLockType();
869: for (int i = 0; i < destLockers.length; i++) {
870: LockInfo clonedLockInfo = (LockInfo) oldOwner
871: .clone();
872: clonedLockInfo.setLocker(destLockers[i]);
873: destLockers[i].addLock(nodeId, lockType,
874: LockGrantType.NEW);
875: addOwner(clonedLockInfo, mb, lockTableIndex);
876: }
877: return oldOwner;
878: } catch (CloneNotSupportedException e) {
879: throw new DatabaseException(e);
880: }
881: } else {
882: return null;
883: }
884: }
885:
886: /**
887: * Return the locker that has a write ownership on this lock. If no
888: * write owner exists, return null.
889: */
890: Locker getWriteOwnerLocker() {
891:
892: LockInfo owner = null;
893: Iterator iter = null;
894:
895: if (ownerSet != null) {
896: iter = ownerSet.iterator();
897: }
898:
899: if (firstOwner != null) {
900: owner = firstOwner;
901: } else if ((iter != null) && (iter.hasNext())) {
902: owner = (LockInfo) iter.next();
903: }
904:
905: while (owner != null) {
906: /* Return locker if it owns a write lock. */
907: if (owner.getLockType().isWriteLock()) {
908: return owner.getLocker();
909: }
910:
911: /* Move on to the next owner. */
912: if ((iter != null) && (iter.hasNext())) {
913: owner = (LockInfo) iter.next();
914: } else {
915: owner = null;
916: }
917: }
918:
919: return null;
920: }
921:
922: /**
923: * Debugging aid, validation before a lock request.
924: */
925: private boolean validateRequest(Locker locker) {
926: if (firstWaiter != null) {
927: if (firstWaiter.getLocker() == locker) {
928: assert false : "locker " + locker
929: + " is already on waiters list.";
930: }
931: }
932:
933: if (waiterList != null) {
934: Iterator iter = waiterList.iterator();
935: while (iter.hasNext()) {
936: LockInfo o = (LockInfo) iter.next();
937: if (o.getLocker() == locker) {
938: assert false : "locker " + locker
939: + " is already on waiters list.";
940: }
941: }
942: }
943: return true;
944: }
945:
946: /**
947: * Debug dumper.
948: */
949: public String toString() {
950: StringBuffer sb = new StringBuffer();
951: sb.append(" LockAddr: ").append(System.identityHashCode(this ));
952: sb.append(" Owners:");
953: if (nOwners() == 0) {
954: sb.append(" (none)");
955: } else {
956: if (firstOwner != null) {
957: sb.append(firstOwner);
958: }
959:
960: if (ownerSet != null) {
961: Iterator iter = ownerSet.iterator();
962: while (iter.hasNext()) {
963: LockInfo info = (LockInfo) iter.next();
964: sb.append(info);
965: }
966: }
967: }
968:
969: sb.append(" Waiters:");
970: if (nWaiters() == 0) {
971: sb.append(" (none)");
972: } else {
973: sb.append(getWaitersListClone());
974: }
975: return sb.toString();
976: }
977: }
|