/** Attempt to upgrade a share lock that we hold to an exclusive lock. */ private boolean tryUpgradeToExclusiveWithShareLockHeld( Locks.ResourceType resourceType, ConcurrentMap<Long, ForsetiLockManager.Lock> lockMap, long resourceId, SharedLock sharedLock, int tries) throws AcquireLockTimeoutException { if (sharedLock.tryAcquireUpdateLock(this)) { try { // Now we just wait for all clients to release the the share lock while (sharedLock.numberOfHolders() > 1) { waitStrategies[resourceType.typeId()].apply(tries++); markAsWaitingFor(sharedLock, resourceType, resourceId); } // No more people other than us holding this lock. Swap it to exclusive // TODO Wait, why do we need to do this? An update lock with zero shared holders is an // TODO exclusive lock, no? Why is it not enough to just atomically raise the update bit, // TODO and then wait for all the shared holders to relinquish their grasp? lockMap.put(resourceId, myExclusiveLock); return true; } catch (DeadlockDetectedException e) { sharedLock.releaseUpdateLock(this); throw e; } catch (Throwable e) { sharedLock.releaseUpdateLock(this); clearWaitList(); throw new RuntimeException(e); } } return false; }
@Override public boolean tryExclusiveLock(Locks.ResourceType resourceType, long... resourceIds) { ConcurrentMap<Long, ForsetiLockManager.Lock> lockMap = lockMaps[resourceType.typeId()]; Map<Long, Integer> heldLocks = exclusiveLockCounts[resourceType.typeId()]; for (long resourceId : resourceIds) { Integer heldCount = heldLocks.get(resourceId); if (heldCount != null) { // We already have a lock on this, just increment our local reference counter. heldLocks.put(resourceId, heldCount + 1); continue; } // Grab the global lock ForsetiLockManager.Lock lock; if ((lock = lockMap.putIfAbsent(resourceId, myExclusiveLock)) != null) { if (lock instanceof SharedLock && sharedLockCounts[resourceType.typeId()].containsKey(resourceId)) { SharedLock sharedLock = (SharedLock) lock; if (sharedLock.tryAcquireUpdateLock(this)) { if (sharedLock.numberOfHolders() == 1) { lockMap.put(resourceId, myExclusiveLock); return true; } else { sharedLock.releaseUpdateLock(this); return false; } } } return false; } heldLocks.put(resourceId, 1); } return true; }