/** 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;
  }
  /**
   * Attempt to upgrade a share lock to an exclusive lock, grabbing the share lock if we don't hold
   * it.
   */
  private boolean tryUpgradeSharedToExclusive(
      Locks.ResourceType resourceType,
      ConcurrentMap<Long, ForsetiLockManager.Lock> lockMap,
      long resourceId,
      SharedLock sharedLock)
      throws AcquireLockTimeoutException {
    int tries = 0;
    if (!sharedLockCounts[resourceType.typeId()].containsKey(resourceId)) {
      // We don't hold the shared lock, we need to grab it to upgrade it to an exclusive one
      if (!sharedLock.acquire(this)) {
        return false;
      }

      try {
        if (tryUpgradeToExclusiveWithShareLockHeld(
            resourceType, lockMap, resourceId, sharedLock, tries)) {
          return true;
        } else {
          releaseGlobalLock(lockMap, resourceId);
          return false;
        }
      } catch (Throwable e) {
        releaseGlobalLock(lockMap, resourceId);
        throw e;
      }
    } else {
      // We do hold the shared lock, so no reason to deal with the complexity in the case above.
      return tryUpgradeToExclusiveWithShareLockHeld(
          resourceType, lockMap, resourceId, sharedLock, tries);
    }
  }
 /**
  * Atomically increment a counter in the ControllerBB sharedMap.
  *
  * @param keyBase A string from ControllerBB that prefixes a vm id to use as a key in the
  *     ControllerBB shared map. The VM id used is the current vm's id.
  */
 public static void incMapCounter(String keyBase) {
   String key = keyBase + RemoteTestModule.getMyVmid();
   Log.getLogWriter().info("Incrementing sharedMap counter " + key);
   SharedLock slock = ControllerBB.getBB().getSharedLock();
   slock.lock();
   try {
     int newValue = 0;
     Object value = ControllerBB.getBB().getSharedMap().get(key);
     if (value == null) {
       newValue = 1;
     } else {
       newValue = ((Integer) value).intValue() + 1;
     }
     ControllerBB.getBB().getSharedMap().put(key, new Integer(newValue));
     Log.getLogWriter().info("Incremented sharedMap counter, count is now " + newValue);
   } finally {
     slock.unlock();
   }
 }
  @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;
  }