EnlistPromotableSinglePhase() public method

Create a promotable single phase enlistment that promotes to MSDTC.
public EnlistPromotableSinglePhase ( IPromotableSinglePhaseNotification promotableSinglePhaseNotification ) : bool
promotableSinglePhaseNotification IPromotableSinglePhaseNotification The object that implements the IPromotableSinglePhaseNotification interface.
return bool
        private void Enlist(Transaction transaction)
        {
            if (transaction == null)
            {
                // no enlistment as we are not in a TransactionScope
                return;
            }

            // try to enlist as a PSPE
            if (!transaction.EnlistPromotableSinglePhase(this))
            {
                // our enlistmente fail so we need to enlist ourselves as durable.

                // we create a transaction directly instead of using BeginTransaction that GraphClient
                // doesn't store it in its stack of scopes.
                 var localTransaction = new Neo4jTransaction(_client);
                localTransaction.ForceKeepAlive();
                _transactionId = localTransaction.Id;
                var resourceManager = GetResourceManager();
                var propagationToken = TransactionInterop.GetTransmitterPropagationToken(transaction);
                var transactionExecutionEnvironment = new TransactionExecutionEnvironment(_client.ExecutionConfiguration)
                {
                    TransactionId =  localTransaction.Id,
                    TransactionBaseEndpoint = _client.TransactionEndpoint
                };
                resourceManager.Enlist(transactionExecutionEnvironment, propagationToken);
                localTransaction.Cancel();
            }

            _enlistedInTransactions.Add(transaction);
        }
        /// <summary>
        /// Instantiate an opened connection enlisted to the Transaction
        /// if promotable is false, the Transaction wraps a local 
        /// transaction inside and can never be promoted
        /// </summary>
        /// <param name="dbResourceAllocator"></param>
        /// <param name="transaction"></param>
        /// <param name="wantPromotable"></param>
        internal SharedConnectionInfo(
            DbResourceAllocator dbResourceAllocator,
            Transaction transaction,
            bool wantPromotable,
            ManualResetEvent handle)
        {
            Debug.Assert((transaction != null), "Null Transaction!");

            if (null == handle)
                throw new ArgumentNullException("handle");

            this.handle = handle;

            if (wantPromotable)
            {
                // Enlist a newly opened connection to this regular Transaction
                this.connection = dbResourceAllocator.OpenNewConnection();
                this.connection.EnlistTransaction(transaction);
            }
            else
            {
                // Make this transaction no longer promotable by attaching our 
                // IPromotableSinglePhaseNotification implementation (LocalTranscaction)
                // and track the DbConnection and DbTransaction associated with the LocalTranscaction
                LocalTransaction localTransaction = new LocalTransaction(dbResourceAllocator, handle);
                transaction.EnlistPromotableSinglePhase(localTransaction);
                this.connection = localTransaction.Connection;
                this.localTransaction = localTransaction.Transaction;
            }
        }
 internal SharedConnectionInfo(DbResourceAllocator dbResourceAllocator, Transaction transaction, bool wantPromotable, ManualResetEvent handle)
 {
     if (handle == null)
     {
         throw new ArgumentNullException("handle");
     }
     this.handle = handle;
     if (wantPromotable)
     {
         this.connection = dbResourceAllocator.OpenNewConnection();
         this.connection.EnlistTransaction(transaction);
     }
     else
     {
         LocalTransaction promotableSinglePhaseNotification = new LocalTransaction(dbResourceAllocator, handle);
         transaction.EnlistPromotableSinglePhase(promotableSinglePhaseNotification);
         this.connection = promotableSinglePhaseNotification.Connection;
         this.localTransaction = promotableSinglePhaseNotification.Transaction;
     }
 }
		public void Enlist(Transaction tx)
		{
			if (tx != null)
			{
				_isolationLevel = tx.IsolationLevel;
				if (!tx.EnlistPromotableSinglePhase(this))
				{
					// must already have a durable resource
					// start transaction
					_npgsqlTx = _connection.BeginTransaction(ConvertIsolationLevel(_isolationLevel));
					_inTransaction = true;
					_rm = CreateResourceManager();
					_callbacks = new NpgsqlTransactionCallbacks(_connection);
					_rm.Enlist(_callbacks, TransactionInterop.GetTransmitterPropagationToken(tx));
					// enlisted in distributed transaction
					// disconnect and cleanup local transaction
					_npgsqlTx.Cancel();
					_npgsqlTx.Dispose();
					_npgsqlTx = null;
				}
			}
		}
        async Task<byte[]> EnlistAsync(Link link, Transaction txn)
        {
            string id = txn.TransactionInformation.LocalIdentifier;
            Enlistment enlistment;
            lock (this.SyncRoot)
            {
                if (!this.enlistments.TryGetValue(id, out enlistment))
                {
                    enlistment = new Enlistment(this, txn);
                    this.enlistments.Add(id, enlistment);
                    txn.TransactionCompleted += this.OnTransactionCompleted;

                    if (!txn.EnlistPromotableSinglePhase(enlistment))
                    {
                        this.enlistments.Remove(id);
                        txn.TransactionCompleted -= this.OnTransactionCompleted;
                        throw new InvalidOperationException("DTC not supported");
                    }
                }
            }

            return await enlistment.EnlistAsync(link);
        }
Example #6
0
        /// <summary>
        /// Enlists in the specified transaction. 
        /// </summary>
        /// <param name="transaction">
        /// A reference to an existing <see cref="System.Transactions.Transaction"/> in which to enlist.
        /// </param>
        public override void EnlistTransaction(Transaction transaction)
        {
            // enlisting in the null transaction is a noop
            if (transaction == null)
                return;

            // guard against trying to enlist in more than one transaction
            if (driver.CurrentTransaction != null)
            {
                if (driver.CurrentTransaction.BaseTransaction == transaction)
                    return;

                throw new MySqlException("Already enlisted");
            }

            // now see if we need to swap out drivers.  We would need to do this since
            // we have to make sure all ops for a given transaction are done on the
            // same physical connection.
            Driver existingDriver = DriverTransactionManager.GetDriverInTransaction(transaction);
            if (existingDriver != null)
            {
                // we can't allow more than one driver to contribute to the same connection
                if (existingDriver.IsInActiveUse)
                    throw new NotSupportedException(Resources.MultipleConnectionsInTransactionNotSupported);

                // there is an existing driver and it's not being currently used.
                // now we need to see if it is using the same connection string
                string text1 = existingDriver.Settings.GetConnectionString(true);
                string text2 = Settings.GetConnectionString(true);
                if (String.Compare(text1, text2, true) != 0)
                    throw new NotSupportedException(Resources.MultipleConnectionsInTransactionNotSupported);

                // close existing driver
                // set this new driver as our existing driver
                CloseFully();
                driver = existingDriver;
            }

            if (driver.CurrentTransaction == null)
            {
                MySqlPromotableTransaction t = new MySqlPromotableTransaction(this, transaction);
                if (!transaction.EnlistPromotableSinglePhase(t))
                    throw new NotSupportedException(Resources.DistributedTxnNotSupported);

                driver.CurrentTransaction = t;
                DriverTransactionManager.SetDriverInTransaction(driver);
                driver.IsInActiveUse = true;
            }
        }
Example #7
0
        private void EnlistNonNull(SysTx.Transaction tx)
        {
            Debug.Assert(null != tx, "null transaction?");
            SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.SqlInternalConnection.EnlistNonNull|ADV> {0}, transaction {1}.", ObjectID, tx.GetHashCode());
            bool hasDelegatedTransaction = false;

            if (Is2005OrNewer)
            {
                SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.SqlInternalConnection.EnlistNonNull|ADV> {0}, attempting to delegate", ObjectID);

                // Promotable transactions are only supported on 2005
                // 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;
                        SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.SqlInternalConnection.EnlistNonNull|ADV> {0}, delegated to transaction {1} with transactionId=0x{2}", ObjectID, null != CurrentTransaction ? CurrentTransaction.ObjectID : 0, null != CurrentTransaction ? CurrentTransaction.TransactionId : SqlInternalTransaction.NullTransactionId);
                    }
                }
                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)
            {
                SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.SqlInternalConnection.EnlistNonNull|ADV> {0}, delegation not possible, enlisting.", ObjectID);
                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;
                SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.SqlInternalConnection.EnlistNonNull|ADV> {0}, enlisted with transaction {1} with transactionId=0x{2}", ObjectID, null != CurrentTransaction ? CurrentTransaction.ObjectID : 0, null != CurrentTransaction ? CurrentTransaction.TransactionId : SqlInternalTransaction.NullTransactionId);
            }

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

            // If we're on a 2005 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 2005 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 2005 or newer server
            // we better have a current transaction by now.

            Debug.Assert(!Is2005OrNewer || null != CurrentTransaction, "delegated/enlisted transaction with null current transaction?");
        }
Example #8
0
		public override void EnlistTransaction( Transaction transaction ) {
			if( transaction != null ) {
				if( this.driver.CurrentTransaction != null ) {
					if( this.driver.CurrentTransaction.BaseTransaction != transaction ) {
						throw new MySqlException( "Already enlisted" );
					}
				} else {
					Driver driverInTransaction = DriverTransactionManager.GetDriverInTransaction( transaction );
					if( driverInTransaction != null ) {
						if( driverInTransaction.IsInActiveUse ) {
							throw new NotSupportedException( Resources.MultipleConnectionsInTransactionNotSupported );
						}
						string connectionString = driverInTransaction.Settings.GetConnectionString( true );
						string strB = this.Settings.GetConnectionString( true );
						if( string.Compare( connectionString, strB, true ) != 0 ) {
							throw new NotSupportedException( Resources.MultipleConnectionsInTransactionNotSupported );
						}
						this.CloseFully();
						this.driver = driverInTransaction;
					}
					if( this.driver.CurrentTransaction == null ) {
						MySqlPromotableTransaction promotableSinglePhaseNotification = new MySqlPromotableTransaction( this, transaction );
						if( !transaction.EnlistPromotableSinglePhase( promotableSinglePhaseNotification ) ) {
							throw new NotSupportedException( Resources.DistributedTxnNotSupported );
						}
						this.driver.CurrentTransaction = promotableSinglePhaseNotification;
						DriverTransactionManager.SetDriverInTransaction( this.driver );
						this.driver.IsInActiveUse = true;
					}
				}
			}
		}
Example #9
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?");
        }
        public override void EnlistTransaction(Transaction systemTransaction)
        {
            lock (m_syncRoot)
            {
                CheckClosed();

                if (systemTransaction == null)
                {
                    throw new ArgumentNullException("transaction");
                }

                HsqlEnlistment enlistment = m_enlistment;

                if (enlistment == null)
                {
                    enlistment = new HsqlEnlistment(this, systemTransaction);

                    if (!systemTransaction.EnlistPromotableSinglePhase(enlistment))
                    {
                        if (m_transaction == null)
                        {
                            BeginTransaction(HsqlConvert.ToIsolationLevel(systemTransaction.IsolationLevel));
                        }

                        enlistment.m_dbTransaction = m_transaction;
                        systemTransaction.EnlistDurable(enlistment.Rmid, enlistment, EnlistmentOptions.None);
                    }

                    m_enlistment = enlistment;

                    GC.KeepAlive(this);
                }
                else if (enlistment.Transaction != systemTransaction)
                {
                    throw new InvalidOperationException(
                        "Connection currently has transaction enlisted."
                        + "  Finish current transaction and retry."); // NOI18N
                }
            }
        }
 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;
 }