public TransactionState this[TransactionId id] { get { TransactionState state; if(transactions.TryGetValue(id, out state)) { return state; } return null; } }
public TransactionState(TransactionId id) { this.id = id; }
/// <summary> /// Converts the given transaction ID into a String /// </summary> public static String ToString(TransactionId txnId) { if (txnId is LocalTransactionId) { LocalTransactionId ltxnId = (LocalTransactionId) txnId; return "" + ltxnId.Value; } else if (txnId is XATransactionId) { XATransactionId xaTxnId = (XATransactionId) txnId; return "XID:" + xaTxnId.FormatId + ":" + ToHexFromBytes(xaTxnId.GlobalTransactionId) + ":" + ToHexFromBytes(xaTxnId.BranchQualifier); } return null; }
public TransactionState removeTransactionState(TransactionId id) { TransactionState ret = transactions[id]; transactions.Remove(id); return ret; }
public void addTransactionState(TransactionId id) { checkShutdown(); transactions.Add(id, new TransactionState(id)); }
public TransactionState this[TransactionId id] { get { return transactions[id]; } }
public virtual bool Equals(TransactionId that) { return(true); }
public void Begin() { if(!InTransaction) { this.transactionId = this.session.Connection.CreateLocalTransactionId(); TransactionInfo info = new TransactionInfo(); info.ConnectionId = this.session.Connection.ConnectionId; info.TransactionId = transactionId; info.Type = (int) TransactionType.Begin; this.session.Connection.Oneway(info); if(Tracer.IsDebugEnabled) { Tracer.Debug("Begin:" + this.transactionId.ToString()); } } }
public TransactionState removeTransactionState(TransactionId id) { TransactionState ret = null; transactions.TryGetValue(id, out ret); transactions.Remove(id); return ret; }
public void InDoubt(Enlistment enlistment) { lock (syncObject) { try { 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; this.netTxState = TxState.None; CountDownLatch latch = this.recoveryComplete; if (latch != null) { latch.countDown(); } this.dtcControlEvent.Set(); } } }
/// <summary> /// Should be called from NetTxSession when created to check if any TX /// data is stored for recovery and whether the Broker has matching info /// stored. If an Transaction is found that belongs to this client and is /// still alive on the Broker it will be recovered, otherwise the stored /// data should be cleared. /// </summary> public void InitializeDtcTxContext() { // initialize the logger with the current Resource Manager Id RecoveryLogger.Initialize(ResourceManagerId); KeyValuePair<XATransactionId, byte[]>[] localRecoverables = RecoveryLogger.GetRecoverables(); if (localRecoverables.Length == 0) { Tracer.Debug("Did not detect any open DTC transaction records on disk."); // No local data so anything stored on the broker can't be recovered here. return; } XATransactionId[] recoverables = TryRecoverBrokerTXIds(); if (recoverables.Length == 0) { Tracer.Debug("Did not detect any recoverable transactions at Broker."); // Broker has no recoverable data so nothing to do here, delete the // old recovery log as its stale. RecoveryLogger.Purge(); return; } List<KeyValuePair<XATransactionId, byte[]>> matches = new List<KeyValuePair<XATransactionId, byte[]>>(); foreach(XATransactionId recoverable in recoverables) { foreach(KeyValuePair<XATransactionId, byte[]> entry in localRecoverables) { if(entry.Key.Equals(recoverable)) { Tracer.DebugFormat("Found a matching TX on Broker to stored Id: {0} reenlisting.", entry.Key); matches.Add(entry); } } } if (matches.Count != 0) { this.recoveryComplete = new CountDownLatch(matches.Count); foreach (KeyValuePair<XATransactionId, byte[]> recoverable in matches) { this.transactionId = recoverable.Key; Tracer.Info("Reenlisting recovered TX with Id: " + this.transactionId); this.currentEnlistment = TransactionManager.Reenlist(ResourceManagerGuid, recoverable.Value, this); } this.recoveryComplete.await(); Tracer.Debug("All Recovered TX enlistments Reports complete, Recovery Complete."); TransactionManager.RecoveryComplete(ResourceManagerGuid); return; } // The old recovery information doesn't match what's on the broker so we // should discard it as its stale now. RecoveryLogger.Purge(); }
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 SinglePhaseCommit(SinglePhaseEnlistment enlistment) { lock (this.syncObject) { try { Tracer.Debug("Single Phase Commit notification received for TX id: " + this.transactionId); if (this.transactionId != null) { BeforeEnd(); // 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.CommitOnePhase; this.connection.CheckConnected(); this.connection.SyncRequest(info); Tracer.Debug("Transaction Single Phase Commit Done TX id: " + this.transactionId); // if server responds that nothing needs to be done, then reply done. enlistment.Done(); AfterCommit(); } } catch (Exception ex) { Tracer.DebugFormat("Transaction[{0}] Single Phase Commit failed with error: {1}", this.transactionId, ex.Message); AfterRollback(); enlistment.Done(); try { this.connection.OnException(ex); } catch (Exception error) { Tracer.Error(error.ToString()); } } finally { this.currentEnlistment = null; this.transactionId = null; this.netTxState = TxState.None; this.dtcControlEvent.Set(); } } }
public void Prepare(PreparingEnlistment preparingEnlistment) { lock (this.syncObject) { this.netTxState = TxState.Pending; try { 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(); // 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.OnException(ex); } catch (Exception error) { Tracer.Error(error.ToString()); } this.currentEnlistment = null; this.transactionId = null; this.netTxState = TxState.None; this.dtcControlEvent.Set(); } } }
public void Begin(Transaction transaction) { lock (syncObject) { this.netTxState = TxState.Active; dtcControlEvent.Reset(); Tracer.Debug("Begin notification received"); if (InNetTransaction) { throw new TransactionInProgressException("A Transaction is already in Progress"); } try { Guid rmId = ResourceManagerGuid; // Enlist this object in the transaction. this.currentEnlistment = transaction.EnlistDurable(rmId, this, EnlistmentOptions.None); Tracer.Debug("Enlisted in Durable Transaction with RM Id: " + rmId); TransactionInformation txInfo = transaction.TransactionInformation; XATransactionId xaId = new XATransactionId(); this.transactionId = xaId; if (txInfo.DistributedIdentifier != Guid.Empty) { xaId.GlobalTransactionId = txInfo.DistributedIdentifier.ToByteArray(); xaId.BranchQualifier = Encoding.UTF8.GetBytes(Guid.NewGuid().ToString()); } else { xaId.GlobalTransactionId = Encoding.UTF8.GetBytes(txInfo.LocalIdentifier); xaId.BranchQualifier = Encoding.UTF8.GetBytes(Guid.NewGuid().ToString()); } // 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.Begin; this.session.Connection.Oneway(info); if (Tracer.IsDebugEnabled) { Tracer.Debug("Began XA'ish Transaction:" + xaId.GlobalTransactionId.ToString()); } } catch (Exception) { dtcControlEvent.Set(); throw; } } }
public void Commit() { if(InTransaction) { this.BeforeEnd(); if(Tracer.IsDebugEnabled) { Tracer.Debug("Commit: " + this.transactionId + " syncCount: " + (synchronizations != null ? synchronizations.Count : 0)); } TransactionInfo info = new TransactionInfo(); info.ConnectionId = this.session.Connection.ConnectionId; info.TransactionId = transactionId; info.Type = (int) TransactionType.CommitOnePhase; this.transactionId = null; this.session.Connection.SyncRequest(info); this.AfterCommit(); } }