public void Aborted(Exception e)
        {
            TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;

            if (etwLog.IsEnabled())
            {
                etwLog.MethodEnter(TraceSourceType.TraceSourceLtm, this);
                etwLog.EnlistmentAborted(_internalEnlistment);
            }

            lock (_internalEnlistment.SyncRoot)
            {
                _internalEnlistment.State.Aborted(_internalEnlistment, e);
            }

            if (etwLog.IsEnabled())
            {
                etwLog.MethodExit(TraceSourceType.TraceSourceLtm, this);
            }
        }
예제 #2
0
        public void ForceRollback()
        {
            TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;

            if (etwLog.IsEnabled())
            {
                etwLog.MethodEnter(TraceSourceType.TraceSourceLtm, this);
                etwLog.EnlistmentForceRollback(_internalEnlistment);
            }

            lock (_internalEnlistment.SyncRoot)
            {
                _internalEnlistment.State.ForceRollback(_internalEnlistment, null);
            }

            if (etwLog.IsEnabled())
            {
                etwLog.MethodExit(TraceSourceType.TraceSourceLtm, this);
            }
        }
예제 #3
0
        /// <summary>
        /// Create a promotable single phase enlistment that promotes to a distributed transaction manager other than MSDTC.
        /// </summary>
        /// <param name="promotableSinglePhaseNotification">The object that implements the IPromotableSinglePhaseNotification interface.</param>
        /// <param name="promoterType">
        /// The promoter type Guid that identifies the format of the byte[] that is returned by the ITransactionPromoter.Promote
        /// call that is implemented by the IPromotableSinglePhaseNotificationObject, and thus the promoter of the transaction.
        /// </param>
        /// <returns>
        /// True if the enlistment is successful.
        ///
        /// False if the transaction already has a durable enlistment or promotable single phase enlistment or
        /// if the transaction has already promoted. In this case, the caller will need to enlist in the transaction through other
        /// means.
        ///
        /// If the Transaction.PromoterType matches the promoter type supported by the caller, then the
        /// Transaction.PromotedToken can be retrieved and used to enlist directly with the identified distributed transaction manager.
        ///
        /// How the enlistment is created with the distributed transaction manager identified by the Transaction.PromoterType
        /// is defined by that distributed transaction manager.
        /// </returns>
        public bool EnlistPromotableSinglePhase(IPromotableSinglePhaseNotification promotableSinglePhaseNotification, Guid promoterType)
        {
            TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;

            if (etwLog.IsEnabled())
            {
                etwLog.MethodEnter(TraceSourceType.TraceSourceLtm, this);
            }

            if (Disposed)
            {
                throw new ObjectDisposedException(nameof(Transaction));
            }

            ArgumentNullException.ThrowIfNull(promotableSinglePhaseNotification);

            if (promoterType == Guid.Empty)
            {
                throw new ArgumentException(SR.PromoterTypeInvalid, nameof(promoterType));
            }

            if (_complete)
            {
                throw TransactionException.CreateTransactionCompletedException(DistributedTxId);
            }

            bool succeeded = false;

            lock (_internalTransaction)
            {
                Debug.Assert(_internalTransaction.State != null);
                succeeded = _internalTransaction.State.EnlistPromotableSinglePhase(_internalTransaction, promotableSinglePhaseNotification, this, promoterType);
            }

            if (etwLog.IsEnabled())
            {
                etwLog.MethodExit(TraceSourceType.TraceSourceLtm, this);
            }

            return(succeeded);
        }
예제 #4
0
        public void SetDistributedTransactionIdentifier(IPromotableSinglePhaseNotification promotableNotification,
                                                        Guid distributedTransactionIdentifier)
        {
            TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;

            if (etwLog.IsEnabled())
            {
                etwLog.MethodEnter(TraceSourceType.TraceSourceLtm, this);
            }

            if (Disposed)
            {
                throw new ObjectDisposedException(nameof(Transaction));
            }

            ArgumentNullException.ThrowIfNull(promotableNotification);

            if (distributedTransactionIdentifier == Guid.Empty)
            {
                throw new ArgumentException(null, nameof(distributedTransactionIdentifier));
            }

            if (_complete)
            {
                throw TransactionException.CreateTransactionCompletedException(DistributedTxId);
            }

            lock (_internalTransaction)
            {
                Debug.Assert(_internalTransaction.State != null);
                _internalTransaction.State.SetDistributedTransactionId(_internalTransaction,
                                                                       promotableNotification,
                                                                       distributedTransactionIdentifier);

                if (etwLog.IsEnabled())
                {
                    etwLog.MethodExit(TraceSourceType.TraceSourceLtm, this);
                }
                return;
            }
        }
예제 #5
0
        // Forward request to the state machine to take the appropriate action.
        //
        public Enlistment EnlistVolatile(ISinglePhaseNotification singlePhaseNotification, EnlistmentOptions enlistmentOptions)
        {
            TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;

            if (etwLog.IsEnabled())
            {
                etwLog.MethodEnter(TraceSourceType.TraceSourceLtm, this);
            }

            if (Disposed)
            {
                throw new ObjectDisposedException(nameof(Transaction));
            }

            if (singlePhaseNotification == null)
            {
                throw new ArgumentNullException(nameof(singlePhaseNotification));
            }

            if (enlistmentOptions != EnlistmentOptions.None && enlistmentOptions != EnlistmentOptions.EnlistDuringPrepareRequired)
            {
                throw new ArgumentOutOfRangeException(nameof(enlistmentOptions));
            }

            if (_complete)
            {
                throw TransactionException.CreateTransactionCompletedException(DistributedTxId);
            }

            lock (_internalTransaction)
            {
                Enlistment enlistment = _internalTransaction.State.EnlistVolatile(_internalTransaction,
                                                                                  singlePhaseNotification, enlistmentOptions, this);

                if (etwLog.IsEnabled())
                {
                    etwLog.MethodExit(TraceSourceType.TraceSourceLtm, this);
                }
                return(enlistment);
            }
        }
예제 #6
0
        internal override void EnterState(InternalEnlistment enlistment)
        {
            // Set the enlistment state
            enlistment.State = this;

            Monitor.Exit(enlistment.Transaction);
            try // Don't hold this lock while calling into the application code.
            {
                TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;
                if (etwLog.IsEnabled())
                {
                    etwLog.EnlistmentStatus(enlistment, NotificationCall.Rollback);
                }

                enlistment.EnlistmentNotification.Rollback(enlistment.SinglePhaseEnlistment);
            }
            finally
            {
                Monitor.Enter(enlistment.Transaction);
            }
        }
        public static IDtcTransaction GetDtcTransaction(Transaction transaction)
        {
            ArgumentNullException.ThrowIfNull(transaction);

            TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;

            if (etwLog.IsEnabled())
            {
                etwLog.MethodEnter(TraceSourceType.TraceSourceOleTx, "TransactionInterop.GetDtcTransaction");
            }

            ConvertToOletxTransaction(transaction);
            IDtcTransaction transactionNative = OletxTransaction.GetDtcTransaction();

            if (etwLog.IsEnabled())
            {
                etwLog.MethodExit(TraceSourceType.TraceSourceOleTx, "TransactionInterop.GetDtcTransaction");
            }

            return(transactionNative);
        }
        public static byte[] GetTransmitterPropagationToken(Transaction transaction)
        {
            ArgumentNullException.ThrowIfNull(transaction);

            TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;

            if (etwLog.IsEnabled())
            {
                etwLog.MethodEnter(TraceSourceType.TraceSourceOleTx, "TransactionInterop.GetTransmitterPropagationToken");
            }

            ConvertToOletxTransaction(transaction);
            byte[] token = OletxTransaction.GetTransmitterPropagationToken();

            if (etwLog.IsEnabled())
            {
                etwLog.MethodExit(TraceSourceType.TraceSourceOleTx, "TransactionInterop.GetTransmitterPropagationToken");
            }

            return(token);
        }
예제 #9
0
    internal static uint AdjustTimeout(TimeSpan timeout)
    {
        uint returnTimeout = 0;

        try
        {
            returnTimeout = Convert.ToUInt32(timeout.TotalMilliseconds, CultureInfo.CurrentCulture);
        }
        catch (OverflowException caughtEx)
        {
            // timeout.TotalMilliseconds might be negative, so let's catch overflow exceptions, just in case.
            TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;
            if (etwLog.IsEnabled())
            {
                etwLog.ExceptionConsumed(TraceSourceType.TraceSourceOleTx, caughtEx);
            }

            returnTimeout = uint.MaxValue;
        }
        return(returnTimeout);
    }
        public void Complete()
        {
            TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;

            if (etwLog.IsEnabled())
            {
                etwLog.MethodEnter(TraceSourceType.TraceSourceLtm, this);
            }

            lock (_internalTransaction)
            {
                if (Disposed)
                {
                    throw new ObjectDisposedException(nameof(DependentTransaction));
                }

                if (_complete)
                {
                    throw TransactionException.CreateTransactionCompletedException(DistributedTxId);
                }

                _complete = true;

                Debug.Assert(_internalTransaction.State != null);
                if (_blocking)
                {
                    _internalTransaction.State.CompleteBlockingClone(_internalTransaction);
                }
                else
                {
                    _internalTransaction.State.CompleteAbortingClone(_internalTransaction);
                }
            }

            if (etwLog.IsEnabled())
            {
                etwLog.TransactionDependentCloneComplete(this, "DependentTransaction");
                etwLog.MethodExit(TraceSourceType.TraceSourceLtm, this);
            }
        }
예제 #11
0
        // Forward the commit to the state machine to take the appropriate action.
        //
        public void Commit()
        {
            TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;

            if (etwLog.IsEnabled())
            {
                etwLog.MethodEnter(TraceSourceType.TraceSourceLtm, this);
                etwLog.TransactionCommit(this, "CommittableTransaction");
            }

            ObjectDisposedException.ThrowIf(Disposed, this);

            lock (_internalTransaction)
            {
                if (_complete)
                {
                    throw TransactionException.CreateTransactionCompletedException(DistributedTxId);
                }

                Debug.Assert(_internalTransaction.State != null);
                _internalTransaction.State.BeginCommit(_internalTransaction, false, null, null);

                // now that commit has started wait for the monitor on the transaction to know
                // if the transaction is done.
                do
                {
                    if (_internalTransaction.State.IsCompleted(_internalTransaction))
                    {
                        break;
                    }
                } while (Monitor.Wait(_internalTransaction));

                _internalTransaction.State.EndCommit(_internalTransaction);
            }

            if (etwLog.IsEnabled())
            {
                etwLog.MethodExit(TraceSourceType.TraceSourceLtm, this);
            }
        }
예제 #12
0
        internal override void EnterState(InternalEnlistment enlistment)
        {
            // Set the enlistment state
            enlistment.State = this;

            Monitor.Exit(enlistment.Transaction);
            try // Don't hold this lock while calling into the application code.
            {
                TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;
                if (etwLog.IsEnabled())
                {
                    etwLog.EnlistmentStatus(enlistment, NotificationCall.InDoubt);
                }

                // Forward the notification to the enlistment
                enlistment.EnlistmentNotification.InDoubt(enlistment.PreparingEnlistment);
            }
            finally
            {
                Monitor.Enter(enlistment.Transaction);
            }
        }
예제 #13
0
        internal override void EnterState(InternalEnlistment enlistment)
        {
            // Set the enlistment state
            enlistment.State = this;

            Monitor.Exit(enlistment.Transaction);
            try // Don't hold this lock while calling into the application code.
            {
                TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;
                if (etwLog.IsEnabled())
                {
                    etwLog.EnlistmentStatus(TraceSourceType.TraceSourceLtm, enlistment.EnlistmentTraceId, NotificationCall.Prepare);
                }

                Debug.Assert(enlistment.EnlistmentNotification != null);
                enlistment.EnlistmentNotification.Prepare(enlistment.PreparingEnlistment);
            }
            finally
            {
                Monitor.Enter(enlistment.Transaction);
            }
        }
    internal void BeginCommit(InternalTransaction internalTransaction)
    {
        TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;

        if (etwLog.IsEnabled())
        {
            etwLog.MethodEnter(TraceSourceType.TraceSourceOleTx, this);
            etwLog.TransactionCommit(TraceSourceType.TraceSourceOleTx, TransactionTraceId, "CommittableTransaction");
        }

        Debug.Assert(0 == Disposed, "OletxTransction object is disposed");
        RealOletxTransaction.InternalTransaction = internalTransaction;

        _commitCalled = true;

        RealOletxTransaction.Commit();

        if (etwLog.IsEnabled())
        {
            etwLog.MethodExit(TraceSourceType.TraceSourceOleTx, this, $"{nameof(OletxCommittableTransaction)}.{nameof(BeginCommit)}");
        }
    }
        public static Transaction GetTransactionFromDtcTransaction(IDtcTransaction transactionNative)
        {
            if (null == transactionNative)
            {
                throw new ArgumentNullException(nameof(transactionNative));
            }

            TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;

            if (etwLog.IsEnabled())
            {
                etwLog.MethodEnter(TraceSourceType.TraceSourceDistributed, "TransactionInterop.GetTransactionFromDtcTransaction");
            }

            Transaction transaction = DistributedTransactionManager.GetTransactionFromDtcTransaction(transactionNative);

            if (etwLog.IsEnabled())
            {
                etwLog.MethodExit(TraceSourceType.TraceSourceDistributed, "TransactionInterop.GetTransactionFromDtcTransaction");
            }
            return(transaction);
        }
예제 #16
0
        public static void RecoveryComplete(Guid resourceManagerIdentifier)
        {
            if (resourceManagerIdentifier == Guid.Empty)
            {
                throw new ArgumentException(SR.BadResourceManagerId, nameof(resourceManagerIdentifier));
            }

            TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;

            if (etwLog.IsEnabled())
            {
                etwLog.MethodEnter(TraceSourceType.TraceSourceBase, "TransactionManager.RecoveryComplete");
                etwLog.TransactionManagerRecoveryComplete(resourceManagerIdentifier);
            }

            DistributedTransactionManager.ResourceManagerRecoveryComplete(resourceManagerIdentifier);

            if (etwLog.IsEnabled())
            {
                etwLog.MethodExit(TraceSourceType.TraceSourceBase, "TransactionManager.RecoveryComplete");
            }
        }
예제 #17
0
        public void Rollback(Exception?e)
        {
            TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;

            if (etwLog.IsEnabled())
            {
                etwLog.MethodEnter(TraceSourceType.TraceSourceLtm, this);
                etwLog.TransactionRollback(this, "Transaction");
            }

            ObjectDisposedException.ThrowIf(Disposed, this);

            lock (_internalTransaction)
            {
                Debug.Assert(_internalTransaction.State != null);
                _internalTransaction.State.Rollback(_internalTransaction, e);
            }

            if (etwLog.IsEnabled())
            {
                etwLog.MethodExit(TraceSourceType.TraceSourceLtm, this);
            }
        }
예제 #18
0
        public static byte[] GetTransmitterPropagationToken(Transaction transaction)
        {
            ArgumentNullException.ThrowIfNull(transaction);

            TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;

            if (etwLog.IsEnabled())
            {
                etwLog.MethodEnter(TraceSourceType.TraceSourceOleTx, $"{nameof(TransactionInterop)}.{nameof(GetTransmitterPropagationToken)}");
            }

            // First, make sure we are working with an OletxTransaction.
            OletxTransaction oletxTx = ConvertToOletxTransaction(transaction);

            byte[] token = GetTransmitterPropagationToken(oletxTx);

            if (etwLog.IsEnabled())
            {
                etwLog.MethodExit(TraceSourceType.TraceSourceOleTx, $"{nameof(TransactionInterop)}.{nameof(GetTransmitterPropagationToken)}");
            }

            return(token);
        }
예제 #19
0
        // Create a dependent clone of the transaction that forwards requests to this object.
        //
        public DependentTransaction DependentClone(
            DependentCloneOption cloneOption
            )
        {
            TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;

            if (etwLog.IsEnabled())
            {
                etwLog.MethodEnter(TraceSourceType.TraceSourceLtm, this);
            }

            if (cloneOption != DependentCloneOption.BlockCommitUntilComplete &&
                cloneOption != DependentCloneOption.RollbackIfNotComplete)
            {
                throw new ArgumentOutOfRangeException(nameof(cloneOption));
            }

            if (Disposed)
            {
                throw new ObjectDisposedException(nameof(Transaction));
            }

            if (_complete)
            {
                throw TransactionException.CreateTransactionCompletedException(DistributedTxId);
            }

            DependentTransaction clone = new DependentTransaction(
                _isoLevel, _internalTransaction, cloneOption == DependentCloneOption.BlockCommitUntilComplete);

            if (etwLog.IsEnabled())
            {
                etwLog.TransactionCloneCreate(clone, "DependentTransaction");
                etwLog.MethodExit(TraceSourceType.TraceSourceLtm, this);
            }
            return(clone);
        }
예제 #20
0
        // Ask the state machine for serialization info.
        //
        void ISerializable.GetObjectData(
            SerializationInfo serializationInfo,
            StreamingContext context)
        {
            TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;

            if (etwLog.IsEnabled())
            {
                etwLog.MethodEnter(TraceSourceType.TraceSourceLtm, this);
            }

            if (Disposed)
            {
                throw new ObjectDisposedException(nameof(Transaction));
            }

            if (serializationInfo == null)
            {
                throw new ArgumentNullException(nameof(serializationInfo));
            }

            if (_complete)
            {
                throw TransactionException.CreateTransactionCompletedException(DistributedTxId);
            }

            lock (_internalTransaction)
            {
                _internalTransaction.State.GetObjectData(_internalTransaction, serializationInfo, context);
            }

            if (etwLog.IsEnabled())
            {
                etwLog.TransactionSerialized(this, "Transaction");
                etwLog.MethodExit(TraceSourceType.TraceSourceLtm, this);
            }
        }
예제 #21
0
        internal override void InternalDispose()
        {
            TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;

            if (etwLog.IsEnabled())
            {
                etwLog.MethodEnter(TraceSourceType.TraceSourceLtm, this);
            }

            if (Interlocked.Exchange(ref _disposed, Transaction._disposedTrueValue) == Transaction._disposedTrueValue)
            {
                return;
            }

            Debug.Assert(_internalTransaction.State != null);
            if (_internalTransaction.State.get_Status(_internalTransaction) == TransactionStatus.Active)
            {
                lock (_internalTransaction)
                {
                    // Since this is the root transaction do state based dispose.
                    _internalTransaction.State.DisposeRoot(_internalTransaction);
                }
            }

            // Attempt to clean up the internal transaction
            long remainingITx = Interlocked.Decrement(ref _internalTransaction._cloneCount);

            if (remainingITx == 0)
            {
                _internalTransaction.Dispose();
            }

            if (etwLog.IsEnabled())
            {
                etwLog.MethodExit(TraceSourceType.TraceSourceLtm, this);
            }
        }
        internal override void EnterState(InternalEnlistment enlistment)
        {
            bool spcCommitted = false;

            // Set the enlistment state
            enlistment.State = this;

            Monitor.Exit(enlistment.Transaction);
            try
            {
                TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;
                if (etwLog.IsEnabled())
                {
                    etwLog.EnlistmentStatus(enlistment, NotificationCall.SinglePhaseCommit);
                }

                // Send the Commit notification to the enlistment
                if (enlistment.SinglePhaseNotification != null)
                {
                    enlistment.SinglePhaseNotification.SinglePhaseCommit(enlistment.SinglePhaseEnlistment);
                }
                else
                {
                    enlistment.PromotableSinglePhaseNotification.SinglePhaseCommit(enlistment.SinglePhaseEnlistment);
                }
                spcCommitted = true;
            }
            finally
            {
                if (!spcCommitted)
                {
                    enlistment.SinglePhaseEnlistment.InDoubt();
                }
                Monitor.Enter(enlistment.Transaction);
            }
        }
예제 #23
0
        public void Complete()
        {
            TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;

            if (etwLog.IsEnabled())
            {
                etwLog.MethodEnter(TraceSourceType.TraceSourceBase, this);
            }
            if (_disposed)
            {
                throw new ObjectDisposedException(nameof(TransactionScope));
            }

            if (_complete)
            {
                throw TransactionException.CreateInvalidOperationException(TraceSourceType.TraceSourceBase, SR.DisposeScope, null);
            }

            _complete = true;
            if (etwLog.IsEnabled())
            {
                etwLog.MethodExit(TraceSourceType.TraceSourceBase, this);
            }
        }
예제 #24
0
        private void Initialize(
            Transaction transactionToUse,
            TimeSpan scopeTimeout,
            bool interopModeSpecified)
        {
            if (null == transactionToUse)
            {
                throw new ArgumentNullException(nameof(transactionToUse));
            }

            ValidateScopeTimeout(nameof(scopeTimeout), scopeTimeout);

            CommonInitialize();

            if (TimeSpan.Zero != scopeTimeout)
            {
                _scopeTimer = new Timer(
                    TimerCallback,
                    this,
                    scopeTimeout,
                    TimeSpan.Zero
                    );
            }

            _expectedCurrent      = transactionToUse;
            _interopModeSpecified = interopModeSpecified;

            TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;

            if (etwLog.IsEnabled())
            {
                etwLog.TransactionScopeCreated(_expectedCurrent.TransactionTraceId, TransactionScopeResult.TransactionPassed);
            }

            PushScope();
        }
예제 #25
0
        public TransactionScope(
            Transaction transactionToUse,
            TimeSpan scopeTimeout,
            TransactionScopeAsyncFlowOption asyncFlowOption)
        {
            TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;

            if (etwLog.IsEnabled())
            {
                etwLog.MethodEnter(TraceSourceType.TraceSourceBase, this);
            }

            ValidateAndSetAsyncFlowOption(asyncFlowOption);

            Initialize(
                transactionToUse,
                scopeTimeout,
                false);

            if (etwLog.IsEnabled())
            {
                etwLog.MethodExit(TraceSourceType.TraceSourceBase, this);
            }
        }
예제 #26
0
        // Create a clone of the transaction that forwards requests to this object.
        //
        public Transaction Clone()
        {
            TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;

            if (etwLog.IsEnabled())
            {
                etwLog.MethodEnter(TraceSourceType.TraceSourceLtm, this);
            }

            ObjectDisposedException.ThrowIf(Disposed, this);

            if (_complete)
            {
                throw TransactionException.CreateTransactionCompletedException(DistributedTxId);
            }

            Transaction clone = InternalClone();

            if (etwLog.IsEnabled())
            {
                etwLog.MethodExit(TraceSourceType.TraceSourceLtm, this);
            }
            return(clone);
        }
        public byte[] RecoveryInformation()
        {
            TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;

            if (etwLog.IsEnabled())
            {
                etwLog.MethodEnter(TraceSourceType.TraceSourceLtm, this);
            }

            try
            {
                lock (_internalEnlistment.SyncRoot)
                {
                    return(_internalEnlistment.State.RecoveryInformation(_internalEnlistment));
                }
            }
            finally
            {
                if (etwLog.IsEnabled())
                {
                    etwLog.MethodExit(TraceSourceType.TraceSourceLtm, this);
                }
            }
        }
        public static IDtcTransaction GetDtcTransaction(Transaction transaction)
        {
            if (null == transaction)
            {
                throw new ArgumentNullException(nameof(transaction));
            }

            TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;

            if (etwLog.IsEnabled())
            {
                etwLog.MethodEnter(TraceSourceType.TraceSourceDistributed, "TransactionInterop.GetDtcTransaction");
            }

            DistributedTransaction dTx = ConvertToDistributedTransaction(transaction);
            IDtcTransaction        transactionNative = dTx.GetDtcTransaction();

            if (etwLog.IsEnabled())
            {
                etwLog.MethodExit(TraceSourceType.TraceSourceDistributed, "TransactionInterop.GetDtcTransaction");
            }

            return(transactionNative);
        }
예제 #29
0
        public static Transaction GetTransactionFromExportCookie(byte[] cookie)
        {
            ArgumentNullException.ThrowIfNull(cookie);

            if (cookie.Length < 32)
            {
                throw new ArgumentException(SR.InvalidArgument, nameof(cookie));
            }

            TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;

            if (etwLog.IsEnabled())
            {
                etwLog.MethodEnter(TraceSourceType.TraceSourceOleTx, $"{nameof(TransactionInterop)}.{nameof(GetTransactionFromExportCookie)}");
            }

            var cookieCopy = new byte[cookie.Length];

            Buffer.BlockCopy(cookie, 0, cookieCopy, 0, cookie.Length);
            cookie = cookieCopy;

            Transaction?    transaction;
            TransactionShim?transactionShim = null;
            Guid            txIdentifier    = Guid.Empty;
            OletxTransactionIsolationLevel oletxIsoLevel = OletxTransactionIsolationLevel.ISOLATIONLEVEL_SERIALIZABLE;
            OutcomeEnlistment?outcomeEnlistment;
            OletxTransaction? oleTx;

            // Extract the transaction guid from the propagation token to see if we already have a
            // transaction object for the transaction.
            // In a cookie, the transaction guid is preceded by a signature guid.
            var txId = new Guid(cookie.AsSpan(16, 16));

            // First check to see if there is a promoted LTM transaction with the same ID.  If there
            // is, just return that.
            transaction = TransactionManager.FindPromotedTransaction(txId);
            if (transaction != null)
            {
                if (etwLog.IsEnabled())
                {
                    etwLog.MethodExit(TraceSourceType.TraceSourceOleTx, "TransactionInterop.GetTransactionFromExportCookie");
                }

                return(transaction);
            }

            // We need to create a new transaction
            RealOletxTransaction?   realTx  = null;
            OletxTransactionManager oletxTm = TransactionManager.DistributedTransactionManager;

            oletxTm.DtcTransactionManagerLock.AcquireReaderLock(-1);
            try
            {
                outcomeEnlistment = new OutcomeEnlistment();
                oletxTm.DtcTransactionManager.ProxyShimFactory.Import(cookie, outcomeEnlistment, out txIdentifier, out oletxIsoLevel, out transactionShim);
            }
            catch (COMException comException)
            {
                OletxTransactionManager.ProxyException(comException);

                // We are unsure of what the exception may mean.  It is possible that
                // we could get E_FAIL when trying to contact a transaction manager that is
                // being blocked by a fire wall.  On the other hand we may get a COMException
                // based on bad data.  The more common situation is that the data is fine
                // (since it is generated by Microsoft code) and the problem is with
                // communication.  So in this case we default for unknown exceptions to
                // assume that the problem is with communication.
                throw TransactionManagerCommunicationException.Create(SR.TraceSourceOletx, comException);
            }
            finally
            {
                oletxTm.DtcTransactionManagerLock.ReleaseReaderLock();
            }

            // We need to create a new RealOletxTransaction.
            realTx = new RealOletxTransaction(
                oletxTm,
                transactionShim,
                outcomeEnlistment,
                txIdentifier,
                oletxIsoLevel,
                false);

            // Now create the associated OletxTransaction.
            oleTx = new OletxTransaction(realTx);

            // If a transaction is found then FindOrCreate will Dispose the oletx
            // created.
            transaction = TransactionManager.FindOrCreatePromotedTransaction(txId, oleTx);

            if (etwLog.IsEnabled())
            {
                etwLog.MethodExit(TraceSourceType.TraceSourceOleTx, $"{nameof(TransactionInterop)}.{nameof(GetTransactionFromExportCookie)}");
            }

            return(transaction);
        }
예제 #30
0
        public static Transaction GetTransactionFromDtcTransaction(IDtcTransaction transactionNative)
        {
            ArgumentNullException.ThrowIfNull(transactionNative, nameof(transactionNative));

            TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;

            if (etwLog.IsEnabled())
            {
                etwLog.MethodEnter(TraceSourceType.TraceSourceOleTx, $"{nameof(TransactionInterop)}.{nameof(GetTransactionFromDtcTransaction)}");
            }

            Transaction?    transaction     = null;
            bool            tooLate         = false;
            TransactionShim?transactionShim = null;
            Guid            txIdentifier    = Guid.Empty;
            OletxTransactionIsolationLevel oletxIsoLevel = OletxTransactionIsolationLevel.ISOLATIONLEVEL_SERIALIZABLE;
            OutcomeEnlistment?   outcomeEnlistment       = null;
            RealOletxTransaction?realTx = null;
            OletxTransaction?    oleTx  = null;

            // Let's get the guid of the transaction from the proxy to see if we already have an object.
            if (transactionNative is not ITransaction myTransactionNative)
            {
                throw new ArgumentException(SR.InvalidArgument, nameof(transactionNative));
            }

            OletxXactTransInfo xactInfo;

            try
            {
                myTransactionNative.GetTransactionInfo(out xactInfo);
            }
            catch (COMException ex) when(ex.ErrorCode == OletxHelper.XACT_E_NOTRANSACTION)
            {
                // If we get here, the transaction has appraently already been committed or aborted.  Allow creation of the
                // OletxTransaction, but it will be marked with a status of InDoubt and attempts to get its Identifier
                // property will result in a TransactionException.
                tooLate      = true;
                xactInfo.Uow = Guid.Empty;
            }

            OletxTransactionManager oletxTm = TransactionManager.DistributedTransactionManager;

            if (!tooLate)
            {
                // First check to see if there is a promoted LTM transaction with the same ID.  If there
                // is, just return that.
                transaction = TransactionManager.FindPromotedTransaction(xactInfo.Uow);
                if (transaction != null)
                {
                    if (etwLog.IsEnabled())
                    {
                        etwLog.MethodExit(TraceSourceType.TraceSourceOleTx, $"{nameof(TransactionInterop)}.{nameof(GetTransactionFromDtcTransaction)}");
                    }

                    return(transaction);
                }

                // We need to create a new RealOletxTransaction...
                oletxTm.DtcTransactionManagerLock.AcquireReaderLock(-1);
                try
                {
                    outcomeEnlistment = new OutcomeEnlistment();
                    oletxTm.DtcTransactionManager.ProxyShimFactory.CreateTransactionShim(
                        transactionNative,
                        outcomeEnlistment,
                        out txIdentifier,
                        out oletxIsoLevel,
                        out transactionShim);
                }
                catch (COMException comException)
                {
                    OletxTransactionManager.ProxyException(comException);
                    throw;
                }
                finally
                {
                    oletxTm.DtcTransactionManagerLock.ReleaseReaderLock();
                }

                // We need to create a new RealOletxTransaction.
                realTx = new RealOletxTransaction(
                    oletxTm,
                    transactionShim,
                    outcomeEnlistment,
                    txIdentifier,
                    oletxIsoLevel,
                    false);

                oleTx = new OletxTransaction(realTx);

                // If a transaction is found then FindOrCreate will Dispose the oletx
                // created.
                transaction = TransactionManager.FindOrCreatePromotedTransaction(xactInfo.Uow, oleTx);
            }
            else
            {
                // It was too late to do a clone of the provided ITransactionNative, so we are just going to
                // create a RealOletxTransaction without a transaction shim or outcome enlistment.
                realTx = new RealOletxTransaction(
                    oletxTm,
                    null,
                    null,
                    txIdentifier,
                    OletxTransactionIsolationLevel.ISOLATIONLEVEL_SERIALIZABLE,
                    false);

                oleTx       = new OletxTransaction(realTx);
                transaction = new Transaction(oleTx);
                TransactionManager.FireDistributedTransactionStarted(transaction);
                oleTx.SavedLtmPromotedTransaction = transaction;

                InternalTransaction.DistributedTransactionOutcome(transaction._internalTransaction, TransactionStatus.InDoubt);
            }

            if (etwLog.IsEnabled())
            {
                etwLog.MethodExit(TraceSourceType.TraceSourceOleTx, $"{nameof(TransactionInterop)}.{nameof(GetTransactionFromDtcTransaction)}");
            }

            return(transaction);
        }