DbConnectionPool.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / whidbey / netfxsp / ndp / fx / src / Data / System / Data / ProviderBase / DbConnectionPool.cs / 6 / DbConnectionPool.cs

                            //------------------------------------------------------------------------------ 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
//-----------------------------------------------------------------------------
 
namespace System.Data.ProviderBase { 

    using System; 
    using System.Collections;
    using System.Collections.Generic;
    using System.Data.Common;
    using System.Diagnostics; 
    using System.Globalization;
    using System.Runtime.CompilerServices; 
    using System.Runtime.ConstrainedExecution; 
    using System.Runtime.InteropServices;
    using System.Security; 
    using System.Security.Permissions;
    using System.Security.Principal;
    using System.Threading;
    using SysTx = System.Transactions; 

    sealed internal class DbConnectionPool { 
        private enum State { 
            Initializing,
            Running, 
            ShuttingDown,
        }

        internal const Bid.ApiGroup PoolerTracePoints = (Bid.ApiGroup)0x1000; 

        sealed private class TransactedConnectionPool : Hashtable { 
            DbConnectionPool _pool; 

            private static int _objectTypeCount; // Bid counter 
            internal readonly int _objectID = System.Threading.Interlocked.Increment(ref _objectTypeCount);

            internal TransactedConnectionPool(DbConnectionPool pool) : base() {
                Debug.Assert(null != pool, "null pool?"); 

                _pool = pool; 
                Bid.PoolerTrace(" %d#, Constructed for connection pool %d#\n", ObjectID, _pool.ObjectID); 
            }
 
            internal int ObjectID {
                get {
                    return _objectID;
                } 
            }
 
            internal DbConnectionPool Pool { 
                get {
                    return _pool; 
                }
            }

            internal DbConnectionInternal GetTransactedObject(SysTx.Transaction transaction) { 
                Debug.Assert(null != transaction, "null transaction?");
 
                DbConnectionInternal transactedObject = null; 

                List connections = (List)this[transaction]; 

                if (null != connections) {
                    lock (connections) {
                        int i = connections.Count - 1; 
                        if (0 <= i) {
                            transactedObject = connections[i]; 
                            connections.RemoveAt(i); 
                        }
                    } 
                }

                if (null != transactedObject) {
                    Bid.PoolerTrace(" %d#, Transaction %d#, Connection %d#, Popped.\n", ObjectID, transaction.GetHashCode(), transactedObject.ObjectID); 
                }
                return transactedObject; 
            } 

            internal void PutTransactedObject(SysTx.Transaction transaction, DbConnectionInternal transactedObject) { 
                Debug.Assert(null != transaction, "null transaction?");
                Debug.Assert(null != transactedObject, "null transactedObject?");

                Bid.PoolerTrace(" %d#, Transaction %d#, Connection %d#, Pushing.\n", ObjectID, transaction.GetHashCode(), transactedObject.ObjectID); 

                List connections = (List)this[transaction]; 
 
                // NOTE: it is possible that the connecton was put on the
                //       deactivate queue, and while it was on the queue, the 
                //       transaction ended, causing the list for the transaction
                //       to have been removed.  In that case, we can't expect
                //       the list to be here.
                if (null != connections) { 
                    lock (connections) {
                        Debug.Assert(0 > connections.IndexOf(transactedObject), "adding to pool a second time?"); 
                        connections.Add(transactedObject); 
                        Pool.PerformanceCounters.NumberOfFreeConnections.Increment();
                    } 
                }
            }

            internal void TransactionBegin(SysTx.Transaction transaction) { 
                Bid.PoolerTrace(" %d#, Transaction %d#, Begin.\n", ObjectID, transaction.GetHashCode());
 
                List connections = (List)this[transaction]; 

                if (null == connections) { 
                    List newConnections= new List(2); // start with only two connections in the list; most times we won't need that many.
                    SysTx.Transaction transactionClone = null;
                    try {
                        transactionClone = transaction.Clone(); 

                        Bid.PoolerTrace(" %d#, Transaction %d#, Adding List to transacted pool.\n", ObjectID, transaction.GetHashCode()); 
                        lock (this) { 
                            connections = (List)this[transaction];
 
                            if (null == connections) {
                                connections = newConnections;
                                this.Add(transactionClone, connections);
                                transactionClone = null; // we've used it -- don't throw it away. 
                            }
                        } 
                    } 
                    finally {
                        if (null != transactionClone) { 
                            transactionClone.Dispose();
                        }
                    }
                    newConnections = null; 
                    Bid.PoolerTrace(" %d#, Transaction %d#, Added.\n", ObjectID, transaction.GetHashCode());
                } 
            } 

            internal void TransactionEnded(SysTx.Transaction transaction, DbConnectionInternal transactedObject) { 
                Bid.PoolerTrace(" %d#, Transaction %d#, Connection %d#, Transaction Completed\n", ObjectID, transaction.GetHashCode(), transactedObject.ObjectID);

                List connections = (List)this[transaction];
                int entry = -1; 

                // NOTE: we may be ending a transaction for a connection that is 
                //       currently not in the pool, and therefore it may not have 
                //       a list for it, because it may have been removed already.
                if (null != connections) { 
                    lock (connections) {
                        entry = connections.IndexOf(transactedObject);

                        if (entry >= 0) { 
                            connections.RemoveAt(entry);
                        } 
 
                        // Once we've completed all the ended notifications, we can
                        // safely remove the list from the transacted pool. 
                        if (0 >= connections.Count) {
                            Bid.PoolerTrace(" %d#, Transaction %d#, Removing List from transacted pool.\n", ObjectID, transaction.GetHashCode());
                            lock (this) {
                                Remove(transaction); 
                            }
                            Bid.PoolerTrace(" %d#, Transaction %d#, Removed.\n", ObjectID, transaction.GetHashCode()); 
 
                            // we really need to dispose our clone; it may have
                            // native resources and GC may not happen soon enough. 
                            transaction.Dispose();
                        }
                    }
                } 

                // If (and only if) we found the connection in the list of 
                // connections, we'll put it back... 
                if (0 <= entry)  {
                    Pool.PerformanceCounters.NumberOfFreeConnections.Decrement(); 
                    Pool.PutObjectFromTransactedPool(transactedObject);
                }
            }
        } 

        private sealed class PoolWaitHandles : DbBuffer { 
 
            private readonly Semaphore _poolSemaphore;
            private readonly ManualResetEvent _errorEvent; 

            // Using a Mutex requires ThreadAffinity because SQL CLR can swap
            // the underlying Win32 thread associated with a managed thread in preemptive mode.
            // Using an AutoResetEvent does not have that complication. 
            private readonly Semaphore _creationSemaphore;
 
            private readonly SafeHandle _poolHandle; 
            private readonly SafeHandle _errorHandle;
            private readonly SafeHandle _creationHandle; 

            private readonly int _releaseFlags;

            internal PoolWaitHandles(Semaphore poolSemaphore, ManualResetEvent errorEvent, Semaphore creationSemaphore) : base(3*IntPtr.Size) { 
                bool mustRelease1 = false, mustRelease2 = false, mustRelease3 = false;
                RuntimeHelpers.PrepareConstrainedRegions(); 
                try { 
                    _poolSemaphore     = poolSemaphore;
                    _errorEvent        = errorEvent; 
                    _creationSemaphore = creationSemaphore;

                    // because SafeWaitHandle doesn't have reliability contract
                    _poolHandle     = poolSemaphore.SafeWaitHandle; 
                    _errorHandle    = errorEvent.SafeWaitHandle;
                    _creationHandle = creationSemaphore.SafeWaitHandle; 
 
                    _poolHandle.DangerousAddRef(ref mustRelease1);
                    _errorHandle.DangerousAddRef(ref mustRelease2); 
                    _creationHandle.DangerousAddRef(ref mustRelease3);

                    Debug.Assert(0 == SEMAPHORE_HANDLE, "SEMAPHORE_HANDLE");
                    Debug.Assert(1 == ERROR_HANDLE, "ERROR_HANDLE"); 
                    Debug.Assert(2 == CREATION_HANDLE, "CREATION_HANDLE");
 
                    WriteIntPtr(SEMAPHORE_HANDLE*IntPtr.Size, _poolHandle.DangerousGetHandle()); 
                    WriteIntPtr(ERROR_HANDLE*IntPtr.Size,     _errorHandle.DangerousGetHandle());
                    WriteIntPtr(CREATION_HANDLE*IntPtr.Size,  _creationHandle.DangerousGetHandle()); 
                }
                finally {
                    if (mustRelease1) {
                        _releaseFlags |= 1; 
                    }
                    if (mustRelease2) { 
                        _releaseFlags |= 2; 
                    }
                    if (mustRelease3) { 
                        _releaseFlags |= 4;
                    }
                }
            } 

            internal SafeHandle CreationHandle { 
                [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 
                get { return _creationHandle; }
            } 

            internal Semaphore CreationSemaphore {
                get { return _creationSemaphore; }
            } 

            internal ManualResetEvent ErrorEvent { 
                get { return _errorEvent; } 
            }
 
            internal Semaphore PoolSemaphore {
                get { return _poolSemaphore; }
            }
 
            protected override bool ReleaseHandle() {
                // NOTE: The SafeHandle class guarantees this will be called exactly once. 
                // we know we can touch these other managed objects because of our original DangerousAddRef 
                if (0 != (1 & _releaseFlags)) {
                    _poolHandle.DangerousRelease(); 
                }
                if (0 != (2 & _releaseFlags)) {
                    _errorHandle.DangerousRelease();
                } 
                if (0 != (4 & _releaseFlags)) {
                    _creationHandle.DangerousRelease(); 
                } 
                return base.ReleaseHandle();
            } 
        }

        private const int MAX_Q_SIZE    = (int)0x00100000;
 
        // The order of these is important; we want the WaitAny call to be signaled
        // for a free object before a creation signal.  Only the index first signaled 
        // object is returned from the WaitAny call. 
        private const int SEMAPHORE_HANDLE = (int)0x0;
        private const int ERROR_HANDLE     = (int)0x1; 
        private const int CREATION_HANDLE  = (int)0x2;
        private const int BOGUS_HANDLE     = (int)0x3;

        private const int WAIT_OBJECT_0 = 0; 
        private const int WAIT_TIMEOUT   = (int)0x102;
        private const int WAIT_ABANDONED = (int)0x80; 
        private const int WAIT_FAILED    = -1; 

        private const int ERROR_WAIT_DEFAULT = 5 * 1000; // 5 seconds 

        // we do want a testable, repeatable set of generated random numbers
        private static readonly Random _random = new Random(5101977); // Value obtained from Dave Driver
 
        private readonly int              _cleanupWait;
        private readonly DbConnectionPoolIdentity _identity; 
 
        private readonly DbConnectionFactory          _connectionFactory;
        private readonly DbConnectionPoolGroup        _connectionPoolGroup; 
        private readonly DbConnectionPoolGroupOptions _connectionPoolGroupOptions;
        private          DbConnectionPoolProviderInfo _connectionPoolProviderInfo;

        private State                     _state; 

        private readonly DbConnectionInternalListStack _stackOld = new DbConnectionInternalListStack(); 
        private readonly DbConnectionInternalListStack _stackNew = new DbConnectionInternalListStack(); 

        private readonly WaitCallback     _poolCreateRequest; 

        private readonly Queue            _deactivateQueue;
        private readonly WaitCallback     _deactivateCallback;
 
        private int                       _waitCount;
        private readonly PoolWaitHandles  _waitHandles; 
 
        private Exception                 _resError;
        private volatile bool             _errorOccurred; 

        private int                       _errorWait;
        private Timer                     _errorTimer;
 
        private Timer                     _cleanupTimer;
 
        private readonly TransactedConnectionPool _transactedConnectionPool; 

        private readonly List _objectList; 
        private int                       _totalObjects;

        private static int _objectTypeCount; // Bid counter
        internal readonly int _objectID = System.Threading.Interlocked.Increment(ref _objectTypeCount); 

        // only created by DbConnectionPoolGroup.GetConnectionPool 
        internal DbConnectionPool( 
                            DbConnectionFactory connectionFactory,
                            DbConnectionPoolGroup connectionPoolGroup, 
                            DbConnectionPoolIdentity identity,
                            DbConnectionPoolProviderInfo connectionPoolProviderInfo ) {
            Debug.Assert(ADP.IsWindowsNT, "Attempting to construct a connection pool on Win9x?");
            Debug.Assert(null != connectionPoolGroup, "null connectionPoolGroup"); 

            if ((null != identity) && identity.IsRestricted) { 
                throw ADP.InternalError(ADP.InternalErrorCode.AttemptingToPoolOnRestrictedToken); 
            }
 
            _state= State.Initializing;

            lock(_random) { // Random.Next is not thread-safe
                _cleanupWait = _random.Next(12, 24)*10*1000; // 2-4 minutes in 10 sec intervals, WebData 103603 
            }
 
            _connectionFactory = connectionFactory; 
            _connectionPoolGroup = connectionPoolGroup;
            _connectionPoolGroupOptions = connectionPoolGroup.PoolGroupOptions; 
            _connectionPoolProviderInfo = connectionPoolProviderInfo;
            _identity = identity;

            if (UseDeactivateQueue) { 
                _deactivateQueue = new Queue();
                _deactivateCallback = new WaitCallback(ProcessDeactivateQueue); 
            } 

            _waitHandles = new PoolWaitHandles( 
                                new Semaphore(0, MAX_Q_SIZE),
                                new ManualResetEvent(false),
                                new Semaphore(1, 1));
 
            _errorWait      = ERROR_WAIT_DEFAULT;
            _errorTimer     = null;  // No error yet. 
 
            _objectList     = new List(MaxPoolSize);
 
            if(ADP.IsPlatformNT5) {
                _transactedConnectionPool = new TransactedConnectionPool(this);
            }
 
            _poolCreateRequest = new WaitCallback(PoolCreateRequest); // used by CleanupCallback
            _state = State.Running; 
 
            Bid.PoolerTrace(" %d#, Constructed.\n", ObjectID);
 
            //_cleanupTimer & QueuePoolCreateRequest is delayed until DbConnectionPoolGroup calls
            // StartBackgroundCallbacks after pool is actually in the collection
        }
 
        private int CreationTimeout {
            get { return PoolGroupOptions.CreationTimeout; } 
        } 

        internal int Count { 
            get { return _totalObjects; }
        }

        internal DbConnectionFactory ConnectionFactory { 
            get { return _connectionFactory; }
        } 
 
        internal bool ErrorOccurred {
            get { return _errorOccurred; } 
        }

        private bool HasTransactionAffinity {
            get { return PoolGroupOptions.HasTransactionAffinity; } 
        }
 
        internal TimeSpan LoadBalanceTimeout { 
            get { return PoolGroupOptions.LoadBalanceTimeout; }
        } 

        private bool NeedToReplenish {
            get {
                if (State.Running != _state) // SQL BU DT 364595 - don't allow connection create when not running. 
                    return false;
 
                int totalObjects = Count; 

                if (totalObjects >= MaxPoolSize) 
                    return false;

                if (totalObjects < MinPoolSize)
                    return true; 

                int freeObjects        = (_stackNew.Count + _stackOld.Count); 
                int waitingRequests    = _waitCount; 
                bool needToReplenish = (freeObjects < waitingRequests) || ((freeObjects == waitingRequests) && (totalObjects > 1));
 
                return needToReplenish;
            }
        }
 
        internal DbConnectionPoolIdentity Identity {
            get { return _identity; } 
        } 

        internal bool IsRunning { 
            get { return State.Running == _state; }
        }

        private int MaxPoolSize { 
            get { return PoolGroupOptions.MaxPoolSize; }
        } 
 
        private int MinPoolSize {
            get { return PoolGroupOptions.MinPoolSize; } 
        }

        internal int ObjectID {
            get { 
                return _objectID;
            } 
        } 

        internal DbConnectionPoolCounters PerformanceCounters { 
            get { return _connectionFactory.PerformanceCounters; }
        }

        internal DbConnectionPoolGroup PoolGroup { 
            get { return _connectionPoolGroup; }
        } 
 
        internal DbConnectionPoolGroupOptions PoolGroupOptions {
            get { return _connectionPoolGroupOptions; } 
        }

        internal DbConnectionPoolProviderInfo ProviderInfo {
            get { return _connectionPoolProviderInfo; } 
        }
 
        private bool UseDeactivateQueue { 
            get { return PoolGroupOptions.UseDeactivateQueue; }
        } 

        internal bool UseLoadBalancing {
            get { return PoolGroupOptions.UseLoadBalancing; }
        } 

        private bool UsingIntegrateSecurity { 
            get { return (null != _identity && DbConnectionPoolIdentity.NoIdentity != _identity); } 
        }
 
        private void CleanupCallback(Object state) {
            // Called when the cleanup-timer ticks over.

            // This is the automatic prunning method.  Every period, we will 
            // perform a two-step process:
            // 
            // First, for each free object above MinPoolSize, we will obtain a 
            // semaphore representing one object and destroy one from old stack.
            // We will continue this until we either reach MinPoolSize, we are 
            // unable to obtain a free object, or we have exhausted all the
            // objects on the old stack.
            //
            // Second we move all free objects on the new stack to the old stack. 
            // So, every period the objects on the old stack are destroyed and
            // the objects on the new stack are pushed to the old stack.  All 
            // objects that are currently out and in use are not on either stack. 
            //
            // With this logic, objects are pruned from the pool if unused for 
            // at least one period but not more than two periods.

            Bid.PoolerTrace(" %d#\n", ObjectID);
 
            // Destroy free objects that put us above MinPoolSize from old stack.
            while(Count > MinPoolSize) { // While above MinPoolSize... 
 
                if (_waitHandles.PoolSemaphore.WaitOne(0, false) /* != WAIT_TIMEOUT */) {
                    // We obtained a objects from the semaphore. 
                    DbConnectionInternal obj = _stackOld.SynchronizedPop();

                    if (null != obj) {
                        // If we obtained one from the old stack, destroy it. 
                        PerformanceCounters.NumberOfFreeConnections.Decrement();
 
                        // Transaction roots must survive even aging out (TxEnd event will clean them up). 
                        bool shouldDestroy = true;
                        lock (obj) {    // Lock to prevent ---- window between IsTransactionRoot and shouldDestroy assignment 
                            if (obj.IsTransactionRoot) {
                                shouldDestroy = false;
                            }
                        } 

                        // !!!!!!!!!! WARNING !!!!!!!!!!!!! 
                        //   ONLY touch obj after lock release if shouldDestroy is false!!!  Otherwise, it may be destroyed 
                        //   by transaction-end thread!
 
                        // Note that there is a minor race condition between this task and the transaction end event, if the latter runs
                        //  between the lock above and the SetInStasis call below. The reslult is that the stasis counter may be
                        //  incremented without a corresponding decrement (the transaction end task is normally expected
                        //  to decrement, but will only do so if the stasis flag is set when it runs). I've minimized the size 
                        //  of the window, but we aren't totally eliminating it due to SetInStasis needing to do bid tracing, which
                        //  we don't want to do under this lock, if possible. It should be possible to eliminate this ---- with 
                        //  more substantial re-architecture of the pool, but we don't have the time to do that work for the current release. 

                        if (shouldDestroy) { 
                            DestroyObject(obj);
                        }
                        else {
                            obj.SetInStasis(); 
                        }
                    } 
                    else { 
                        // Else we exhausted the old stack (the object the
                        // semaphore represents is on the new stack), so break. 
                        _waitHandles.PoolSemaphore.Release(1);
                        break;
                    }
                } 
                else {
                    break; 
                } 
            }
 
            // Push to the old-stack.  For each free object, move object from
            // new stack to old stack.
            if(_waitHandles.PoolSemaphore.WaitOne(0, false) /* != WAIT_TIMEOUT */) {
                for(;;) { 
                    DbConnectionInternal obj = _stackNew.SynchronizedPop();
 
                    if (null == obj) 
                        break;
 
                    Bid.PoolerTrace(" %d#, ChangeStacks=%d#\n", ObjectID, obj.ObjectID);

                    Debug.Assert(!obj.IsEmancipated, "pooled object not in pool");
                    Debug.Assert(obj.CanBePooled,     "pooled object is not poolable"); 

                    _stackOld.SynchronizedPush(obj); 
                } 
                _waitHandles.PoolSemaphore.Release(1);
            } 

            // Queue up a request to bring us up to MinPoolSize
            QueuePoolCreateRequest();
        } 

        internal void Clear() { 
            Bid.PoolerTrace(" %d#, Clearing.\n", ObjectID); 

            DbConnectionInternal obj; 

            // First, quickly doom everything.
            lock(_objectList) {
                int count = _objectList.Count; 

                for (int i = 0; i < count; ++i) { 
                    obj = _objectList[i]; 

                    if (null != obj) { 
                        obj.DoNotPoolThisConnection();
                    }
                }
            } 

            // Second, dispose of all the free connections. 
            while (null != (obj = _stackNew.SynchronizedPop())) { 
                PerformanceCounters.NumberOfFreeConnections.Decrement();
                DestroyObject(obj); 
            }
            while (null != (obj = _stackOld.SynchronizedPop())) {
                PerformanceCounters.NumberOfFreeConnections.Decrement();
                DestroyObject(obj); 
            }
 
            // Finally, reclaim everything that's emancipated (which, because 
            // it's been doomed, will cause it to be disposed of as well)
            ReclaimEmancipatedObjects(); 

            Bid.PoolerTrace(" %d#, Cleared.\n", ObjectID);
        }
 
        private Timer CreateCleanupTimer() {
            return (new Timer(new TimerCallback(this.CleanupCallback), null, _cleanupWait, _cleanupWait)); 
        } 

        private DbConnectionInternal CreateObject(DbConnection owningObject) { 
            DbConnectionInternal newObj = null;

            try {
                newObj = _connectionFactory.CreatePooledConnection(owningObject, this, _connectionPoolGroup.ConnectionOptions); 
                if (null == newObj) {
                    throw ADP.InternalError(ADP.InternalErrorCode.CreateObjectReturnedNull);    // CreateObject succeeded, but null object 
                } 
                if (!newObj.CanBePooled) {
                    throw ADP.InternalError(ADP.InternalErrorCode.NewObjectCannotBePooled);        // CreateObject succeeded, but non-poolable object 
                }
                newObj.PrePush(null);

                lock (_objectList) { 
                    _objectList.Add(newObj);
                    _totalObjects = _objectList.Count; 
                    PerformanceCounters.NumberOfPooledConnections.Increment();   // 
                }
                Bid.PoolerTrace(" %d#, Connection %d#, Added to pool.\n", ObjectID, newObj.ObjectID); 

                // Reset the error wait:
                _errorWait = ERROR_WAIT_DEFAULT;
            } 
            catch(Exception e)  {
                // 
                if (!ADP.IsCatchableExceptionType(e)) { 
                    throw;
                } 

                ADP.TraceExceptionForCapture(e);

                newObj = null; // set to null, so we do not return bad new object 
                // Failed to create instance
                _resError = e; 
                _waitHandles.ErrorEvent.Set(); 
                   _errorOccurred = true;
                _errorTimer = new Timer(new TimerCallback(this.ErrorCallback), null, _errorWait, _errorWait); 

                if (30000 < _errorWait) {
                    _errorWait = 60000;
                } 
                else {
                    _errorWait *= 2; 
                } 
                throw;
            } 
            return newObj;
        }

        private void DeactivateObject(DbConnectionInternal obj) { 
            Bid.PoolerTrace(" %d#, Connection %d#, Deactivating.\n", ObjectID, obj.ObjectID);
 
            obj.DeactivateConnection(); // we presume this operation is safe outside of a lock... 

            if ((State.Running == _state) && !obj.IsConnectionDoomed) { 
                bool returnToGeneralPool = true;

                lock (obj) {
                    // A connection with a delegated transaction cannot currently 
                    // be returned to a different customer until the transaction
                    // actually completes, so we send it into Stasis -- the SysTx 
                    // transaction object will ensure that it is owned (not lost), 
                    // and it will be certain to put it back into the pool.
                    if (obj.IsNonPoolableTransactionRoot) { 
                        obj.SetInStasis();
                        returnToGeneralPool = false;
                    }
                    else { 
                        // We must put this connection into the transacted pool
                        // while inside a lock to prevent a race condition with 
                        // the transaction asyncronously completing on a second 
                        // thread.
                        SysTx.Transaction transaction = obj.EnlistedTransaction; 
                        if (null != transaction) {
                            TransactionBegin(transaction);  // Delayed creation of transacted pool
                            _transactedConnectionPool.PutTransactedObject(transaction, obj);
                            returnToGeneralPool = false; 
                        }
                    } 
                } 

                // Only push the connection into the general pool if we didn't 
                // already push it onto the transacted pool.
                if (returnToGeneralPool) {
                    PutNewObject(obj);
                } 
            }
            else { 
                // the object is not fit for reuse -- just dispose of it. 
                DestroyObject(obj);
                QueuePoolCreateRequest(); 
            }
        }

        private void DestroyObject(DbConnectionInternal obj) { 
            // A connection with a delegated transaction cannot be disposed of
            // until the delegated transaction has actually completed.  Instead, 
            // we simply leave it alone; when the transaction completes, it will 
            // come back through PutObjectFromTransactedPool, which will call us
            // again. 
            if (obj.IsTxRootWaitingForTxEnd) {
                Bid.PoolerTrace(" %d#, Connection %d#, Has Delegated Transaction, waiting to Dispose.\n", ObjectID, obj.ObjectID);
            }
            else { 
                Bid.PoolerTrace(" %d#, Connection %d#, Removing from pool.\n", ObjectID, obj.ObjectID);
 
                bool removed = false; 
                lock (_objectList) {
                    removed = _objectList.Remove(obj); 
                    Debug.Assert(removed, "attempt to DestroyObject not in list");
                    _totalObjects = _objectList.Count;
                }
 
                if (removed) {
                    Bid.PoolerTrace(" %d#, Connection %d#, Removed from pool.\n", ObjectID, obj.ObjectID); 
                    PerformanceCounters.NumberOfPooledConnections.Decrement(); 
                }
                obj.Dispose(); 

                Bid.PoolerTrace(" %d#, Connection %d#, Disposed.\n", ObjectID, obj.ObjectID);
                PerformanceCounters.HardDisconnectsPerSecond.Increment();
            } 
        }
 
        private void ErrorCallback(Object state) { 
            Bid.PoolerTrace(" %d#, Resetting Error handling.\n", ObjectID);
 
            _errorOccurred = false;
            _waitHandles.ErrorEvent.Reset();
            Timer t     = _errorTimer;
            _errorTimer = null; 
            if (t != null) {
                t.Dispose(); // Cancel timer request. 
            } 
        }
 
        internal DbConnectionInternal GetConnection(DbConnection owningObject) {
            DbConnectionInternal obj = null;
            SysTx.Transaction transaction = null;
 
            PerformanceCounters.SoftConnectsPerSecond.Increment();
 
            if(_state != State.Running) { 
                Bid.PoolerTrace(" %d#, DbConnectionInternal State != Running.\n", ObjectID);
                return null; 
            }

            Bid.PoolerTrace(" %d#, Getting connection.\n", ObjectID);
            // If automatic transaction enlistment is required, then we try to 
            // get the connection from the transacted connection pool first.
            if (HasTransactionAffinity) { 
                obj = GetFromTransactedPool(out transaction); 
            }
 
            if (null == obj) {
                Interlocked.Increment(ref _waitCount);
                uint waitHandleCount = 3;
                uint timeout = (uint)CreationTimeout; 

                do { 
                    int waitResult = BOGUS_HANDLE; 
                    int releaseSemaphoreResult = 0;
 
                    bool mustRelease = false;
                    RuntimeHelpers.PrepareConstrainedRegions();
                    try {
                        _waitHandles.DangerousAddRef(ref mustRelease); 

                        // We absolutely must have the value of waitResult set, 
                        // or we may leak the mutex in async abort cases. 
                        RuntimeHelpers.PrepareConstrainedRegions();
                        try { 
                            Debug.Assert(2 == waitHandleCount || 3 == waitHandleCount, "unexpected waithandle count");
                        }
                        finally {
                            waitResult = SafeNativeMethods.WaitForMultipleObjectsEx(waitHandleCount, _waitHandles.DangerousGetHandle(), false, timeout, false); 
                        }
 
                        // From the WaitAny docs: "If more than one object became signaled during 
                        // the call, this is the array index of the signaled object with the
                        // smallest index value of all the signaled objects."  This is important 
                        // so that the free object signal will be returned before a creation
                        // signal.

                        switch (waitResult) { 
                        case WAIT_TIMEOUT:
                            Bid.PoolerTrace(" %d#, Wait timed out.\n", ObjectID); 
                            Interlocked.Decrement(ref _waitCount); 
                            return null;
 
                        case ERROR_HANDLE:
                            // Throw the error that PoolCreateRequest stashed.
                            Bid.PoolerTrace(" %d#, Errors are set.\n", ObjectID);
                            Interlocked.Decrement(ref _waitCount); 
                            throw _resError;
 
                        case CREATION_HANDLE: 
                            Bid.PoolerTrace(" %d#, Creating new connection.\n", ObjectID);
 
                            try {
                                obj = UserCreateRequest(owningObject);
                            }
                            catch { 
                                if (null == obj) {
                                    Interlocked.Decrement(ref _waitCount); 
                                } 
                                throw;
                            } 
                            finally {
                                // SQLBUDT #386664 - ensure that we release this waiter, regardless
                                // of any exceptions that may be thrown.
                                if (null != obj) { 
                                    Interlocked.Decrement(ref _waitCount);
                                } 
                            } 

                            if (null == obj) { 
                                // If we were not able to create an object, check to see if
                                // we reached MaxPoolSize.  If so, we will no longer wait on
                                // the CreationHandle, but instead wait for a free object or
                                // the timeout. 

                                // 
 
                                if (Count >= MaxPoolSize && 0 != MaxPoolSize) {
                                    if (!ReclaimEmancipatedObjects()) { 
                                        // modify handle array not to wait on creation mutex anymore
                                        Debug.Assert(2 == CREATION_HANDLE, "creation handle changed value");
                                        waitHandleCount = 2;
                                    } 
                                }
                            } 
                            break; 

                        case SEMAPHORE_HANDLE: 
                            //
                            //    guaranteed available inventory
                            //
                            Interlocked.Decrement(ref _waitCount); 
                            obj = GetFromGeneralPool();
                            break; 
 
                        case WAIT_FAILED:
                            Bid.PoolerTrace(" %d#, Wait failed.\n", ObjectID); 
                            Interlocked.Decrement(ref _waitCount);
                            Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
                            goto default; // if ThrowExceptionForHR didn't throw for some reason
                        case (WAIT_ABANDONED+SEMAPHORE_HANDLE): 
                            Bid.PoolerTrace(" %d#, Semaphore handle abandonded.\n", ObjectID);
                            Interlocked.Decrement(ref _waitCount); 
                            throw new AbandonedMutexException(SEMAPHORE_HANDLE,_waitHandles.PoolSemaphore); 
                        case (WAIT_ABANDONED+ERROR_HANDLE):
                            Bid.PoolerTrace(" %d#, Error handle abandonded.\n", ObjectID); 
                            Interlocked.Decrement(ref _waitCount);
                            throw new AbandonedMutexException(ERROR_HANDLE,_waitHandles.ErrorEvent);
                        case (WAIT_ABANDONED+CREATION_HANDLE):
                            Bid.PoolerTrace(" %d#, Creation handle abandoned.\n", ObjectID); 
                            Interlocked.Decrement(ref _waitCount);
                            throw new AbandonedMutexException(CREATION_HANDLE,_waitHandles.CreationSemaphore); 
                        default: 
                            Bid.PoolerTrace(" %d#, WaitForMultipleObjects=%d\n", ObjectID, waitResult);
                            Interlocked.Decrement(ref _waitCount); 
                            throw ADP.InternalError(ADP.InternalErrorCode.UnexpectedWaitAnyResult);
                        }
                    }
                    finally { 
                        if (CREATION_HANDLE == waitResult) {
                            int result = SafeNativeMethods.ReleaseSemaphore(_waitHandles.CreationHandle.DangerousGetHandle(), 1, IntPtr.Zero); 
                            if (0 == result) { // failure case 
                                releaseSemaphoreResult = Marshal.GetHRForLastWin32Error();
                            } 
                        }
                        if (mustRelease) {
                            _waitHandles.DangerousRelease();
                        } 
                    }
                    if (0 != releaseSemaphoreResult) { 
                        Marshal.ThrowExceptionForHR(releaseSemaphoreResult); // will only throw if (hresult < 0) 
                    }
                } while (null == obj); 
            }

            if (null != obj) {
                lock (obj) {   // Protect against Clear and ReclaimEmancipatedObjects, which call IsEmancipated, which is affected by PrePush and PostPop 
                    obj.PostPop(owningObject);
                } 
                try { 
                    obj.ActivateConnection(transaction);
                } 
                catch(SecurityException) {
                    // if Activate throws an exception
                    // put it back in the pool or have it properly disposed of
                    this.PutObject(obj, owningObject); 
                    throw;
                } 
            } 
            return(obj);
        } 

        private DbConnectionInternal GetFromGeneralPool() {
            DbConnectionInternal obj = null;
 
            obj = _stackNew.SynchronizedPop();
            if (null == obj) { 
                obj = _stackOld.SynchronizedPop(); 
            }
 
            // SQLBUDT #356870 -- When another thread is clearing this pool,
            // it will remove all connections in this pool which causes the
            // following assert to fire, which really mucks up stress against
            //  checked bits.  The assert is benign, so we're commenting it out. 
            //Debug.Assert(obj != null, "GetFromGeneralPool called with nothing in the pool!");
 
            if (null != obj) { 
                Bid.PoolerTrace(" %d#, Connection %d#, Popped from general pool.\n", ObjectID, obj.ObjectID);
                PerformanceCounters.NumberOfFreeConnections.Decrement(); 
            }
            return(obj);
        }
 
        private DbConnectionInternal GetFromTransactedPool(out SysTx.Transaction transaction) {
            transaction = ADP.GetCurrentTransaction(); 
            DbConnectionInternal obj = null; 

            if (null != transaction && null != _transactedConnectionPool) { 
                obj = _transactedConnectionPool.GetTransactedObject(transaction);

                if (null != obj) {
                    Bid.PoolerTrace(" %d#, Connection %d#, Popped from transacted pool.\n", ObjectID, obj.ObjectID); 
                    PerformanceCounters.NumberOfFreeConnections.Decrement();
                } 
            } 
            return obj;
        } 

        private void PoolCreateRequest(object state) {
            // called by pooler to ensure pool requests are currently being satisfied -
            // creation mutex has not been obtained 

            IntPtr hscp; 
 
            Bid.PoolerScopeEnter(out hscp, " %d#\n", ObjectID);
 
            try {
                if (State.Running == _state) {
                    // Before creating any new objects, reclaim any released objects that were
                    // not closed. 
                    ReclaimEmancipatedObjects();
 
                    if (!ErrorOccurred) { 
                        if (NeedToReplenish) {
                            // Check to see if pool was created using integrated security and if so, make 
                            // sure the identity of current user matches that of user that created pool.
                            // If it doesn't match, do not create any objects on the ThreadPool thread,
                            // since either Open will fail or we will open a object for this pool that does
                            // not belong in this pool.  The side effect of this is that if using integrated 
                            // security min pool size cannot be guaranteed.
                            if (UsingIntegrateSecurity && !_identity.Equals(DbConnectionPoolIdentity.GetCurrent())) { 
                                return; 
                            }
                            bool mustRelease = false; 
                            int waitResult = BOGUS_HANDLE;
                            uint timeout = (uint)CreationTimeout;

                            RuntimeHelpers.PrepareConstrainedRegions(); 
                            try {
                                _waitHandles.DangerousAddRef(ref mustRelease); 
 
                                // Obtain creation mutex so we're the only one creating objects
                                // and we must have the wait result 
                                RuntimeHelpers.PrepareConstrainedRegions();
                                try { } finally {
                                    waitResult = SafeNativeMethods.WaitForSingleObjectEx(_waitHandles.CreationHandle.DangerousGetHandle(), timeout, false);
                                } 
                                if (WAIT_OBJECT_0 == waitResult) {
                                    DbConnectionInternal newObj; 
 
                                    // Check ErrorOccurred again after obtaining mutex
                                    if (!ErrorOccurred) { 
                                        while (NeedToReplenish) {
                                            newObj = CreateObject((DbConnection)null);

                                            // We do not need to check error flag here, since we know if 
                                            // CreateObject returned null, we are in error case.
                                            if (null != newObj) { 
                                                PutNewObject(newObj); 
                                            }
                                            else { 
                                                break;
                                            }
                                        }
                                    } 
                                }
                                else if (WAIT_TIMEOUT == waitResult) { 
                                    // do not wait forever and potential block this worker thread 
                                    // instead wait for a period of time and just requeue to try again
                                    QueuePoolCreateRequest(); 
                                }
                                else {
                                    // trace waitResult and ignore the failure
                                    Bid.PoolerTrace(" %d#, PoolCreateRequest called WaitForSingleObject failed %d", ObjectID, waitResult); 
                                }
                            } 
                            catch (Exception e) { 
                                //
                                if (!ADP.IsCatchableExceptionType(e)) { 
                                    throw;
                                }

                                // Now that CreateObject can throw, we need to catch the exception and discard it. 
                                // There is no further action we can take beyond tracing.  The error will be
                                // thrown to the user the next time they request a connection. 
                                Bid.PoolerTrace(" %d#, PoolCreateRequest called CreateConnection which threw an exception: " + e.ToString(), ObjectID); 
                            }
                            finally { 
                                if (WAIT_OBJECT_0 == waitResult) {
                                    // reuse waitResult and ignore its value
                                    waitResult = SafeNativeMethods.ReleaseSemaphore(_waitHandles.CreationHandle.DangerousGetHandle(), 1, IntPtr.Zero);
                                } 
                                if (mustRelease) {
                                    _waitHandles.DangerousRelease(); 
                                } 
                            }
                        } 
                    }
                }
            }
            finally { 
                Bid.ScopeLeave(ref hscp);
            } 
        } 

        private void ProcessDeactivateQueue(object state) { 
            IntPtr hscp;

            Bid.PoolerScopeEnter(out hscp, " %d#\n", ObjectID);
 
            try {
                object[] deactivateQueue; 
                lock (_deactivateQueue.SyncRoot) { 
                    deactivateQueue = _deactivateQueue.ToArray();
                    _deactivateQueue.Clear(); 
                }

                foreach (DbConnectionInternal obj in deactivateQueue) {
                    PerformanceCounters.NumberOfStasisConnections.Decrement(); 
                    DeactivateObject(obj);
                } 
            } 
            finally {
                Bid.ScopeLeave(ref hscp); 
            }
        }

        internal void PutNewObject(DbConnectionInternal obj) { 
            Debug.Assert(null != obj,        "why are we adding a null object to the pool?");
            Debug.Assert(obj.CanBePooled,    "non-poolable object in pool"); 
 
            Bid.PoolerTrace(" %d#, Connection %d#, Pushing to general pool.\n", ObjectID, obj.ObjectID);
 
            _stackNew.SynchronizedPush(obj);
            _waitHandles.PoolSemaphore.Release(1);
            PerformanceCounters.NumberOfFreeConnections.Increment();
 
        }
 
        internal void PutObject(DbConnectionInternal obj, object owningObject) { 
            Debug.Assert(null != obj, "null obj?");
 
            PerformanceCounters.SoftDisconnectsPerSecond.Increment();

            // Once a connection is closing (which is the state that we're in at
            // this point in time) you cannot delegate a transaction to or enlist 
            // a transaction in it, so we can correctly presume that if there was
            // not a delegated or enlisted transaction to start with, that there 
            // will not be a delegated or enlisted transaction once we leave the 
            // lock.
 
            lock (obj) {
                // Calling PrePush prevents the object from being reclaimed
                // once we leave the lock, because it sets _pooledCount such
                // that it won't appear to be out of the pool.  What that 
                // means, is that we're now responsible for this connection:
                // it won't get reclaimed if we drop the ball somewhere. 
                obj.PrePush(owningObject); 

                // 
            }

            if (UseDeactivateQueue) {
                // If we're using the DeactivateQueue, we'll just queue it up and 
                // be done; all the hard work will be done on the despooler thread.
 
                bool needToQueueWorkItem; 

                Bid.PoolerTrace(" %d#, Connection %d#, Queueing for deactivation.\n", ObjectID, obj.ObjectID); 
                PerformanceCounters.NumberOfStasisConnections.Increment();

                lock (_deactivateQueue.SyncRoot) {
                    needToQueueWorkItem = (0 == _deactivateQueue.Count); 
                    _deactivateQueue.Enqueue(obj);
                } 
                if (needToQueueWorkItem) { 
                    // Make sure we actually get around to deactivating the object
                    // and making it available again. 
                    ThreadPool.QueueUserWorkItem(_deactivateCallback, null);
                }
            }
            else { 
                // no deactivate queue -- do the work right now.
                DeactivateObject(obj); 
            } 
        }
 
        internal void PutObjectFromTransactedPool(DbConnectionInternal obj) {
            Debug.Assert(null != obj, "null pooledObject?");
            Debug.Assert(!obj.HasEnlistedTransaction, "pooledObject is still enlisted?");
 
            // called by the transacted connection pool , once it's removed the
            // connection from it's list.  We put the connection back in general 
            // circulation. 

            // NOTE: there is no locking required here because if we're in this 
            // method, we can safely presume that the caller is the only person
            // that is using the connection, and that all pre-push logic has been
            // done and all transactions are ended.
 
            Bid.PoolerTrace(" %d#, Connection %d#, Transaction has ended.\n", ObjectID, obj.ObjectID);
 
            if (_state == State.Running && obj.CanBePooled) { 
                PutNewObject(obj);
            } 
            else {
                DestroyObject(obj);
                QueuePoolCreateRequest();
            } 
        }
 
        private void QueuePoolCreateRequest() { 
            if (State.Running == _state) {
                // Make sure we're at quota by posting a callback to the threadpool. 
                ThreadPool.QueueUserWorkItem(_poolCreateRequest);
            }
        }
 
        private bool ReclaimEmancipatedObjects() {
            bool emancipatedObjectFound = false; 
 
            Bid.PoolerTrace(" %d#\n", ObjectID);
 
            List reclaimedObjects = new List();
            int count;

            lock(_objectList) { 
                count = _objectList.Count;
 
                for (int i = 0; i < count; ++i) { 
                    DbConnectionInternal obj = _objectList[i];
 
                    if (null != obj) {
                        bool locked = false;

                        try { 
                            locked = Monitor.TryEnter(obj);
 
                            if (locked) { // avoid race condition with PrePush/PostPop and IsEmancipated 
                                if (obj.IsEmancipated) {
                                    // Inside the lock, we want to do as little 
                                    // as possible, so we simply mark the object
                                    // as being in the pool, but hand it off to
                                    // an out of pool list to be deactivated,
                                    // etc. 
                                    obj.PrePush(null);
                                    reclaimedObjects.Add(obj); 
                                } 
                            }
                        } 
                        finally {
                            if (locked)
                                Monitor.Exit(obj);
                        } 
                    }
                } 
            } 

            // NOTE: we don't want to call DeactivateObject while we're locked, 
            // because it can make roundtrips to the server and this will block
            // object creation in the pooler.  Instead, we queue things we need
            // to do up, and process them outside the lock.
            count = reclaimedObjects.Count; 

            for (int i = 0; i < count; ++i) { 
                DbConnectionInternal obj = reclaimedObjects[i]; 

                Bid.PoolerTrace(" %d#, Connection %d#, Reclaiming.\n", ObjectID, obj.ObjectID); 
                PerformanceCounters.NumberOfReclaimedConnections.Increment();

                emancipatedObjectFound = true;
 
                // NOTE: it is not possible for us to have a connection that has
                // a delegated transaction at this point, because IsEmancipated 
                // would not have returned true if it did, and when a connection 
                // is emancipated, you can't enlist in a transaction (because you
                // can't get to it to make the call...) 
                DeactivateObject(obj);
            }
            return emancipatedObjectFound;
        } 

        internal void Startup() { 
            Bid.PoolerTrace(" %d#, CleanupWait=%d\n", ObjectID, _cleanupWait); 

            _cleanupTimer = CreateCleanupTimer(); 
            if (NeedToReplenish) {
                QueuePoolCreateRequest();
            }
        } 

        internal void Shutdown() { 
            Bid.PoolerTrace(" %d#\n", ObjectID); 

            _state = State.ShuttingDown; 

            Timer t; // deactivate timer callbacks

            t = _cleanupTimer; 
            _cleanupTimer = null;
            if (null != t) { 
                t.Dispose(); 
            }
 
            t = _errorTimer;
            _errorTimer = null;
            if (null != t) {
                t.Dispose(); 
            }
        } 
 
        internal void TransactionBegin(SysTx.Transaction transaction) {
            TransactedConnectionPool transactedConnectionPool = _transactedConnectionPool; 
            if (null != transactedConnectionPool) {
                transactedConnectionPool.TransactionBegin(transaction);
            }
        } 

        internal void TransactionEnded(SysTx.Transaction transaction, DbConnectionInternal transactedObject) { 
            Debug.Assert(null != transaction, "null transaction?"); 
            Debug.Assert(null != transactedObject, "null transactedObject?");
            // Note: connection may still be associated with transaction due to Explicit Unbinding requirement. 

            Bid.PoolerTrace(" %d#, Transaction %d#, Connection %d#, Transaction Completed\n", ObjectID, transaction.GetHashCode(), transactedObject.ObjectID);

            // called by the internal connection when it get's told that the 
            // transaction is completed.  We tell the transacted pool to remove
            // the connection from it's list, then we put the connection back in 
            // general circulation. 

            TransactedConnectionPool transactedConnectionPool = _transactedConnectionPool; 
            if (null != transactedConnectionPool) {
                transactedConnectionPool.TransactionEnded(transaction, transactedObject);
            }
        } 

        private DbConnectionInternal UserCreateRequest(DbConnection owningObject) { 
            // called by user when they were not able to obtain a free object but 
            // instead obtained creation mutex
 
            DbConnectionInternal obj = null;
            if (ErrorOccurred) {
               throw _resError;
            } 
            else {
                 if ((Count < MaxPoolSize) || (0 == MaxPoolSize)) { 
                    // If we have an odd number of total objects, reclaim any dead objects. 
                    // If we did not find any objects to reclaim, create a new one.
 
                    //
                     if ((Count & 0x1) == 0x1 || !ReclaimEmancipatedObjects())
                        obj = CreateObject(owningObject);
                } 
                return obj;
            } 
        } 

        private class DbConnectionInternalListStack { 
            private DbConnectionInternal _stack;
#if DEBUG
            private int _version;
            private int _count; 
#endif
            internal DbConnectionInternalListStack() { 
            } 

            internal int Count { 
                get {
                    int count = 0;
                    lock(this) {
                        for(DbConnectionInternal x = _stack; null != x; x = x.NextPooledObject) { 
                            ++count;
                        } 
                    } 
#if DEBUG
                    Debug.Assert(count == _count, "count is corrupt"); 
#endif
                    return count;
                }
            } 

            internal DbConnectionInternal SynchronizedPop() { 
                DbConnectionInternal value; 
                lock(this) {
                    value = _stack; 
                    if (null != value) {
                        _stack = value.NextPooledObject;
                        value.NextPooledObject = null;
#if DEBUG 
                        _version++;
                        _count--; 
#endif 
                    }
#if DEBUG 
                    Debug.Assert((null != value || 0 == _count) && (0 <= _count), "broken SynchronizedPop");
#endif
                }
                return value; 
            }
 
            internal void SynchronizedPush(DbConnectionInternal value) { 
                Debug.Assert(null != value, "pushing null value");
                lock(this) { 
#if DEBUG
                    Debug.Assert(null == value.NextPooledObject, "pushing value with non-null NextPooledObject");
                    int index = 0;
                    for(DbConnectionInternal x = _stack; null != x; x = x.NextPooledObject, ++index) { 
                        Debug.Assert(x != value, "double push: connection already in stack");
                    } 
                    Debug.Assert(_count == index, "SynchronizedPush count is corrupt"); 
#endif
                    value.NextPooledObject = _stack; 
                    _stack = value;
#if DEBUG
                    _version++;
                    _count++; 
#endif
                } 
            } 
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
//-----------------------------------------------------------------------------
 
namespace System.Data.ProviderBase { 

    using System; 
    using System.Collections;
    using System.Collections.Generic;
    using System.Data.Common;
    using System.Diagnostics; 
    using System.Globalization;
    using System.Runtime.CompilerServices; 
    using System.Runtime.ConstrainedExecution; 
    using System.Runtime.InteropServices;
    using System.Security; 
    using System.Security.Permissions;
    using System.Security.Principal;
    using System.Threading;
    using SysTx = System.Transactions; 

    sealed internal class DbConnectionPool { 
        private enum State { 
            Initializing,
            Running, 
            ShuttingDown,
        }

        internal const Bid.ApiGroup PoolerTracePoints = (Bid.ApiGroup)0x1000; 

        sealed private class TransactedConnectionPool : Hashtable { 
            DbConnectionPool _pool; 

            private static int _objectTypeCount; // Bid counter 
            internal readonly int _objectID = System.Threading.Interlocked.Increment(ref _objectTypeCount);

            internal TransactedConnectionPool(DbConnectionPool pool) : base() {
                Debug.Assert(null != pool, "null pool?"); 

                _pool = pool; 
                Bid.PoolerTrace(" %d#, Constructed for connection pool %d#\n", ObjectID, _pool.ObjectID); 
            }
 
            internal int ObjectID {
                get {
                    return _objectID;
                } 
            }
 
            internal DbConnectionPool Pool { 
                get {
                    return _pool; 
                }
            }

            internal DbConnectionInternal GetTransactedObject(SysTx.Transaction transaction) { 
                Debug.Assert(null != transaction, "null transaction?");
 
                DbConnectionInternal transactedObject = null; 

                List connections = (List)this[transaction]; 

                if (null != connections) {
                    lock (connections) {
                        int i = connections.Count - 1; 
                        if (0 <= i) {
                            transactedObject = connections[i]; 
                            connections.RemoveAt(i); 
                        }
                    } 
                }

                if (null != transactedObject) {
                    Bid.PoolerTrace(" %d#, Transaction %d#, Connection %d#, Popped.\n", ObjectID, transaction.GetHashCode(), transactedObject.ObjectID); 
                }
                return transactedObject; 
            } 

            internal void PutTransactedObject(SysTx.Transaction transaction, DbConnectionInternal transactedObject) { 
                Debug.Assert(null != transaction, "null transaction?");
                Debug.Assert(null != transactedObject, "null transactedObject?");

                Bid.PoolerTrace(" %d#, Transaction %d#, Connection %d#, Pushing.\n", ObjectID, transaction.GetHashCode(), transactedObject.ObjectID); 

                List connections = (List)this[transaction]; 
 
                // NOTE: it is possible that the connecton was put on the
                //       deactivate queue, and while it was on the queue, the 
                //       transaction ended, causing the list for the transaction
                //       to have been removed.  In that case, we can't expect
                //       the list to be here.
                if (null != connections) { 
                    lock (connections) {
                        Debug.Assert(0 > connections.IndexOf(transactedObject), "adding to pool a second time?"); 
                        connections.Add(transactedObject); 
                        Pool.PerformanceCounters.NumberOfFreeConnections.Increment();
                    } 
                }
            }

            internal void TransactionBegin(SysTx.Transaction transaction) { 
                Bid.PoolerTrace(" %d#, Transaction %d#, Begin.\n", ObjectID, transaction.GetHashCode());
 
                List connections = (List)this[transaction]; 

                if (null == connections) { 
                    List newConnections= new List(2); // start with only two connections in the list; most times we won't need that many.
                    SysTx.Transaction transactionClone = null;
                    try {
                        transactionClone = transaction.Clone(); 

                        Bid.PoolerTrace(" %d#, Transaction %d#, Adding List to transacted pool.\n", ObjectID, transaction.GetHashCode()); 
                        lock (this) { 
                            connections = (List)this[transaction];
 
                            if (null == connections) {
                                connections = newConnections;
                                this.Add(transactionClone, connections);
                                transactionClone = null; // we've used it -- don't throw it away. 
                            }
                        } 
                    } 
                    finally {
                        if (null != transactionClone) { 
                            transactionClone.Dispose();
                        }
                    }
                    newConnections = null; 
                    Bid.PoolerTrace(" %d#, Transaction %d#, Added.\n", ObjectID, transaction.GetHashCode());
                } 
            } 

            internal void TransactionEnded(SysTx.Transaction transaction, DbConnectionInternal transactedObject) { 
                Bid.PoolerTrace(" %d#, Transaction %d#, Connection %d#, Transaction Completed\n", ObjectID, transaction.GetHashCode(), transactedObject.ObjectID);

                List connections = (List)this[transaction];
                int entry = -1; 

                // NOTE: we may be ending a transaction for a connection that is 
                //       currently not in the pool, and therefore it may not have 
                //       a list for it, because it may have been removed already.
                if (null != connections) { 
                    lock (connections) {
                        entry = connections.IndexOf(transactedObject);

                        if (entry >= 0) { 
                            connections.RemoveAt(entry);
                        } 
 
                        // Once we've completed all the ended notifications, we can
                        // safely remove the list from the transacted pool. 
                        if (0 >= connections.Count) {
                            Bid.PoolerTrace(" %d#, Transaction %d#, Removing List from transacted pool.\n", ObjectID, transaction.GetHashCode());
                            lock (this) {
                                Remove(transaction); 
                            }
                            Bid.PoolerTrace(" %d#, Transaction %d#, Removed.\n", ObjectID, transaction.GetHashCode()); 
 
                            // we really need to dispose our clone; it may have
                            // native resources and GC may not happen soon enough. 
                            transaction.Dispose();
                        }
                    }
                } 

                // If (and only if) we found the connection in the list of 
                // connections, we'll put it back... 
                if (0 <= entry)  {
                    Pool.PerformanceCounters.NumberOfFreeConnections.Decrement(); 
                    Pool.PutObjectFromTransactedPool(transactedObject);
                }
            }
        } 

        private sealed class PoolWaitHandles : DbBuffer { 
 
            private readonly Semaphore _poolSemaphore;
            private readonly ManualResetEvent _errorEvent; 

            // Using a Mutex requires ThreadAffinity because SQL CLR can swap
            // the underlying Win32 thread associated with a managed thread in preemptive mode.
            // Using an AutoResetEvent does not have that complication. 
            private readonly Semaphore _creationSemaphore;
 
            private readonly SafeHandle _poolHandle; 
            private readonly SafeHandle _errorHandle;
            private readonly SafeHandle _creationHandle; 

            private readonly int _releaseFlags;

            internal PoolWaitHandles(Semaphore poolSemaphore, ManualResetEvent errorEvent, Semaphore creationSemaphore) : base(3*IntPtr.Size) { 
                bool mustRelease1 = false, mustRelease2 = false, mustRelease3 = false;
                RuntimeHelpers.PrepareConstrainedRegions(); 
                try { 
                    _poolSemaphore     = poolSemaphore;
                    _errorEvent        = errorEvent; 
                    _creationSemaphore = creationSemaphore;

                    // because SafeWaitHandle doesn't have reliability contract
                    _poolHandle     = poolSemaphore.SafeWaitHandle; 
                    _errorHandle    = errorEvent.SafeWaitHandle;
                    _creationHandle = creationSemaphore.SafeWaitHandle; 
 
                    _poolHandle.DangerousAddRef(ref mustRelease1);
                    _errorHandle.DangerousAddRef(ref mustRelease2); 
                    _creationHandle.DangerousAddRef(ref mustRelease3);

                    Debug.Assert(0 == SEMAPHORE_HANDLE, "SEMAPHORE_HANDLE");
                    Debug.Assert(1 == ERROR_HANDLE, "ERROR_HANDLE"); 
                    Debug.Assert(2 == CREATION_HANDLE, "CREATION_HANDLE");
 
                    WriteIntPtr(SEMAPHORE_HANDLE*IntPtr.Size, _poolHandle.DangerousGetHandle()); 
                    WriteIntPtr(ERROR_HANDLE*IntPtr.Size,     _errorHandle.DangerousGetHandle());
                    WriteIntPtr(CREATION_HANDLE*IntPtr.Size,  _creationHandle.DangerousGetHandle()); 
                }
                finally {
                    if (mustRelease1) {
                        _releaseFlags |= 1; 
                    }
                    if (mustRelease2) { 
                        _releaseFlags |= 2; 
                    }
                    if (mustRelease3) { 
                        _releaseFlags |= 4;
                    }
                }
            } 

            internal SafeHandle CreationHandle { 
                [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 
                get { return _creationHandle; }
            } 

            internal Semaphore CreationSemaphore {
                get { return _creationSemaphore; }
            } 

            internal ManualResetEvent ErrorEvent { 
                get { return _errorEvent; } 
            }
 
            internal Semaphore PoolSemaphore {
                get { return _poolSemaphore; }
            }
 
            protected override bool ReleaseHandle() {
                // NOTE: The SafeHandle class guarantees this will be called exactly once. 
                // we know we can touch these other managed objects because of our original DangerousAddRef 
                if (0 != (1 & _releaseFlags)) {
                    _poolHandle.DangerousRelease(); 
                }
                if (0 != (2 & _releaseFlags)) {
                    _errorHandle.DangerousRelease();
                } 
                if (0 != (4 & _releaseFlags)) {
                    _creationHandle.DangerousRelease(); 
                } 
                return base.ReleaseHandle();
            } 
        }

        private const int MAX_Q_SIZE    = (int)0x00100000;
 
        // The order of these is important; we want the WaitAny call to be signaled
        // for a free object before a creation signal.  Only the index first signaled 
        // object is returned from the WaitAny call. 
        private const int SEMAPHORE_HANDLE = (int)0x0;
        private const int ERROR_HANDLE     = (int)0x1; 
        private const int CREATION_HANDLE  = (int)0x2;
        private const int BOGUS_HANDLE     = (int)0x3;

        private const int WAIT_OBJECT_0 = 0; 
        private const int WAIT_TIMEOUT   = (int)0x102;
        private const int WAIT_ABANDONED = (int)0x80; 
        private const int WAIT_FAILED    = -1; 

        private const int ERROR_WAIT_DEFAULT = 5 * 1000; // 5 seconds 

        // we do want a testable, repeatable set of generated random numbers
        private static readonly Random _random = new Random(5101977); // Value obtained from Dave Driver
 
        private readonly int              _cleanupWait;
        private readonly DbConnectionPoolIdentity _identity; 
 
        private readonly DbConnectionFactory          _connectionFactory;
        private readonly DbConnectionPoolGroup        _connectionPoolGroup; 
        private readonly DbConnectionPoolGroupOptions _connectionPoolGroupOptions;
        private          DbConnectionPoolProviderInfo _connectionPoolProviderInfo;

        private State                     _state; 

        private readonly DbConnectionInternalListStack _stackOld = new DbConnectionInternalListStack(); 
        private readonly DbConnectionInternalListStack _stackNew = new DbConnectionInternalListStack(); 

        private readonly WaitCallback     _poolCreateRequest; 

        private readonly Queue            _deactivateQueue;
        private readonly WaitCallback     _deactivateCallback;
 
        private int                       _waitCount;
        private readonly PoolWaitHandles  _waitHandles; 
 
        private Exception                 _resError;
        private volatile bool             _errorOccurred; 

        private int                       _errorWait;
        private Timer                     _errorTimer;
 
        private Timer                     _cleanupTimer;
 
        private readonly TransactedConnectionPool _transactedConnectionPool; 

        private readonly List _objectList; 
        private int                       _totalObjects;

        private static int _objectTypeCount; // Bid counter
        internal readonly int _objectID = System.Threading.Interlocked.Increment(ref _objectTypeCount); 

        // only created by DbConnectionPoolGroup.GetConnectionPool 
        internal DbConnectionPool( 
                            DbConnectionFactory connectionFactory,
                            DbConnectionPoolGroup connectionPoolGroup, 
                            DbConnectionPoolIdentity identity,
                            DbConnectionPoolProviderInfo connectionPoolProviderInfo ) {
            Debug.Assert(ADP.IsWindowsNT, "Attempting to construct a connection pool on Win9x?");
            Debug.Assert(null != connectionPoolGroup, "null connectionPoolGroup"); 

            if ((null != identity) && identity.IsRestricted) { 
                throw ADP.InternalError(ADP.InternalErrorCode.AttemptingToPoolOnRestrictedToken); 
            }
 
            _state= State.Initializing;

            lock(_random) { // Random.Next is not thread-safe
                _cleanupWait = _random.Next(12, 24)*10*1000; // 2-4 minutes in 10 sec intervals, WebData 103603 
            }
 
            _connectionFactory = connectionFactory; 
            _connectionPoolGroup = connectionPoolGroup;
            _connectionPoolGroupOptions = connectionPoolGroup.PoolGroupOptions; 
            _connectionPoolProviderInfo = connectionPoolProviderInfo;
            _identity = identity;

            if (UseDeactivateQueue) { 
                _deactivateQueue = new Queue();
                _deactivateCallback = new WaitCallback(ProcessDeactivateQueue); 
            } 

            _waitHandles = new PoolWaitHandles( 
                                new Semaphore(0, MAX_Q_SIZE),
                                new ManualResetEvent(false),
                                new Semaphore(1, 1));
 
            _errorWait      = ERROR_WAIT_DEFAULT;
            _errorTimer     = null;  // No error yet. 
 
            _objectList     = new List(MaxPoolSize);
 
            if(ADP.IsPlatformNT5) {
                _transactedConnectionPool = new TransactedConnectionPool(this);
            }
 
            _poolCreateRequest = new WaitCallback(PoolCreateRequest); // used by CleanupCallback
            _state = State.Running; 
 
            Bid.PoolerTrace(" %d#, Constructed.\n", ObjectID);
 
            //_cleanupTimer & QueuePoolCreateRequest is delayed until DbConnectionPoolGroup calls
            // StartBackgroundCallbacks after pool is actually in the collection
        }
 
        private int CreationTimeout {
            get { return PoolGroupOptions.CreationTimeout; } 
        } 

        internal int Count { 
            get { return _totalObjects; }
        }

        internal DbConnectionFactory ConnectionFactory { 
            get { return _connectionFactory; }
        } 
 
        internal bool ErrorOccurred {
            get { return _errorOccurred; } 
        }

        private bool HasTransactionAffinity {
            get { return PoolGroupOptions.HasTransactionAffinity; } 
        }
 
        internal TimeSpan LoadBalanceTimeout { 
            get { return PoolGroupOptions.LoadBalanceTimeout; }
        } 

        private bool NeedToReplenish {
            get {
                if (State.Running != _state) // SQL BU DT 364595 - don't allow connection create when not running. 
                    return false;
 
                int totalObjects = Count; 

                if (totalObjects >= MaxPoolSize) 
                    return false;

                if (totalObjects < MinPoolSize)
                    return true; 

                int freeObjects        = (_stackNew.Count + _stackOld.Count); 
                int waitingRequests    = _waitCount; 
                bool needToReplenish = (freeObjects < waitingRequests) || ((freeObjects == waitingRequests) && (totalObjects > 1));
 
                return needToReplenish;
            }
        }
 
        internal DbConnectionPoolIdentity Identity {
            get { return _identity; } 
        } 

        internal bool IsRunning { 
            get { return State.Running == _state; }
        }

        private int MaxPoolSize { 
            get { return PoolGroupOptions.MaxPoolSize; }
        } 
 
        private int MinPoolSize {
            get { return PoolGroupOptions.MinPoolSize; } 
        }

        internal int ObjectID {
            get { 
                return _objectID;
            } 
        } 

        internal DbConnectionPoolCounters PerformanceCounters { 
            get { return _connectionFactory.PerformanceCounters; }
        }

        internal DbConnectionPoolGroup PoolGroup { 
            get { return _connectionPoolGroup; }
        } 
 
        internal DbConnectionPoolGroupOptions PoolGroupOptions {
            get { return _connectionPoolGroupOptions; } 
        }

        internal DbConnectionPoolProviderInfo ProviderInfo {
            get { return _connectionPoolProviderInfo; } 
        }
 
        private bool UseDeactivateQueue { 
            get { return PoolGroupOptions.UseDeactivateQueue; }
        } 

        internal bool UseLoadBalancing {
            get { return PoolGroupOptions.UseLoadBalancing; }
        } 

        private bool UsingIntegrateSecurity { 
            get { return (null != _identity && DbConnectionPoolIdentity.NoIdentity != _identity); } 
        }
 
        private void CleanupCallback(Object state) {
            // Called when the cleanup-timer ticks over.

            // This is the automatic prunning method.  Every period, we will 
            // perform a two-step process:
            // 
            // First, for each free object above MinPoolSize, we will obtain a 
            // semaphore representing one object and destroy one from old stack.
            // We will continue this until we either reach MinPoolSize, we are 
            // unable to obtain a free object, or we have exhausted all the
            // objects on the old stack.
            //
            // Second we move all free objects on the new stack to the old stack. 
            // So, every period the objects on the old stack are destroyed and
            // the objects on the new stack are pushed to the old stack.  All 
            // objects that are currently out and in use are not on either stack. 
            //
            // With this logic, objects are pruned from the pool if unused for 
            // at least one period but not more than two periods.

            Bid.PoolerTrace(" %d#\n", ObjectID);
 
            // Destroy free objects that put us above MinPoolSize from old stack.
            while(Count > MinPoolSize) { // While above MinPoolSize... 
 
                if (_waitHandles.PoolSemaphore.WaitOne(0, false) /* != WAIT_TIMEOUT */) {
                    // We obtained a objects from the semaphore. 
                    DbConnectionInternal obj = _stackOld.SynchronizedPop();

                    if (null != obj) {
                        // If we obtained one from the old stack, destroy it. 
                        PerformanceCounters.NumberOfFreeConnections.Decrement();
 
                        // Transaction roots must survive even aging out (TxEnd event will clean them up). 
                        bool shouldDestroy = true;
                        lock (obj) {    // Lock to prevent ---- window between IsTransactionRoot and shouldDestroy assignment 
                            if (obj.IsTransactionRoot) {
                                shouldDestroy = false;
                            }
                        } 

                        // !!!!!!!!!! WARNING !!!!!!!!!!!!! 
                        //   ONLY touch obj after lock release if shouldDestroy is false!!!  Otherwise, it may be destroyed 
                        //   by transaction-end thread!
 
                        // Note that there is a minor race condition between this task and the transaction end event, if the latter runs
                        //  between the lock above and the SetInStasis call below. The reslult is that the stasis counter may be
                        //  incremented without a corresponding decrement (the transaction end task is normally expected
                        //  to decrement, but will only do so if the stasis flag is set when it runs). I've minimized the size 
                        //  of the window, but we aren't totally eliminating it due to SetInStasis needing to do bid tracing, which
                        //  we don't want to do under this lock, if possible. It should be possible to eliminate this ---- with 
                        //  more substantial re-architecture of the pool, but we don't have the time to do that work for the current release. 

                        if (shouldDestroy) { 
                            DestroyObject(obj);
                        }
                        else {
                            obj.SetInStasis(); 
                        }
                    } 
                    else { 
                        // Else we exhausted the old stack (the object the
                        // semaphore represents is on the new stack), so break. 
                        _waitHandles.PoolSemaphore.Release(1);
                        break;
                    }
                } 
                else {
                    break; 
                } 
            }
 
            // Push to the old-stack.  For each free object, move object from
            // new stack to old stack.
            if(_waitHandles.PoolSemaphore.WaitOne(0, false) /* != WAIT_TIMEOUT */) {
                for(;;) { 
                    DbConnectionInternal obj = _stackNew.SynchronizedPop();
 
                    if (null == obj) 
                        break;
 
                    Bid.PoolerTrace(" %d#, ChangeStacks=%d#\n", ObjectID, obj.ObjectID);

                    Debug.Assert(!obj.IsEmancipated, "pooled object not in pool");
                    Debug.Assert(obj.CanBePooled,     "pooled object is not poolable"); 

                    _stackOld.SynchronizedPush(obj); 
                } 
                _waitHandles.PoolSemaphore.Release(1);
            } 

            // Queue up a request to bring us up to MinPoolSize
            QueuePoolCreateRequest();
        } 

        internal void Clear() { 
            Bid.PoolerTrace(" %d#, Clearing.\n", ObjectID); 

            DbConnectionInternal obj; 

            // First, quickly doom everything.
            lock(_objectList) {
                int count = _objectList.Count; 

                for (int i = 0; i < count; ++i) { 
                    obj = _objectList[i]; 

                    if (null != obj) { 
                        obj.DoNotPoolThisConnection();
                    }
                }
            } 

            // Second, dispose of all the free connections. 
            while (null != (obj = _stackNew.SynchronizedPop())) { 
                PerformanceCounters.NumberOfFreeConnections.Decrement();
                DestroyObject(obj); 
            }
            while (null != (obj = _stackOld.SynchronizedPop())) {
                PerformanceCounters.NumberOfFreeConnections.Decrement();
                DestroyObject(obj); 
            }
 
            // Finally, reclaim everything that's emancipated (which, because 
            // it's been doomed, will cause it to be disposed of as well)
            ReclaimEmancipatedObjects(); 

            Bid.PoolerTrace(" %d#, Cleared.\n", ObjectID);
        }
 
        private Timer CreateCleanupTimer() {
            return (new Timer(new TimerCallback(this.CleanupCallback), null, _cleanupWait, _cleanupWait)); 
        } 

        private DbConnectionInternal CreateObject(DbConnection owningObject) { 
            DbConnectionInternal newObj = null;

            try {
                newObj = _connectionFactory.CreatePooledConnection(owningObject, this, _connectionPoolGroup.ConnectionOptions); 
                if (null == newObj) {
                    throw ADP.InternalError(ADP.InternalErrorCode.CreateObjectReturnedNull);    // CreateObject succeeded, but null object 
                } 
                if (!newObj.CanBePooled) {
                    throw ADP.InternalError(ADP.InternalErrorCode.NewObjectCannotBePooled);        // CreateObject succeeded, but non-poolable object 
                }
                newObj.PrePush(null);

                lock (_objectList) { 
                    _objectList.Add(newObj);
                    _totalObjects = _objectList.Count; 
                    PerformanceCounters.NumberOfPooledConnections.Increment();   // 
                }
                Bid.PoolerTrace(" %d#, Connection %d#, Added to pool.\n", ObjectID, newObj.ObjectID); 

                // Reset the error wait:
                _errorWait = ERROR_WAIT_DEFAULT;
            } 
            catch(Exception e)  {
                // 
                if (!ADP.IsCatchableExceptionType(e)) { 
                    throw;
                } 

                ADP.TraceExceptionForCapture(e);

                newObj = null; // set to null, so we do not return bad new object 
                // Failed to create instance
                _resError = e; 
                _waitHandles.ErrorEvent.Set(); 
                   _errorOccurred = true;
                _errorTimer = new Timer(new TimerCallback(this.ErrorCallback), null, _errorWait, _errorWait); 

                if (30000 < _errorWait) {
                    _errorWait = 60000;
                } 
                else {
                    _errorWait *= 2; 
                } 
                throw;
            } 
            return newObj;
        }

        private void DeactivateObject(DbConnectionInternal obj) { 
            Bid.PoolerTrace(" %d#, Connection %d#, Deactivating.\n", ObjectID, obj.ObjectID);
 
            obj.DeactivateConnection(); // we presume this operation is safe outside of a lock... 

            if ((State.Running == _state) && !obj.IsConnectionDoomed) { 
                bool returnToGeneralPool = true;

                lock (obj) {
                    // A connection with a delegated transaction cannot currently 
                    // be returned to a different customer until the transaction
                    // actually completes, so we send it into Stasis -- the SysTx 
                    // transaction object will ensure that it is owned (not lost), 
                    // and it will be certain to put it back into the pool.
                    if (obj.IsNonPoolableTransactionRoot) { 
                        obj.SetInStasis();
                        returnToGeneralPool = false;
                    }
                    else { 
                        // We must put this connection into the transacted pool
                        // while inside a lock to prevent a race condition with 
                        // the transaction asyncronously completing on a second 
                        // thread.
                        SysTx.Transaction transaction = obj.EnlistedTransaction; 
                        if (null != transaction) {
                            TransactionBegin(transaction);  // Delayed creation of transacted pool
                            _transactedConnectionPool.PutTransactedObject(transaction, obj);
                            returnToGeneralPool = false; 
                        }
                    } 
                } 

                // Only push the connection into the general pool if we didn't 
                // already push it onto the transacted pool.
                if (returnToGeneralPool) {
                    PutNewObject(obj);
                } 
            }
            else { 
                // the object is not fit for reuse -- just dispose of it. 
                DestroyObject(obj);
                QueuePoolCreateRequest(); 
            }
        }

        private void DestroyObject(DbConnectionInternal obj) { 
            // A connection with a delegated transaction cannot be disposed of
            // until the delegated transaction has actually completed.  Instead, 
            // we simply leave it alone; when the transaction completes, it will 
            // come back through PutObjectFromTransactedPool, which will call us
            // again. 
            if (obj.IsTxRootWaitingForTxEnd) {
                Bid.PoolerTrace(" %d#, Connection %d#, Has Delegated Transaction, waiting to Dispose.\n", ObjectID, obj.ObjectID);
            }
            else { 
                Bid.PoolerTrace(" %d#, Connection %d#, Removing from pool.\n", ObjectID, obj.ObjectID);
 
                bool removed = false; 
                lock (_objectList) {
                    removed = _objectList.Remove(obj); 
                    Debug.Assert(removed, "attempt to DestroyObject not in list");
                    _totalObjects = _objectList.Count;
                }
 
                if (removed) {
                    Bid.PoolerTrace(" %d#, Connection %d#, Removed from pool.\n", ObjectID, obj.ObjectID); 
                    PerformanceCounters.NumberOfPooledConnections.Decrement(); 
                }
                obj.Dispose(); 

                Bid.PoolerTrace(" %d#, Connection %d#, Disposed.\n", ObjectID, obj.ObjectID);
                PerformanceCounters.HardDisconnectsPerSecond.Increment();
            } 
        }
 
        private void ErrorCallback(Object state) { 
            Bid.PoolerTrace(" %d#, Resetting Error handling.\n", ObjectID);
 
            _errorOccurred = false;
            _waitHandles.ErrorEvent.Reset();
            Timer t     = _errorTimer;
            _errorTimer = null; 
            if (t != null) {
                t.Dispose(); // Cancel timer request. 
            } 
        }
 
        internal DbConnectionInternal GetConnection(DbConnection owningObject) {
            DbConnectionInternal obj = null;
            SysTx.Transaction transaction = null;
 
            PerformanceCounters.SoftConnectsPerSecond.Increment();
 
            if(_state != State.Running) { 
                Bid.PoolerTrace(" %d#, DbConnectionInternal State != Running.\n", ObjectID);
                return null; 
            }

            Bid.PoolerTrace(" %d#, Getting connection.\n", ObjectID);
            // If automatic transaction enlistment is required, then we try to 
            // get the connection from the transacted connection pool first.
            if (HasTransactionAffinity) { 
                obj = GetFromTransactedPool(out transaction); 
            }
 
            if (null == obj) {
                Interlocked.Increment(ref _waitCount);
                uint waitHandleCount = 3;
                uint timeout = (uint)CreationTimeout; 

                do { 
                    int waitResult = BOGUS_HANDLE; 
                    int releaseSemaphoreResult = 0;
 
                    bool mustRelease = false;
                    RuntimeHelpers.PrepareConstrainedRegions();
                    try {
                        _waitHandles.DangerousAddRef(ref mustRelease); 

                        // We absolutely must have the value of waitResult set, 
                        // or we may leak the mutex in async abort cases. 
                        RuntimeHelpers.PrepareConstrainedRegions();
                        try { 
                            Debug.Assert(2 == waitHandleCount || 3 == waitHandleCount, "unexpected waithandle count");
                        }
                        finally {
                            waitResult = SafeNativeMethods.WaitForMultipleObjectsEx(waitHandleCount, _waitHandles.DangerousGetHandle(), false, timeout, false); 
                        }
 
                        // From the WaitAny docs: "If more than one object became signaled during 
                        // the call, this is the array index of the signaled object with the
                        // smallest index value of all the signaled objects."  This is important 
                        // so that the free object signal will be returned before a creation
                        // signal.

                        switch (waitResult) { 
                        case WAIT_TIMEOUT:
                            Bid.PoolerTrace(" %d#, Wait timed out.\n", ObjectID); 
                            Interlocked.Decrement(ref _waitCount); 
                            return null;
 
                        case ERROR_HANDLE:
                            // Throw the error that PoolCreateRequest stashed.
                            Bid.PoolerTrace(" %d#, Errors are set.\n", ObjectID);
                            Interlocked.Decrement(ref _waitCount); 
                            throw _resError;
 
                        case CREATION_HANDLE: 
                            Bid.PoolerTrace(" %d#, Creating new connection.\n", ObjectID);
 
                            try {
                                obj = UserCreateRequest(owningObject);
                            }
                            catch { 
                                if (null == obj) {
                                    Interlocked.Decrement(ref _waitCount); 
                                } 
                                throw;
                            } 
                            finally {
                                // SQLBUDT #386664 - ensure that we release this waiter, regardless
                                // of any exceptions that may be thrown.
                                if (null != obj) { 
                                    Interlocked.Decrement(ref _waitCount);
                                } 
                            } 

                            if (null == obj) { 
                                // If we were not able to create an object, check to see if
                                // we reached MaxPoolSize.  If so, we will no longer wait on
                                // the CreationHandle, but instead wait for a free object or
                                // the timeout. 

                                // 
 
                                if (Count >= MaxPoolSize && 0 != MaxPoolSize) {
                                    if (!ReclaimEmancipatedObjects()) { 
                                        // modify handle array not to wait on creation mutex anymore
                                        Debug.Assert(2 == CREATION_HANDLE, "creation handle changed value");
                                        waitHandleCount = 2;
                                    } 
                                }
                            } 
                            break; 

                        case SEMAPHORE_HANDLE: 
                            //
                            //    guaranteed available inventory
                            //
                            Interlocked.Decrement(ref _waitCount); 
                            obj = GetFromGeneralPool();
                            break; 
 
                        case WAIT_FAILED:
                            Bid.PoolerTrace(" %d#, Wait failed.\n", ObjectID); 
                            Interlocked.Decrement(ref _waitCount);
                            Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
                            goto default; // if ThrowExceptionForHR didn't throw for some reason
                        case (WAIT_ABANDONED+SEMAPHORE_HANDLE): 
                            Bid.PoolerTrace(" %d#, Semaphore handle abandonded.\n", ObjectID);
                            Interlocked.Decrement(ref _waitCount); 
                            throw new AbandonedMutexException(SEMAPHORE_HANDLE,_waitHandles.PoolSemaphore); 
                        case (WAIT_ABANDONED+ERROR_HANDLE):
                            Bid.PoolerTrace(" %d#, Error handle abandonded.\n", ObjectID); 
                            Interlocked.Decrement(ref _waitCount);
                            throw new AbandonedMutexException(ERROR_HANDLE,_waitHandles.ErrorEvent);
                        case (WAIT_ABANDONED+CREATION_HANDLE):
                            Bid.PoolerTrace(" %d#, Creation handle abandoned.\n", ObjectID); 
                            Interlocked.Decrement(ref _waitCount);
                            throw new AbandonedMutexException(CREATION_HANDLE,_waitHandles.CreationSemaphore); 
                        default: 
                            Bid.PoolerTrace(" %d#, WaitForMultipleObjects=%d\n", ObjectID, waitResult);
                            Interlocked.Decrement(ref _waitCount); 
                            throw ADP.InternalError(ADP.InternalErrorCode.UnexpectedWaitAnyResult);
                        }
                    }
                    finally { 
                        if (CREATION_HANDLE == waitResult) {
                            int result = SafeNativeMethods.ReleaseSemaphore(_waitHandles.CreationHandle.DangerousGetHandle(), 1, IntPtr.Zero); 
                            if (0 == result) { // failure case 
                                releaseSemaphoreResult = Marshal.GetHRForLastWin32Error();
                            } 
                        }
                        if (mustRelease) {
                            _waitHandles.DangerousRelease();
                        } 
                    }
                    if (0 != releaseSemaphoreResult) { 
                        Marshal.ThrowExceptionForHR(releaseSemaphoreResult); // will only throw if (hresult < 0) 
                    }
                } while (null == obj); 
            }

            if (null != obj) {
                lock (obj) {   // Protect against Clear and ReclaimEmancipatedObjects, which call IsEmancipated, which is affected by PrePush and PostPop 
                    obj.PostPop(owningObject);
                } 
                try { 
                    obj.ActivateConnection(transaction);
                } 
                catch(SecurityException) {
                    // if Activate throws an exception
                    // put it back in the pool or have it properly disposed of
                    this.PutObject(obj, owningObject); 
                    throw;
                } 
            } 
            return(obj);
        } 

        private DbConnectionInternal GetFromGeneralPool() {
            DbConnectionInternal obj = null;
 
            obj = _stackNew.SynchronizedPop();
            if (null == obj) { 
                obj = _stackOld.SynchronizedPop(); 
            }
 
            // SQLBUDT #356870 -- When another thread is clearing this pool,
            // it will remove all connections in this pool which causes the
            // following assert to fire, which really mucks up stress against
            //  checked bits.  The assert is benign, so we're commenting it out. 
            //Debug.Assert(obj != null, "GetFromGeneralPool called with nothing in the pool!");
 
            if (null != obj) { 
                Bid.PoolerTrace(" %d#, Connection %d#, Popped from general pool.\n", ObjectID, obj.ObjectID);
                PerformanceCounters.NumberOfFreeConnections.Decrement(); 
            }
            return(obj);
        }
 
        private DbConnectionInternal GetFromTransactedPool(out SysTx.Transaction transaction) {
            transaction = ADP.GetCurrentTransaction(); 
            DbConnectionInternal obj = null; 

            if (null != transaction && null != _transactedConnectionPool) { 
                obj = _transactedConnectionPool.GetTransactedObject(transaction);

                if (null != obj) {
                    Bid.PoolerTrace(" %d#, Connection %d#, Popped from transacted pool.\n", ObjectID, obj.ObjectID); 
                    PerformanceCounters.NumberOfFreeConnections.Decrement();
                } 
            } 
            return obj;
        } 

        private void PoolCreateRequest(object state) {
            // called by pooler to ensure pool requests are currently being satisfied -
            // creation mutex has not been obtained 

            IntPtr hscp; 
 
            Bid.PoolerScopeEnter(out hscp, " %d#\n", ObjectID);
 
            try {
                if (State.Running == _state) {
                    // Before creating any new objects, reclaim any released objects that were
                    // not closed. 
                    ReclaimEmancipatedObjects();
 
                    if (!ErrorOccurred) { 
                        if (NeedToReplenish) {
                            // Check to see if pool was created using integrated security and if so, make 
                            // sure the identity of current user matches that of user that created pool.
                            // If it doesn't match, do not create any objects on the ThreadPool thread,
                            // since either Open will fail or we will open a object for this pool that does
                            // not belong in this pool.  The side effect of this is that if using integrated 
                            // security min pool size cannot be guaranteed.
                            if (UsingIntegrateSecurity && !_identity.Equals(DbConnectionPoolIdentity.GetCurrent())) { 
                                return; 
                            }
                            bool mustRelease = false; 
                            int waitResult = BOGUS_HANDLE;
                            uint timeout = (uint)CreationTimeout;

                            RuntimeHelpers.PrepareConstrainedRegions(); 
                            try {
                                _waitHandles.DangerousAddRef(ref mustRelease); 
 
                                // Obtain creation mutex so we're the only one creating objects
                                // and we must have the wait result 
                                RuntimeHelpers.PrepareConstrainedRegions();
                                try { } finally {
                                    waitResult = SafeNativeMethods.WaitForSingleObjectEx(_waitHandles.CreationHandle.DangerousGetHandle(), timeout, false);
                                } 
                                if (WAIT_OBJECT_0 == waitResult) {
                                    DbConnectionInternal newObj; 
 
                                    // Check ErrorOccurred again after obtaining mutex
                                    if (!ErrorOccurred) { 
                                        while (NeedToReplenish) {
                                            newObj = CreateObject((DbConnection)null);

                                            // We do not need to check error flag here, since we know if 
                                            // CreateObject returned null, we are in error case.
                                            if (null != newObj) { 
                                                PutNewObject(newObj); 
                                            }
                                            else { 
                                                break;
                                            }
                                        }
                                    } 
                                }
                                else if (WAIT_TIMEOUT == waitResult) { 
                                    // do not wait forever and potential block this worker thread 
                                    // instead wait for a period of time and just requeue to try again
                                    QueuePoolCreateRequest(); 
                                }
                                else {
                                    // trace waitResult and ignore the failure
                                    Bid.PoolerTrace(" %d#, PoolCreateRequest called WaitForSingleObject failed %d", ObjectID, waitResult); 
                                }
                            } 
                            catch (Exception e) { 
                                //
                                if (!ADP.IsCatchableExceptionType(e)) { 
                                    throw;
                                }

                                // Now that CreateObject can throw, we need to catch the exception and discard it. 
                                // There is no further action we can take beyond tracing.  The error will be
                                // thrown to the user the next time they request a connection. 
                                Bid.PoolerTrace(" %d#, PoolCreateRequest called CreateConnection which threw an exception: " + e.ToString(), ObjectID); 
                            }
                            finally { 
                                if (WAIT_OBJECT_0 == waitResult) {
                                    // reuse waitResult and ignore its value
                                    waitResult = SafeNativeMethods.ReleaseSemaphore(_waitHandles.CreationHandle.DangerousGetHandle(), 1, IntPtr.Zero);
                                } 
                                if (mustRelease) {
                                    _waitHandles.DangerousRelease(); 
                                } 
                            }
                        } 
                    }
                }
            }
            finally { 
                Bid.ScopeLeave(ref hscp);
            } 
        } 

        private void ProcessDeactivateQueue(object state) { 
            IntPtr hscp;

            Bid.PoolerScopeEnter(out hscp, " %d#\n", ObjectID);
 
            try {
                object[] deactivateQueue; 
                lock (_deactivateQueue.SyncRoot) { 
                    deactivateQueue = _deactivateQueue.ToArray();
                    _deactivateQueue.Clear(); 
                }

                foreach (DbConnectionInternal obj in deactivateQueue) {
                    PerformanceCounters.NumberOfStasisConnections.Decrement(); 
                    DeactivateObject(obj);
                } 
            } 
            finally {
                Bid.ScopeLeave(ref hscp); 
            }
        }

        internal void PutNewObject(DbConnectionInternal obj) { 
            Debug.Assert(null != obj,        "why are we adding a null object to the pool?");
            Debug.Assert(obj.CanBePooled,    "non-poolable object in pool"); 
 
            Bid.PoolerTrace(" %d#, Connection %d#, Pushing to general pool.\n", ObjectID, obj.ObjectID);
 
            _stackNew.SynchronizedPush(obj);
            _waitHandles.PoolSemaphore.Release(1);
            PerformanceCounters.NumberOfFreeConnections.Increment();
 
        }
 
        internal void PutObject(DbConnectionInternal obj, object owningObject) { 
            Debug.Assert(null != obj, "null obj?");
 
            PerformanceCounters.SoftDisconnectsPerSecond.Increment();

            // Once a connection is closing (which is the state that we're in at
            // this point in time) you cannot delegate a transaction to or enlist 
            // a transaction in it, so we can correctly presume that if there was
            // not a delegated or enlisted transaction to start with, that there 
            // will not be a delegated or enlisted transaction once we leave the 
            // lock.
 
            lock (obj) {
                // Calling PrePush prevents the object from being reclaimed
                // once we leave the lock, because it sets _pooledCount such
                // that it won't appear to be out of the pool.  What that 
                // means, is that we're now responsible for this connection:
                // it won't get reclaimed if we drop the ball somewhere. 
                obj.PrePush(owningObject); 

                // 
            }

            if (UseDeactivateQueue) {
                // If we're using the DeactivateQueue, we'll just queue it up and 
                // be done; all the hard work will be done on the despooler thread.
 
                bool needToQueueWorkItem; 

                Bid.PoolerTrace(" %d#, Connection %d#, Queueing for deactivation.\n", ObjectID, obj.ObjectID); 
                PerformanceCounters.NumberOfStasisConnections.Increment();

                lock (_deactivateQueue.SyncRoot) {
                    needToQueueWorkItem = (0 == _deactivateQueue.Count); 
                    _deactivateQueue.Enqueue(obj);
                } 
                if (needToQueueWorkItem) { 
                    // Make sure we actually get around to deactivating the object
                    // and making it available again. 
                    ThreadPool.QueueUserWorkItem(_deactivateCallback, null);
                }
            }
            else { 
                // no deactivate queue -- do the work right now.
                DeactivateObject(obj); 
            } 
        }
 
        internal void PutObjectFromTransactedPool(DbConnectionInternal obj) {
            Debug.Assert(null != obj, "null pooledObject?");
            Debug.Assert(!obj.HasEnlistedTransaction, "pooledObject is still enlisted?");
 
            // called by the transacted connection pool , once it's removed the
            // connection from it's list.  We put the connection back in general 
            // circulation. 

            // NOTE: there is no locking required here because if we're in this 
            // method, we can safely presume that the caller is the only person
            // that is using the connection, and that all pre-push logic has been
            // done and all transactions are ended.
 
            Bid.PoolerTrace(" %d#, Connection %d#, Transaction has ended.\n", ObjectID, obj.ObjectID);
 
            if (_state == State.Running && obj.CanBePooled) { 
                PutNewObject(obj);
            } 
            else {
                DestroyObject(obj);
                QueuePoolCreateRequest();
            } 
        }
 
        private void QueuePoolCreateRequest() { 
            if (State.Running == _state) {
                // Make sure we're at quota by posting a callback to the threadpool. 
                ThreadPool.QueueUserWorkItem(_poolCreateRequest);
            }
        }
 
        private bool ReclaimEmancipatedObjects() {
            bool emancipatedObjectFound = false; 
 
            Bid.PoolerTrace(" %d#\n", ObjectID);
 
            List reclaimedObjects = new List();
            int count;

            lock(_objectList) { 
                count = _objectList.Count;
 
                for (int i = 0; i < count; ++i) { 
                    DbConnectionInternal obj = _objectList[i];
 
                    if (null != obj) {
                        bool locked = false;

                        try { 
                            locked = Monitor.TryEnter(obj);
 
                            if (locked) { // avoid race condition with PrePush/PostPop and IsEmancipated 
                                if (obj.IsEmancipated) {
                                    // Inside the lock, we want to do as little 
                                    // as possible, so we simply mark the object
                                    // as being in the pool, but hand it off to
                                    // an out of pool list to be deactivated,
                                    // etc. 
                                    obj.PrePush(null);
                                    reclaimedObjects.Add(obj); 
                                } 
                            }
                        } 
                        finally {
                            if (locked)
                                Monitor.Exit(obj);
                        } 
                    }
                } 
            } 

            // NOTE: we don't want to call DeactivateObject while we're locked, 
            // because it can make roundtrips to the server and this will block
            // object creation in the pooler.  Instead, we queue things we need
            // to do up, and process them outside the lock.
            count = reclaimedObjects.Count; 

            for (int i = 0; i < count; ++i) { 
                DbConnectionInternal obj = reclaimedObjects[i]; 

                Bid.PoolerTrace(" %d#, Connection %d#, Reclaiming.\n", ObjectID, obj.ObjectID); 
                PerformanceCounters.NumberOfReclaimedConnections.Increment();

                emancipatedObjectFound = true;
 
                // NOTE: it is not possible for us to have a connection that has
                // a delegated transaction at this point, because IsEmancipated 
                // would not have returned true if it did, and when a connection 
                // is emancipated, you can't enlist in a transaction (because you
                // can't get to it to make the call...) 
                DeactivateObject(obj);
            }
            return emancipatedObjectFound;
        } 

        internal void Startup() { 
            Bid.PoolerTrace(" %d#, CleanupWait=%d\n", ObjectID, _cleanupWait); 

            _cleanupTimer = CreateCleanupTimer(); 
            if (NeedToReplenish) {
                QueuePoolCreateRequest();
            }
        } 

        internal void Shutdown() { 
            Bid.PoolerTrace(" %d#\n", ObjectID); 

            _state = State.ShuttingDown; 

            Timer t; // deactivate timer callbacks

            t = _cleanupTimer; 
            _cleanupTimer = null;
            if (null != t) { 
                t.Dispose(); 
            }
 
            t = _errorTimer;
            _errorTimer = null;
            if (null != t) {
                t.Dispose(); 
            }
        } 
 
        internal void TransactionBegin(SysTx.Transaction transaction) {
            TransactedConnectionPool transactedConnectionPool = _transactedConnectionPool; 
            if (null != transactedConnectionPool) {
                transactedConnectionPool.TransactionBegin(transaction);
            }
        } 

        internal void TransactionEnded(SysTx.Transaction transaction, DbConnectionInternal transactedObject) { 
            Debug.Assert(null != transaction, "null transaction?"); 
            Debug.Assert(null != transactedObject, "null transactedObject?");
            // Note: connection may still be associated with transaction due to Explicit Unbinding requirement. 

            Bid.PoolerTrace(" %d#, Transaction %d#, Connection %d#, Transaction Completed\n", ObjectID, transaction.GetHashCode(), transactedObject.ObjectID);

            // called by the internal connection when it get's told that the 
            // transaction is completed.  We tell the transacted pool to remove
            // the connection from it's list, then we put the connection back in 
            // general circulation. 

            TransactedConnectionPool transactedConnectionPool = _transactedConnectionPool; 
            if (null != transactedConnectionPool) {
                transactedConnectionPool.TransactionEnded(transaction, transactedObject);
            }
        } 

        private DbConnectionInternal UserCreateRequest(DbConnection owningObject) { 
            // called by user when they were not able to obtain a free object but 
            // instead obtained creation mutex
 
            DbConnectionInternal obj = null;
            if (ErrorOccurred) {
               throw _resError;
            } 
            else {
                 if ((Count < MaxPoolSize) || (0 == MaxPoolSize)) { 
                    // If we have an odd number of total objects, reclaim any dead objects. 
                    // If we did not find any objects to reclaim, create a new one.
 
                    //
                     if ((Count & 0x1) == 0x1 || !ReclaimEmancipatedObjects())
                        obj = CreateObject(owningObject);
                } 
                return obj;
            } 
        } 

        private class DbConnectionInternalListStack { 
            private DbConnectionInternal _stack;
#if DEBUG
            private int _version;
            private int _count; 
#endif
            internal DbConnectionInternalListStack() { 
            } 

            internal int Count { 
                get {
                    int count = 0;
                    lock(this) {
                        for(DbConnectionInternal x = _stack; null != x; x = x.NextPooledObject) { 
                            ++count;
                        } 
                    } 
#if DEBUG
                    Debug.Assert(count == _count, "count is corrupt"); 
#endif
                    return count;
                }
            } 

            internal DbConnectionInternal SynchronizedPop() { 
                DbConnectionInternal value; 
                lock(this) {
                    value = _stack; 
                    if (null != value) {
                        _stack = value.NextPooledObject;
                        value.NextPooledObject = null;
#if DEBUG 
                        _version++;
                        _count--; 
#endif 
                    }
#if DEBUG 
                    Debug.Assert((null != value || 0 == _count) && (0 <= _count), "broken SynchronizedPop");
#endif
                }
                return value; 
            }
 
            internal void SynchronizedPush(DbConnectionInternal value) { 
                Debug.Assert(null != value, "pushing null value");
                lock(this) { 
#if DEBUG
                    Debug.Assert(null == value.NextPooledObject, "pushing value with non-null NextPooledObject");
                    int index = 0;
                    for(DbConnectionInternal x = _stack; null != x; x = x.NextPooledObject, ++index) { 
                        Debug.Assert(x != value, "double push: connection already in stack");
                    } 
                    Debug.Assert(_count == index, "SynchronizedPush count is corrupt"); 
#endif
                    value.NextPooledObject = _stack; 
                    _stack = value;
#if DEBUG
                    _version++;
                    _count++; 
#endif
                } 
            } 
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK