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
- Statements.cs
- CustomAttributeBuilder.cs
- WebSysDisplayNameAttribute.cs
- DataControlButton.cs
- FormViewModeEventArgs.cs
- _FtpControlStream.cs
- BuildProvider.cs
- StoreContentChangedEventArgs.cs
- AffineTransform3D.cs
- DependencyPropertyDescriptor.cs
- NameNode.cs
- Int64Animation.cs
- LogPolicy.cs
- ArgIterator.cs
- XmlWriterSettings.cs
- AnnouncementEndpoint.cs
- ExtentKey.cs
- FileVersion.cs
- KeyValuePair.cs
- FormViewCommandEventArgs.cs
- TriState.cs
- GreaterThanOrEqual.cs
- basemetadatamappingvisitor.cs
- XslTransformFileEditor.cs
- Parsers.cs
- PolicyDesigner.cs
- LiteralLink.cs
- DoubleMinMaxAggregationOperator.cs
- _KerberosClient.cs
- PrintDialog.cs
- Vector3DCollectionValueSerializer.cs
- FontCacheUtil.cs
- RegistrySecurity.cs
- UserControlParser.cs
- ConfigsHelper.cs
- QilVisitor.cs
- FormViewDeletedEventArgs.cs
- SafePEFileHandle.cs
- PieceNameHelper.cs
- WebPartEditorCancelVerb.cs
- StateDesigner.LayoutSelectionGlyph.cs
- ItemMap.cs
- CompareInfo.cs
- DbConnectionPoolOptions.cs
- SafeNativeMethods.cs
- SqlConnectionManager.cs
- MissingFieldException.cs
- WeakReference.cs
- RectValueSerializer.cs
- ContextDataSourceView.cs
- RangeBase.cs
- SafeFileMappingHandle.cs
- CustomLineCap.cs
- Propagator.Evaluator.cs
- Visitors.cs
- ChannelHandler.cs
- BmpBitmapDecoder.cs
- BookmarkScopeManager.cs
- ClosureBinding.cs
- ColorConverter.cs
- WindowsListViewGroup.cs
- DiscardableAttribute.cs
- VariantWrapper.cs
- TextServicesContext.cs
- ProfessionalColors.cs
- EditorZoneDesigner.cs
- _BasicClient.cs
- ExchangeUtilities.cs
- DistributedTransactionPermission.cs
- Condition.cs
- EntityConnectionStringBuilder.cs
- MailBnfHelper.cs
- isolationinterop.cs
- ProfileSection.cs
- GeneratedCodeAttribute.cs
- _SafeNetHandles.cs
- ListViewDataItem.cs
- FixedBufferAttribute.cs
- HttpInputStream.cs
- CompModSwitches.cs
- LocalizabilityAttribute.cs
- AppSettingsReader.cs
- DataGridViewColumnStateChangedEventArgs.cs
- RawStylusActions.cs
- Emitter.cs
- XmlMapping.cs
- PaperSize.cs
- EnumBuilder.cs
- Package.cs
- TrackBarDesigner.cs
- SystemEvents.cs
- ToolStripContentPanelRenderEventArgs.cs
- WindowManager.cs
- LayoutEvent.cs
- AbstractDataSvcMapFileLoader.cs
- WebBrowserNavigatingEventHandler.cs
- TemplatingOptionsDialog.cs
- DataKey.cs
- FormatConvertedBitmap.cs
- ProcessInputEventArgs.cs