Esempio n. 1
0
  /**
   * Attempt to acquire a lock of <i>type</i> on <i>nodeId</i>. If the lock acquisition would result
   * in a deadlock, throw an exception.<br>
   * If the requested lock is not currently available, block until it is or until timeout
   * milliseconds have elapsed.<br>
   * If a lock of <i>type</i> is already held, return EXISTING.<br>
   * If a WRITE lock is held and a READ lock is requested, return PROMOTION.<br>
   * If a lock request is for a lock that is not currently held, return either NEW or DENIED
   * depending on whether the lock is granted or not.<br>
   *
   * @param nodeId The NodeId to lock.
   * @param locker The Locker to lock this on behalf of.
   * @param type The lock type requested.
   * @param timeout milliseconds to time out after if lock couldn't be obtained. 0 means block
   *     indefinitely. Not used if nonBlockingRequest is true.
   * @param nonBlockingRequest if true, means don't block if lock can't be acquired, and ignore the
   *     timeout parameter.
   * @return a LockGrantType indicating whether the request was fulfilled or not. LockGrantType.NEW
   *     means the lock grant was fulfilled and the caller did not previously hold the lock.
   *     PROMOTION means the lock was granted and it was a promotion from READ to WRITE. EXISTING
   *     means the lock was already granted (not a promotion). DENIED means the lock was not granted
   *     because the timeout passed without acquiring the lock or timeout was 0 and the lock was not
   *     immediately available.
   * @throws LockConflictException if lock could not be acquired.
   * @throws IllegalArgumentException via db/cursor read/write methods, if non-transactional access
   *     to a replicated environment is attempted, and read-uncommitted is not specified.
   */
  public LockGrantType lock(
      long nodeId,
      Locker locker,
      LockType type,
      long timeout,
      boolean nonBlockingRequest,
      DatabaseImpl database)
      throws LockConflictException, DatabaseException {

    assert timeout >= 0;

    /* No lock needed for dirty-read, return as soon as possible. */
    if (type == LockType.NONE) {
      return LockGrantType.NONE_NEEDED;
    }

    /*
     * Assert that a replication-defined locker is used for locks on
     * replicated databases.  Two cases are exempt from this rule:
     * - Only NameLNs that identify replicated DBs are replicated, not
     *   all NameLNs in the naming DB, so the naming DB is exempt.
     * - Non-preemption is permissible for selected internal operations
     *   because we can ensure that they are not long running and will not
     *   hold locks interminably.  A BasicLocker is often used internally
     *   in such cases.
     */
    if (envImpl.isReplicated()
        && database != null
        && database.isReplicated()
        && !database.getId().equals(DbTree.NAME_DB_ID)
        && (locker.getPreemptable() || type.isWriteLock())
        && !locker.isReplicationDefined()) {
      throw EnvironmentFailureException.unexpectedState("Locker: " + locker.getClass().getName());
    }

    /*
     * Lock on locker before latching the lockTable to avoid having another
     * notifier perform the notify before the waiter is actually waiting.
     */
    synchronized (locker) {
      LockGrantType ret = null;
      ret = lockInternal(nodeId, locker, type, timeout, nonBlockingRequest, database);
      return ret;
    }
  }