internal override void EnterState(InternalTransaction tx)
{
if (tx._outcomeSource._isoLevel == IsolationLevel.Snapshot)
{
throw TransactionException.CreateInvalidOperationException(TraceSourceType.TraceSourceLtm,
SR.CannotPromoteSnapshot, null, tx == null ? Guid.Empty : tx.DistributedTxId);
}
// Assign the state
CommonEnterState(tx);
// Create a transaction with the distributed transaction manager
DistributedTransaction distributedTx = null;
try
{
// Ask the delegation interface to promote the transaction.
if (tx._durableEnlistment != null)
{
TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;
if (etwLog.IsEnabled())
{
etwLog.EnlistmentStatus(tx._durableEnlistment, NotificationCall.Promote);
}
}
distributedTx = TransactionStatePSPEOperation.PSPEPromote(tx);
}
catch (TransactionPromotionException e)
{
tx._innerException = e;
TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;
if (etwLog.IsEnabled())
{
etwLog.ExceptionConsumed(e);
}
}
finally
{
if (((object)distributedTx) == null)
{
// There was an exception trying to create the distributed transaction abort
// the local transaction and exit.
tx.State.ChangeStateAbortedDuringPromotion(tx);
}
}
if (((object)distributedTx) == null)
{
return;
}
// If tx.PromotedTransaction is already set to the distributedTx that was
// returned, then the PSPE enlistment must have used
// Transaction.PSPEPromoteAndConvertToEnlistDurable to promote the transaction
// within the same AppDomain. So we don't need to add the distributedTx to the
// PromotedTransactionTable and we don't need to call
// FireDistributedTransactionStarted and we don't need to promote the
// enlistments. That was all done when the transaction was changed to
// TransactionStatePromoted.
if (tx.PromotedTransaction != distributedTx)
{
// Associate the distributed transaction with the local transaction.
tx.PromotedTransaction = distributedTx;
// Add a weak reference to the transaction to the promotedTransactionTable.
Hashtable promotedTransactionTable = TransactionManager.PromotedTransactionTable;
lock (promotedTransactionTable)
{
// Since we are adding this reference to the table create an object that will clean that
// entry up.
tx._finalizedObject = new FinalizedObject(tx, tx.PromotedTransaction.Identifier);
WeakReference weakRef = new WeakReference(tx._outcomeSource, false);
promotedTransactionTable[tx.PromotedTransaction.Identifier] = weakRef;
}
TransactionManager.FireDistributedTransactionStarted(tx._outcomeSource);
TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;
if (etwLog.IsEnabled())
{
etwLog.TransactionPromoted(tx.TransactionTraceId, distributedTx.TransactionTraceId);
}
// Once we have a promoted transaction promote the enlistments.
PromoteEnlistmentsAndOutcome(tx);
}
}