private DbConnectionPool?GetConnectionPool(DbConnection owningObject, DbConnectionPoolGroup connectionPoolGroup) { // if poolgroup is disabled, it will be replaced with a new entry Debug.Assert(null != owningObject, "null owningObject?"); Debug.Assert(null != connectionPoolGroup, "null connectionPoolGroup?"); // It is possible that while the outer connection object has // been sitting around in a closed and unused state in some long // running app, the pruner may have come along and remove this // the pool entry from the master list. If we were to use a // pool entry in this state, we would create "unmanaged" pools, // which would be bad. To avoid this problem, we automagically // re-create the pool entry whenever it's disabled. // however, don't rebuild connectionOptions if no pooling is involved - let new connections do that work if (connectionPoolGroup.IsDisabled && (null != connectionPoolGroup.PoolGroupOptions)) { // reusing existing pool option in case user originally used SetConnectionPoolOptions DbConnectionPoolGroupOptions?poolOptions = connectionPoolGroup.PoolGroupOptions; // get the string to hash on again DbConnectionOptions?connectionOptions = connectionPoolGroup.ConnectionOptions; Debug.Assert(null != connectionOptions, "prevent expansion of connectionString"); connectionPoolGroup = GetConnectionPoolGroup(connectionPoolGroup.PoolKey, poolOptions, ref connectionOptions) !; Debug.Assert(null != connectionPoolGroup, "null connectionPoolGroup?"); SetConnectionPoolGroup(owningObject, connectionPoolGroup); } DbConnectionPool?connectionPool = connectionPoolGroup.GetConnectionPool(this); return(connectionPool); }
internal void MakePooledConnection(DbConnectionPool connectionPool) { // Used by DbConnectionFactory to indicate that this object IS part of // a connection pool. _createTime = DateTime.UtcNow; _connectionPool = connectionPool; }
internal void MakeNonPooledObject(object owningObject) { // Used by DbConnectionFactory to indicate that this object IS NOT part of // a connection pool. _connectionPool = null; _owningObject.Target = owningObject; _pooledCount = -1; }
internal void MakePooledConnection(DbConnectionPool connectionPool) { // Used by DbConnectionFactory to indicate that this object IS part of // a connection pool. // TODO: consider using ADP.TimerCurrent() for this. _createTime = DateTime.UtcNow; _connectionPool = connectionPool; _performanceCounters = connectionPool.PerformanceCounters; }
internal virtual void DelegatedTransactionEnded() { // Called by System.Transactions when the delegated transaction has // completed. We need to make closed connections that are in stasis // available again, or disposed closed/leaked non-pooled connections. // IMPORTANT NOTE: You must have taken a lock on the object before // you call this method to prevent race conditions with Clear and // ReclaimEmancipatedObjects. if (1 == _pooledCount) { // When _pooledCount is 1, it indicates a closed, pooled, // connection so it is ready to put back into the pool for // general use. TerminateStasis(true); Deactivate(); // call it one more time just in case DbConnectionPool?pool = Pool; if (null == pool) { throw ADP.InternalError(ADP.InternalErrorCode.PooledObjectWithoutPool); // pooled connection does not have a pool } pool.PutObjectFromTransactedPool(this); } else if (-1 == _pooledCount && !_owningObject.IsAlive) { // When _pooledCount is -1 and the owning object no longer exists, // it indicates a closed (or leaked), non-pooled connection so // it is safe to dispose. TerminateStasis(false); Deactivate(); // call it one more time just in case // it's a non-pooled connection, we need to dispose of it // once and for all, or the server will have fits about us // leaving connections open until the client-side GC kicks // in. PerformanceCounters !.NumberOfNonPooledConnections.Decrement(); Dispose(); } // When _pooledCount is 0, the connection is a pooled connection // that is either open (if the owning object is alive) or leaked (if // the owning object is not alive) In either case, we can't muck // with the connection here. }
protected abstract DbConnectionInternal CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, object poolGroupProviderInfo, DbConnectionPool?pool, DbConnection?owningConnection);
protected virtual DbConnectionInternal?CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, object poolGroupProviderInfo, DbConnectionPool?pool, DbConnection?owningConnection, DbConnectionOptions?userOptions) { return(CreateConnection(options, poolKey, poolGroupProviderInfo, pool, owningConnection)); }
protected override DbConnectionInternal CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, object poolGroupProviderInfo, DbConnectionPool?pool, DbConnection?owningObject) { // TODO-NULLABLE: owningObject may actually be null (see DbConnectionPool.CreateObject), in which case this will throw... DbConnectionInternal result = new OleDbConnectionInternal((OleDbConnectionString)options, (OleDbConnection)owningObject !); return(result); }
protected override DbConnectionInternal CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, object poolGroupProviderInfo, DbConnectionPool?pool, DbConnection?owningObject) { // TODO: owningObject may actually be null (see DbConnectionPool.CreateObject), in which case this will throw... DbConnectionInternal result = new OdbcConnectionOpen((owningObject as OdbcConnection) !, (options as OdbcConnectionString) !); return(result); }
internal DbConnectionPool?GetConnectionPool(DbConnectionFactory connectionFactory) { // When this method returns null it indicates that the connection // factory should not use pooling. // We don't support connection pooling on Win9x; // PoolGroupOptions will only be null when we're not supposed to pool // connections. DbConnectionPool?pool = null; if (null != _poolGroupOptions) { DbConnectionPoolIdentity?currentIdentity = DbConnectionPoolIdentity.NoIdentity; if (_poolGroupOptions.PoolByIdentity) { // if we're pooling by identity (because integrated security is // being used for these connections) then we need to go out and // search for the connectionPool that matches the current identity. currentIdentity = DbConnectionPoolIdentity.GetCurrent(); // If the current token is restricted in some way, then we must // not attempt to pool these connections. if (currentIdentity.IsRestricted) { currentIdentity = null; } } if (null != currentIdentity) { if (!_poolCollection.TryGetValue(currentIdentity, out pool)) // find the pool { lock (this) { // Did someone already add it to the list? if (!_poolCollection.TryGetValue(currentIdentity, out pool)) { DbConnectionPoolProviderInfo?connectionPoolProviderInfo = connectionFactory.CreateConnectionPoolProviderInfo(this.ConnectionOptions); DbConnectionPool newPool = new DbConnectionPool(connectionFactory, this, currentIdentity, connectionPoolProviderInfo); if (MarkPoolGroupAsActive()) { // If we get here, we know for certain that we there isn't // a pool that matches the current identity, so we have to // add the optimistically created one newPool.Startup(); // must start pool before usage bool addResult = _poolCollection.TryAdd(currentIdentity, newPool); Debug.Assert(addResult, "No other pool with current identity should exist at this point"); pool = newPool; } else { // else pool entry has been disabled so don't create new pools Debug.Assert(PoolGroupStateDisabled == _state, "state should be disabled"); // don't need to call connectionFactory.QueuePoolForRelease(newPool) because // pool callbacks were delayed and no risk of connections being created newPool.Shutdown(); } } else { // else found an existing pool to use instead Debug.Assert(PoolGroupStateActive == _state, "state should be active since a pool exists and lock holds"); } } } // the found pool could be in any state } } if (null == pool) { lock (this) { // keep the pool entry state active when not pooling MarkPoolGroupAsActive(); } } return(pool); }
internal virtual void CloseConnection(DbConnection owningObject, DbConnectionFactory connectionFactory) { // The implementation here is the implementation required for the // "open" internal connections, since our own private "closed" // singleton internal connection objects override this method to // prevent anything funny from happening (like disposing themselves // or putting them into a connection pool) // // Derived class should override DbConnectionInternal.Deactivate and DbConnectionInternal.Dispose // for cleaning up after DbConnection.Close // protected override void Deactivate() { // override DbConnectionInternal.Close // // do derived class connection deactivation for both pooled & non-pooled connections // } // public override void Dispose() { // override DbConnectionInternal.Close // // do derived class cleanup // base.Dispose(); // } // // overriding DbConnection.Close is also possible, but must provider for their own synchronization // public override void Close() { // override DbConnection.Close // base.Close(); // // do derived class outer connection for both pooled & non-pooled connections // // user must do their own synchronization here // } // // if the DbConnectionInternal derived class needs to close the connection it should // delegate to the DbConnection if one exists or directly call dispose // DbConnection owningObject = (DbConnection)Owner; // if (null != owningObject) { // owningObject.Close(); // force the closed state on the outer object. // } // else { // Dispose(); // } // //////////////////////////////////////////////////////////////// // DON'T MESS WITH THIS CODE UNLESS YOU KNOW WHAT YOU'RE DOING! //////////////////////////////////////////////////////////////// Debug.Assert(null != owningObject, "null owningObject"); Debug.Assert(null != connectionFactory, "null connectionFactory"); // if an exception occurs after the state change but before the try block // the connection will be stuck in OpenBusy state. The commented out try-catch // block doesn't really help because a ThreadAbort during the finally block // would just revert the connection to a bad state. // Open->Closed: guarantee internal connection is returned to correct pool if (connectionFactory.SetInnerConnectionFrom(owningObject, DbConnectionOpenBusy.SingletonInstance, this)) { // Lock to prevent race condition with cancellation lock (this) { object?lockToken = ObtainAdditionalLocksForClose(); try { PrepareForCloseConnection(); DbConnectionPool?connectionPool = Pool; // The singleton closed classes won't have owners and // connection pools, and we won't want to put them back // into the pool. if (null != connectionPool) { connectionPool.PutObject(this, owningObject); // PutObject calls Deactivate for us... // NOTE: Before we leave the PutObject call, another // thread may have already popped the connection from // the pool, so don't expect to be able to verify it. } else { Deactivate(); // ensure we de-activate non-pooled connections, or the data readers and transactions may not get cleaned up... // To prevent an endless recursion, we need to clear // the owning object before we call dispose so that // we can't get here a second time... Ordinarily, I // would call setting the owner to null a hack, but // this is safe since we're about to dispose the // object and it won't have an owner after that for // certain. _owningObject.Target = null; Dispose(); } } finally { ReleaseAdditionalLocksForClose(lockToken); // if a ThreadAbort puts us here then its possible the outer connection will not reference // this and this will be orphaned, not reclaimed by object pool until outer connection goes out of scope. connectionFactory.SetInnerConnectionEvent(owningObject, DbConnectionClosedPreviouslyOpened.SingletonInstance); } } } }
protected override DbConnectionInternal CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, object poolGroupProviderInfo, DbConnectionPool?pool, DbConnection?owningObject) { DbConnectionInternal result = new OleDbConnectionInternal((OleDbConnectionString)options, (OleDbConnection?)owningObject); return(result); }