Code:
/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / TransactionBridge / Microsoft / Transactions / Wsat / StateMachines / Coordinator.cs / 1 / Coordinator.cs
//------------------------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- // This file contains the the implementations of the various states used by // the coordinator state machine (both durable and volatile) using System; using System.Diagnostics; using System.ServiceModel.Channels; using Microsoft.Transactions.Bridge; using Microsoft.Transactions.Wsat.InputOutput; using Microsoft.Transactions.Wsat.Messaging; using Microsoft.Transactions.Wsat.Protocol; using Microsoft.Transactions.Wsat.Recovery; using DiagnosticUtility = Microsoft.Transactions.Bridge.DiagnosticUtility; namespace Microsoft.Transactions.Wsat.StateMachines { //============================================================================= // CoordinatorInitializing // // An EnlistTransaction message was received, and a new transaction // object was created to process it. //============================================================================= class CoordinatorInitializing : InactiveState { public CoordinatorInitializing(ProtocolState state) : base(state) { } public override void OnEvent(MsgEnlistTransactionEvent e) { CoordinatorEnlistment coordinator = e.Coordinator; // If InboundTransactions are disabled, we don't even try to create // a superior enlistment with the TM. Instead, we simply forward // the event to a subordinate enlistment. // If the transaction already exists, good. Otherwise, fail. if (!state.TransactionManager.Settings.NetworkInboundAccess) { ForwardEnlistmentEventToSubordinate(e); coordinator.StateMachine.ChangeState(state.States.CoordinatorInitializationFailed); } else { CoordinationContext context = e.Body.CurrentContext; // Resolve the registration proxy RegistrationProxy proxy = state.TryCreateRegistrationProxy(context.RegistrationService); if (proxy == null) { coordinator.ContextManager.Fault = this.state.Faults.RegistrationProxyFailed; coordinator.StateMachine.ChangeState(state.States.CoordinatorInitializationFailed); } else { try { coordinator.SetRegistrationProxy(proxy); EnlistmentOptions options = coordinator.CreateEnlistmentOptions(context.Expires, context.ExpiresPresent, context.IsolationLevel, context.IsolationFlags, context.Description); // Ask the TM to create a superior enlistment for us state.TransactionManagerSend.EnlistTransaction(coordinator, options, e); e.StateMachine.ChangeState(state.States.CoordinatorEnlisting); } finally { proxy.Release(); } } } } } //============================================================================== // CoordinatorEnlisting // // The TM has been asked to create a new superior enlistment //============================================================================= class CoordinatorEnlisting : InactiveState { public CoordinatorEnlisting (ProtocolState state) : base (state) {} public override void OnEvent(TmEnlistTransactionResponseEvent e) { CoordinatorEnlistment coordinator = e.Coordinator; MsgEnlistTransactionEvent source = e.SourceEvent; switch (e.Status) { case Status.Success: if (EnlistTransactionRecord.ShouldTrace) { EnlistTransactionRecord.Trace(coordinator.EnlistmentId, source.Body.CurrentContext); } coordinator.OnCoordinatorEnlisted(); coordinator.StateMachine.ChangeState(state.States.CoordinatorEnlisted); break; case Status.DuplicateTransaction: ForwardEnlistmentEventToSubordinate(source); coordinator.StateMachine.ChangeState(state.States.CoordinatorInitializationFailed); break; default: if (EnlistTransactionFailureRecord.ShouldTrace) { EnlistTransactionFailureRecord.Trace( coordinator.EnlistmentId, source.Body.CurrentContext, SR.GetString (SR.PplCreateSuperiorEnlistmentFailed, e.Status.ToString()) ); } coordinator.ContextManager.Fault = this.state.Faults.TMEnlistFailed(e.Status); coordinator.StateMachine.ChangeState(state.States.CoordinatorInitializationFailed); break; } } } //============================================================================== // CoordinatorEnlisted // // The TM has created a new superior enlistment // // This is a bootstrap state that is only visited once //============================================================================== class CoordinatorEnlisted : ActiveState { public CoordinatorEnlisted (ProtocolState state) : base (state) {} public override void Enter (StateMachine stateMachine) { base.Enter (stateMachine); // We have to register for durable 2PC before responding to Enlist messages. // This is because we don't want to split the transaction tree. If we have // only a volatile 2PC pipe between us and our coordinator, we might not // receive a reliable outcome message. Furthermore, while the TM will send // us EnlistPrePrepare notifications, it will not send us an "EnlistPrepare". // So we need to fault in the durable pipe every time we're superior to the TM // and subordinate to another WS-AT node. // // We cannot return a coordination context to a subordinate until our superior // sends us a register response for durable 2PC. The reason is that someone could // cross-marshal that context to some other protocol, like OleTx, and register // for 2PC. The TM won't tell us about this event, so there will be someone out there // who thinks that the transaction is real when it really isn't, because we // don't have a pipe to our superior yet, and we can't provide any guarantees. // // Bottom line: we state axiomatically that a protocol provider must always establish // a durable pipe to its superior before responding to Enlist messages // Ask our superior for a durable pipe CoordinatorEnlistment coordinator = (CoordinatorEnlistment) stateMachine.Enlistment; state.RegistrationParticipant.SendDurableRegister(coordinator); } public override void OnEvent(MsgRegisterDurableResponseEvent e) { SetDurableCoordinatorActive (e); e.Coordinator.StateMachine.ChangeState(state.States.CoordinatorActive); } public override void OnEvent(TmEnlistPrePrepareEvent e) { EnlistPrePrepare (e); // Now we're registering for both protocols e.StateMachine.ChangeState(state.States.CoordinatorRegisteringBoth); } public override void OnEvent(TmAsyncRollbackEvent e) { ProcessTmAsyncRollback(e); } } //============================================================================= // CoordinatorRegisteringBoth // // The TM has created a new superior enlistment // We sent our superior a register request for durable // We received an EnlistPrePrepare from the TM // // This is a bootstrap state that is only visited once //============================================================================== class CoordinatorRegisteringBoth : ActiveState { public CoordinatorRegisteringBoth (ProtocolState state) : base (state) {} public override void Enter (StateMachine stateMachine) { base.Enter (stateMachine); CoordinatorEnlistment coordinator = (CoordinatorEnlistment)stateMachine.Enlistment; if (coordinator.RegisterVolatileCoordinator == null) { // Assumption is that the RegisterVolatileCoordinator is set. // If the assumption is incorrect, then the rest // of the assumptions in the code are incorrect and this is a product bug. DiagnosticUtility.FailFast("CoordinatorRegisteringBoth requires RegisterVolatileCoordinator"); } } public override void OnEvent(MsgRegisterDurableResponseEvent e) { SetDurableCoordinatorActive (e); e.StateMachine.ChangeState(state.States.CoordinatorRegisteringVolatile); } public override void OnEvent(MsgRegisterVolatileResponseEvent e) { // We can't set our volatile coordinator to be active, because we don't have // a durable pipe yet. If we responded to the EnlistPrePrepare now, we would // begin sending responses to CCC w/context with volatile registers, which // could then be used to cross-marshal to other protocols, which would then // assume a durable pipe. // // So we just save the EPR and keep waiting for the durable register response e.VolatileCoordinator.SetCoordinatorProxy(e.Proxy); e.StateMachine.ChangeState(state.States.CoordinatorRegisteringDurable); } public override void OnEvent(TmAsyncRollbackEvent e) { ProcessTmAsyncRollback(e); } } //============================================================================= // CoordinatorRegisteringDurable // // The TM has created a new superior enlistment // We sent our superior a register request for durable // We already received a register response for volatile // // This is a bootstrap state that is only visited once //============================================================================= class CoordinatorRegisteringDurable : ActiveState { public CoordinatorRegisteringDurable (ProtocolState state) : base (state) {} public override void Enter(StateMachine stateMachine) { base.Enter(stateMachine); CoordinatorEnlistment coordinator = (CoordinatorEnlistment) stateMachine.Enlistment; if (coordinator.RegisterVolatileCoordinator == null) { // Assumption is that the RegisterVolatileCoordinator is set. // If the assumption is incorrect, then the rest // of the assumptions in the code are incorrect and this is a product bug. DiagnosticUtility.FailFast("CoordinatorRegisteringDurable requires RegisterVolatileCoordinator"); } } public override void OnEvent(MsgRegisterDurableResponseEvent e) { SetDurableCoordinatorActive(e); e.StateMachine.ChangeState(state.States.CoordinatorVolatileActive); } public override void OnEvent(MsgVolatileRollbackEvent e) { state.TransactionManagerSend.Rollback(e.VolatileCoordinator); e.StateMachine.ChangeState(state.States.CoordinatorAborted); } public override void OnEvent(TmAsyncRollbackEvent e) { ProcessTmAsyncRollback(e); } } //============================================================================= // CoordinatorRegisteringVolatile // // The TM has created a new superior enlistment // We registered for durable // We sent our superior a register request for volatile // // We will return to this state for each phase zero wave //============================================================================== class CoordinatorRegisteringVolatile : ActiveState { public CoordinatorRegisteringVolatile (ProtocolState state) : base (state) {} public override void Enter(StateMachine stateMachine) { base.Enter(stateMachine); CoordinatorEnlistment coordinator = (CoordinatorEnlistment) stateMachine.Enlistment; if (coordinator.RegisterVolatileCoordinator == null) { // Assumption is that the RegisterVolatileCoordinator is set. // If the assumption is incorrect, then the rest // of the assumptions in the code are incorrect and this is a product bug. DiagnosticUtility.FailFast("CoordinatorRegisteringVolatile requires RegisterVolatileCoordinator"); } } public override void OnEvent(MsgRegisterVolatileResponseEvent e) { e.VolatileCoordinator.SetCoordinatorProxy (e.Proxy); e.StateMachine.ChangeState(state.States.CoordinatorVolatileActive); } public override void OnEvent(MsgVolatilePrepareEvent e) { VolatileCoordinatorEnlistment volatileCoordinator = e.VolatileCoordinator; CoordinatorEnlistment coordinator = volatileCoordinator.Coordinator; if (ReferenceEquals(volatileCoordinator, coordinator.LastCompletedVolatileCoordinator)) { // A duplicate message for the last completed volatile coordinator - resend ReadOnly state.TwoPhaseCommitParticipant.SendVolatileReadOnly(volatileCoordinator); } else { // Ignore duplicate message from older volatile coordinator return; } } public override void OnEvent(MsgVolatileRollbackEvent e) { VolatileCoordinatorEnlistment volatileCoordinator = e.VolatileCoordinator; CoordinatorEnlistment coordinator = volatileCoordinator.Coordinator; if (ReferenceEquals(volatileCoordinator, coordinator.LastCompletedVolatileCoordinator)) { state.TwoPhaseCommitParticipant.SendVolatileAborted(volatileCoordinator); state.TransactionManagerSend.Rollback(volatileCoordinator); e.StateMachine.ChangeState(state.States.CoordinatorAborted); } else { base.OnEvent(e); } } public override void OnEvent(MsgDurableRollbackEvent e) { state.TransactionManagerSend.Rollback(e.Coordinator); e.StateMachine.ChangeState(state.States.CoordinatorAborted); } public override void OnEvent(TmAsyncRollbackEvent e) { ProcessTmAsyncRollback(e); } } //============================================================================= // CoordinatorVolatileActive // // The TM has created a new superior enlistment // We have created a durable registration // We have an outstanding volatile registration // // We await a volatile Prepare from our superior //============================================================================== class CoordinatorVolatileActive : ActiveState { public CoordinatorVolatileActive (ProtocolState state) : base (state) {} public override void Enter (StateMachine stateMachine) { base.Enter (stateMachine); CoordinatorEnlistment coordinator = (CoordinatorEnlistment) stateMachine.Enlistment; if (coordinator.RegisterVolatileCoordinator == null) { // Assumption is that the RegisterVolatileCoordinator is set. // If the assumption is incorrect, then the rest // of the assumptions in the code are incorrect and this is a product bug. DiagnosticUtility.FailFast("CoordinatorVolatileActive requires RegisterVolatileCoordinator"); } if (RegisterCoordinatorRecord.ShouldTrace) { RegisterCoordinatorRecord.Trace( coordinator.EnlistmentId, coordinator.SuperiorContext, ControlProtocol.Volatile2PC, coordinator.RegisterVolatileCoordinator.CoordinatorProxy.To, this.state.ProtocolVersion ); } // Release the pending EnlistPrePrepare TmEnlistPrePrepareEvent e = coordinator.EnlistPrePrepareEvent; coordinator.EnlistPrePrepareEvent = null; coordinator.SetCallback(e.Callback, e.CallbackState); state.TransactionManagerSend.EnlistPrePrepareResponse (coordinator, Status.Success); } public override void OnEvent(MsgVolatilePrepareEvent e) { VolatileCoordinatorEnlistment volatileCoordinator = e.VolatileCoordinator; CoordinatorEnlistment coordinator = volatileCoordinator.Coordinator; if (ReferenceEquals(volatileCoordinator, coordinator.LastCompletedVolatileCoordinator)) { // A duplicate message for the previous volatile coordinator - resend ReadOnly state.TwoPhaseCommitParticipant.SendVolatileReadOnly(volatileCoordinator); } else if (ReferenceEquals(volatileCoordinator, coordinator.RegisterVolatileCoordinator)) { // Rotate the pointers coordinator.PreparingVolatileCoordinator = volatileCoordinator; coordinator.RegisterVolatileCoordinator = null; state.TransactionManagerSend.PrePrepare(volatileCoordinator); e.StateMachine.ChangeState(state.States.CoordinatorVolatilePreparing); } else { // Ignore - we've already completed this enlistment return; } } public override void OnEvent(MsgVolatileRollbackEvent e) { VolatileCoordinatorEnlistment volatileCoordinator = e.VolatileCoordinator; CoordinatorEnlistment coordinator = volatileCoordinator.Coordinator; if (ReferenceEquals(volatileCoordinator, coordinator.RegisterVolatileCoordinator) || ReferenceEquals(volatileCoordinator, coordinator.LastCompletedVolatileCoordinator)) { state.TransactionManagerSend.Rollback(volatileCoordinator); e.StateMachine.ChangeState(state.States.CoordinatorAborted); } else { base.OnEvent(e); } } public override void OnEvent(MsgDurableRollbackEvent e) { state.TransactionManagerSend.Rollback(e.Coordinator); e.StateMachine.ChangeState(state.States.CoordinatorAborted); } public override void OnEvent(TmAsyncRollbackEvent e) { ProcessTmAsyncRollback(e); } } //============================================================================== // CoordinatorVolatilePreparing // // We told the TM to PrePrepare the current Phase Zero wave //============================================================================= class CoordinatorVolatilePreparing : ActiveState { public CoordinatorVolatilePreparing (ProtocolState state) : base (state) {} public override void Enter (StateMachine stateMachine) { base.Enter (stateMachine); CoordinatorEnlistment coordinator = (CoordinatorEnlistment) stateMachine.Enlistment; if (coordinator.RegisterVolatileCoordinator != null) { // Assumption is that the RegisterVolatileCoordinator is not set yet. // If the assumption is incorrect, then the rest // of the assumptions in the code are incorrect and this is a product bug. DiagnosticUtility.FailFast("CoordinatorVolatilePreparing requires null RegisterVolatileCoordinator"); } if (coordinator.PreparingVolatileCoordinator == null) { // Assumption is that the PreparingVolatileCoordinator is set. // If the assumption is incorrect, then the rest // of the assumptions in the code are incorrect and this is a product bug. DiagnosticUtility.FailFast("CoordinatorVolatilePreparing requires PreparingVolatileCoordinator"); } } // Tolerate duplicate messages public override void OnEvent(MsgVolatilePrepareEvent e) { return; } public override void OnEvent(MsgVolatileRollbackEvent e) { VolatileCoordinatorEnlistment volatileCoordinator = e.VolatileCoordinator; CoordinatorEnlistment coordinator = volatileCoordinator.Coordinator; if (ReferenceEquals(volatileCoordinator, coordinator.PreparingVolatileCoordinator)) { state.TransactionManagerSend.Rollback(volatileCoordinator); e.StateMachine.ChangeState(state.States.CoordinatorAborted); } else { base.OnEvent(e); } } public override void OnEvent(MsgDurableRollbackEvent e) { state.TransactionManagerSend.Rollback(e.Coordinator); e.StateMachine.ChangeState(state.States.CoordinatorAborted); } public override void OnEvent(TmPrePrepareResponseEvent e) { switch (e.Status) { case Status.PrePrepared: // We're always registered for durable 2PC, so we can lose the volatile pipe // Therefore, we respond readonly and save messages state.TwoPhaseCommitParticipant.SendVolatileReadOnly (e.VolatileCoordinator); // Rotate the volatile coordinator pointers CoordinatorEnlistment coordinator = e.VolatileCoordinator.Coordinator; coordinator.LastCompletedVolatileCoordinator = coordinator.PreparingVolatileCoordinator; coordinator.PreparingVolatileCoordinator = null; e.StateMachine.ChangeState(state.States.CoordinatorActive); break; case Status.Aborted: // The Aborted response is sent on state enter e.StateMachine.ChangeState(state.States.CoordinatorAborted); break; default: // An invalid Enum value on this internal code path indicates // a product bug and violates assumptions about // valid values in MSDTC. DiagnosticUtility.FailFast("Invalid status code"); break; // Keep the compiler happy } } // The next Phase Zero wave has begun, so we need to open a new pipe public override void OnEvent(TmEnlistPrePrepareEvent e) { EnlistPrePrepare(e); // Now we're registering for both protocols e.StateMachine.ChangeState(state.States.CoordinatorVolatilePreparingRegistering); } public override void OnEvent(TmAsyncRollbackEvent e) { ProcessTmAsyncRollback(e); } } //============================================================================== // CoordinatorVolatilePreparingRegistering // // We told the TM to PrePrepare the current wave // The TM asked us for another volatile enlistment // We sent a register to our superior //============================================================================= class CoordinatorVolatilePreparingRegistering : ActiveState { public CoordinatorVolatilePreparingRegistering (ProtocolState state) : base (state) {} public override void Enter (StateMachine stateMachine) { base.Enter(stateMachine); CoordinatorEnlistment coordinator = (CoordinatorEnlistment) stateMachine.Enlistment; if (coordinator.PreparingVolatileCoordinator == null) { // Assumption is that the PreparingVolatileCoordinator is set. // If the assumption is incorrect, then the rest // of the assumptions in the code are incorrect and this is a product bug. DiagnosticUtility.FailFast("CoordinatorVolatilePreparingRegistering requires PreparingVolatileCoordinator"); } if (coordinator.RegisterVolatileCoordinator == null) { // Assumption is that the RegisterVolatileCoordinator is set. // If the assumption is incorrect, then the rest // of the assumptions in the code are incorrect and this is a product bug. DiagnosticUtility.FailFast("CoordinatorVolatilePreparingRegistering requires RegisterVolatileCoordinator"); } } public override void OnEvent(MsgRegisterVolatileResponseEvent e) { e.VolatileCoordinator.SetCoordinatorProxy(e.Proxy); e.StateMachine.ChangeState(state.States.CoordinatorVolatilePreparingRegistered); } // Tolerate duplicate messages public override void OnEvent(MsgVolatilePrepareEvent e) { // We can't see a Prepare for the next volatile participant in this state, // because we haven't received RegisterResponse, so the dispatcher // won't be able to authorize the incoming message return; } public override void OnEvent(MsgVolatileRollbackEvent e) { VolatileCoordinatorEnlistment volatileCoordinator = e.VolatileCoordinator; CoordinatorEnlistment coordinator = volatileCoordinator.Coordinator; if (ReferenceEquals(volatileCoordinator, coordinator.PreparingVolatileCoordinator)) { state.TransactionManagerSend.Rollback(volatileCoordinator); e.StateMachine.ChangeState(state.States.CoordinatorAborted); } else { base.OnEvent(e); } } public override void OnEvent(MsgDurableRollbackEvent e) { state.TransactionManagerSend.Rollback(e.Coordinator); e.StateMachine.ChangeState(state.States.CoordinatorAborted); } public override void OnEvent(TmPrePrepareResponseEvent e) { switch (e.Status) { case Status.PrePrepared: // We're always registered for durable 2PC, so we can lose the volatile pipe // Therefore, we respond readonly and save messages state.TwoPhaseCommitParticipant.SendVolatileReadOnly(e.VolatileCoordinator); // Rotate the volatile coordinator pointers CoordinatorEnlistment coordinator = e.VolatileCoordinator.Coordinator; coordinator.LastCompletedVolatileCoordinator = coordinator.PreparingVolatileCoordinator; coordinator.PreparingVolatileCoordinator = null; e.StateMachine.ChangeState(state.States.CoordinatorRegisteringVolatile); break; case Status.Aborted: // The Aborted response is sent on state enter e.StateMachine.ChangeState(state.States.CoordinatorAborted); break; default: // An invalid Enum value on this internal code path indicates // a product bug and violates assumptions about // valid values in MSDTC. DiagnosticUtility.FailFast("Invalid status code"); break; // Keep the compiler happy } } public override void OnEvent(TmAsyncRollbackEvent e) { ProcessTmAsyncRollback(e); } } //============================================================================= // CoordinatorVolatilePreparingRegistered // // We told the TM to PrePrepare the current wave // The TM asked us for another volatile enlistment // We registered for the next wave with our superior // Our superior sent us a register response // We're still waiting for the TM to respond to our PrePrepare //============================================================================= class CoordinatorVolatilePreparingRegistered : ActiveState { public CoordinatorVolatilePreparingRegistered (ProtocolState state) : base (state) {} public override void Enter (StateMachine stateMachine) { base.Enter (stateMachine); CoordinatorEnlistment coordinator = (CoordinatorEnlistment) stateMachine.Enlistment; if (coordinator.PreparingVolatileCoordinator == null) { // Assumption is that the PreparingVolatileCoordinator is set. // If the assumption is incorrect, then the rest // of the assumptions in the code are incorrect and this is a product bug. DiagnosticUtility.FailFast("CoordinatorVolatilePreparingRegistered requires PreparingVolatileCoordinator"); } if (coordinator.RegisterVolatileCoordinator == null) { // Assumption is that the RegisterVolatileCoordinator is set. // If the assumption is incorrect, then the rest // of the assumptions in the code are incorrect and this is a product bug. DiagnosticUtility.FailFast("CoordinatorVolatilePreparingRegistered requires RegisterVolatileCoordinator"); } } public override void OnEvent(MsgVolatilePrepareEvent e) { VolatileCoordinatorEnlistment volatileCoordinator = e.VolatileCoordinator; CoordinatorEnlistment coordinator = volatileCoordinator.Coordinator; if (ReferenceEquals(volatileCoordinator, coordinator.RegisterVolatileCoordinator)) { // The volatile coordinator sent Prepare before we responded to the previous wave base.OnEvent(e); } else { // Ignore duplicate messages return; } } public override void OnEvent(MsgVolatileRollbackEvent e) { VolatileCoordinatorEnlistment volatileCoordinator = e.VolatileCoordinator; CoordinatorEnlistment coordinator = volatileCoordinator.Coordinator; if (ReferenceEquals(volatileCoordinator, coordinator.RegisterVolatileCoordinator) || ReferenceEquals(volatileCoordinator, coordinator.PreparingVolatileCoordinator)) { state.TransactionManagerSend.Rollback(volatileCoordinator); e.StateMachine.ChangeState(state.States.CoordinatorAborted); } else { base.OnEvent(e); } } public override void OnEvent(MsgDurableRollbackEvent e) { state.TransactionManagerSend.Rollback(e.Coordinator); e.StateMachine.ChangeState(state.States.CoordinatorAborted); } public override void OnEvent(TmPrePrepareResponseEvent e) { switch (e.Status) { case Status.PrePrepared: // We're always registered for durable 2PC, so we can lose the volatile pipe // Therefore, we respond readonly and save messages state.TwoPhaseCommitParticipant.SendVolatileReadOnly(e.VolatileCoordinator); // Rotate the volatile coordinator pointers CoordinatorEnlistment coordinator = e.VolatileCoordinator.Coordinator; coordinator.LastCompletedVolatileCoordinator = coordinator.PreparingVolatileCoordinator; coordinator.PreparingVolatileCoordinator = null; e.StateMachine.ChangeState(state.States.CoordinatorVolatileActive); break; case Status.Aborted: // The Aborted response is sent on state enter e.StateMachine.ChangeState(state.States.CoordinatorAborted); break; default: // An invalid Enum value on this internal code path indicates // a product bug and violates assumptions about // valid values in MSDTC. DiagnosticUtility.FailFast("Invalid status code"); break; // Keep the compiler happy } } public override void OnEvent(TmAsyncRollbackEvent e) { ProcessTmAsyncRollback(e); } } //============================================================================== // CoordinatorActive // // The TM has created a new superior enlistment // We established a durable registration // We have gone through any number of Phase Zero waves //============================================================================= class CoordinatorActive : ActiveState { public CoordinatorActive (ProtocolState state) : base (state) {} public override void Enter (StateMachine stateMachine) { base.Enter(stateMachine); CoordinatorEnlistment coordinator = (CoordinatorEnlistment)stateMachine.Enlistment; if (coordinator.RegisterVolatileCoordinator != null) { // Assumption is that the RegisterVolatileCoordinator is not set. // If the assumption is incorrect, then the rest // of the assumptions in the code are incorrect and this is a product bug. DiagnosticUtility.FailFast("CoordinatorActive requires null RegisterVolatileCoordinator"); } } // Sigh... Start another Phase Zero wave public override void OnEvent(TmEnlistPrePrepareEvent e) { EnlistPrePrepare(e); // Now we're registering for both protocols e.StateMachine.ChangeState(state.States.CoordinatorRegisteringVolatile); } public override void OnEvent(MsgVolatilePrepareEvent e) { VolatileCoordinatorEnlistment volatileCoordinator = e.VolatileCoordinator; CoordinatorEnlistment coordinator = volatileCoordinator.Coordinator; if (ReferenceEquals(volatileCoordinator, coordinator.LastCompletedVolatileCoordinator)) { state.TwoPhaseCommitParticipant.SendVolatileReadOnly(volatileCoordinator); } else { // Ignore return; } } public override void OnEvent(MsgDurablePrepareEvent e) { CoordinatorEnlistment coordinator = e.Coordinator; Exception failed = null; try { byte[] recovery = state.LogEntrySerialization.Serialize(coordinator); coordinator.Enlistment.SetRecoveryData(recovery); state.TransactionManagerSend.Prepare(coordinator); e.StateMachine.ChangeState(state.States.CoordinatorPreparing); } catch (SerializationException exception) { DiagnosticUtility.ExceptionUtility.TraceHandledException(exception, TraceEventType.Error); failed = exception; } if (failed != null) { if (DebugTrace.Error) DebugTrace.Trace(TraceLevel.Error, "Failed to serialize log entry for coordinator: {0}", failed); CoordinatorRecoveryLogEntryCreationFailureRecord.TraceAndLog( coordinator.EnlistmentId, coordinator.Enlistment.RemoteTransactionId, failed.Message, failed ); // We react to serialization failures by aborting the transaction state.TwoPhaseCommitParticipant.SendDurableAborted(coordinator); state.TransactionManagerSend.Rollback(coordinator); e.StateMachine.ChangeState(state.States.DurableAborted); } } public override void OnEvent(MsgVolatileRollbackEvent e) { VolatileCoordinatorEnlistment volatileCoordinator = e.VolatileCoordinator; CoordinatorEnlistment coordinator = volatileCoordinator.Coordinator; if (ReferenceEquals(volatileCoordinator, coordinator.LastCompletedVolatileCoordinator)) { state.TwoPhaseCommitParticipant.SendVolatileAborted(volatileCoordinator); state.TransactionManagerSend.Rollback(volatileCoordinator); e.StateMachine.ChangeState(state.States.CoordinatorAborted); } else { base.OnEvent(e); } } public override void OnEvent(MsgDurableRollbackEvent e) { state.TransactionManagerSend.Rollback(e.Coordinator); e.StateMachine.ChangeState(state.States.CoordinatorAborted); } public override void OnEvent(TmAsyncRollbackEvent e) { ProcessTmAsyncRollback(e); } } //============================================================================== // CoordinatorPreparing // // The coordinator sent Prepare and we forwarded it to the TM //============================================================================== class CoordinatorPreparing : ActiveState { public CoordinatorPreparing (ProtocolState state) : base (state) {} // Tolerate duplicate messages public override void OnEvent(MsgVolatilePrepareEvent e) { return; } // Tolerate duplicate messages public override void OnEvent(MsgDurablePrepareEvent e) { return; } public override void OnEvent(MsgDurableRollbackEvent e) { state.TransactionManagerSend.Rollback(e.Coordinator); e.StateMachine.ChangeState(state.States.CoordinatorAborted); } public override void OnEvent(TmPrepareResponseEvent e) { CoordinatorEnlistment coordinator = e.Coordinator; State newState; switch (e.Status) { case Status.Prepared: state.TwoPhaseCommitParticipant.SendPrepared (coordinator); newState = state.States.CoordinatorPrepared; break; case Status.Readonly: state.TwoPhaseCommitParticipant.SendDurableReadOnly (coordinator); newState = state.States.CoordinatorReadOnlyInDoubt; break; case Status.Aborted: // The Aborted response is sent on state enter newState = state.States.CoordinatorAborted; break; default: // An invalid Enum value on this internal code path indicates // a product bug and violates assumptions about // valid values in MSDTC. DiagnosticUtility.FailFast("Invalid status code"); newState = null; // Keep the compiler happy break; } e.StateMachine.ChangeState(newState); } public override void OnEvent(TmAsyncRollbackEvent e) { ProcessTmAsyncRollback(e); } } //============================================================================= // CoordinatorPrepared // // The TM said Prepared //============================================================================== class CoordinatorPrepared : DecidedState { public CoordinatorPrepared (ProtocolState state) : base (state) {} public override void Enter (StateMachine stateMachine) { base.Enter (stateMachine); // Create a prepared timer stateMachine.StartTimer (TimerProfile.Prepared); } public override void Leave (StateMachine stateMachine) { base.Leave (stateMachine); // Cancel the prepared timer stateMachine.CancelTimer(); } // Tolerate duplicate messages public override void OnEvent(MsgVolatilePrepareEvent e) { return; } // Respond to the duplicate message public override void OnEvent(MsgDurablePrepareEvent e) { state.TwoPhaseCommitParticipant.SendPrepared (e.Coordinator); } public override void OnEvent(MsgDurableCommitEvent e) { CoordinatorEnlistment coordinator = e.Coordinator; state.TransactionManagerSend.Commit (coordinator); e.StateMachine.ChangeState(state.States.CoordinatorCommitting); } public override void OnEvent(MsgDurableRollbackEvent e) { state.TransactionManagerSend.Rollback(e.Coordinator); e.StateMachine.ChangeState(state.States.CoordinatorAborted); } public override void OnEvent(TmCoordinatorForgetEvent e) { CoordinatorEnlistment coordinator = e.Coordinator; coordinator.SetCallback(e.Callback, e.CallbackState); state.TransactionManagerSend.ForgetResponse(coordinator, Status.Success); e.StateMachine.ChangeState(state.States.CoordinatorForgotten); } // Just keep sending Prepared messages until we receive a response public override void OnEvent(TimerCoordinatorEvent e) { CoordinatorEnlistment coordinator = e.Coordinator; if (PreparedMessageRetryRecord.ShouldTrace) { coordinator.Retries ++; PreparedMessageRetryRecord.Trace( coordinator.EnlistmentId, coordinator.Enlistment.RemoteTransactionId, coordinator.Retries ); } state.Perf.PreparedRetryCountPerInterval.Increment(); state.TwoPhaseCommitParticipant.SendPrepared (coordinator); } } //============================================================================= // CoordinatorCommitting // // Our coordinator told us to commit the transaction. We told the TM the same //============================================================================= class CoordinatorCommitting : DecidedState { public CoordinatorCommitting (ProtocolState state) : base (state) {} // Tolerate duplicate messages public override void OnEvent(MsgVolatilePrepareEvent e) { return; } // Tolerate duplicate messages public override void OnEvent(MsgDurablePrepareEvent e) { return; } // Tolerate duplicate messages public override void OnEvent(MsgDurableCommitEvent e) { return; } public override void OnEvent(MsgDurableRollbackEvent e) { // We implement this event because the spec's state tables dictate a non-standard response: // we fault with InconsistentInternalState instead of InvalidState TraceInvalidEvent (e, false); state.TwoPhaseCommitParticipant.SendFault(e.FaultTo, e.MessageId, this.state.Faults.InconsistentInternalState); } public override void OnEvent(TmCommitResponseEvent e) { if (e.Status != Status.Committed) { // The only valid status is Committed. If this is not true, we // shouldn't be in this state method. DiagnosticUtility.FailFast("Transaction manager should respond Committed to Commit"); } state.TwoPhaseCommitParticipant.SendCommitted (e.Coordinator); e.StateMachine.ChangeState(state.States.CoordinatorCommitted); } public override void OnEvent(TmCoordinatorForgetEvent e) { CoordinatorEnlistment coordinator = e.Coordinator; coordinator.SetCallback(e.Callback, e.CallbackState); state.TransactionManagerSend.ForgetResponse(coordinator, Status.Success); e.StateMachine.ChangeState(state.States.CoordinatorForgotten); } // This is a repost from the recovery queue. Ignore it public override void OnEvent(TmReplayEvent e) { return; } // Tolerate timer notifications left over from the Prepared or Replaying states public override void OnEvent(TimerCoordinatorEvent e) { return; } } //============================================================================= // CoordinatorRecovering // // The TM asked us for replay. A new coordinator enlistment was created to process it //============================================================================== class CoordinatorRecovering : DecidedState { public CoordinatorRecovering (ProtocolState state) : base (state) {} public override void OnEvent(TmReplayEvent e) { if (!state.Recovering) { // Being here outside of recovery is impossible. // This only safe thing to do is crash so that // we don't corrupt any transaction state. DiagnosticUtility.FailFast("Replay events should only be delivered during recovery"); } CoordinatorEnlistment coordinator = e.Coordinator; // We're still recovering, so queue up a replay for later state.EnqueueRecoveryReplay(e); coordinator.SetCallback(e.Callback, e.CallbackState); state.TransactionManagerSend.Replayed(coordinator); e.StateMachine.ChangeState(state.States.CoordinatorAwaitingEndOfRecovery); } } //============================================================================= // CoordinatorAwaitingEndOfRecovery // // Waiting for recovery to finish so we can send our coordinator a replay message //============================================================================== class CoordinatorAwaitingEndOfRecovery : DecidedState { public CoordinatorAwaitingEndOfRecovery (ProtocolState state) : base (state) {} // Tolerate duplicate messages public override void OnEvent(MsgDurablePrepareEvent e) { return; } public override void OnEvent(MsgDurableCommitEvent e) { state.TransactionManagerSend.Commit (e.Coordinator); e.StateMachine.ChangeState(state.States.CoordinatorCommitting); } public override void OnEvent(MsgDurableRollbackEvent e) { state.TransactionManagerSend.Rollback(e.Coordinator); e.StateMachine.ChangeState(state.States.CoordinatorAborted); } // This is a repost sent after the end of recovery, after our listeners were opened public override void OnEvent(TmReplayEvent e) { if (state.Recovering) { // Being here inside of recovery is impossible. // This only safe thing to do is crash so that // we don't corrupt any transaction state. DiagnosticUtility.FailFast("Replay events should only be re-delivered after recovery"); } e.StateMachine.ChangeState(state.States.CoordinatorRecovered); } public override void OnEvent(TmCoordinatorForgetEvent e) { CoordinatorEnlistment coordinator = e.Coordinator; coordinator.SetCallback(e.Callback, e.CallbackState); state.TransactionManagerSend.ForgetResponse(coordinator, Status.Success); e.StateMachine.ChangeState(state.States.CoordinatorForgotten); } } //============================================================================== // CoordinatorFailedRecovery // // We failed to create a proxy during recovery, so we sit idle and wait // On restart, perhaps we will have better luck with policy negotiation //============================================================================= class CoordinatorFailedRecovery : DecidedState { public CoordinatorFailedRecovery (ProtocolState state) : base (state) {} public override void OnEvent(TmReplayEvent e) { // Ack the coordinator CoordinatorEnlistment coordinator = e.Coordinator; coordinator.SetCallback(e.Callback, e.CallbackState); state.TransactionManagerSend.Replayed(coordinator); } public override void OnEvent(TmCoordinatorForgetEvent e) { CoordinatorEnlistment coordinator = e.Coordinator; coordinator.SetCallback(e.Callback, e.CallbackState); state.TransactionManagerSend.ForgetResponse(coordinator, Status.Success); e.StateMachine.ChangeState(state.States.CoordinatorForgotten); } } //============================================================================== // CoordinatorRecovered // // We are ready to send Replay to our coordinator //============================================================================= class CoordinatorRecovered : DecidedState { public CoordinatorRecovered (ProtocolState state) : base (state) {} public override void Enter (StateMachine stateMachine) { base.Enter (stateMachine); CoordinatorEnlistment coordinator = (CoordinatorEnlistment) stateMachine.Enlistment; // Ensure our proxy to our coordinator has a 'from' coordinator.CreateParticipantService(); // Send our coordinator a replay state.TwoPhaseCommitParticipant.SendRecoverMessage(coordinator); // Start a replay timer stateMachine.StartTimer (TimerProfile.Replaying); } public override void Leave (StateMachine stateMachine) { base.Leave (stateMachine); // Cancel the replay timer stateMachine.CancelTimer(); } public override void OnEvent(MsgDurableCommitEvent e) { CoordinatorEnlistment coordinator = e.Coordinator; state.TransactionManagerSend.Commit (coordinator); e.StateMachine.ChangeState(state.States.CoordinatorCommitting); } public override void OnEvent(MsgDurableRollbackEvent e) { state.TransactionManagerSend.Rollback(e.Coordinator); e.StateMachine.ChangeState(state.States.CoordinatorAborted); } public override void OnEvent(TmCoordinatorForgetEvent e) { CoordinatorEnlistment coordinator = e.Coordinator; coordinator.SetCallback(e.Callback, e.CallbackState); state.TransactionManagerSend.ForgetResponse(coordinator, Status.Success); e.StateMachine.ChangeState(state.States.CoordinatorForgotten); } // We just keep sending replay messages until we receive a response public override void OnEvent(TimerCoordinatorEvent e) { CoordinatorEnlistment coordinator = e.Coordinator; if (ReplayMessageRetryRecord.ShouldTrace) { coordinator.Retries ++; ReplayMessageRetryRecord.Trace( coordinator.EnlistmentId, coordinator.Enlistment.RemoteTransactionId, coordinator.Retries ); } state.Perf.ReplayRetryCountPerInterval.Increment(); state.TwoPhaseCommitParticipant.SendRecoverMessage (e.Coordinator); } } //============================================================================= // CoordinatorCommitted // // We think we're done, and the transaction committed //============================================================================= class CoordinatorCommitted : TerminalState { public CoordinatorCommitted (ProtocolState state) : base (state) {} public override void Enter (StateMachine stateMachine) { base.Enter (stateMachine); if (CoordinatorStateMachineFinishedRecord.ShouldTrace) { CoordinatorStateMachineFinishedRecord.Trace( stateMachine.Enlistment.EnlistmentId, stateMachine.Enlistment.Enlistment.RemoteTransactionId, TransactionOutcome.Committed ); } } // Tolerate duplicate messages public override void OnEvent(MsgVolatilePrepareEvent e) { return; } // Tolerate duplicate messages public override void OnEvent(MsgDurablePrepareEvent e) { return; } public override void OnEvent(MsgDurableRollbackEvent e) { // We implement this event because the spec's state tables dictate a non-standard response: // we fault with InconsistentInternalState instead of InvalidState TraceInvalidEvent (e, false); state.TwoPhaseCommitParticipant.SendFault(e.ReplyTo, e.MessageId, this.state.Faults.InconsistentInternalState); } public override void OnEvent(MsgDurableCommitEvent e) { state.TwoPhaseCommitParticipant.SendCommitted(e.ReplyTo); } public override void OnEvent(TimerCoordinatorEvent e) { return; } } //============================================================================== // CoordinatorAborted // // We think we're done, and the transaction aborted //============================================================================= class CoordinatorAborted : TerminalState { public CoordinatorAborted(ProtocolState state) : base (state) {} public override void Enter (StateMachine stateMachine) { if (CoordinatorStateMachineFinishedRecord.ShouldTrace) { CoordinatorStateMachineFinishedRecord.Trace ( stateMachine.Enlistment.EnlistmentId, stateMachine.Enlistment.Enlistment.RemoteTransactionId, TransactionOutcome.Aborted ); } // Send out some aborted notifications CoordinatorEnlistment coordinator = (CoordinatorEnlistment)stateMachine.Enlistment; TrySendAborted(coordinator); if (coordinator.RegisterVolatileCoordinator != null) TrySendAborted(coordinator.RegisterVolatileCoordinator); if (coordinator.PreparingVolatileCoordinator != null) TrySendAborted(coordinator.PreparingVolatileCoordinator); // This may close proxies, so we do it last base.Enter(stateMachine); } public override void OnEvent(MsgRegisterDurableResponseEvent e) { return; } public override void OnEvent(MsgRegisterVolatileResponseEvent e) { return; } public override void OnEvent(TmEnlistPrePrepareEvent e) { CoordinatorEnlistment coordinator = e.Coordinator; coordinator.SetCallback(e.Callback, e.CallbackState); state.TransactionManagerSend.EnlistPrePrepareResponse (coordinator, Status.Aborted); } public override void OnEvent(MsgVolatilePrepareEvent e) { state.TwoPhaseCommitParticipant.SendAborted(e.ReplyTo); } public override void OnEvent(MsgDurablePrepareEvent e) { state.TwoPhaseCommitParticipant.SendAborted(e.ReplyTo); } public override void OnEvent(MsgDurableCommitEvent e) { // We implement this event because the spec's state tables dictate a non-standard response: // we fault with InconsistentInternalState instead of InvalidState TraceInvalidEvent (e, false); state.TwoPhaseCommitParticipant.SendFault(e.FaultTo, e.MessageId, this.state.Faults.InconsistentInternalState); } public override void OnEvent(MsgVolatileRollbackEvent e) { state.TwoPhaseCommitParticipant.SendAborted(e.ReplyTo); } public override void OnEvent(MsgDurableRollbackEvent e) { state.TwoPhaseCommitParticipant.SendAborted(e.ReplyTo); } public override void OnEvent(TmPrePrepareResponseEvent e) { return; } public override void OnEvent(TmPrepareResponseEvent e) { return; } public override void OnEvent(TmRollbackResponseEvent e) { return; } public override void OnEvent(TmAsyncRollbackEvent e) { CoordinatorEnlistment coordinator = (CoordinatorEnlistment) e.Enlistment; coordinator.SetCallback(e.Callback, e.CallbackState); state.TransactionManagerSend.Aborted(coordinator); } public override void OnEvent(TmReplayEvent e) { return; } public override void OnEvent(TmCoordinatorForgetEvent e) { // Just ack the TM CoordinatorEnlistment coordinator = e.Coordinator; coordinator.SetCallback(e.Callback, e.CallbackState); state.TransactionManagerSend.ForgetResponse(coordinator, Status.Success); } public override void OnEvent(TimerCoordinatorEvent e) { return; } } //============================================================================== // CoordinatorForgotten // // We were asked to forget the transaction // This happens as a result of an administrative action //============================================================================== class CoordinatorForgotten : TerminalState { public CoordinatorForgotten(ProtocolState state) : base(state) { } public override void Enter(StateMachine stateMachine) { base.Enter (stateMachine); if (CoordinatorStateMachineFinishedRecord.ShouldTrace) { CoordinatorStateMachineFinishedRecord.Trace( stateMachine.Enlistment.EnlistmentId, stateMachine.Enlistment.Enlistment.RemoteTransactionId, TransactionOutcome.InDoubt ); } } public override void OnEvent(MsgVolatilePrepareEvent e) { return; } public override void OnEvent(MsgVolatileRollbackEvent e) { return; } public override void OnEvent(MsgDurablePrepareEvent e) { return; } public override void OnEvent(MsgDurableCommitEvent e) { return; } public override void OnEvent(MsgDurableRollbackEvent e) { return; } public override void OnEvent(TimerCoordinatorEvent e) { return; } } //============================================================================= // CoordinatorReadOnlyInDoubt // // We think we're done because we sent a durable readonly //============================================================================== class CoordinatorReadOnlyInDoubt : TerminalState { public CoordinatorReadOnlyInDoubt (ProtocolState state) : base (state) {} public override void Enter (StateMachine stateMachine) { base.Enter (stateMachine); if (CoordinatorStateMachineFinishedRecord.ShouldTrace) { CoordinatorStateMachineFinishedRecord.Trace( stateMachine.Enlistment.EnlistmentId, stateMachine.Enlistment.Enlistment.RemoteTransactionId, TransactionOutcome.InDoubt ); } } public override void OnEvent(MsgVolatilePrepareEvent e) { return; } public override void OnEvent(MsgDurablePrepareEvent e) { state.TwoPhaseCommitParticipant.SendReadOnly(e.ReplyTo); } public override void OnEvent(MsgDurableRollbackEvent e) { state.TwoPhaseCommitParticipant.SendAborted(e.ReplyTo); } } //============================================================================= // CoordinatorInitializationFailed // // We think we're done because we couldn't create a superior enlistment //============================================================================= class CoordinatorInitializationFailed : TerminalState { public CoordinatorInitializationFailed(ProtocolState state) : base(state) { } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- CodeAttributeArgument.cs
- FilteredXmlReader.cs
- DebugViewWriter.cs
- XmlSchemaComplexContent.cs
- ValueChangedEventManager.cs
- TextShapeableCharacters.cs
- LateBoundBitmapDecoder.cs
- WebControlAdapter.cs
- ThousandthOfEmRealPoints.cs
- FunctionImportElement.cs
- RootAction.cs
- UnionExpr.cs
- ArraySegment.cs
- QilTargetType.cs
- DataControlFieldCell.cs
- SessionPageStatePersister.cs
- SessionKeyExpiredException.cs
- coordinatorscratchpad.cs
- MethodCallTranslator.cs
- QueueProcessor.cs
- WinInetCache.cs
- DataGridViewCellCollection.cs
- Decoder.cs
- TraceUtils.cs
- InkCollectionBehavior.cs
- FlowDocumentPageViewerAutomationPeer.cs
- InvalidCastException.cs
- PopupEventArgs.cs
- PipeSecurity.cs
- SmiEventSink.cs
- SplitterEvent.cs
- embossbitmapeffect.cs
- XmlUtil.cs
- Vector3D.cs
- DataGridViewSelectedRowCollection.cs
- HttpCachePolicyWrapper.cs
- ChildDocumentBlock.cs
- TdsParserSafeHandles.cs
- FormsAuthenticationUserCollection.cs
- RootAction.cs
- UnitySerializationHolder.cs
- KeyboardNavigation.cs
- Matrix3D.cs
- RepeaterItem.cs
- LocalizableResourceBuilder.cs
- DCSafeHandle.cs
- _Events.cs
- RSAPKCS1SignatureFormatter.cs
- DataGridHeaderBorder.cs
- DesignParameter.cs
- EntityContainer.cs
- RunInstallerAttribute.cs
- ExecutionContext.cs
- GlobalEventManager.cs
- DateTimeSerializationSection.cs
- InstanceDescriptor.cs
- SqlLiftIndependentRowExpressions.cs
- MediaElementAutomationPeer.cs
- MultiDataTrigger.cs
- SoapDocumentMethodAttribute.cs
- _AutoWebProxyScriptEngine.cs
- HostedElements.cs
- DesignerCategoryAttribute.cs
- BaseInfoTable.cs
- ObjectHelper.cs
- DesignerActionKeyboardBehavior.cs
- ConfigViewGenerator.cs
- DrawingGroup.cs
- BitmapSourceSafeMILHandle.cs
- StoryFragments.cs
- Type.cs
- AsymmetricSignatureFormatter.cs
- AuthorizationPolicyTypeElementCollection.cs
- SystemIPv4InterfaceProperties.cs
- XPathSelectionIterator.cs
- MsmqProcessProtocolHandler.cs
- RuntimeHandles.cs
- NativeMsmqMessage.cs
- HeaderLabel.cs
- TextServicesHost.cs
- ReturnEventArgs.cs
- RemotingServices.cs
- LocalizedNameDescriptionPair.cs
- DiscoveryClientDocuments.cs
- FunctionImportElement.cs
- KnownBoxes.cs
- SystemIPInterfaceProperties.cs
- LeafCellTreeNode.cs
- SqlNodeTypeOperators.cs
- autovalidator.cs
- PackageDocument.cs
- ExceptionRoutedEventArgs.cs
- ConfigXmlCDataSection.cs
- diagnosticsswitches.cs
- TextMessageEncodingElement.cs
- NominalTypeEliminator.cs
- BindingsCollection.cs
- ProgressBarRenderer.cs
- EventArgs.cs
- ValueType.cs