void IPromotedEnlistment.EnlistmentDone() { if (DiagnosticTrace.Verbose) { MethodEnteredTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), "OletxEnlistment.EnlistmentDone"); EnlistmentCallbackPositiveTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), base.InternalTraceIdentifier, EnlistmentCallback.Done); } OletxVolatileEnlistmentState active = OletxVolatileEnlistmentState.Active; OletxVolatileEnlistmentContainer container = null; lock (this) { active = this.state; container = this.container; if ((((this.state != OletxVolatileEnlistmentState.Active) && (OletxVolatileEnlistmentState.Preparing != this.state)) && ((OletxVolatileEnlistmentState.Aborting != this.state) && (OletxVolatileEnlistmentState.Committing != this.state))) && (OletxVolatileEnlistmentState.InDoubt != this.state)) { throw TransactionException.CreateEnlistmentStateException(System.Transactions.SR.GetString("TraceSourceOletx"), null); } this.state = OletxVolatileEnlistmentState.Done; } if ((OletxVolatileEnlistmentState.Preparing == active) && (container != null)) { container.DecrementOutstandingNotifications(true); } if (DiagnosticTrace.Verbose) { MethodExitedTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), "OletxEnlistment.EnlistmentDone"); } }
internal void Prepare(OletxVolatileEnlistmentContainer container) { OletxVolatileEnlistmentState active = OletxVolatileEnlistmentState.Active; IEnlistmentNotificationInternal iEnlistmentNotification = null; lock (this) { iEnlistmentNotification = this.iEnlistmentNotification; if (this.state == OletxVolatileEnlistmentState.Active) { active = this.state = OletxVolatileEnlistmentState.Preparing; } else { active = this.state; } this.container = container; } if (OletxVolatileEnlistmentState.Preparing == active) { if (iEnlistmentNotification != null) { if (DiagnosticTrace.Verbose) { EnlistmentNotificationCallTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), base.InternalTraceIdentifier, NotificationCall.Prepare); } iEnlistmentNotification.Prepare(this); return; } if (DiagnosticTrace.Critical) { InternalErrorTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), ""); } throw new InvalidOperationException(System.Transactions.SR.GetString("InternalError")); } if (OletxVolatileEnlistmentState.Done == active) { container.DecrementOutstandingNotifications(true); } else if ((OletxVolatileEnlistmentState.Prepared == active) && this.enlistDuringPrepareRequired) { container.DecrementOutstandingNotifications(true); } else if ((OletxVolatileEnlistmentState.Aborting == active) || (OletxVolatileEnlistmentState.Aborted == active)) { container.DecrementOutstandingNotifications(false); } else { if (DiagnosticTrace.Critical) { InternalErrorTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), ""); } throw new InvalidOperationException(System.Transactions.SR.GetString("InternalError")); } }
void IPromotedEnlistment.Prepared() { if (DiagnosticTrace.Verbose) { MethodEnteredTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), "OletxPreparingEnlistment.Prepared"); EnlistmentCallbackPositiveTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), base.InternalTraceIdentifier, EnlistmentCallback.Prepared); } OletxVolatileEnlistmentContainer container = null; TransactionStatus active = TransactionStatus.Active; lock (this) { if (OletxVolatileEnlistmentState.Preparing != this.state) { throw TransactionException.CreateEnlistmentStateException(System.Transactions.SR.GetString("TraceSourceOletx"), null); } this.state = OletxVolatileEnlistmentState.Prepared; active = this.pendingOutcome; if (this.container == null) { if (DiagnosticTrace.Critical) { InternalErrorTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), ""); } throw new InvalidOperationException(System.Transactions.SR.GetString("InternalError")); } container = this.container; } container.DecrementOutstandingNotifications(true); switch (active) { case TransactionStatus.Active: break; case TransactionStatus.Aborted: this.Rollback(); break; case TransactionStatus.InDoubt: this.InDoubt(); break; default: if (DiagnosticTrace.Critical) { InternalErrorTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), ""); } throw new InvalidOperationException(System.Transactions.SR.GetString("InternalError")); } if (DiagnosticTrace.Verbose) { MethodExitedTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), "OletxPreparingEnlistment.Prepared"); } }
internal void InDoubt() { OletxVolatileEnlistmentState active = OletxVolatileEnlistmentState.Active; IEnlistmentNotificationInternal iEnlistmentNotification = null; lock (this) { if (OletxVolatileEnlistmentState.Prepared == this.state) { active = this.state = OletxVolatileEnlistmentState.InDoubt; iEnlistmentNotification = this.iEnlistmentNotification; } else { if (OletxVolatileEnlistmentState.Preparing == this.state) { this.pendingOutcome = TransactionStatus.InDoubt; } active = this.state; } } if (OletxVolatileEnlistmentState.InDoubt == active) { if (iEnlistmentNotification != null) { if (DiagnosticTrace.Verbose) { EnlistmentNotificationCallTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), base.InternalTraceIdentifier, NotificationCall.InDoubt); } iEnlistmentNotification.InDoubt(this); return; } if (DiagnosticTrace.Critical) { InternalErrorTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), ""); } throw new InvalidOperationException(System.Transactions.SR.GetString("InternalError")); } if ((OletxVolatileEnlistmentState.Preparing != active) && (OletxVolatileEnlistmentState.Done != active)) { if (DiagnosticTrace.Critical) { InternalErrorTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), ""); } throw new InvalidOperationException(System.Transactions.SR.GetString("InternalError")); } }
void IPromotedEnlistment.ForceRollback(Exception e) { if (DiagnosticTrace.Verbose) { MethodEnteredTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), "OletxPreparingEnlistment.ForceRollback"); } if (DiagnosticTrace.Warning) { EnlistmentCallbackNegativeTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), base.InternalTraceIdentifier, EnlistmentCallback.ForceRollback); } OletxVolatileEnlistmentContainer container = null; lock (this) { if (OletxVolatileEnlistmentState.Preparing != this.state) { throw TransactionException.CreateEnlistmentStateException(System.Transactions.SR.GetString("TraceSourceOletx"), null); } this.state = OletxVolatileEnlistmentState.Done; if (this.container == null) { if (DiagnosticTrace.Critical) { InternalErrorTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), ""); } throw new InvalidOperationException(System.Transactions.SR.GetString("InternalError")); } container = this.container; } Interlocked.CompareExchange <Exception>(ref base.oletxTransaction.realOletxTransaction.innerException, e, null); container.DecrementOutstandingNotifications(false); if (DiagnosticTrace.Verbose) { MethodExitedTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), "OletxPreparingEnlistment.ForceRollback"); } }
void IPromotedEnlistment.ForceRollback(Exception e) { if (DiagnosticTrace.Verbose) { MethodEnteredTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), "OletxPreparingEnlistment.ForceRollback"); } if (DiagnosticTrace.Warning) { EnlistmentCallbackNegativeTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), base.InternalTraceIdentifier, EnlistmentCallback.ForceRollback); } OletxVolatileEnlistmentContainer container = null; lock (this) { if (OletxVolatileEnlistmentState.Preparing != this.state) { throw TransactionException.CreateEnlistmentStateException(System.Transactions.SR.GetString("TraceSourceOletx"), null); } this.state = OletxVolatileEnlistmentState.Done; if (this.container == null) { if (DiagnosticTrace.Critical) { InternalErrorTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), ""); } throw new InvalidOperationException(System.Transactions.SR.GetString("InternalError")); } container = this.container; } Interlocked.CompareExchange<Exception>(ref base.oletxTransaction.realOletxTransaction.innerException, e, null); container.DecrementOutstandingNotifications(false); if (DiagnosticTrace.Verbose) { MethodExitedTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), "OletxPreparingEnlistment.ForceRollback"); } }
void IPromotedEnlistment.ForceRollback(Exception e) { if ( DiagnosticTrace.Verbose ) { MethodEnteredTraceRecord.Trace( SR.GetString( SR.TraceSourceOletx ), "OletxPreparingEnlistment.ForceRollback" ); } if ( DiagnosticTrace.Warning ) { EnlistmentCallbackNegativeTraceRecord.Trace( SR.GetString( SR.TraceSourceOletx ), this.InternalTraceIdentifier, EnlistmentCallback.ForceRollback ); } OletxVolatileEnlistmentContainer localContainer = null; lock ( this ) { if ( OletxVolatileEnlistmentState.Preparing != state ) { throw TransactionException.CreateEnlistmentStateException( SR.GetString( SR.TraceSourceOletx ), null, this.DistributedTxId ); } // There are no more notifications that need to happen on this enlistment. state = OletxVolatileEnlistmentState.Done; if ( null == container ) { if ( DiagnosticTrace.Critical ) { InternalErrorTraceRecord.Trace( SR.GetString( SR.TraceSourceOletx ), "" ); } Debug.Assert( false, "OletxVolatileEnlistment.ForceRollback, no container member." ); throw new InvalidOperationException( SR.GetString( SR.InternalError ) ); } localContainer = container; } Interlocked.CompareExchange<Exception>( ref this.oletxTransaction.realOletxTransaction.innerException, e, null ); // Vote no. localContainer.DecrementOutstandingNotifications( false ); if ( DiagnosticTrace.Verbose ) { MethodExitedTraceRecord.Trace( SR.GetString( SR.TraceSourceOletx ), "OletxPreparingEnlistment.ForceRollback" ); } }
void IPromotedEnlistment.Prepared() { if ( DiagnosticTrace.Verbose ) { MethodEnteredTraceRecord.Trace( SR.GetString( SR.TraceSourceOletx ), "OletxPreparingEnlistment.Prepared" ); EnlistmentCallbackPositiveTraceRecord.Trace( SR.GetString( SR.TraceSourceOletx ), this.InternalTraceIdentifier, EnlistmentCallback.Prepared ); } OletxVolatileEnlistmentContainer localContainer = null; TransactionStatus localPendingOutcome = TransactionStatus.Active; lock ( this ) { if ( OletxVolatileEnlistmentState.Preparing != state ) { throw TransactionException.CreateEnlistmentStateException( SR.GetString( SR.TraceSourceOletx ), null, this.DistributedTxId ); } state = OletxVolatileEnlistmentState.Prepared; localPendingOutcome = pendingOutcome; if ( null == container ) { if ( DiagnosticTrace.Critical ) { InternalErrorTraceRecord.Trace( SR.GetString( SR.TraceSourceOletx ), "" ); } Debug.Assert( false, "OletxVolatileEnlistment.Prepared, no container member." ); throw new InvalidOperationException( SR.GetString( SR.InternalError ) ); } localContainer = container; } // Vote yes. localContainer.DecrementOutstandingNotifications( true ); switch ( localPendingOutcome ) { case TransactionStatus.Active: { // nothing to do. Everything is proceeding as normal. break; } case TransactionStatus.Aborted: { // The transaction aborted while the Prepare was outstanding. // We need to tell the app to rollback. Rollback(); break; } case TransactionStatus.InDoubt: { // The transaction went InDoubt while the Prepare was outstanding. // We need to tell the app. InDoubt(); break; } default: { // This shouldn't happen. if ( DiagnosticTrace.Critical ) { InternalErrorTraceRecord.Trace( SR.GetString( SR.TraceSourceOletx ), "" ); } Debug.Assert( false, "OletxVolatileEnlistment.Prepared, invalid pending outcome value." ); throw new InvalidOperationException( SR.GetString( SR.InternalError ) ); } } if ( DiagnosticTrace.Verbose ) { MethodExitedTraceRecord.Trace( SR.GetString( SR.TraceSourceOletx ), "OletxPreparingEnlistment.Prepared" ); } }
void IPromotedEnlistment.EnlistmentDone() { if ( DiagnosticTrace.Verbose ) { MethodEnteredTraceRecord.Trace( SR.GetString( SR.TraceSourceOletx ), "OletxEnlistment.EnlistmentDone" ); EnlistmentCallbackPositiveTraceRecord.Trace( SR.GetString( SR.TraceSourceOletx ), this.InternalTraceIdentifier, EnlistmentCallback.Done ); } OletxVolatileEnlistmentState localState = OletxVolatileEnlistmentState.Active; OletxVolatileEnlistmentContainer localContainer = null; lock ( this ) { localState = state; localContainer = container; if ( ( OletxVolatileEnlistmentState.Active != state ) && ( OletxVolatileEnlistmentState.Preparing != state ) && ( OletxVolatileEnlistmentState.Aborting != state ) && ( OletxVolatileEnlistmentState.Committing != state ) && ( OletxVolatileEnlistmentState.InDoubt != state ) ) { throw TransactionException.CreateEnlistmentStateException( SR.GetString( SR.TraceSourceOletx ), null, this.DistributedTxId ); } state = OletxVolatileEnlistmentState.Done; } // For the Preparing state, we need to decrement the outstanding // count with the container. If the state is Active, it is an early vote so we // just stay in the Done state and when we get the Prepare, we will vote appropriately. if ( OletxVolatileEnlistmentState.Preparing == localState ) { if ( null != localContainer ) { // Specify true. If aborting, it is okay because the transaction is already // aborting. localContainer.DecrementOutstandingNotifications( true ); } } if ( DiagnosticTrace.Verbose ) { MethodExitedTraceRecord.Trace( SR.GetString( SR.TraceSourceOletx ), "OletxEnlistment.EnlistmentDone" ); } }
internal void InDoubt() { OletxVolatileEnlistmentState localState = OletxVolatileEnlistmentState.Active; IEnlistmentNotificationInternal localEnlistmentNotification = null; lock ( this ) { // The app may have already called EnlistmentDone. If this occurs, don't bother sending // the notification to the app and we don't need to tell the proxy. if ( OletxVolatileEnlistmentState.Prepared == state ) { localState = state = OletxVolatileEnlistmentState.InDoubt; localEnlistmentNotification = iEnlistmentNotification; } else { if ( OletxVolatileEnlistmentState.Preparing == state ) { pendingOutcome = TransactionStatus.InDoubt; } localState = state; } } // Tell the application to do the work. if ( OletxVolatileEnlistmentState.InDoubt == localState ) { if ( null != localEnlistmentNotification ) { if ( DiagnosticTrace.Verbose ) { EnlistmentNotificationCallTraceRecord.Trace( SR.GetString( SR.TraceSourceOletx ), this.InternalTraceIdentifier, NotificationCall.InDoubt ); } localEnlistmentNotification.InDoubt( this ); } else { if ( DiagnosticTrace.Critical ) { InternalErrorTraceRecord.Trace( SR.GetString( SR.TraceSourceOletx ), "" ); } Debug.Assert( false, "OletxVolatileEnlistment.InDoubt, no enlistmentNotification member." ); throw new InvalidOperationException( SR.GetString( SR.InternalError ) ); } } else if ( OletxVolatileEnlistmentState.Preparing == localState ) { // We have already set pendingOutcome, so there is nothing else to do. } else if ( OletxVolatileEnlistmentState.Done == localState ) { // Early Exit - state was Done } else { if ( DiagnosticTrace.Critical ) { InternalErrorTraceRecord.Trace( SR.GetString( SR.TraceSourceOletx ), "" ); } Debug.Assert( false, "OletxVolatileEnlistment.InDoubt, invalid state." ); throw new InvalidOperationException( SR.GetString( SR.InternalError ) ); } }
internal void Rollback() { OletxVolatileEnlistmentState localState = OletxVolatileEnlistmentState.Active; IEnlistmentNotificationInternal localEnlistmentNotification = null; lock ( this ) { // The app may have already called EnlistmentDone. If this occurs, don't bother sending // the notification to the app and we don't need to tell the proxy. if ( ( OletxVolatileEnlistmentState.Prepared == state ) || ( OletxVolatileEnlistmentState.Active == state ) ) { localState = state = OletxVolatileEnlistmentState.Aborting; localEnlistmentNotification = iEnlistmentNotification; } else { if ( OletxVolatileEnlistmentState.Preparing == state ) { pendingOutcome = TransactionStatus.Aborted; } localState = state; } } // Tell the application to do the work. if ( OletxVolatileEnlistmentState.Aborting == localState ) { if ( null != localEnlistmentNotification ) { if ( DiagnosticTrace.Verbose ) { EnlistmentNotificationCallTraceRecord.Trace( SR.GetString( SR.TraceSourceOletx ), this.InternalTraceIdentifier, NotificationCall.Rollback ); } localEnlistmentNotification.Rollback( this ); } // There is a small ---- where Rollback could be called when the enlistment is already // aborting the transaciton, so just ignore that call. When the app enlistment // finishes responding to its Rollback notification with EnlistmentDone, things will get // cleaned up. } else if ( OletxVolatileEnlistmentState.Preparing == localState ) { // We need to tolerate this state, but we have already marked the // enlistment as pendingRollback, so there is nothing else to do here. } else if ( OletxVolatileEnlistmentState.Done == localState ) { // Early Exit - state was Done } else { if ( DiagnosticTrace.Critical ) { InternalErrorTraceRecord.Trace( SR.GetString( SR.TraceSourceOletx ), "" ); } Debug.Assert( false, "OletxVolatileEnlistment.Rollback, invalid state." ); throw new InvalidOperationException( SR.GetString( SR.InternalError ) ); } }
internal void Prepare( OletxVolatileEnlistmentContainer container ) { OletxVolatileEnlistmentState localState = OletxVolatileEnlistmentState.Active; IEnlistmentNotificationInternal localEnlistmentNotification = null; lock ( this ) { localEnlistmentNotification = iEnlistmentNotification; // The app may have already called EnlistmentDone. If this occurs, don't bother sending // the notification to the app. if ( OletxVolatileEnlistmentState.Active == state ) { localState = state = OletxVolatileEnlistmentState.Preparing; } else { localState = state; } this.container = container; } // Tell the application to do the work. if ( OletxVolatileEnlistmentState.Preparing == localState ) { if ( null != localEnlistmentNotification ) { if ( DiagnosticTrace.Verbose ) { EnlistmentNotificationCallTraceRecord.Trace( SR.GetString( SR.TraceSourceOletx ), this.InternalTraceIdentifier, NotificationCall.Prepare ); } localEnlistmentNotification.Prepare( this ); } else { if ( DiagnosticTrace.Critical ) { InternalErrorTraceRecord.Trace( SR.GetString( SR.TraceSourceOletx ), "" ); } Debug.Assert( false, "OletxVolatileEnlistment.Prepare, no enlistmentNotification member." ); throw new InvalidOperationException( SR.GetString( SR.InternalError ) ); } } else if ( OletxVolatileEnlistmentState.Done == localState ) { // Voting yes because it was an early read-only vote. container.DecrementOutstandingNotifications( true ); // We must have had a ---- between EnlistmentDone and the proxy telling // us Phase0Request. Just return. return; } // It is okay to be in Prepared state if we are edpr=true because we already // did our prepare in Phase0. else if ( ( OletxVolatileEnlistmentState.Prepared == localState ) && ( this.enlistDuringPrepareRequired ) ) { container.DecrementOutstandingNotifications( true ); return; } else if ( ( OletxVolatileEnlistmentState.Aborting == localState ) || ( OletxVolatileEnlistmentState.Aborted == localState ) ) { // An abort has ----d with this volatile Prepare // decrement the outstanding notifications making sure to vote no. container.DecrementOutstandingNotifications( false ); return; } else { if ( DiagnosticTrace.Critical ) { InternalErrorTraceRecord.Trace( SR.GetString( SR.TraceSourceOletx ), "" ); } Debug.Assert( false, "OletxVolatileEnlistment.Prepare, invalid state." ); throw new InvalidOperationException( SR.GetString( SR.InternalError ) ); } }