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(); } } }
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(); } }