/** 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(); } }
/** Starts creation of an overflow connection. */ private boolean startCreateOverflow() throws ResourceException { int size = _connectionPool.size(); int createCount = _createCount.incrementAndGet(); if (createCount + size <= _maxConnections + _maxOverflowConnections) return true; _createCount.decrementAndGet(); String message = L.l( "{0} cannot create overflow connection after {1}ms" + " (pool-size={2}" + ", max-connections={3}" + ", create-count={4}" + ", max-create-connections={5}" + ", max-overflow-connections={6})", this, _connectionWaitTimeout, _connectionPool.size(), _maxConnections, _createCount.get(), _maxCreateConnections, _maxOverflowConnections); HealthStatusService.updateCurrentHealthStatus(this, HealthStatus.WARNING, message); throw new ResourceException(message); }
/** Sets the max number of connections simultaneously creating */ public void setMaxCreateConnections(int maxConnections) throws ConfigException { if (maxConnections == 0) throw new ConfigException(L.l("max-create-connections '0' must be at least 1.")); _maxCreateConnections = maxConnections; if (maxConnections < 0) _maxCreateConnections = Integer.MAX_VALUE / 2; }
/** Initialize the connection manager. */ public Object init(ManagedConnectionFactory mcf) throws ConfigException, ResourceException { if (!_lifecycle.toInit()) return null; _mcf = mcf; if (_name == null) { int v = _idGen.incrementAndGet(); _name = mcf.getClass().getSimpleName() + "-" + v; } if (_tm == null) throw new ConfigException(L.l("the connection manager needs a transaction manager.")); _idlePool = new IdlePoolSet(_maxIdleCount); _connectionTime = MeterService.createActiveTimeMeter("Resin|Database|Connection"); _idleTime = MeterService.createActiveTimeMeter("Resin|Database|Idle"); _queryTime = MeterService.createActiveTimeMeter("Resin|Database|Query"); registerSelf(); _alarm = new WeakAlarm(this); if (!(mcf instanceof ValidatingManagedConnectionFactory)) { // never check _lastValidCheckTime = Long.MAX_VALUE / 2; } // recover any resources on startup if (_isEnableXA) { Subject subject = null; ManagedConnection mConn = mcf.createManagedConnection(subject, null); try { XAResource xa = mConn.getXAResource(); _tm.recover(xa); } catch (NotSupportedException e) { log.finer(e.toString()); } catch (Throwable e) { log.log(Level.FINER, e.toString(), e); } finally { mConn.destroy(); } } return mcf.createConnectionFactory(this); }
/** 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)); }