internal int Clear() { // must be multi-thread safe with competing calls by Clear and Prune via background thread // will return the number of connections in the group after clearing has finished // First, note the old collection and create a new collection to be used ConcurrentDictionary <DbConnectionPoolIdentity, DbConnectionPool> oldPoolCollection = null; lock (this) { if (_poolCollection.Count > 0) { oldPoolCollection = _poolCollection; _poolCollection = new ConcurrentDictionary <DbConnectionPoolIdentity, DbConnectionPool>(); } } // Then, if a new collection was created, release the pools from the old collection if (oldPoolCollection != null) { foreach (var entry in oldPoolCollection) { DbConnectionPool pool = entry.Value; if (pool != null) { DbConnectionFactory connectionFactory = pool.ConnectionFactory; connectionFactory.QueuePoolForRelease(pool, true); } } } // Finally, return the pool collection count - this may be non-zero if something was added while we were clearing return(_poolCollection.Count); }
internal bool Prune() { // must only call from DbConnectionFactory.PruneConnectionPoolGroups on background timer thread // must lock(DbConnectionFactory._connectionPoolGroups.SyncRoot) before calling ReadyToRemove // to avoid conflict with DbConnectionFactory.CreateConnectionPoolGroup replacing pool entry lock (this) { if (_poolCollection.Count > 0) { var newPoolCollection = new ConcurrentDictionary <DbConnectionPoolIdentity, DbConnectionPool>(); foreach (KeyValuePair <DbConnectionPoolIdentity, DbConnectionPool> entry in _poolCollection) { DbConnectionPool pool = entry.Value; if (pool != null) { // Actually prune the pool if there are no connections in the pool and no errors occurred. // Empty pool during pruning indicates zero or low activity, but // an error state indicates the pool needs to stay around to // throttle new connection attempts. if ((!pool.ErrorOccurred) && (0 == pool.Count)) { // Order is important here. First we remove the pool // from the collection of pools so no one will try // to use it while we're processing and finally we put the // pool into a list of pools to be released when they // are completely empty. DbConnectionFactory connectionFactory = pool.ConnectionFactory; #if NETFRAMEWORK connectionFactory.PerformanceCounters.NumberOfActiveConnectionPools.Decrement(); #endif connectionFactory.QueuePoolForRelease(pool, false); } else { newPoolCollection.TryAdd(entry.Key, entry.Value); } } } _poolCollection = newPoolCollection; } // must be pruning thread to change state and no connections // otherwise pruning thread risks making entry disabled soon after user calls ClearPool if (0 == _poolCollection.Count) { if (PoolGroupStateActive == _state) { _state = PoolGroupStateIdle; SqlClientEventSource.Log.TryTraceEvent("<prov.DbConnectionPoolGroup.ClearInternal|RES|INFO|CPOOL> {0}, Idle", ObjectID); } else if (PoolGroupStateIdle == _state) { _state = PoolGroupStateDisabled; SqlClientEventSource.Log.TryTraceEvent("<prov.DbConnectionPoolGroup.ReadyToRemove|RES|INFO|CPOOL> {0}, Disabled", ObjectID); } } return(PoolGroupStateDisabled == _state); } }
internal int Clear() { // must be multi-thread safe with competing calls by Clear and Prune via background thread // will return the number of connections in the group after clearing has finished // First, note the old collection and create a new collection to be used ConcurrentDictionary <DbConnectionPoolIdentity, DbConnectionPool> oldPoolCollection = null; lock (this) { if (_poolCollection.Count > 0) { oldPoolCollection = _poolCollection; _poolCollection = new ConcurrentDictionary <DbConnectionPoolIdentity, DbConnectionPool>(); } } // Then, if a new collection was created, release the pools from the old collection if (oldPoolCollection != null) { foreach (var entry in oldPoolCollection) { DbConnectionPool pool = entry.Value; if (pool != null) { // TODO: SQLBU 422890 // Pruning a pool while a connection is currently attempting to connect // will cause the pool to be prematurely abandoned. The only known effect so // far is that the errorWait throttling will be reset when this occurs. // We should be able to avoid this situation by not pruning the pool if // it's _waitCount is non-zero (i.e. no connections *in* the pool, but also // no connections attempting to be created for the pool). DbConnectionFactory connectionFactory = pool.ConnectionFactory; connectionFactory.PerformanceCounters.NumberOfActiveConnectionPools.Decrement(); connectionFactory.QueuePoolForRelease(pool, true); } } } // Finally, return the pool collection count - this may be non-zero if something was added while we were clearing return(_poolCollection.Count); }
internal bool Prune() { // must only call from DbConnectionFactory.PruneConnectionPoolGroups on background timer thread // must lock(DbConnectionFactory._connectionPoolGroups.SyncRoot) before calling ReadyToRemove // to avoid conflict with DbConnectionFactory.CreateConnectionPoolGroup replacing pool entry lock (this) { if (_poolCollection.Count > 0) { var newPoolCollection = new ConcurrentDictionary <DbConnectionPoolIdentity, DbConnectionPool>(); foreach (var entry in _poolCollection) { DbConnectionPool pool = entry.Value; if (pool != null) { // TODO: SQLBU 422890 // Pruning a pool while a connection is currently attempting to connect // will cause the pool to be prematurely abandoned. The only known effect so // far is that the errorWait throttling will be reset when this occurs. // We should be able to avoid this situation by not pruning the pool if // it's _waitCount is non-zero (i.e. no connections *in* the pool, but also // no connections attempting to be created for the pool). // Actually prune the pool if there are no connections in the pool and no errors occurred. // Empty pool during pruning indicates zero or low activity, but // an error state indicates the pool needs to stay around to // throttle new connection attempts. if ((!pool.ErrorOccurred) && (0 == pool.Count)) { // Order is important here. First we remove the pool // from the collection of pools so no one will try // to use it while we're processing and finally we put the // pool into a list of pools to be released when they // are completely empty. DbConnectionFactory connectionFactory = pool.ConnectionFactory; connectionFactory.PerformanceCounters.NumberOfActiveConnectionPools.Decrement(); connectionFactory.QueuePoolForRelease(pool, false); } else { newPoolCollection.TryAdd(entry.Key, entry.Value); } } } _poolCollection = newPoolCollection; } // must be pruning thread to change state and no connections // otherwise pruning thread risks making entry disabled soon after user calls ClearPool if (0 == _poolCollection.Count) { if (PoolGroupStateActive == _state) { _state = PoolGroupStateIdle; Bid.Trace("<prov.DbConnectionPoolGroup.ClearInternal|RES|INFO|CPOOL> %d#, Idle\n", ObjectID); } else if (PoolGroupStateIdle == _state) { _state = PoolGroupStateDisabled; Bid.Trace("<prov.DbConnectionPoolGroup.ReadyToRemove|RES|INFO|CPOOL> %d#, Disabled\n", ObjectID); } } return(PoolGroupStateDisabled == _state); } }