/** Adds a connection to the idle pool. */
  void toIdle(ManagedPoolItem item) {
    try {
      if (_maxConnections < _connectionPool.size() || item.isConnectionError()) {
        return;
      }

      ManagedConnection mConn = item.getManagedConnection();

      if (mConn == null) {
        return;
      }

      mConn.cleanup();

      long now = CurrentTime.getCurrentTime();

      if (_idlePool.size() == 0) _idlePoolExpire = now + _idleTimeout;

      if (_idlePoolExpire < now) {
        // shrink the idle pool when non-empty for idleTimeout
        _idlePoolExpire = now + _idleTimeout;
      } else if (_idlePool.add(mConn)) {
        item = null;
        return;
      }
    } catch (Exception e) {
      log.log(Level.FINE, e.toString(), e);
    } finally {
      notifyConnectionAvailable();

      if (item != null) item.destroy();
    }
  }
  private boolean waitForAvailableConnection(long expireTime) {
    _availableWaitCount.incrementAndGet();

    try {
      synchronized (_availableLock) {
        // return false only if the timeout occurs before the wait
        boolean isAfterWait = false;

        while (!isIdleAvailable() && !isCreateAvailable()) {
          try {
            long now = CurrentTime.getCurrentTimeActual();

            long delta = expireTime - now;

            if (delta <= 0) return isAfterWait;

            Thread.interrupted();
            _availableLock.wait(delta);

            isAfterWait = true;
          } catch (InterruptedException e) {
            log.log(Level.FINER, e.toString(), e);
          }
        }

        return true;
      }
    } finally {
      _availableWaitCount.decrementAndGet();
    }
  }
  /** Creates a new connection. */
  private UserPoolItem createConnection(
      ManagedConnectionFactory mcf,
      Subject subject,
      ConnectionRequestInfo info,
      UserPoolItem oldPoolItem)
      throws ResourceException {
    boolean isValid = false;
    ManagedPoolItem poolItem = null;

    try {
      ManagedConnection mConn = mcf.createManagedConnection(subject, info);

      if (mConn == null)
        throw new ResourceException(
            L.l("'{0}' did not return a connection from createManagedConnection", mcf));

      poolItem = new ManagedPoolItem(this, mcf, mConn);

      UserPoolItem userPoolItem;

      // Ensure the connection is still valid
      userPoolItem = poolItem.toActive(subject, info, oldPoolItem);

      if (userPoolItem == null) {
        throw new ResourceException(L.l("Connection '{0}' was not valid on creation", poolItem));
      }

      _connectionCreateCountTotal.incrementAndGet();

      synchronized (_connectionPool) {
        _connectionPool.add(poolItem);
      }

      poolItem = null;
      isValid = true;

      return userPoolItem;
    } finally {
      if (!isValid) {
        _connectionFailCountTotal.incrementAndGet();
        _lastFailTime = CurrentTime.getCurrentTime();
      }

      // server/308b - connection removed on rollback-only, when it's
      // theoretically possible to reuse it
      if (poolItem != null) poolItem.destroy();
    }
  }
  /** Allocates a connection from the idle pool. */
  private UserPoolItem allocateIdleConnection(
      ManagedConnectionFactory mcf,
      Subject subject,
      ConnectionRequestInfo info,
      UserPoolItem oldPoolItem)
      throws ResourceException {
    while (_lifecycle.isActive()) {
      ManagedConnection mConn;

      long now = CurrentTime.getCurrentTime();

      if (_lastValidCheckTime + 15000L < now) {
        _lastValidCheckTime = now;

        if (mcf instanceof ValidatingManagedConnectionFactory) {
          ValidatingManagedConnectionFactory vmcf;
          vmcf = (ValidatingManagedConnectionFactory) mcf;

          validate(vmcf);
        }
      }

      ManagedPoolItem poolItem = null;

      while (true) {
        // asks the Driver's ManagedConnectionFactory to match an
        // idle connection
        synchronized (_connectionPool) {
          mConn = mcf.matchManagedConnections(_idlePool, subject, info);

          // If there are no more idle connections, return null
          if (mConn == null) return null;

          // remove can fail for threading reasons, so only succeed if it works.
          if (!_idlePool.remove(mConn)) {
            mConn = null;
          }
        }

        if (mConn != null) {
          poolItem = findPoolItem(mConn);

          if (poolItem == null)
            throw new IllegalStateException(
                L.l("Unexpected non-matching PoolItem found for {0}", mConn));

          break;
        }
      }

      try {
        // Ensure the connection is still valid
        UserPoolItem userPoolItem;
        userPoolItem = poolItem.toActive(subject, info, oldPoolItem);

        if (userPoolItem != null) {
          poolItem = null;
          return userPoolItem;
        }
      } finally {
        if (poolItem != null) poolItem.destroy();
      }
    }

    return null;
  }
  /**
   * Allocates the pool item for a connection, creating one if necessary.
   *
   * @param mcf the driver's ManagedConnectionFactory for creating pooled connections
   * @param subject the user's authentication credentials
   * @param info the user's extra connection information
   */
  UserPoolItem allocatePoolConnection(
      ManagedConnectionFactory mcf,
      Subject subject,
      ConnectionRequestInfo info,
      UserPoolItem oldPoolItem)
      throws ResourceException {
    long expireTime = CurrentTime.getCurrentTimeActual() + _connectionWaitTimeout;

    if (!_lifecycle.isActive()) {
      throw new IllegalStateException(
          L.l("{0}: Can't allocate connection because the connection pool is closed.", this));
    }

    do {
      UserPoolItem userPoolItem = allocateIdleConnection(mcf, subject, info, oldPoolItem);

      if (userPoolItem != null) return userPoolItem;

      // if no item in pool, try to create one
      if (startCreateConnection()) {
        try {
          return createConnection(mcf, subject, info, oldPoolItem);
        } finally {
          finishCreateConnection();
        }
      }
    } while (_lifecycle.isActive() && waitForAvailableConnection(expireTime));

    if (!_lifecycle.isActive())
      throw new IllegalStateException(
          L.l("{0}: Can't allocate connection because the connection pool is closed.", this));

    String message =
        (this
            + " pool throttled create timeout"
            + " (pool-size="
            + _connectionPool.size()
            + ", max-connections="
            + _maxConnections
            + ", create-count="
            + _createCount.get()
            + ", max-create-connections="
            + _maxCreateConnections
            + ")");

    HealthStatusService.updateCurrentHealthStatus(this, HealthStatus.WARNING, message);

    if (startCreateOverflow()) {
      try {
        return createConnection(mcf, subject, info, oldPoolItem);
      } finally {
        finishCreateConnection();
      }
    }

    message =
        (this
            + " pool overflow failed to create"
            + " (pool-size="
            + _connectionPool.size()
            + ", max-connections="
            + _maxConnections
            + ", create-count="
            + _createCount.get()
            + ", max-create-connections="
            + _maxCreateConnections
            + ")");

    HealthStatusService.updateCurrentHealthStatus(this, HealthStatus.CRITICAL, message);

    throw new ResourceException(
        L.l("Can't create overflow connection connection-max={0}", _maxConnections));
  }