internal override void EnterState(InternalTransaction tx)
{
Debug.Assert((tx._promoterType == Guid.Empty) || (tx._promoterType == TransactionInterop.PromoterTypeDtc), "Promoted to MSTC but PromoterType is not TransactionInterop.PromoterTypeDtc");
// The promoterType may not yet be set. This state assumes we are promoting to MSDTC.
tx.SetPromoterTypeToMSDTC();
if (tx._outcomeSource._isoLevel == IsolationLevel.Snapshot)
{
throw TransactionException.CreateInvalidOperationException(TraceSourceType.TraceSourceLtm,
SR.CannotPromoteSnapshot, null);
}
// Set the transaction state
CommonEnterState(tx);
// Create a transaction with the distributed transaction manager
DistributedCommittableTransaction distributedTx = null;
try
{
TimeSpan newTimeout;
if (tx.AbsoluteTimeout == long.MaxValue)
{
// The transaction has no timeout
newTimeout = TimeSpan.Zero;
}
else
{
newTimeout = TransactionManager.TransactionTable.RecalcTimeout(tx);
if (newTimeout <= TimeSpan.Zero)
{
return;
}
}
// Just create a new transaction.
TransactionOptions options = new TransactionOptions();
options.IsolationLevel = tx._outcomeSource._isoLevel;
options.Timeout = newTimeout;
// Create a new distributed transaction.
distributedTx =
TransactionManager.DistributedTransactionManager.CreateTransaction(options);
distributedTx.SavedLtmPromotedTransaction = tx._outcomeSource;
TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;
if (etwLog.IsEnabled())
{
etwLog.TransactionPromoted(tx.TransactionTraceId, distributedTx.TransactionTraceId);
}
}
catch (TransactionException te)
{
// There was an exception trying to create the distributed transaction.
// Save the exception and let the transaction get aborted by the finally block.
tx._innerException = te;
TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;
if (etwLog.IsEnabled())
{
etwLog.ExceptionConsumed(te);
}
return;
}
finally
{
if (distributedTx == null)
{
// There was an exception trying to create the distributed transaction abort
// the local transaction and exit.
tx.State.ChangeStateAbortedDuringPromotion(tx);
}
}
// 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, distributedTx.Identifier);
WeakReference weakRef = new WeakReference(tx._outcomeSource, false);
promotedTransactionTable[distributedTx.Identifier] = weakRef;
}
TransactionManager.FireDistributedTransactionStarted(tx._outcomeSource);
// Once we have a promoted transaction promote the enlistments.
PromoteEnlistmentsAndOutcome(tx);
}