protected override void CleanupTransactionOnCompletion(Transaction transaction)
        {
            SqlDelegatedTransaction delegatedTransaction = this.DelegatedTransaction;

            if (delegatedTransaction != null)
            {
                delegatedTransaction.TransactionEnded(transaction);
            }
        }
示例#2
0
        override protected void CleanupTransactionOnCompletion(Transaction transaction)
        {
            // Note: unlocked, potentially multi-threaded code, so pull delegate to local to
            //  ensure it doesn't change between test and call.
            SqlDelegatedTransaction delegatedTransaction = DelegatedTransaction;

            if (null != delegatedTransaction)
            {
                delegatedTransaction.TransactionEnded(transaction);
            }
        }
示例#3
0
        private void TransactionEndedByServer(long transactionId)
        {
            SqlDelegatedTransaction delegatedTransaction = base.DelegatedTransaction;

            if (delegatedTransaction != null)
            {
                delegatedTransaction.Transaction.Rollback();
                base.DelegatedTransaction = null;
            }
            this.TransactionEnded(transactionId, System.Data.SqlClient.TransactionState.Unknown);
        }
        private void TransactionEndedByServer(long transactionId, TransactionState transactionState)
        {
            // Some extra steps required when the server initiates the ending of a transaction unilaterally
            //  as opposed to the client initiating it.
            //  Basically, we have to make the delegated transaction (if there is one) aware of the situation.

            SqlDelegatedTransaction delegatedTransaction = DelegatedTransaction;

            if (null != delegatedTransaction)
            {
                delegatedTransaction.Transaction.Rollback(); // just to make sure...
                DelegatedTransaction = null;                 // He's dead, Jim.
            }

            // Now handle the standard transaction-ended stuff.
            TransactionEnded(transactionId, transactionState);
        }
示例#5
0
        private void EnlistNonNull(Transaction tx)
        {
            Debug.Assert(null != tx, "null transaction?");

            bool hasDelegatedTransaction = false;

            // Promotable transactions are only supported on Yukon
            // servers or newer.
            SqlDelegatedTransaction delegatedTransaction = new SqlDelegatedTransaction(this, tx);

            try
            {
                // NOTE: System.Transactions claims to resolve all
                // potential race conditions between multiple delegate
                // requests of the same transaction to different
                // connections in their code, such that only one
                // attempt to delegate will succeed.

                // NOTE: PromotableSinglePhaseEnlist will eventually
                // make a round trip to the server; doing this inside
                // a lock is not the best choice.  We presume that you
                // aren't trying to enlist concurrently on two threads
                // and leave it at that -- We don't claim any thread
                // safety with regard to multiple concurrent requests
                // to enlist the same connection in different
                // transactions, which is good, because we don't have
                // it anyway.

                // PromotableSinglePhaseEnlist may not actually promote
                // the transaction when it is already delegated (this is
                // the way they resolve the race condition when two
                // threads attempt to delegate the same Lightweight
                // Transaction)  In that case, we can safely ignore
                // our delegated transaction, and proceed to enlist
                // in the promoted one.

                // NOTE: Global Transactions is an Azure SQL DB only
                // feature where the Transaction Manager (TM) is not
                // MS-DTC. Sys.Tx added APIs to support Non MS-DTC
                // promoter types/TM in .NET 4.6.1. Following directions
                // from .NETFX shiproom, to avoid a "hard-dependency"
                // (compile time) on Sys.Tx, we use reflection to invoke
                // the new APIs. Further, the _isGlobalTransaction flag
                // indicates that this is an Azure SQL DB Transaction
                // that could be promoted to a Global Transaction (it's
                // always false for on-prem Sql Server). The Promote()
                // call in SqlDelegatedTransaction makes sure that the
                // right Sys.Tx.dll is loaded and that Global Transactions
                // are actually allowed for this Azure SQL DB.

                if (_isGlobalTransaction)
                {
                    if (SysTxForGlobalTransactions.EnlistPromotableSinglePhase == null)
                    {
                        // This could be a local Azure SQL DB transaction.
                        hasDelegatedTransaction = tx.EnlistPromotableSinglePhase(delegatedTransaction);
                    }
                    else
                    {
                        hasDelegatedTransaction = (bool)SysTxForGlobalTransactions.EnlistPromotableSinglePhase.Invoke(tx, new object[] { delegatedTransaction, _globalTransactionTMID });
                    }
                }
                else
                {
                    // This is an MS-DTC distributed transaction
                    hasDelegatedTransaction = tx.EnlistPromotableSinglePhase(delegatedTransaction);
                }

                if (hasDelegatedTransaction)
                {
                    this.DelegatedTransaction = delegatedTransaction;
                }
            }
            catch (SqlException e)
            {
                // we do not want to eat the error if it is a fatal one
                if (e.Class >= TdsEnums.FATAL_ERROR_CLASS)
                {
                    throw;
                }

                // if the parser is null or its state is not openloggedin, the connection is no longer good.
                SqlInternalConnectionTds tdsConnection = this as SqlInternalConnectionTds;
                if (tdsConnection != null)
                {
                    TdsParser parser = tdsConnection.Parser;
                    if (parser == null || parser.State != TdsParserState.OpenLoggedIn)
                    {
                        throw;
                    }
                }

                // In this case, SqlDelegatedTransaction.Initialize
                // failed and we don't necessarily want to reject
                // things -- there may have been a legitimate reason
                // for the failure.
            }

            if (!hasDelegatedTransaction)
            {
                byte[] cookie = null;

                if (_isGlobalTransaction)
                {
                    if (SysTxForGlobalTransactions.GetPromotedToken == null)
                    {
                        throw SQL.UnsupportedSysTxForGlobalTransactions();
                    }

                    cookie = (byte[])SysTxForGlobalTransactions.GetPromotedToken.Invoke(tx, null);
                }
                else
                {
                    if (null == _whereAbouts)
                    {
                        byte[] dtcAddress = GetDTCAddress();

                        if (null == dtcAddress)
                        {
                            throw SQL.CannotGetDTCAddress();
                        }
                        _whereAbouts = dtcAddress;
                    }
                    cookie = GetTransactionCookie(tx, _whereAbouts);
                }

                // send cookie to server to finish enlistment
                PropagateTransactionCookie(cookie);

                _isEnlistedInTransaction = true;
            }

            EnlistedTransaction = tx; // Tell the base class about our enlistment


            // If we're on a Yukon or newer server, and we delegate the
            // transaction successfully, we will have done a begin transaction,
            // which produces a transaction id that we should execute all requests
            // on.  The TdsParser or SmiEventSink will store this information as
            // the current transaction.
            //
            // Likewise, propagating a transaction to a Yukon or newer server will
            // produce a transaction id that The TdsParser or SmiEventSink will
            // store as the current transaction.
            //
            // In either case, when we're working with a Yukon or newer server
            // we better have a current transaction by now.

            Debug.Assert(null != CurrentTransaction, "delegated/enlisted transaction with null current transaction?");
        }
示例#6
0
        private void EnlistNonNull(SysTx.Transaction tx)
        {
            Debug.Assert(null != tx, "null transaction?");

            if (Bid.AdvancedOn)
            {
                Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, transaction %d#.\n", base.ObjectID, tx.GetHashCode());
            }

            bool hasDelegatedTransaction = false;

            if (IsYukonOrNewer)
            {
                if (Bid.AdvancedOn)
                {
                    Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, attempting to delegate\n", base.ObjectID);
                }

                // Promotable transactions are only supported on Yukon
                // servers or newer.
                SqlDelegatedTransaction delegatedTransaction = new SqlDelegatedTransaction(this, tx);

                try {
                    // NOTE: System.Transactions claims to resolve all
                    // potential race conditions between multiple delegate
                    // requests of the same transaction to different
                    // connections in their code, such that only one
                    // attempt to delegate will succeed.

                    // NOTE: PromotableSinglePhaseEnlist will eventually
                    // make a round trip to the server; doing this inside
                    // a lock is not the best choice.  We presume that you
                    // aren't trying to enlist concurrently on two threads
                    // and leave it at that -- We don't claim any thread
                    // safety with regard to multiple concurrent requests
                    // to enlist the same connection in different
                    // transactions, which is good, because we don't have
                    // it anyway.

                    // PromotableSinglePhaseEnlist may not actually promote
                    // the transaction when it is already delegated (this is
                    // the way they resolve the race condition when two
                    // threads attempt to delegate the same Lightweight
                    // Transaction)  In that case, we can safely ignore
                    // our delegated transaction, and proceed to enlist
                    // in the promoted one.

                    if (tx.EnlistPromotableSinglePhase(delegatedTransaction))
                    {
                        hasDelegatedTransaction = true;

                        this.DelegatedTransaction = delegatedTransaction;

                        if (Bid.AdvancedOn)
                        {
                            long transactionId       = SqlInternalTransaction.NullTransactionId;
                            int  transactionObjectID = 0;
                            if (null != CurrentTransaction)
                            {
                                transactionId       = CurrentTransaction.TransactionId;
                                transactionObjectID = CurrentTransaction.ObjectID;
                            }
                            Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, delegated to transaction %d# with transactionId=0x%I64x\n", base.ObjectID, transactionObjectID, transactionId);
                        }
                    }
                }
                catch (SqlException e) {
                    // we do not want to eat the error if it is a fatal one
                    if (e.Class >= TdsEnums.FATAL_ERROR_CLASS)
                    {
                        throw;
                    }

                    // if the parser is null or its state is not openloggedin, the connection is no longer good.
                    SqlInternalConnectionTds tdsConnection = this as SqlInternalConnectionTds;
                    if (tdsConnection != null)
                    {
                        TdsParser parser = tdsConnection.Parser;
                        if (parser == null || parser.State != TdsParserState.OpenLoggedIn)
                        {
                            throw;
                        }
                    }

                    ADP.TraceExceptionWithoutRethrow(e);

                    // In this case, SqlDelegatedTransaction.Initialize
                    // failed and we don't necessarily want to reject
                    // things -- there may have been a legitimate reason
                    // for the failure.
                }
            }

            if (!hasDelegatedTransaction)
            {
                if (Bid.AdvancedOn)
                {
                    Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, delegation not possible, enlisting.\n", base.ObjectID);
                }

                byte[] cookie = null;

                if (null == _whereAbouts)
                {
                    byte[] dtcAddress = GetDTCAddress();

                    if (null == dtcAddress)
                    {
                        throw SQL.CannotGetDTCAddress();
                    }
                    _whereAbouts = dtcAddress;
                }

                cookie = GetTransactionCookie(tx, _whereAbouts);

                // send cookie to server to finish enlistment
                PropagateTransactionCookie(cookie);

                _isEnlistedInTransaction = true;

                if (Bid.AdvancedOn)
                {
                    long transactionId       = SqlInternalTransaction.NullTransactionId;
                    int  transactionObjectID = 0;
                    if (null != CurrentTransaction)
                    {
                        transactionId       = CurrentTransaction.TransactionId;
                        transactionObjectID = CurrentTransaction.ObjectID;
                    }
                    Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, enlisted with transaction %d# with transactionId=0x%I64x\n", base.ObjectID, transactionObjectID, transactionId);
                }
            }

            EnlistedTransaction = tx; // Tell the base class about our enlistment


            // If we're on a Yukon or newer server, and we we delegate the
            // transaction successfully, we will have done a begin transaction,
            // which produces a transaction id that we should execute all requests
            // on.  The TdsParser or SmiEventSink will store this information as
            // the current transaction.
            //
            // Likewise, propagating a transaction to a Yukon or newer server will
            // produce a transaction id that The TdsParser or SmiEventSink will
            // store as the current transaction.
            //
            // In either case, when we're working with a Yukon or newer server
            // we better have a current transaction by now.

            Debug.Assert(!IsYukonOrNewer || null != CurrentTransaction, "delegated/enlisted transaction with null current transaction?");
        }
 private void EnlistNonNull(Transaction tx)
 {
     if (Bid.AdvancedOn)
     {
         Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, transaction %d#.\n", base.ObjectID, tx.GetHashCode());
     }
     bool flag = false;
     if (this.IsYukonOrNewer)
     {
         if (Bid.AdvancedOn)
         {
             Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, attempting to delegate\n", base.ObjectID);
         }
         SqlDelegatedTransaction promotableSinglePhaseNotification = new SqlDelegatedTransaction(this, tx);
         try
         {
             if (tx.EnlistPromotableSinglePhase(promotableSinglePhaseNotification))
             {
                 flag = true;
                 this.DelegatedTransaction = promotableSinglePhaseNotification;
                 if (Bid.AdvancedOn)
                 {
                     long transactionId = 0L;
                     int objectID = 0;
                     if (this.CurrentTransaction != null)
                     {
                         transactionId = this.CurrentTransaction.TransactionId;
                         objectID = this.CurrentTransaction.ObjectID;
                     }
                     Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, delegated to transaction %d# with transactionId=0x%I64x\n", base.ObjectID, objectID, transactionId);
                 }
             }
         }
         catch (SqlException exception)
         {
             if (exception.Class >= 20)
             {
                 throw;
             }
             SqlInternalConnectionTds tds = this as SqlInternalConnectionTds;
             if (tds != null)
             {
                 TdsParser parser = tds.Parser;
                 if ((parser == null) || (parser.State != TdsParserState.OpenLoggedIn))
                 {
                     throw;
                 }
             }
             ADP.TraceExceptionWithoutRethrow(exception);
         }
     }
     if (!flag)
     {
         if (Bid.AdvancedOn)
         {
             Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, delegation not possible, enlisting.\n", base.ObjectID);
         }
         byte[] transactionCookie = null;
         if (this._whereAbouts == null)
         {
             byte[] dTCAddress = this.GetDTCAddress();
             if (dTCAddress == null)
             {
                 throw SQL.CannotGetDTCAddress();
             }
             this._whereAbouts = dTCAddress;
         }
         transactionCookie = GetTransactionCookie(tx, this._whereAbouts);
         this.PropagateTransactionCookie(transactionCookie);
         this._isEnlistedInTransaction = true;
         if (Bid.AdvancedOn)
         {
             long num2 = 0L;
             int num = 0;
             if (this.CurrentTransaction != null)
             {
                 num2 = this.CurrentTransaction.TransactionId;
                 num = this.CurrentTransaction.ObjectID;
             }
             Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, enlisted with transaction %d# with transactionId=0x%I64x\n", base.ObjectID, num, num2);
         }
     }
     base.EnlistedTransaction = tx;
 }
        private void EnlistNonNull(SysTx.Transaction tx) {
            Debug.Assert(null != tx, "null transaction?");

            if (Bid.AdvancedOn) {
                Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, transaction %d#.\n", base.ObjectID, tx.GetHashCode());
            }
            
            bool hasDelegatedTransaction = false;

            if (IsYukonOrNewer) {
                if (Bid.AdvancedOn) {
                    Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, attempting to delegate\n", base.ObjectID);
                }

                // Promotable transactions are only supported on Yukon
                // servers or newer.
                SqlDelegatedTransaction delegatedTransaction = new SqlDelegatedTransaction(this, tx);
                
                try {
                    // NOTE: System.Transactions claims to resolve all
                    // potential race conditions between multiple delegate
                    // requests of the same transaction to different
                    // connections in their code, such that only one
                    // attempt to delegate will succeed.

                    // NOTE: PromotableSinglePhaseEnlist will eventually
                    // make a round trip to the server; doing this inside
                    // a lock is not the best choice.  We presume that you
                    // aren't trying to enlist concurrently on two threads
                    // and leave it at that -- We don't claim any thread
                    // safety with regard to multiple concurrent requests
                    // to enlist the same connection in different
                    // transactions, which is good, because we don't have
                    // it anyway.

                    // PromotableSinglePhaseEnlist may not actually promote
                    // the transaction when it is already delegated (this is
                    // the way they resolve the race condition when two
                    // threads attempt to delegate the same Lightweight
                    // Transaction)  In that case, we can safely ignore
                    // our delegated transaction, and proceed to enlist
                    // in the promoted one.

                    if (tx.EnlistPromotableSinglePhase(delegatedTransaction)) {
                        hasDelegatedTransaction = true;

                        this.DelegatedTransaction = delegatedTransaction;

                        if (Bid.AdvancedOn) {
                            long transactionId = SqlInternalTransaction.NullTransactionId;
                            int transactionObjectID = 0; 
                            if (null != CurrentTransaction) {
                                transactionId = CurrentTransaction.TransactionId;
                                transactionObjectID = CurrentTransaction.ObjectID;
                            }
                            Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, delegated to transaction %d# with transactionId=0x%I64x\n", base.ObjectID, transactionObjectID, transactionId);
                        }
                    }
                }
                catch (SqlException e) {
                    // we do not want to eat the error if it is a fatal one
                    if (e.Class >= TdsEnums.FATAL_ERROR_CLASS) {
                        throw;
                    }

                    // if the parser is null or its state is not openloggedin, the connection is no longer good.
                    SqlInternalConnectionTds tdsConnection = this as SqlInternalConnectionTds;
                    if (tdsConnection != null)
                    {
                        TdsParser parser = tdsConnection.Parser;
                        if (parser == null || parser.State != TdsParserState.OpenLoggedIn)
                        {
                            throw;
                        }
                    }

                    ADP.TraceExceptionWithoutRethrow(e);

                    // In this case, SqlDelegatedTransaction.Initialize
                    // failed and we don't necessarily want to reject
                    // things -- there may have been a legitimate reason
                    // for the failure.
                }
            }
            
            if (!hasDelegatedTransaction) {
                if (Bid.AdvancedOn) {
                    Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, delegation not possible, enlisting.\n", base.ObjectID);
                }

                byte[] cookie = null;

                if (null == _whereAbouts) {
                     byte[] dtcAddress = GetDTCAddress();

                     if (null == dtcAddress) {
                        throw SQL.CannotGetDTCAddress();
                     }
                     _whereAbouts = dtcAddress;
                }
                    
                cookie = GetTransactionCookie(tx, _whereAbouts);

                // send cookie to server to finish enlistment
                PropagateTransactionCookie(cookie);
                
                _isEnlistedInTransaction = true;

                if (Bid.AdvancedOn) {
                    long transactionId = SqlInternalTransaction.NullTransactionId;
                    int transactionObjectID = 0; 
                    if (null != CurrentTransaction) {
                        transactionId = CurrentTransaction.TransactionId;
                        transactionObjectID = CurrentTransaction.ObjectID;
                    }
                    Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, enlisted with transaction %d# with transactionId=0x%I64x\n", base.ObjectID, transactionObjectID, transactionId);
                }
            }

            EnlistedTransaction = tx; // Tell the base class about our enlistment


            // If we're on a Yukon or newer server, and we we delegate the 
            // transaction successfully, we will have done a begin transaction, 
            // which produces a transaction id that we should execute all requests
            // on.  The TdsParser or SmiEventSink will store this information as
            // the current transaction.
            // 
            // Likewise, propagating a transaction to a Yukon or newer server will
            // produce a transaction id that The TdsParser or SmiEventSink will 
            // store as the current transaction.
            //
            // In either case, when we're working with a Yukon or newer server 
            // we better have a current transaction by now.

            Debug.Assert(!IsYukonOrNewer || null != CurrentTransaction, "delegated/enlisted transaction with null current transaction?");
        }
        private void EnlistNonNull(Transaction tx)
        {
            if (Bid.AdvancedOn)
            {
                Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, transaction %d#.\n", base.ObjectID, tx.GetHashCode());
            }
            bool flag = false;

            if (this.IsYukonOrNewer)
            {
                if (Bid.AdvancedOn)
                {
                    Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, attempting to delegate\n", base.ObjectID);
                }
                SqlDelegatedTransaction promotableSinglePhaseNotification = new SqlDelegatedTransaction(this, tx);
                try
                {
                    if (tx.EnlistPromotableSinglePhase(promotableSinglePhaseNotification))
                    {
                        flag = true;
                        this.DelegatedTransaction = promotableSinglePhaseNotification;
                        if (Bid.AdvancedOn)
                        {
                            long transactionId = 0L;
                            int  objectID      = 0;
                            if (this.CurrentTransaction != null)
                            {
                                transactionId = this.CurrentTransaction.TransactionId;
                                objectID      = this.CurrentTransaction.ObjectID;
                            }
                            Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, delegated to transaction %d# with transactionId=0x%I64x\n", base.ObjectID, objectID, transactionId);
                        }
                    }
                }
                catch (SqlException exception)
                {
                    if (exception.Class >= 20)
                    {
                        throw;
                    }
                    SqlInternalConnectionTds tds = this as SqlInternalConnectionTds;
                    if (tds != null)
                    {
                        TdsParser parser = tds.Parser;
                        if ((parser == null) || (parser.State != TdsParserState.OpenLoggedIn))
                        {
                            throw;
                        }
                    }
                    ADP.TraceExceptionWithoutRethrow(exception);
                }
            }
            if (!flag)
            {
                if (Bid.AdvancedOn)
                {
                    Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, delegation not possible, enlisting.\n", base.ObjectID);
                }
                byte[] transactionCookie = null;
                if (this._whereAbouts == null)
                {
                    byte[] dTCAddress = this.GetDTCAddress();
                    if (dTCAddress == null)
                    {
                        throw SQL.CannotGetDTCAddress();
                    }
                    this._whereAbouts = dTCAddress;
                }
                transactionCookie = GetTransactionCookie(tx, this._whereAbouts);
                this.PropagateTransactionCookie(transactionCookie);
                this._isEnlistedInTransaction = true;
                if (Bid.AdvancedOn)
                {
                    long num2 = 0L;
                    int  num  = 0;
                    if (this.CurrentTransaction != null)
                    {
                        num2 = this.CurrentTransaction.TransactionId;
                        num  = this.CurrentTransaction.ObjectID;
                    }
                    Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, enlisted with transaction %d# with transactionId=0x%I64x\n", base.ObjectID, num, num2);
                }
            }
            base.EnlistedTransaction = tx;
        }