System.Transactions.TransactionStatePSPEOperation.PSPEPromote C# (CSharp) Method

PSPEPromote() private method

private PSPEPromote ( InternalTransaction tx ) : DistributedTransaction
tx InternalTransaction
return DistributedTransaction
        internal DistributedTransaction PSPEPromote(InternalTransaction tx)
        {
            bool changeToReturnState = true;

            TransactionState returnState = tx.State;
            Debug.Assert(returnState == TransactionStateDelegated ||
                returnState == TransactionStateDelegatedSubordinate ||
                returnState == TransactionStateDelegatedNonMSDTC,
                "PSPEPromote called from state other than TransactionStateDelegated[NonMSDTC]");
            CommonEnterState(tx);

            DistributedTransaction distributedTx = null;
            try
            {
                if (tx._attemptingPSPEPromote)
                {
                    // There should not already be a PSPEPromote call outstanding.
                    throw TransactionException.CreateInvalidOperationException(
                            TraceSourceType.TraceSourceLtm,
                            SR.PromotedReturnedInvalidValue,
                            null,
                            tx.DistributedTxId
                            );
                }
                tx._attemptingPSPEPromote = true;

                byte[] propagationToken = tx._promoter.Promote();

                // If the PromoterType is NOT MSDTC, then we can't assume that the returned
                // byte[] is an MSDTC propagation token and we can't create an DistributedTransaction from it.
                if (tx._promoterType != TransactionInterop.PromoterTypeDtc)
                {
                    if (propagationToken == null)
                    {
                        throw TransactionException.CreateInvalidOperationException(
                                TraceSourceType.TraceSourceLtm,
                                SR.PromotedReturnedInvalidValue,
                                null,
                                tx.DistributedTxId
                                );
                    }

                    tx.promotedToken = propagationToken;
                    return null;
                }

                // From this point forward, we know that the PromoterType is TransactionInterop.PromoterTypeDtc so we can
                // treat the propagationToken as an MSDTC propagation token. If one was returned.
                if (propagationToken == null)
                {
                    // If the returned propagationToken is null AND the tx.PromotedTransaction is null, the promote failed.
                    // But if the PSPE promoter used PSPEPromoteAndConvertToEnlistDurable, tx.PromotedTransaction will NOT be null
                    // at this point and we just use tx.PromotedTransaction as distributedTx and we don't bother to change to the
                    // "return state" because the transaction is already in the state it needs to be in.
                    if (tx.PromotedTransaction == null)
                    {
                        // The PSPE has returned an invalid promoted transaction.
                        throw TransactionException.CreateInvalidOperationException(
                                TraceSourceType.TraceSourceLtm,
                                SR.PromotedReturnedInvalidValue,
                                null,
                                tx.DistributedTxId
                                );
                    }
                    // The transaction has already transitioned to TransactionStatePromoted, so we don't want
                    // to change the state to the "returnState" because TransactionStateDelegatedBase.EnterState, would
                    // try to promote the enlistments again.
                    changeToReturnState = false;
                    distributedTx = tx.PromotedTransaction;
                }

                // At this point, if we haven't yet set distributedTx, we need to get it using the returned
                // propagation token. The PSPE promoter must NOT have used PSPEPromoteAndConvertToEnlistDurable.
                if (distributedTx == null)
                {
                    try
                    {
                        distributedTx = TransactionInterop.GetDistributedTransactionFromTransmitterPropagationToken(
                                            propagationToken
                                            );
                    }
                    catch (ArgumentException e)
                    {
                        // The PSPE has returned an invalid promoted transaction.
                        throw TransactionException.CreateInvalidOperationException(
                                TraceSourceType.TraceSourceLtm,
                                SR.PromotedReturnedInvalidValue,
                                e,
                                tx.DistributedTxId
                                );
                    }

                    if (TransactionManager.FindPromotedTransaction(distributedTx.Identifier) != null)
                    {
                        // If there is already a promoted transaction then someone has committed an error.
                        distributedTx.Dispose();
                        throw TransactionException.CreateInvalidOperationException(
                                TraceSourceType.TraceSourceLtm,
                                SR.PromotedTransactionExists,
                                null,
                                tx.DistributedTxId
                                );
                    }
                }
            }
            finally
            {
                tx._attemptingPSPEPromote = false;
                // If we get here and changeToReturnState is false, the PSPE enlistment must have requested that we
                // promote and convert the enlistment to a durable enlistment
                // (Transaction.PSPEPromoteAndConvertToEnlistDurable). In that case, the internal transaction is
                // already in TransactionStatePromoted, so we don't want to put it BACK into TransactionStateDelegatedBase.
                if (changeToReturnState)
                {
                    returnState.CommonEnterState(tx);
                }
            }

            return distributedTx;
        }