public async Task CommitAsync(Enlistment enlistment)
        {
            using (await this.syncObject.LockAsync().Await())
            {
                try
                {
                    Tracer.Debug("Commit notification received for TX id: " + this.TransactionId);

                    if (this.TransactionId != null)
                    {
                        // Now notify the broker that a new XA'ish transaction has completed.
                        TransactionInfo info = new TransactionInfo();
                        info.ConnectionId  = this.connection.ConnectionId;
                        info.TransactionId = this.TransactionId;
                        info.Type          = (int)TransactionType.CommitTwoPhase;

                        await this.connection.CheckConnectedAsync().Await();

                        await this.connection.SyncRequestAsync(info).Await();

                        Tracer.Debug("Transaction Commit Done TX id: " + this.TransactionId);

                        RecoveryLogger.LogRecovered(this.TransactionId as XATransactionId);

                        // if server responds that nothing needs to be done, then reply done.
                        enlistment.Done();

                        AfterCommit();
                    }
                }
                catch (Exception ex)
                {
                    Tracer.DebugFormat("Transaction[{0}] Commit failed with error: {1}",
                                       this.TransactionId, ex.Message);
                    try
                    {
                        this.connection.OnAsyncException(ex);
                    }
                    catch (Exception error)
                    {
                        Tracer.Error(error.ToString());
                    }
                }
                finally
                {
                    this.currentEnlistment = null;
                    this.TransactionId     = null;
                    this.netTxState        = TxState.None;

                    CountDownLatch latch = this.recoveryComplete;
                    if (latch != null)
                    {
                        latch.countDown();
                    }

                    this.dtcControlEvent.Set();
                }
            }
        }
        public async Task InDoubtAsync(Enlistment enlistment)
        {
            using (await syncObject.LockAsync().Await())
            {
                try
                {
                    Tracer.Debug("In Doubt notification received for TX id: " + this.TransactionId);

                    await BeforeEndAsync().Await();

                    // Now notify the broker that Rollback should be performed.
                    TransactionInfo info = new TransactionInfo();
                    info.ConnectionId  = this.connection.ConnectionId;
                    info.TransactionId = this.TransactionId;
                    info.Type          = (int)TransactionType.End;

                    await this.connection.CheckConnectedAsync().Await();

                    await this.connection.SyncRequestAsync((TransactionInfo)info.Clone()).Await();

                    info.Type = (int)TransactionType.Rollback;
                    await this.connection.CheckConnectedAsync().Await();

                    await this.connection.SyncRequestAsync(info).Await();

                    Tracer.Debug("InDoubt Transaction Rollback Done TX id: " + this.TransactionId);

                    RecoveryLogger.LogRecovered(this.TransactionId as XATransactionId);

                    // if server responds that nothing needs to be done, then reply done.
                    enlistment.Done();

                    AfterRollback();
                }
                finally
                {
                    this.currentEnlistment = null;
                    this.TransactionId     = null;
                    this.netTxState        = TxState.None;

                    CountDownLatch latch = this.recoveryComplete;
                    if (latch != null)
                    {
                        latch.countDown();
                    }

                    this.dtcControlEvent.Set();
                }
            }
        }
        public void InDoubt(Enlistment enlistment)
        {
            try
            {
                dtcControlEvent.Reset();

                Tracer.Debug("In Doubt notification received for TX id: " + this.transactionId);

                BeforeEnd();

                // Now notify the broker that Rollback should be performed.
                TransactionInfo info = new TransactionInfo();
                info.ConnectionId  = this.connection.ConnectionId;
                info.TransactionId = this.transactionId;
                info.Type          = (int)TransactionType.End;

                this.connection.CheckConnected();
                this.connection.SyncRequest(info);

                info.Type = (int)TransactionType.Rollback;
                this.connection.CheckConnected();
                this.connection.SyncRequest(info);

                Tracer.Debug("InDoubt Transaction Rollback Done TX id: " + this.transactionId);

                RecoveryLogger.LogRecovered(this.transactionId as XATransactionId);

                // if server responds that nothing needs to be done, then reply done.
                enlistment.Done();

                AfterRollback();
            }
            finally
            {
                this.currentEnlistment = null;
                this.transactionId     = null;

                CountDownLatch latch = this.recoveryComplete;
                if (latch != null)
                {
                    latch.countDown();
                }

                this.dtcControlEvent.Set();
            }
        }
        public async Task PrepareAsync(PreparingEnlistment preparingEnlistment)
        {
            using (await this.syncObject.LockAsync().Await())
            {
                this.netTxState = TxState.Pending;

                try
                {
                    Tracer.Debug("Prepare notification received for TX id: " + this.TransactionId);

                    await BeforeEndAsync().Await();

                    // Before sending the request to the broker, log the recovery bits, if
                    // this fails we can't prepare and the TX should be rolled back.
                    RecoveryLogger.LogRecoveryInfo(this.TransactionId as XATransactionId,
                                                   preparingEnlistment.RecoveryInformation());

                    // Inform the broker that work on the XA'sh TX Branch is complete.
                    TransactionInfo info = new TransactionInfo();
                    info.ConnectionId  = this.connection.ConnectionId;
                    info.TransactionId = this.TransactionId;
                    info.Type          = (int)TransactionType.End;

                    await this.connection.CheckConnectedAsync().Await();

                    await this.connection.SyncRequestAsync((TransactionInfo)info.Clone()).Await();

                    // Prepare the Transaction for commit.
                    info.Type = (int)TransactionType.Prepare;
                    IntegerResponse response = (IntegerResponse)await this.connection.SyncRequestAsync(info).Await();

                    if (response.Result == XA_READONLY)
                    {
                        Tracer.Debug("Transaction Prepare done and doesn't need a commit, TX id: " + this.TransactionId);

                        this.TransactionId     = null;
                        this.currentEnlistment = null;

                        // Read Only means there's nothing to recover because there was no
                        // change on the broker.
                        RecoveryLogger.LogRecovered(this.TransactionId as XATransactionId);

                        // if server responds that nothing needs to be done, then reply done.
                        // otherwise the DTC will call Commit or Rollback but another transaction
                        // can already be in progress and this one would be commited or rolled back
                        // immediately.
                        preparingEnlistment.Done();

                        // Done so commit won't be called.
                        AfterCommit();

                        // A Read-Only TX is considered closed at this point, DTC won't call us again.
                        this.dtcControlEvent.Set();
                    }
                    else
                    {
                        Tracer.Debug("Transaction Prepare succeeded TX id: " + this.TransactionId);

                        // If work finished correctly, reply prepared
                        preparingEnlistment.Prepared();
                    }
                }
                catch (Exception ex)
                {
                    Tracer.DebugFormat("Transaction[{0}] Prepare failed with error: {1}",
                                       this.TransactionId, ex.Message);

                    AfterRollback();
                    preparingEnlistment.ForceRollback();
                    try
                    {
                        this.connection.OnAsyncException(ex);
                    }
                    catch (Exception error)
                    {
                        Tracer.Error(error.ToString());
                    }

                    this.currentEnlistment = null;
                    this.TransactionId     = null;
                    this.netTxState        = TxState.None;
                    this.dtcControlEvent.Set();
                }
            }
        }
示例#5
0
        public void Rollback(Enlistment enlistment)
        {
            lock (this.syncObject)
            {
                try
                {
                    Tracer.Debug("Rollback notification received for TX id: " + this.transactionId);

                    if (this.transactionId != null)
                    {
                        BeforeEnd();

                        // Now notify the broker that a new XA'ish transaction has started.
                        TransactionInfo info = new TransactionInfo();
                        info.ConnectionId  = this.connection.ConnectionId;
                        info.TransactionId = this.transactionId;
                        info.Type          = (int)TransactionType.End;

                        this.connection.CheckConnected();
                        this.connection.SyncRequest(info);

                        info.Type = (int)TransactionType.Rollback;
                        this.connection.CheckConnected();
                        this.connection.SyncRequest(info);

                        Tracer.Debug("Transaction Rollback Done TX id: " + this.transactionId);

                        RecoveryLogger.LogRecovered(this.transactionId as XATransactionId);

                        // if server responds that nothing needs to be done, then reply done.
                        enlistment.Done();

                        AfterRollback();
                    }
                }
                catch (Exception ex)
                {
                    Tracer.DebugFormat("Transaction[{0}] Rollback failed with error: {1}",
                                       this.transactionId, ex.Message);
                    AfterRollback();
                    try
                    {
                        this.connection.OnException(ex);
                    }
                    catch (Exception error)
                    {
                        Tracer.Error(error.ToString());
                    }
                }
                finally
                {
                    this.currentEnlistment = null;
                    this.transactionId     = null;
                    this.netTxState        = TxState.None;

                    CountDownLatch latch = this.recoveryComplete;
                    if (latch != null)
                    {
                        latch.countDown();
                    }

                    this.dtcControlEvent.Set();
                }
            }
        }
        public void Prepare(PreparingEnlistment preparingEnlistment)
        {
            try
            {
                dtcControlEvent.Reset();

                Tracer.Debug("Prepare notification received for TX id: " + this.transactionId);

                BeforeEnd();

                // Before sending the request to the broker, log the recovery bits, if
                // this fails we can't prepare and the TX should be rolled back.
                RecoveryLogger.LogRecoveryInfo(this.transactionId as XATransactionId,
                                               preparingEnlistment.RecoveryInformation());

                // Inform the broker that work on the XA'sh TX Branch is complete.
                TransactionInfo info = new TransactionInfo();
                info.ConnectionId  = this.connection.ConnectionId;
                info.TransactionId = this.transactionId;
                info.Type          = (int)TransactionType.End;

                this.connection.CheckConnected();
                this.connection.SyncRequest(info);

                // Prepare the Transaction for commit.
                info.Type = (int)TransactionType.Prepare;
                IntegerResponse response = (IntegerResponse)this.connection.SyncRequest(info);
                if (response.Result == XA_READONLY)
                {
                    Tracer.Debug("Transaction Prepare done and doesn't need a commit, TX id: " + this.transactionId);

                    this.transactionId     = null;
                    this.currentEnlistment = null;

                    // Read Only means there's nothing to recover because there was no
                    // change on the broker.
                    RecoveryLogger.LogRecovered(this.transactionId as XATransactionId);

                    // if server responds that nothing needs to be done, then reply prepared
                    // but clear the current state data so we appear done to the commit method.
                    preparingEnlistment.Prepared();

                    // Done so commit won't be called.
                    AfterCommit();
                }
                else
                {
                    Tracer.Debug("Transaction Prepare succeeded TX id: " + this.transactionId);

                    // If work finished correctly, reply prepared
                    preparingEnlistment.Prepared();
                }
            }
            catch (Exception ex)
            {
                Tracer.DebugFormat("Transaction[{0}] Prepare failed with error: {1}",
                                   this.transactionId, ex.Message);

                AfterRollback();
                preparingEnlistment.ForceRollback();
                try
                {
                    this.connection.OnException(ex);
                }
                catch (Exception error)
                {
                    Tracer.Error(error.ToString());
                }

                this.currentEnlistment = null;
                this.transactionId     = null;
            }
            finally
            {
                this.dtcControlEvent.Set();
            }
        }