internal override Enlistment PromoteAndEnlistDurable(
InternalTransaction tx,
Guid resourceManagerIdentifier,
IPromotableSinglePhaseNotification promotableNotification,
ISinglePhaseNotification enlistmentNotification,
EnlistmentOptions enlistmentOptions,
Transaction atomicTransaction
)
{
// This call is only allowed if we have an outstanding call to ITransactionPromoter.Promote.
if (!tx._attemptingPSPEPromote)
{
throw TransactionException.CreateTransactionStateException(tx._innerException, tx.DistributedTxId);
}
if (promotableNotification != tx._promoter)
{
throw TransactionException.CreateInvalidOperationException(
TraceSourceType.TraceSourceLtm,
SR.InvalidIPromotableSinglePhaseNotificationSpecified,
null,
tx.DistributedTxId
);
}
Enlistment enlistment;
// First promote the transaction. We do this by simply changing the state of the transaction to Promoted.
// In TransactionStateActive.EnlistPromotableSinglePhase, tx.durableEnlistment was set to point at the InternalEnlistment
// for that PSPE enlistment. We are going to replace that with a "true" durable enlistment here. But we need to
// set tx.durableEnlistment to null BEFORE we promote because if we don't the promotion will attempt to promote
// the tx.durableEnlistment. Because we are doing the EnlistDurable AFTER promotion, it will be a "promoted"
// durable enlistment and we can safely set tx.durableEnlistment to the InternalEnlistment of that Enlistment.
tx._durableEnlistment = null;
tx._promoteState = TransactionState.TransactionStatePromoted;
tx._promoteState.EnterState(tx);
// Now we need to create the durable enlistment that will replace the PSPE enlistment. Use the internalEnlistment of
// this newly created durable enlistment as the tx.durableEnlistment.
enlistment = tx.State.EnlistDurable(tx, resourceManagerIdentifier, enlistmentNotification, enlistmentOptions, atomicTransaction);
tx._durableEnlistment = enlistment.InternalEnlistment;
return enlistment;
}