DbConnectionInternal.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Data / System / Data / ProviderBase / DbConnectionInternal.cs / 1305376 / DbConnectionInternal.cs

                            //------------------------------------------------------------------------------ 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
// [....]
//----------------------------------------------------------------------------- 
 
namespace System.Data.ProviderBase {
 
    using System;
    using System.ComponentModel;
    using System.Data;
    using System.Data.Common; 
    using System.Diagnostics;
    using System.Globalization; 
    using System.Runtime.ConstrainedExecution; 
    using System.Runtime.InteropServices;
    using System.Runtime.InteropServices.ComTypes; 
    using System.Security;
    using System.Security.Permissions;
    using System.Threading;
    using SysTx = System.Transactions; 

    internal abstract class DbConnectionInternal { // V1.1.3300 
        private static int _objectTypeCount; 
        internal readonly int _objectID = Interlocked.Increment(ref _objectTypeCount);
 
        internal static readonly StateChangeEventArgs StateChangeClosed = new StateChangeEventArgs(ConnectionState.Open, ConnectionState.Closed);
        internal static readonly StateChangeEventArgs StateChangeOpen   = new StateChangeEventArgs(ConnectionState.Closed, ConnectionState.Open);

        private readonly bool            _allowSetConnectionString; 
        private readonly bool            _hidePassword;
        private readonly ConnectionState _state; 
 
        private readonly WeakReference   _owningObject = new WeakReference(null, false);  // [usage must be thread safe] the owning object, when not in the pool. (both Pooled and Non-Pooled connections)
 
        // should only be used by DbConnectionPool.DbConnectionInternalListStack.Synchronized(Push|Pop)
        private DbConnectionInternal _nextPooledObject;
        internal DbConnectionInternal NextPooledObject {
            get { return _nextPooledObject; } 
            set { _nextPooledObject = value; }
        } 
 
        private DbConnectionPool         _connectionPool;           // the pooler that the connection came from (Pooled connections only)
        private DbConnectionPoolCounters _performanceCounters;      // the performance counters we're supposed to update 
        private DbReferenceCollection    _referenceCollection;      // collection of objects that we need to notify in some way when we're being deactivated
        private int                      _pooledCount;              // [usage must be thread safe] the number of times this object has been pushed into the pool less the number of times it's been popped (0 != inPool)

        private bool                     _connectionIsDoomed;       // true when the connection should no longer be used. 
        private bool                     _cannotBePooled;           // true when the connection should no longer be pooled.
        private bool                     _isInStasis; 
 
        private DateTime                 _createTime;               // when the connection was created.
 
        private SysTx.Transaction        _enlistedTransaction;      // [usage must be thread-safe] the transaction that we're enlisted in, either manually or automatically

        // _enlistedTransaction is a clone, so that transaction information can be queried even if the original transaction object is disposed.
        // However, there are times when we need to know if the original transaction object was disposed, so we keep a reference to it here. 
        // This field should only be assigned a value at the same time _enlistedTransaction is updated.
        // Also, this reference should not be disposed, since we aren't taking ownership of it. 
        private SysTx.Transaction _enlistedTransactionOriginal; 

#if DEBUG 
        private int                      _activateCount;            // debug only counter to verify activate/deactivates are in [....].
#endif //DEBUG

        protected DbConnectionInternal() : this(ConnectionState.Open, true, false) { // V1.1.3300 
        }
 
        // Constructor for internal connections 
        internal DbConnectionInternal(ConnectionState state, bool hidePassword, bool allowSetConnectionString) {
            _allowSetConnectionString = allowSetConnectionString; 
            _hidePassword = hidePassword;
            _state = state;
        }
 
        internal bool AllowSetConnectionString {
            get { 
                return _allowSetConnectionString; 
            }
        } 

        internal bool CanBePooled {
            get {
                bool flag = (!_connectionIsDoomed && !_cannotBePooled && !_owningObject.IsAlive); 
                return flag;
            } 
        } 

        protected internal SysTx.Transaction EnlistedTransaction { 
            get {
                return _enlistedTransaction;
            }
            set { 
                SysTx.Transaction currentEnlistedTransaction = _enlistedTransaction;
                if (((null == currentEnlistedTransaction) && (null != value)) 
                    || ((null != currentEnlistedTransaction) && !currentEnlistedTransaction.Equals(value))) {  // WebData 20000024 

                    // Pay attention to the order here: 
                    // 1) defect from any notifications
                    // 2) replace the transaction
                    // 3) re-enlist in notifications for the new transaction
 
                    // SQLBUDT #230558 we need to use a clone of the transaction
                    // when we store it, or we'll end up keeping it past the 
                    // duration of the using block of the TransactionScope 
                    SysTx.Transaction valueClone = null;
                    SysTx.Transaction previousTransactionClone = null; 
                    try {
                        if (null != value) {
                            valueClone = value.Clone();
                        } 

                        // NOTE: rather than take locks around several potential round- 
                        // trips to the server, and/or virtual function calls, we simply 
                        // presume that you aren't doing something illegal from multiple
                        // threads, and check once we get around to finalizing things 
                        // inside a lock.

                        lock(this) {
                            // NOTE: There is still a race condition here, when we are 
                            // called from EnlistTransaction (which cannot re-enlist)
                            // instead of EnlistDistributedTransaction (which can), 
                            // however this should have been handled by the outer 
                            // connection which checks to ensure that it's OK.  The
                            // only case where we have the race condition is multiple 
                            // concurrent enlist requests to the same connection, which
                            // is a bit out of line with something we should have to
                            // support.
 
                            // enlisted transaction can be nullified in Dispose call without lock
                            previousTransactionClone = Interlocked.Exchange(ref _enlistedTransaction, valueClone); 
                            _enlistedTransactionOriginal = value; 
                            value = valueClone;
                            valueClone = null; // we've stored it, don't dispose it. 
                        }
                    }
                    finally {
                        // we really need to dispose our clones; they may have 
                        // native resources and GC may not happen soon enough.
                        // VSDevDiv 479564: don't dispose if still holding reference in _enlistedTransaction 
                        if (null != previousTransactionClone && 
                                !Object.ReferenceEquals(previousTransactionClone, _enlistedTransaction)) {
                            previousTransactionClone.Dispose(); 
                        }
                        if (null != valueClone && !Object.ReferenceEquals(valueClone, _enlistedTransaction)) {
                            valueClone.Dispose();
                        } 
                    }
 
                    // I don't believe that we need to lock to protect the actual 
                    // enlistment in the transaction; it would only protect us
                    // against multiple concurrent calls to enlist, which really 
                    // isn't supported anyway.

                    if (null != value) {
                        if (Bid.IsOn(DbConnectionPool.PoolerTracePoints)) { 
                            int x = value.GetHashCode();
                            Bid.PoolerTrace(" %d#, Transaction %d#, Enlisting.\n", ObjectID, x); 
                        } 
                        TransactionOutcomeEnlist(value);
                    } 
                }
            }
        }
 
#if !ORACLE
        ///  
        /// Get boolean value that indicates whether the enlisted transaction has been disposed. 
        /// 
        ///  
        /// True if there is an enlisted transaction, and it has been diposed.
        /// False if there is an enlisted transaction that has not been disposed, or if the transaction reference is null.
        /// 
        ///  
        /// This method must be called while holding a lock on the DbConnectionInternal instance.
        ///  
        protected bool EnlistedTransactionDisposed 
        {
            get 
            {
                // Until the Transaction.Disposed property is public it is necessary to access a member
                // that throws if the object is disposed to determine if in fact the transaction is disposed.
                try 
                {
                    bool disposed; 
 
                    SysTx.Transaction currentEnlistedTransactionOriginal = _enlistedTransactionOriginal;
                    if (currentEnlistedTransactionOriginal != null) 
                    {
                        disposed = currentEnlistedTransactionOriginal.TransactionInformation == null;
                    }
                    else 
                    {
                        // Don't expect to get here in the general case, 
                        // Since this getter is called by CheckEnlistedTransactionBinding 
                        // after checking for a non-null enlisted transaction (and it does so under lock).
                        disposed = false; 
                    }

                    return disposed;
                } 
                catch (ObjectDisposedException)
                { 
                    return true; 
                }
            } 
        }
#endif

        // Is this connection in stasis, waiting for transaction to end before returning to pool? 
        internal bool IsTxRootWaitingForTxEnd {
            get { 
                return _isInStasis; 
            }
        } 

        /// 
        /// Get boolean that specifies whether an enlisted transaction can be unbound from
        /// the connection when that transaction completes. 
        /// 
        ///  
        /// True if the enlisted transaction can be unbound on transaction completion; otherwise false. 
        /// 
        virtual protected bool UnbindOnTransactionCompletion 
        {
            get
            {
                return true; 
            }
        } 
 
        // Is this a connection that must be put in stasis (or is already in stasis) pending the end of it's transaction?
        virtual protected internal bool IsNonPoolableTransactionRoot { 
            get {
                return false; // if you want to have delegated transactions that are non-poolable, you better override this...
            }
        } 

        virtual internal bool IsTransactionRoot { 
            get { 
                return false; // if you want to have delegated transactions, you better override this...
            } 
        }

        protected internal bool IsConnectionDoomed {
            get { 
                return _connectionIsDoomed;
            } 
        } 

        internal bool IsEmancipated { 
            get {
                // NOTE: There are race conditions between PrePush, PostPop and this
                //       property getter -- only use this while this object is locked;
                //       (DbConnectionPool.Clear and ReclaimEmancipatedObjects 
                //       do this for us)
 
                // Remember how this works (I keep getting confused...) 
                //
                //    _pooledCount is incremented when the connection is pushed into the pool 
                //    _pooledCount is decremented when the connection is popped from the pool
                //    _pooledCount is set to -1 when the connection is not pooled (just in case...)
                //
                // That means that: 
                //
                //    _pooledCount > 1    connection is in the pool multiple times (this is a serious bug...) 
                //    _pooledCount == 1   connection is in the pool 
                //    _pooledCount == 0   connection is out of the pool
                //    _pooledCount == -1  connection is not a pooled connection; we shouldn't be here for non-pooled connections. 
                //    _pooledCount < -1   connection out of the pool multiple times (not sure how this could happen...)
                //
                // Now, our job is to return TRUE when the connection is out
                // of the pool and it's owning object is no longer around to 
                // return it.
 
                bool value = !IsTxRootWaitingForTxEnd && (_pooledCount < 1) && !_owningObject.IsAlive; 
                return value;
            } 
        }

        internal int ObjectID {
            get { 
                return _objectID;
            } 
        } 

        protected internal object Owner { 
            // We use a weak reference to the owning object so we can identify when
            // it has been garbage collected without thowing exceptions.
            get {
                return _owningObject.Target; 
            }
        } 
 
        internal DbConnectionPool Pool {
            get { 
                return _connectionPool;
            }
        }
 
        protected DbConnectionPoolCounters PerformanceCounters {
            get { 
                return _performanceCounters; 
            }
        } 

        virtual protected bool ReadyToPrepareTransaction {
            get {
                return true; 
            }
        } 
 
        protected internal DbReferenceCollection ReferenceCollection {
            get { 
                return _referenceCollection;
            }
        }
 
        abstract public string ServerVersion {
            get; 
        } 

        // this should be abstract but untill it is added to all the providers virtual will have to do [....] 
        virtual public string ServerVersionNormalized {
            get{
                throw ADP.NotSupported();
            } 
        }
 
        public bool ShouldHidePassword { 
            get {
                return _hidePassword; 
            }
        }

        public ConnectionState State { 
            get {
                return _state; 
            } 
        }
 
        abstract protected void Activate(SysTx.Transaction transaction);

        internal void ActivateConnection(SysTx.Transaction transaction) {
            // Internal method called from the connection pooler so we don't expose 
            // the Activate method publicly.
 
            Bid.PoolerTrace(" %d#, Activating\n", ObjectID); 
#if DEBUG
            int activateCount = Interlocked.Increment(ref _activateCount); 
            Debug.Assert(1 == activateCount, "activated multiple times?");
#endif // DEBUG

            Activate(transaction); 

            PerformanceCounters.NumberOfActiveConnections.Increment(); 
        } 

        internal void AddWeakReference(object value, int tag) { 
            if (null == _referenceCollection) {
                _referenceCollection = CreateReferenceCollection();
                if (null == _referenceCollection) {
                    throw ADP.InternalError(ADP.InternalErrorCode.CreateReferenceCollectionReturnedNull); 
                }
            } 
            _referenceCollection.Add(value, tag); 
        }
 
        abstract public DbTransaction BeginTransaction(IsolationLevel il);

        virtual public void ChangeDatabase(string value) {
            throw ADP.MethodNotImplemented("ChangeDatabase"); 
        }
 
        internal virtual void CloseConnection(DbConnection owningObject, DbConnectionFactory connectionFactory) { 
            // The implementation here is the implementation required for the
            // "open" internal connections, since our own private "closed" 
            // singleton internal connection objects override this method to
            // prevent anything funny from happening (like disposing themselves
            // or putting them into a connection pool)
            // 
            // Derived class should override DbConnectionInternal.Deactivate and DbConnectionInternal.Dispose
            // for cleaning up after DbConnection.Close 
            //     protected override void Deactivate() { // override DbConnectionInternal.Close 
            //         // do derived class connection deactivation for both pooled & non-pooled connections
            //     } 
            //     public override void Dispose() { // override DbConnectionInternal.Close
            //         // do derived class cleanup
            //         base.Dispose();
            //     } 
            //
            // overriding DbConnection.Close is also possible, but must provider for their own synchronization 
            //     public override void Close() { // override DbConnection.Close 
            //         base.Close();
            //         // do derived class outer connection for both pooled & non-pooled connections 
            //         // user must do their own synchronization here
            //     }
            //
            //     if the DbConnectionInternal derived class needs to close the connection it should 
            //     delegate to the DbConnection if one exists or directly call dispose
            //         DbConnection owningObject = (DbConnection)Owner; 
            //         if (null != owningObject) { 
            //             owningObject.Close(); // force the closed state on the outer object.
            //         } 
            //         else {
            //             Dispose();
            //         }
            // 
            ////////////////////////////////////////////////////////////////
            // DON'T MESS WITH THIS CODE UNLESS YOU KNOW WHAT YOU'RE DOING! 
            //////////////////////////////////////////////////////////////// 
            Debug.Assert(null != owningObject, "null owningObject");
            Debug.Assert(null != connectionFactory, "null connectionFactory"); 
            Debug.Assert(owningObject == Owner, "Close with different owner");
            Debug.Assert(connectionFactory.GetInnerConnection(owningObject) == this || this.IsConnectionDoomed, "Close of not this");

            Bid.PoolerTrace(" %d# Closing.\n", ObjectID); 

            // if an exception occurs after the state change but before the try block 
            // the connection will be stuck in OpenBusy state.  The commented out try-catch 
            // block doesn't really help because a ThreadAbort during the finally block
            // would just refert the connection to a bad state. 
            // Open->Closed: guarantee internal connection is returned to correct pool
            if (connectionFactory.SetInnerConnectionFrom(owningObject, DbConnectionOpenBusy.SingletonInstance, this)) {
                try {
 
                    DbConnectionPool connectionPool = Pool;
 
                    // Detach from enlisted transactions that are no longer active on close 
                    SysTx.Transaction enlistedTransaction = EnlistedTransaction;
                    if (null != enlistedTransaction && SysTx.TransactionStatus.Active != enlistedTransaction.TransactionInformation.Status) { 
                        DetachTransaction(enlistedTransaction, true);
                    }

                    // The singleton closed classes won't have owners and 
                    // connection pools, and we won't want to put them back
                    // into the pool. 
                    if (null != connectionPool) { 
                        connectionPool.PutObject(this, owningObject);   // PutObject calls Deactivate for us...
                        // NOTE: Before we leave the PutObject call, another 
                        // thread may have already popped the connection from
                        // the pool, so don't expect to be able to verify it.
                    }
                    else { 
                        Deactivate();   // ensure we de-activate non-pooled connections, or the data readers and transactions may not get cleaned up...
 
                        PerformanceCounters.HardDisconnectsPerSecond.Increment(); 

                        // To prevent an endless recursion, we need to clear 
                        // the owning object before we call dispose so that
                        // we can't get here a second time... Ordinarily, I
                        // would call setting the owner to null a hack, but
                        // this is safe since we're about to dispose the 
                        // object and it won't have an owner after that for
                        // certain. 
                        _owningObject.Target = null; 

                        if (IsTransactionRoot) { 
                            SetInStasis();
                        }
                        else {
                            PerformanceCounters.NumberOfNonPooledConnections.Decrement(); 
#if !ORACLE
                            if (this.GetType() != typeof(System.Data.SqlClient.SqlInternalConnectionSmi)) 
#endif 
                            {
                                Dispose(); 
                            }
                        }
                    }
                } 
                finally {
                    // if a ThreadAbort puts us here then its possible the outer connection will not reference 
                    // this and this will be orphaned, not reclaimed by object pool until outer connection goes out of scope. 
                    connectionFactory.SetInnerConnectionEvent(owningObject, DbConnectionClosedPreviouslyOpened.SingletonInstance);
                } 
            }
        }

        virtual protected DbReferenceCollection CreateReferenceCollection() { 
            throw ADP.InternalError(ADP.InternalErrorCode.AttemptingToConstructReferenceCollectionOnStaticObject);
        } 
 
        abstract protected void Deactivate();
 
        internal void DeactivateConnection() {
            // Internal method called from the connection pooler so we don't expose
            // the Deactivate method publicly.
 
            Bid.PoolerTrace(" %d#, Deactivating\n", ObjectID);
#if DEBUG 
            int activateCount = Interlocked.Decrement(ref _activateCount); 
            Debug.Assert(0 == activateCount, "activated multiple times?");
#endif // DEBUG 

            PerformanceCounters.NumberOfActiveConnections.Decrement();

            if (!_connectionIsDoomed && Pool.UseLoadBalancing) { 
                // If we're not already doomed, check the connection's lifetime and
                // doom it if it's lifetime has elapsed. 
 
                DateTime now = DateTime.UtcNow;  // WebData 111116
                if ((now.Ticks - _createTime.Ticks) > Pool.LoadBalanceTimeout.Ticks) { 
                    DoNotPoolThisConnection();
                }
            }
            Deactivate(); 
        }
 
        virtual internal void DelegatedTransactionEnded() { 
            // Called by System.Transactions when the delegated transaction has
            // completed.  We need to make closed connections that are in stasis 
            // available again, or disposed closed/leaked non-pooled connections.

            // IMPORTANT NOTE: You must have taken a lock on the object before
            // you call this method to prevent race conditions with Clear and 
            // ReclaimEmancipatedObjects.
 
            Bid.Trace(" %d#, Delegated Transaction Completed.\n", ObjectID); 

            if (1 == _pooledCount) { 
                // When _pooledCount is 1, it indicates a closed, pooled,
                // connection so it is ready to put back into the pool for
                // general use.
 
                TerminateStasis(true);
 
                Deactivate(); // call it one more time just in case 

                DbConnectionPool pool = Pool; 

                if (null == pool) {
                    throw ADP.InternalError(ADP.InternalErrorCode.PooledObjectWithoutPool);      // pooled connection does not have a pool
                } 
                pool.PutObjectFromTransactedPool(this);
            } 
            else if (-1 == _pooledCount && !_owningObject.IsAlive) { 
                // When _pooledCount is -1 and the owning object no longer exists,
                // it indicates a closed (or leaked), non-pooled connection so 
                // it is safe to dispose.

                TerminateStasis(false);
 
                Deactivate(); // call it one more time just in case
 
                // it's a non-pooled connection, we need to dispose of it 
                // once and for all, or the server will have fits about us
                // leaving connections open until the client-side GC kicks 
                // in.
                PerformanceCounters.NumberOfNonPooledConnections.Decrement();
                Dispose();
            } 
            // When _pooledCount is 0, the connection is a pooled connection
            // that is either open (if the owning object is alive) or leaked (if 
            // the owning object is not alive)  In either case, we can't muck 
            // with the connection here.
        } 

        public virtual void Dispose()
        {
            _connectionPool = null; 
            _performanceCounters = null;
            _connectionIsDoomed = true; 
            _enlistedTransactionOriginal = null; // should not be disposed 

            // Dispose of the _enlistedTransaction since it is a clone 
            // of the original reference.
            // VSDD 780271 - _enlistedTransaction can be changed by another thread (TX end event)
            SysTx.Transaction enlistedTransaction = Interlocked.Exchange(ref _enlistedTransaction, null);
            if (enlistedTransaction != null) 
            {
                enlistedTransaction.Dispose(); 
            } 
        }
 
        protected internal void DoNotPoolThisConnection() {
            _cannotBePooled = true;
            Bid.PoolerTrace(" %d#, Marking pooled object as non-poolable so it will be disposed\n", ObjectID);
        } 

        /// Ensure that this connection cannot be put back into the pool. 
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 
        protected internal void DoomThisConnection() {
            _connectionIsDoomed = true; 
            Bid.PoolerTrace(" %d#, Dooming\n", ObjectID);
        }

        abstract public void EnlistTransaction(SysTx.Transaction transaction); 

        virtual protected internal DataTable GetSchema(DbConnectionFactory factory, DbConnectionPoolGroup poolGroup, DbConnection outerConnection, string collectionName, string[] restrictions){ 
            Debug.Assert(outerConnection != null,"outerConnection may not be null."); 

            DbMetaDataFactory metaDataFactory = factory.GetMetaDataFactory(poolGroup, this); 
            Debug.Assert(metaDataFactory != null,"metaDataFactory may not be null.");

            return metaDataFactory.GetSchema(outerConnection, collectionName,restrictions);
        } 

        internal void MakeNonPooledObject(object owningObject, DbConnectionPoolCounters performanceCounters) { 
            // Used by DbConnectionFactory to indicate that this object IS NOT part of 
            // a connection pool.
 
            _connectionPool = null;
            _performanceCounters = performanceCounters;
            _owningObject.Target = owningObject;
            _pooledCount = -1; 
        }
 
        internal void MakePooledConnection(DbConnectionPool connectionPool) { 
            // Used by DbConnectionFactory to indicate that this object IS part of
            // a connection pool. 

            //
            _createTime = DateTime.UtcNow; // WebData 111116
 
            _connectionPool = connectionPool;
            _performanceCounters = connectionPool.PerformanceCounters; 
        } 

        internal void NotifyWeakReference(int message) { 
            DbReferenceCollection referenceCollection = ReferenceCollection;
            if (null != referenceCollection) {
                referenceCollection.Notify(message);
            } 
        }
 
        /// The default implementation is for the open connection objects, and 
        /// it simply throws.  Our private closed-state connection objects
        /// override this and do the correct thing. 
        // User code should either override DbConnectionInternal.Activate when it comes out of the pool
        // or override DbConnectionFactory.CreateConnection when the connection is created for non-pooled connections
        internal virtual void OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory) {
            throw ADP.ConnectionAlreadyOpen(State); 
        }
 
        internal void PrePush(object expectedOwner) { 
            // Called by DbConnectionPool when we're about to be put into it's pool, we
            // take this opportunity to ensure ownership and pool counts are legit. 

            // IMPORTANT NOTE: You must have taken a lock on the object before
            // you call this method to prevent race conditions with Clear and
            // ReclaimEmancipatedObjects. 

            //3 // The following tests are retail assertions of things we can't allow to happen. 
            if (null == expectedOwner) { 
                if (null != _owningObject.Target) {
                    throw ADP.InternalError(ADP.InternalErrorCode.UnpooledObjectHasOwner);      // new unpooled object has an owner 
                }
            }
            else if (_owningObject.Target != expectedOwner) {
                throw ADP.InternalError(ADP.InternalErrorCode.UnpooledObjectHasWrongOwner); // unpooled object has incorrect owner 
            }
            if (0 != _pooledCount) { 
                throw ADP.InternalError(ADP.InternalErrorCode.PushingObjectSecondTime);         // pushing object onto stack a second time 
            }
            if (Bid.IsOn(DbConnectionPool.PoolerTracePoints)) { 
                //DbConnection x = (expectedOwner as DbConnection);
                Bid.PoolerTrace(" %d#, Preparing to push into pool, owning connection %d#, pooledCount=%d\n", ObjectID, 0, _pooledCount);
            }
            _pooledCount++; 
            _owningObject.Target = null; // NOTE: doing this and checking for InternalError.PooledObjectHasOwner degrades the close by 2%
        } 
 
        internal void PostPop(object newOwner) {
            // Called by DbConnectionPool right after it pulls this from it's pool, we 
            // take this opportunity to ensure ownership and pool counts are legit.

            Debug.Assert(!IsEmancipated,"pooled object not in pool");
 
            // SQLBUDT #356871 -- When another thread is clearing this pool, it
            // will doom all connections in this pool without prejudice 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(CanBePooled,   "pooled object is not poolable");

            // IMPORTANT NOTE: You must have taken a lock on the object before
            // you call this method to prevent race conditions with Clear and 
            // ReclaimEmancipatedObjects.
 
            if (null != _owningObject.Target) { 
                throw ADP.InternalError(ADP.InternalErrorCode.PooledObjectHasOwner);        // pooled connection already has an owner!
            } 
            _owningObject.Target = newOwner;
            _pooledCount--;
            if (Bid.IsOn(DbConnectionPool.PoolerTracePoints)) {
                //DbConnection x = (newOwner as DbConnection); 
                Bid.PoolerTrace(" %d#, Preparing to pop from pool,  owning connection %d#, pooledCount=%d\n", ObjectID, 0, _pooledCount);
            } 
            //3 // The following tests are retail assertions of things we can't allow to happen. 
            if (null != Pool) {
                if (0 != _pooledCount) { 
                    throw ADP.InternalError(ADP.InternalErrorCode.PooledObjectInPoolMoreThanOnce);  // popping object off stack with multiple pooledCount
                }
            }
            else if (-1 != _pooledCount) { 
                throw ADP.InternalError(ADP.InternalErrorCode.NonPooledObjectUsedMoreThanOnce); // popping object off stack with multiple pooledCount
            } 
        } 

        internal void RemoveWeakReference(object value) { 
            DbReferenceCollection referenceCollection = ReferenceCollection;
            if (null != referenceCollection) {
                referenceCollection.Remove(value);
            } 
        }
 
        // Cleanup connection's transaction-specific structures (currently used by Delegated transaction). 
        //  This is a separate method because cleanup can be triggered in multiple ways for a delegated
        //  transaction. 
        virtual protected void CleanupTransactionOnCompletion(SysTx.Transaction transaction) {
        }

        // Detach transaction from connection. 
        internal void DetachTransaction(SysTx.Transaction transaction, bool isExplicitlyReleasing) {
            Bid.Trace(" %d#, Transaction Completed. (pooledCount=%d)\n", ObjectID, _pooledCount); 
 
            // potentially a multi-threaded event, so lock the connection to make sure we don't enlist in a new
            // transaction between compare and assignment. No need to short circuit outside of lock, since failed comparisons should 
            // be the exception, not the rule.
            lock (this) {
                // Detach if detach-on-end behavior, or if outer connection was closed
                DbConnection owner = (DbConnection)Owner; 
                if (isExplicitlyReleasing || UnbindOnTransactionCompletion || null == owner) {
                    SysTx.Transaction currentEnlistedTransaction = _enlistedTransaction; 
                    if (currentEnlistedTransaction != null && transaction.Equals(currentEnlistedTransaction)) { 

                        EnlistedTransaction = null; 

                        if (IsTxRootWaitingForTxEnd) {
                            DelegatedTransactionEnded();
                        } 
                    }
                } 
            } 
        }
 
        // Handle transaction detach, pool cleanup and other post-transaction cleanup tasks associated with
        internal void CleanupConnectionOnTransactionCompletion(SysTx.Transaction transaction) {
            DetachTransaction(transaction, false);
 
            DbConnectionPool pool = Pool;
            if (null != pool) { 
                pool.TransactionEnded(transaction, this); 
            }
        } 

        void TransactionCompletedEvent(object sender, SysTx.TransactionEventArgs e) {
            SysTx.Transaction transaction = e.Transaction;
 
            Bid.Trace(" %d#, Transaction Completed. (pooledCount=%d)\n", ObjectID, _pooledCount);
 
            CleanupTransactionOnCompletion(transaction); 

            CleanupConnectionOnTransactionCompletion(transaction); 
        }


        // 
        [SecurityPermission(SecurityAction.Assert, Flags=SecurityPermissionFlag.UnmanagedCode)]
        private void TransactionOutcomeEnlist(SysTx.Transaction transaction) { 
            transaction.TransactionCompleted += new SysTx.TransactionCompletedEventHandler(TransactionCompletedEvent); 
        }
 
        internal void SetInStasis() {
            _isInStasis = true;
            Bid.PoolerTrace(" %d#, Non-Pooled Connection has Delegated Transaction, waiting to Dispose.\n", ObjectID);
            PerformanceCounters.NumberOfStasisConnections.Increment(); 
        }
 
        private void TerminateStasis(bool returningToPool) { 
            if (returningToPool) {
                Bid.PoolerTrace(" %d#, Delegated Transaction has ended, connection is closed.  Returning to general pool.\n", ObjectID); 
            }
            else {
                Bid.PoolerTrace(" %d#, Delegated Transaction has ended, connection is closed/leaked.  Disposing.\n", ObjectID);
            } 
            PerformanceCounters.NumberOfStasisConnections.Decrement();
            _isInStasis = false; 
        } 
    }
} 

// 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.ComponentModel;
    using System.Data;
    using System.Data.Common; 
    using System.Diagnostics;
    using System.Globalization; 
    using System.Runtime.ConstrainedExecution; 
    using System.Runtime.InteropServices;
    using System.Runtime.InteropServices.ComTypes; 
    using System.Security;
    using System.Security.Permissions;
    using System.Threading;
    using SysTx = System.Transactions; 

    internal abstract class DbConnectionInternal { // V1.1.3300 
        private static int _objectTypeCount; 
        internal readonly int _objectID = Interlocked.Increment(ref _objectTypeCount);
 
        internal static readonly StateChangeEventArgs StateChangeClosed = new StateChangeEventArgs(ConnectionState.Open, ConnectionState.Closed);
        internal static readonly StateChangeEventArgs StateChangeOpen   = new StateChangeEventArgs(ConnectionState.Closed, ConnectionState.Open);

        private readonly bool            _allowSetConnectionString; 
        private readonly bool            _hidePassword;
        private readonly ConnectionState _state; 
 
        private readonly WeakReference   _owningObject = new WeakReference(null, false);  // [usage must be thread safe] the owning object, when not in the pool. (both Pooled and Non-Pooled connections)
 
        // should only be used by DbConnectionPool.DbConnectionInternalListStack.Synchronized(Push|Pop)
        private DbConnectionInternal _nextPooledObject;
        internal DbConnectionInternal NextPooledObject {
            get { return _nextPooledObject; } 
            set { _nextPooledObject = value; }
        } 
 
        private DbConnectionPool         _connectionPool;           // the pooler that the connection came from (Pooled connections only)
        private DbConnectionPoolCounters _performanceCounters;      // the performance counters we're supposed to update 
        private DbReferenceCollection    _referenceCollection;      // collection of objects that we need to notify in some way when we're being deactivated
        private int                      _pooledCount;              // [usage must be thread safe] the number of times this object has been pushed into the pool less the number of times it's been popped (0 != inPool)

        private bool                     _connectionIsDoomed;       // true when the connection should no longer be used. 
        private bool                     _cannotBePooled;           // true when the connection should no longer be pooled.
        private bool                     _isInStasis; 
 
        private DateTime                 _createTime;               // when the connection was created.
 
        private SysTx.Transaction        _enlistedTransaction;      // [usage must be thread-safe] the transaction that we're enlisted in, either manually or automatically

        // _enlistedTransaction is a clone, so that transaction information can be queried even if the original transaction object is disposed.
        // However, there are times when we need to know if the original transaction object was disposed, so we keep a reference to it here. 
        // This field should only be assigned a value at the same time _enlistedTransaction is updated.
        // Also, this reference should not be disposed, since we aren't taking ownership of it. 
        private SysTx.Transaction _enlistedTransactionOriginal; 

#if DEBUG 
        private int                      _activateCount;            // debug only counter to verify activate/deactivates are in [....].
#endif //DEBUG

        protected DbConnectionInternal() : this(ConnectionState.Open, true, false) { // V1.1.3300 
        }
 
        // Constructor for internal connections 
        internal DbConnectionInternal(ConnectionState state, bool hidePassword, bool allowSetConnectionString) {
            _allowSetConnectionString = allowSetConnectionString; 
            _hidePassword = hidePassword;
            _state = state;
        }
 
        internal bool AllowSetConnectionString {
            get { 
                return _allowSetConnectionString; 
            }
        } 

        internal bool CanBePooled {
            get {
                bool flag = (!_connectionIsDoomed && !_cannotBePooled && !_owningObject.IsAlive); 
                return flag;
            } 
        } 

        protected internal SysTx.Transaction EnlistedTransaction { 
            get {
                return _enlistedTransaction;
            }
            set { 
                SysTx.Transaction currentEnlistedTransaction = _enlistedTransaction;
                if (((null == currentEnlistedTransaction) && (null != value)) 
                    || ((null != currentEnlistedTransaction) && !currentEnlistedTransaction.Equals(value))) {  // WebData 20000024 

                    // Pay attention to the order here: 
                    // 1) defect from any notifications
                    // 2) replace the transaction
                    // 3) re-enlist in notifications for the new transaction
 
                    // SQLBUDT #230558 we need to use a clone of the transaction
                    // when we store it, or we'll end up keeping it past the 
                    // duration of the using block of the TransactionScope 
                    SysTx.Transaction valueClone = null;
                    SysTx.Transaction previousTransactionClone = null; 
                    try {
                        if (null != value) {
                            valueClone = value.Clone();
                        } 

                        // NOTE: rather than take locks around several potential round- 
                        // trips to the server, and/or virtual function calls, we simply 
                        // presume that you aren't doing something illegal from multiple
                        // threads, and check once we get around to finalizing things 
                        // inside a lock.

                        lock(this) {
                            // NOTE: There is still a race condition here, when we are 
                            // called from EnlistTransaction (which cannot re-enlist)
                            // instead of EnlistDistributedTransaction (which can), 
                            // however this should have been handled by the outer 
                            // connection which checks to ensure that it's OK.  The
                            // only case where we have the race condition is multiple 
                            // concurrent enlist requests to the same connection, which
                            // is a bit out of line with something we should have to
                            // support.
 
                            // enlisted transaction can be nullified in Dispose call without lock
                            previousTransactionClone = Interlocked.Exchange(ref _enlistedTransaction, valueClone); 
                            _enlistedTransactionOriginal = value; 
                            value = valueClone;
                            valueClone = null; // we've stored it, don't dispose it. 
                        }
                    }
                    finally {
                        // we really need to dispose our clones; they may have 
                        // native resources and GC may not happen soon enough.
                        // VSDevDiv 479564: don't dispose if still holding reference in _enlistedTransaction 
                        if (null != previousTransactionClone && 
                                !Object.ReferenceEquals(previousTransactionClone, _enlistedTransaction)) {
                            previousTransactionClone.Dispose(); 
                        }
                        if (null != valueClone && !Object.ReferenceEquals(valueClone, _enlistedTransaction)) {
                            valueClone.Dispose();
                        } 
                    }
 
                    // I don't believe that we need to lock to protect the actual 
                    // enlistment in the transaction; it would only protect us
                    // against multiple concurrent calls to enlist, which really 
                    // isn't supported anyway.

                    if (null != value) {
                        if (Bid.IsOn(DbConnectionPool.PoolerTracePoints)) { 
                            int x = value.GetHashCode();
                            Bid.PoolerTrace(" %d#, Transaction %d#, Enlisting.\n", ObjectID, x); 
                        } 
                        TransactionOutcomeEnlist(value);
                    } 
                }
            }
        }
 
#if !ORACLE
        ///  
        /// Get boolean value that indicates whether the enlisted transaction has been disposed. 
        /// 
        ///  
        /// True if there is an enlisted transaction, and it has been diposed.
        /// False if there is an enlisted transaction that has not been disposed, or if the transaction reference is null.
        /// 
        ///  
        /// This method must be called while holding a lock on the DbConnectionInternal instance.
        ///  
        protected bool EnlistedTransactionDisposed 
        {
            get 
            {
                // Until the Transaction.Disposed property is public it is necessary to access a member
                // that throws if the object is disposed to determine if in fact the transaction is disposed.
                try 
                {
                    bool disposed; 
 
                    SysTx.Transaction currentEnlistedTransactionOriginal = _enlistedTransactionOriginal;
                    if (currentEnlistedTransactionOriginal != null) 
                    {
                        disposed = currentEnlistedTransactionOriginal.TransactionInformation == null;
                    }
                    else 
                    {
                        // Don't expect to get here in the general case, 
                        // Since this getter is called by CheckEnlistedTransactionBinding 
                        // after checking for a non-null enlisted transaction (and it does so under lock).
                        disposed = false; 
                    }

                    return disposed;
                } 
                catch (ObjectDisposedException)
                { 
                    return true; 
                }
            } 
        }
#endif

        // Is this connection in stasis, waiting for transaction to end before returning to pool? 
        internal bool IsTxRootWaitingForTxEnd {
            get { 
                return _isInStasis; 
            }
        } 

        /// 
        /// Get boolean that specifies whether an enlisted transaction can be unbound from
        /// the connection when that transaction completes. 
        /// 
        ///  
        /// True if the enlisted transaction can be unbound on transaction completion; otherwise false. 
        /// 
        virtual protected bool UnbindOnTransactionCompletion 
        {
            get
            {
                return true; 
            }
        } 
 
        // Is this a connection that must be put in stasis (or is already in stasis) pending the end of it's transaction?
        virtual protected internal bool IsNonPoolableTransactionRoot { 
            get {
                return false; // if you want to have delegated transactions that are non-poolable, you better override this...
            }
        } 

        virtual internal bool IsTransactionRoot { 
            get { 
                return false; // if you want to have delegated transactions, you better override this...
            } 
        }

        protected internal bool IsConnectionDoomed {
            get { 
                return _connectionIsDoomed;
            } 
        } 

        internal bool IsEmancipated { 
            get {
                // NOTE: There are race conditions between PrePush, PostPop and this
                //       property getter -- only use this while this object is locked;
                //       (DbConnectionPool.Clear and ReclaimEmancipatedObjects 
                //       do this for us)
 
                // Remember how this works (I keep getting confused...) 
                //
                //    _pooledCount is incremented when the connection is pushed into the pool 
                //    _pooledCount is decremented when the connection is popped from the pool
                //    _pooledCount is set to -1 when the connection is not pooled (just in case...)
                //
                // That means that: 
                //
                //    _pooledCount > 1    connection is in the pool multiple times (this is a serious bug...) 
                //    _pooledCount == 1   connection is in the pool 
                //    _pooledCount == 0   connection is out of the pool
                //    _pooledCount == -1  connection is not a pooled connection; we shouldn't be here for non-pooled connections. 
                //    _pooledCount < -1   connection out of the pool multiple times (not sure how this could happen...)
                //
                // Now, our job is to return TRUE when the connection is out
                // of the pool and it's owning object is no longer around to 
                // return it.
 
                bool value = !IsTxRootWaitingForTxEnd && (_pooledCount < 1) && !_owningObject.IsAlive; 
                return value;
            } 
        }

        internal int ObjectID {
            get { 
                return _objectID;
            } 
        } 

        protected internal object Owner { 
            // We use a weak reference to the owning object so we can identify when
            // it has been garbage collected without thowing exceptions.
            get {
                return _owningObject.Target; 
            }
        } 
 
        internal DbConnectionPool Pool {
            get { 
                return _connectionPool;
            }
        }
 
        protected DbConnectionPoolCounters PerformanceCounters {
            get { 
                return _performanceCounters; 
            }
        } 

        virtual protected bool ReadyToPrepareTransaction {
            get {
                return true; 
            }
        } 
 
        protected internal DbReferenceCollection ReferenceCollection {
            get { 
                return _referenceCollection;
            }
        }
 
        abstract public string ServerVersion {
            get; 
        } 

        // this should be abstract but untill it is added to all the providers virtual will have to do [....] 
        virtual public string ServerVersionNormalized {
            get{
                throw ADP.NotSupported();
            } 
        }
 
        public bool ShouldHidePassword { 
            get {
                return _hidePassword; 
            }
        }

        public ConnectionState State { 
            get {
                return _state; 
            } 
        }
 
        abstract protected void Activate(SysTx.Transaction transaction);

        internal void ActivateConnection(SysTx.Transaction transaction) {
            // Internal method called from the connection pooler so we don't expose 
            // the Activate method publicly.
 
            Bid.PoolerTrace(" %d#, Activating\n", ObjectID); 
#if DEBUG
            int activateCount = Interlocked.Increment(ref _activateCount); 
            Debug.Assert(1 == activateCount, "activated multiple times?");
#endif // DEBUG

            Activate(transaction); 

            PerformanceCounters.NumberOfActiveConnections.Increment(); 
        } 

        internal void AddWeakReference(object value, int tag) { 
            if (null == _referenceCollection) {
                _referenceCollection = CreateReferenceCollection();
                if (null == _referenceCollection) {
                    throw ADP.InternalError(ADP.InternalErrorCode.CreateReferenceCollectionReturnedNull); 
                }
            } 
            _referenceCollection.Add(value, tag); 
        }
 
        abstract public DbTransaction BeginTransaction(IsolationLevel il);

        virtual public void ChangeDatabase(string value) {
            throw ADP.MethodNotImplemented("ChangeDatabase"); 
        }
 
        internal virtual void CloseConnection(DbConnection owningObject, DbConnectionFactory connectionFactory) { 
            // The implementation here is the implementation required for the
            // "open" internal connections, since our own private "closed" 
            // singleton internal connection objects override this method to
            // prevent anything funny from happening (like disposing themselves
            // or putting them into a connection pool)
            // 
            // Derived class should override DbConnectionInternal.Deactivate and DbConnectionInternal.Dispose
            // for cleaning up after DbConnection.Close 
            //     protected override void Deactivate() { // override DbConnectionInternal.Close 
            //         // do derived class connection deactivation for both pooled & non-pooled connections
            //     } 
            //     public override void Dispose() { // override DbConnectionInternal.Close
            //         // do derived class cleanup
            //         base.Dispose();
            //     } 
            //
            // overriding DbConnection.Close is also possible, but must provider for their own synchronization 
            //     public override void Close() { // override DbConnection.Close 
            //         base.Close();
            //         // do derived class outer connection for both pooled & non-pooled connections 
            //         // user must do their own synchronization here
            //     }
            //
            //     if the DbConnectionInternal derived class needs to close the connection it should 
            //     delegate to the DbConnection if one exists or directly call dispose
            //         DbConnection owningObject = (DbConnection)Owner; 
            //         if (null != owningObject) { 
            //             owningObject.Close(); // force the closed state on the outer object.
            //         } 
            //         else {
            //             Dispose();
            //         }
            // 
            ////////////////////////////////////////////////////////////////
            // DON'T MESS WITH THIS CODE UNLESS YOU KNOW WHAT YOU'RE DOING! 
            //////////////////////////////////////////////////////////////// 
            Debug.Assert(null != owningObject, "null owningObject");
            Debug.Assert(null != connectionFactory, "null connectionFactory"); 
            Debug.Assert(owningObject == Owner, "Close with different owner");
            Debug.Assert(connectionFactory.GetInnerConnection(owningObject) == this || this.IsConnectionDoomed, "Close of not this");

            Bid.PoolerTrace(" %d# Closing.\n", ObjectID); 

            // if an exception occurs after the state change but before the try block 
            // the connection will be stuck in OpenBusy state.  The commented out try-catch 
            // block doesn't really help because a ThreadAbort during the finally block
            // would just refert the connection to a bad state. 
            // Open->Closed: guarantee internal connection is returned to correct pool
            if (connectionFactory.SetInnerConnectionFrom(owningObject, DbConnectionOpenBusy.SingletonInstance, this)) {
                try {
 
                    DbConnectionPool connectionPool = Pool;
 
                    // Detach from enlisted transactions that are no longer active on close 
                    SysTx.Transaction enlistedTransaction = EnlistedTransaction;
                    if (null != enlistedTransaction && SysTx.TransactionStatus.Active != enlistedTransaction.TransactionInformation.Status) { 
                        DetachTransaction(enlistedTransaction, true);
                    }

                    // The singleton closed classes won't have owners and 
                    // connection pools, and we won't want to put them back
                    // into the pool. 
                    if (null != connectionPool) { 
                        connectionPool.PutObject(this, owningObject);   // PutObject calls Deactivate for us...
                        // NOTE: Before we leave the PutObject call, another 
                        // thread may have already popped the connection from
                        // the pool, so don't expect to be able to verify it.
                    }
                    else { 
                        Deactivate();   // ensure we de-activate non-pooled connections, or the data readers and transactions may not get cleaned up...
 
                        PerformanceCounters.HardDisconnectsPerSecond.Increment(); 

                        // To prevent an endless recursion, we need to clear 
                        // the owning object before we call dispose so that
                        // we can't get here a second time... Ordinarily, I
                        // would call setting the owner to null a hack, but
                        // this is safe since we're about to dispose the 
                        // object and it won't have an owner after that for
                        // certain. 
                        _owningObject.Target = null; 

                        if (IsTransactionRoot) { 
                            SetInStasis();
                        }
                        else {
                            PerformanceCounters.NumberOfNonPooledConnections.Decrement(); 
#if !ORACLE
                            if (this.GetType() != typeof(System.Data.SqlClient.SqlInternalConnectionSmi)) 
#endif 
                            {
                                Dispose(); 
                            }
                        }
                    }
                } 
                finally {
                    // if a ThreadAbort puts us here then its possible the outer connection will not reference 
                    // this and this will be orphaned, not reclaimed by object pool until outer connection goes out of scope. 
                    connectionFactory.SetInnerConnectionEvent(owningObject, DbConnectionClosedPreviouslyOpened.SingletonInstance);
                } 
            }
        }

        virtual protected DbReferenceCollection CreateReferenceCollection() { 
            throw ADP.InternalError(ADP.InternalErrorCode.AttemptingToConstructReferenceCollectionOnStaticObject);
        } 
 
        abstract protected void Deactivate();
 
        internal void DeactivateConnection() {
            // Internal method called from the connection pooler so we don't expose
            // the Deactivate method publicly.
 
            Bid.PoolerTrace(" %d#, Deactivating\n", ObjectID);
#if DEBUG 
            int activateCount = Interlocked.Decrement(ref _activateCount); 
            Debug.Assert(0 == activateCount, "activated multiple times?");
#endif // DEBUG 

            PerformanceCounters.NumberOfActiveConnections.Decrement();

            if (!_connectionIsDoomed && Pool.UseLoadBalancing) { 
                // If we're not already doomed, check the connection's lifetime and
                // doom it if it's lifetime has elapsed. 
 
                DateTime now = DateTime.UtcNow;  // WebData 111116
                if ((now.Ticks - _createTime.Ticks) > Pool.LoadBalanceTimeout.Ticks) { 
                    DoNotPoolThisConnection();
                }
            }
            Deactivate(); 
        }
 
        virtual internal void DelegatedTransactionEnded() { 
            // Called by System.Transactions when the delegated transaction has
            // completed.  We need to make closed connections that are in stasis 
            // available again, or disposed closed/leaked non-pooled connections.

            // IMPORTANT NOTE: You must have taken a lock on the object before
            // you call this method to prevent race conditions with Clear and 
            // ReclaimEmancipatedObjects.
 
            Bid.Trace(" %d#, Delegated Transaction Completed.\n", ObjectID); 

            if (1 == _pooledCount) { 
                // When _pooledCount is 1, it indicates a closed, pooled,
                // connection so it is ready to put back into the pool for
                // general use.
 
                TerminateStasis(true);
 
                Deactivate(); // call it one more time just in case 

                DbConnectionPool pool = Pool; 

                if (null == pool) {
                    throw ADP.InternalError(ADP.InternalErrorCode.PooledObjectWithoutPool);      // pooled connection does not have a pool
                } 
                pool.PutObjectFromTransactedPool(this);
            } 
            else if (-1 == _pooledCount && !_owningObject.IsAlive) { 
                // When _pooledCount is -1 and the owning object no longer exists,
                // it indicates a closed (or leaked), non-pooled connection so 
                // it is safe to dispose.

                TerminateStasis(false);
 
                Deactivate(); // call it one more time just in case
 
                // it's a non-pooled connection, we need to dispose of it 
                // once and for all, or the server will have fits about us
                // leaving connections open until the client-side GC kicks 
                // in.
                PerformanceCounters.NumberOfNonPooledConnections.Decrement();
                Dispose();
            } 
            // When _pooledCount is 0, the connection is a pooled connection
            // that is either open (if the owning object is alive) or leaked (if 
            // the owning object is not alive)  In either case, we can't muck 
            // with the connection here.
        } 

        public virtual void Dispose()
        {
            _connectionPool = null; 
            _performanceCounters = null;
            _connectionIsDoomed = true; 
            _enlistedTransactionOriginal = null; // should not be disposed 

            // Dispose of the _enlistedTransaction since it is a clone 
            // of the original reference.
            // VSDD 780271 - _enlistedTransaction can be changed by another thread (TX end event)
            SysTx.Transaction enlistedTransaction = Interlocked.Exchange(ref _enlistedTransaction, null);
            if (enlistedTransaction != null) 
            {
                enlistedTransaction.Dispose(); 
            } 
        }
 
        protected internal void DoNotPoolThisConnection() {
            _cannotBePooled = true;
            Bid.PoolerTrace(" %d#, Marking pooled object as non-poolable so it will be disposed\n", ObjectID);
        } 

        /// Ensure that this connection cannot be put back into the pool. 
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 
        protected internal void DoomThisConnection() {
            _connectionIsDoomed = true; 
            Bid.PoolerTrace(" %d#, Dooming\n", ObjectID);
        }

        abstract public void EnlistTransaction(SysTx.Transaction transaction); 

        virtual protected internal DataTable GetSchema(DbConnectionFactory factory, DbConnectionPoolGroup poolGroup, DbConnection outerConnection, string collectionName, string[] restrictions){ 
            Debug.Assert(outerConnection != null,"outerConnection may not be null."); 

            DbMetaDataFactory metaDataFactory = factory.GetMetaDataFactory(poolGroup, this); 
            Debug.Assert(metaDataFactory != null,"metaDataFactory may not be null.");

            return metaDataFactory.GetSchema(outerConnection, collectionName,restrictions);
        } 

        internal void MakeNonPooledObject(object owningObject, DbConnectionPoolCounters performanceCounters) { 
            // Used by DbConnectionFactory to indicate that this object IS NOT part of 
            // a connection pool.
 
            _connectionPool = null;
            _performanceCounters = performanceCounters;
            _owningObject.Target = owningObject;
            _pooledCount = -1; 
        }
 
        internal void MakePooledConnection(DbConnectionPool connectionPool) { 
            // Used by DbConnectionFactory to indicate that this object IS part of
            // a connection pool. 

            //
            _createTime = DateTime.UtcNow; // WebData 111116
 
            _connectionPool = connectionPool;
            _performanceCounters = connectionPool.PerformanceCounters; 
        } 

        internal void NotifyWeakReference(int message) { 
            DbReferenceCollection referenceCollection = ReferenceCollection;
            if (null != referenceCollection) {
                referenceCollection.Notify(message);
            } 
        }
 
        /// The default implementation is for the open connection objects, and 
        /// it simply throws.  Our private closed-state connection objects
        /// override this and do the correct thing. 
        // User code should either override DbConnectionInternal.Activate when it comes out of the pool
        // or override DbConnectionFactory.CreateConnection when the connection is created for non-pooled connections
        internal virtual void OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory) {
            throw ADP.ConnectionAlreadyOpen(State); 
        }
 
        internal void PrePush(object expectedOwner) { 
            // Called by DbConnectionPool when we're about to be put into it's pool, we
            // take this opportunity to ensure ownership and pool counts are legit. 

            // IMPORTANT NOTE: You must have taken a lock on the object before
            // you call this method to prevent race conditions with Clear and
            // ReclaimEmancipatedObjects. 

            //3 // The following tests are retail assertions of things we can't allow to happen. 
            if (null == expectedOwner) { 
                if (null != _owningObject.Target) {
                    throw ADP.InternalError(ADP.InternalErrorCode.UnpooledObjectHasOwner);      // new unpooled object has an owner 
                }
            }
            else if (_owningObject.Target != expectedOwner) {
                throw ADP.InternalError(ADP.InternalErrorCode.UnpooledObjectHasWrongOwner); // unpooled object has incorrect owner 
            }
            if (0 != _pooledCount) { 
                throw ADP.InternalError(ADP.InternalErrorCode.PushingObjectSecondTime);         // pushing object onto stack a second time 
            }
            if (Bid.IsOn(DbConnectionPool.PoolerTracePoints)) { 
                //DbConnection x = (expectedOwner as DbConnection);
                Bid.PoolerTrace(" %d#, Preparing to push into pool, owning connection %d#, pooledCount=%d\n", ObjectID, 0, _pooledCount);
            }
            _pooledCount++; 
            _owningObject.Target = null; // NOTE: doing this and checking for InternalError.PooledObjectHasOwner degrades the close by 2%
        } 
 
        internal void PostPop(object newOwner) {
            // Called by DbConnectionPool right after it pulls this from it's pool, we 
            // take this opportunity to ensure ownership and pool counts are legit.

            Debug.Assert(!IsEmancipated,"pooled object not in pool");
 
            // SQLBUDT #356871 -- When another thread is clearing this pool, it
            // will doom all connections in this pool without prejudice 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(CanBePooled,   "pooled object is not poolable");

            // IMPORTANT NOTE: You must have taken a lock on the object before
            // you call this method to prevent race conditions with Clear and 
            // ReclaimEmancipatedObjects.
 
            if (null != _owningObject.Target) { 
                throw ADP.InternalError(ADP.InternalErrorCode.PooledObjectHasOwner);        // pooled connection already has an owner!
            } 
            _owningObject.Target = newOwner;
            _pooledCount--;
            if (Bid.IsOn(DbConnectionPool.PoolerTracePoints)) {
                //DbConnection x = (newOwner as DbConnection); 
                Bid.PoolerTrace(" %d#, Preparing to pop from pool,  owning connection %d#, pooledCount=%d\n", ObjectID, 0, _pooledCount);
            } 
            //3 // The following tests are retail assertions of things we can't allow to happen. 
            if (null != Pool) {
                if (0 != _pooledCount) { 
                    throw ADP.InternalError(ADP.InternalErrorCode.PooledObjectInPoolMoreThanOnce);  // popping object off stack with multiple pooledCount
                }
            }
            else if (-1 != _pooledCount) { 
                throw ADP.InternalError(ADP.InternalErrorCode.NonPooledObjectUsedMoreThanOnce); // popping object off stack with multiple pooledCount
            } 
        } 

        internal void RemoveWeakReference(object value) { 
            DbReferenceCollection referenceCollection = ReferenceCollection;
            if (null != referenceCollection) {
                referenceCollection.Remove(value);
            } 
        }
 
        // Cleanup connection's transaction-specific structures (currently used by Delegated transaction). 
        //  This is a separate method because cleanup can be triggered in multiple ways for a delegated
        //  transaction. 
        virtual protected void CleanupTransactionOnCompletion(SysTx.Transaction transaction) {
        }

        // Detach transaction from connection. 
        internal void DetachTransaction(SysTx.Transaction transaction, bool isExplicitlyReleasing) {
            Bid.Trace(" %d#, Transaction Completed. (pooledCount=%d)\n", ObjectID, _pooledCount); 
 
            // potentially a multi-threaded event, so lock the connection to make sure we don't enlist in a new
            // transaction between compare and assignment. No need to short circuit outside of lock, since failed comparisons should 
            // be the exception, not the rule.
            lock (this) {
                // Detach if detach-on-end behavior, or if outer connection was closed
                DbConnection owner = (DbConnection)Owner; 
                if (isExplicitlyReleasing || UnbindOnTransactionCompletion || null == owner) {
                    SysTx.Transaction currentEnlistedTransaction = _enlistedTransaction; 
                    if (currentEnlistedTransaction != null && transaction.Equals(currentEnlistedTransaction)) { 

                        EnlistedTransaction = null; 

                        if (IsTxRootWaitingForTxEnd) {
                            DelegatedTransactionEnded();
                        } 
                    }
                } 
            } 
        }
 
        // Handle transaction detach, pool cleanup and other post-transaction cleanup tasks associated with
        internal void CleanupConnectionOnTransactionCompletion(SysTx.Transaction transaction) {
            DetachTransaction(transaction, false);
 
            DbConnectionPool pool = Pool;
            if (null != pool) { 
                pool.TransactionEnded(transaction, this); 
            }
        } 

        void TransactionCompletedEvent(object sender, SysTx.TransactionEventArgs e) {
            SysTx.Transaction transaction = e.Transaction;
 
            Bid.Trace(" %d#, Transaction Completed. (pooledCount=%d)\n", ObjectID, _pooledCount);
 
            CleanupTransactionOnCompletion(transaction); 

            CleanupConnectionOnTransactionCompletion(transaction); 
        }


        // 
        [SecurityPermission(SecurityAction.Assert, Flags=SecurityPermissionFlag.UnmanagedCode)]
        private void TransactionOutcomeEnlist(SysTx.Transaction transaction) { 
            transaction.TransactionCompleted += new SysTx.TransactionCompletedEventHandler(TransactionCompletedEvent); 
        }
 
        internal void SetInStasis() {
            _isInStasis = true;
            Bid.PoolerTrace(" %d#, Non-Pooled Connection has Delegated Transaction, waiting to Dispose.\n", ObjectID);
            PerformanceCounters.NumberOfStasisConnections.Increment(); 
        }
 
        private void TerminateStasis(bool returningToPool) { 
            if (returningToPool) {
                Bid.PoolerTrace(" %d#, Delegated Transaction has ended, connection is closed.  Returning to general pool.\n", ObjectID); 
            }
            else {
                Bid.PoolerTrace(" %d#, Delegated Transaction has ended, connection is closed/leaked.  Disposing.\n", ObjectID);
            } 
            PerformanceCounters.NumberOfStasisConnections.Decrement();
            _isInStasis = false; 
        } 
    }
} 

// 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