/** 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;
  }