Example #1
0
        internal OletxEnlistment(
            IEnlistmentNotificationInternal enlistmentNotification,
            OletxTransactionStatus xactStatus,
            byte[] prepareInfoByteArray,
            OletxResourceManager oletxResourceManager
            ) : base( oletxResourceManager, null )
        {
            Guid myGuid = Guid.Empty;

            // This will get set later by the creator of this object after it
            // has enlisted with the proxy.
            this.enlistmentShim = null;
            this.phase0Shim = null;

            this.canDoSinglePhase = false;
            this.iEnlistmentNotification = enlistmentNotification;
            this.state = OletxEnlistmentState.Active;

            // Do this before we do any tracing because it will affect the trace identifiers that we generate.
            Debug.Assert( ( null != prepareInfoByteArray ),  
                "OletxEnlistment.ctor - null oletxTransaction without a prepareInfoByteArray" );

            int prepareInfoLength = prepareInfoByteArray.Length;
            this.proxyPrepareInfoByteArray = new byte[prepareInfoLength];
            Array.Copy(prepareInfoByteArray, proxyPrepareInfoByteArray, prepareInfoLength);

            byte[] txGuidByteArray = new byte[16];
            Array.Copy(proxyPrepareInfoByteArray, txGuidByteArray, 16);

            this.transactionGuid = new Guid( txGuidByteArray );
            this.transactionGuidString = this.transactionGuid.ToString();
            
            // If this is being created as part of a Reenlist and we already know the
            // outcome, then tell the application.
            switch (xactStatus)
            {
                case OletxTransactionStatus.OLETX_TRANSACTION_STATUS_ABORTED:
                {
                    this.state = OletxEnlistmentState.Aborting;
                    if ( DiagnosticTrace.Verbose )
                    {
                        EnlistmentNotificationCallTraceRecord.Trace( SR.GetString( SR.TraceSourceOletx ),
                            this.InternalTraceIdentifier,
                            NotificationCall.Rollback
                            );
                    }

                    iEnlistmentNotification.Rollback( this );
                    break;
                }

                case OletxTransactionStatus.OLETX_TRANSACTION_STATUS_COMMITTED:
                {
                    this.state = OletxEnlistmentState.Committing;
                    // We are going to send the notification to the RM.  We need to put the
                    // enlistment on the reenlistPendingList.  We lock the reenlistList because
                    // we have decided that is the lock that protects both lists.  The entry will
                    // be taken off the reenlistPendingList when the enlistment has
                    // EnlistmentDone called on it.  The enlistment will call
                    // RemoveFromReenlistPending.
                    lock ( oletxResourceManager.reenlistList )
                    {
                        oletxResourceManager.reenlistPendingList.Add( this );
                    }

                    if ( DiagnosticTrace.Verbose )
                    {
                        EnlistmentNotificationCallTraceRecord.Trace( SR.GetString( SR.TraceSourceOletx ),
                            this.InternalTraceIdentifier,
                            NotificationCall.Commit
                            );
                    }

                    iEnlistmentNotification.Commit( this );
                    break;
                }

                case OletxTransactionStatus.OLETX_TRANSACTION_STATUS_PREPARED:
                {
                    this.state = OletxEnlistmentState.Prepared;
                    lock ( oletxResourceManager.reenlistList )
                    {
                        oletxResourceManager.reenlistList.Add( this );
                        oletxResourceManager.StartReenlistThread();
                    }
                    break;
                }

                default:
                {
                    if ( DiagnosticTrace.Critical )
                    {
                        InternalErrorTraceRecord.Trace( SR.GetString( SR.TraceSourceOletx ),
                            SR.GetString( SR.OletxEnlistmentUnexpectedTransactionStatus )
                            );
                    }

                    throw TransactionException.Create( SR.GetString( SR.TraceSourceOletx ), SR.GetString( SR.OletxEnlistmentUnexpectedTransactionStatus ), null );
                }
            }

            if ( DiagnosticTrace.Information )
            {
                EnlistmentTraceRecord.Trace( SR.GetString( SR.TraceSourceOletx ),
                    this.InternalTraceIdentifier,
                    EnlistmentType.Durable,
                    EnlistmentOptions.None
                    );
            }

            // Always do this last in case anything prior to this fails.
            AddToEnlistmentTable();
        }
        internal OletxEnlistment(IEnlistmentNotificationInternal enlistmentNotification, OletxTransactionStatus xactStatus, byte[] prepareInfoByteArray, OletxResourceManager oletxResourceManager) : base(oletxResourceManager, null)
        {
            this.transactionGuid         = Guid.Empty;
            this.phase1Handle            = IntPtr.Zero;
            this.enlistmentShim          = null;
            this.phase0Shim              = null;
            this.canDoSinglePhase        = false;
            this.iEnlistmentNotification = enlistmentNotification;
            this.state = OletxEnlistmentState.Active;
            int length = prepareInfoByteArray.Length;

            this.proxyPrepareInfoByteArray = new byte[length];
            Array.Copy(prepareInfoByteArray, this.proxyPrepareInfoByteArray, length);
            byte[] destinationArray = new byte[0x10];
            Array.Copy(this.proxyPrepareInfoByteArray, destinationArray, 0x10);
            this.transactionGuid       = new Guid(destinationArray);
            base.transactionGuidString = this.transactionGuid.ToString();
            switch (xactStatus)
            {
            case OletxTransactionStatus.OLETX_TRANSACTION_STATUS_PREPARED:
                this.state = OletxEnlistmentState.Prepared;
                lock (oletxResourceManager.reenlistList)
                {
                    oletxResourceManager.reenlistList.Add(this);
                    oletxResourceManager.StartReenlistThread();
                    goto Label_01CD;
                }
                break;

            case OletxTransactionStatus.OLETX_TRANSACTION_STATUS_ABORTED:
                this.state = OletxEnlistmentState.Aborting;
                if (DiagnosticTrace.Verbose)
                {
                    EnlistmentNotificationCallTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), base.InternalTraceIdentifier, NotificationCall.Rollback);
                }
                this.iEnlistmentNotification.Rollback(this);
                goto Label_01CD;

            case OletxTransactionStatus.OLETX_TRANSACTION_STATUS_COMMITTED:
                this.state = OletxEnlistmentState.Committing;
                lock (oletxResourceManager.reenlistList)
                {
                    oletxResourceManager.reenlistPendingList.Add(this);
                }
                if (DiagnosticTrace.Verbose)
                {
                    EnlistmentNotificationCallTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), base.InternalTraceIdentifier, NotificationCall.Commit);
                }
                this.iEnlistmentNotification.Commit(this);
                goto Label_01CD;
            }
            if (DiagnosticTrace.Critical)
            {
                InternalErrorTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), System.Transactions.SR.GetString("OletxEnlistmentUnexpectedTransactionStatus"));
            }
            throw TransactionException.Create(System.Transactions.SR.GetString("TraceSourceOletx"), System.Transactions.SR.GetString("OletxEnlistmentUnexpectedTransactionStatus"), null);
Label_01CD:
            if (DiagnosticTrace.Information)
            {
                EnlistmentTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), base.InternalTraceIdentifier, EnlistmentType.Durable, EnlistmentOptions.None);
            }
            base.AddToEnlistmentTable();
        }
        internal OletxEnlistment(IEnlistmentNotificationInternal enlistmentNotification, OletxTransactionStatus xactStatus, byte[] prepareInfoByteArray, OletxResourceManager oletxResourceManager) : base(oletxResourceManager, null)
        {
            this.transactionGuid = Guid.Empty;
            this.phase1Handle = IntPtr.Zero;
            this.enlistmentShim = null;
            this.phase0Shim = null;
            this.canDoSinglePhase = false;
            this.iEnlistmentNotification = enlistmentNotification;
            this.state = OletxEnlistmentState.Active;
            int length = prepareInfoByteArray.Length;
            this.proxyPrepareInfoByteArray = new byte[length];
            Array.Copy(prepareInfoByteArray, this.proxyPrepareInfoByteArray, length);
            byte[] destinationArray = new byte[0x10];
            Array.Copy(this.proxyPrepareInfoByteArray, destinationArray, 0x10);
            this.transactionGuid = new Guid(destinationArray);
            base.transactionGuidString = this.transactionGuid.ToString();
            switch (xactStatus)
            {
                case OletxTransactionStatus.OLETX_TRANSACTION_STATUS_PREPARED:
                    this.state = OletxEnlistmentState.Prepared;
                    lock (oletxResourceManager.reenlistList)
                    {
                        oletxResourceManager.reenlistList.Add(this);
                        oletxResourceManager.StartReenlistThread();
                        goto Label_01CD;
                    }
                    break;

                case OletxTransactionStatus.OLETX_TRANSACTION_STATUS_ABORTED:
                    this.state = OletxEnlistmentState.Aborting;
                    if (DiagnosticTrace.Verbose)
                    {
                        EnlistmentNotificationCallTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), base.InternalTraceIdentifier, NotificationCall.Rollback);
                    }
                    this.iEnlistmentNotification.Rollback(this);
                    goto Label_01CD;

                case OletxTransactionStatus.OLETX_TRANSACTION_STATUS_COMMITTED:
                    this.state = OletxEnlistmentState.Committing;
                    lock (oletxResourceManager.reenlistList)
                    {
                        oletxResourceManager.reenlistPendingList.Add(this);
                    }
                    if (DiagnosticTrace.Verbose)
                    {
                        EnlistmentNotificationCallTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), base.InternalTraceIdentifier, NotificationCall.Commit);
                    }
                    this.iEnlistmentNotification.Commit(this);
                    goto Label_01CD;
            }
            if (DiagnosticTrace.Critical)
            {
                InternalErrorTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), System.Transactions.SR.GetString("OletxEnlistmentUnexpectedTransactionStatus"));
            }
            throw TransactionException.Create(System.Transactions.SR.GetString("TraceSourceOletx"), System.Transactions.SR.GetString("OletxEnlistmentUnexpectedTransactionStatus"), null);
        Label_01CD:
            if (DiagnosticTrace.Information)
            {
                EnlistmentTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), base.InternalTraceIdentifier, EnlistmentType.Durable, EnlistmentOptions.None);
            }
            base.AddToEnlistmentTable();
        }
Example #4
0
    internal OletxEnlistment(
        IEnlistmentNotificationInternal enlistmentNotification,
        OletxTransactionStatus xactStatus,
        byte[] prepareInfoByteArray,
        OletxResourceManager oletxResourceManager)
        : base(oletxResourceManager, null)
    {
        // This will get set later by the creator of this object after it
        // has enlisted with the proxy.
        EnlistmentShim = null;
        _phase0Shim    = null;

        _canDoSinglePhase        = false;
        _iEnlistmentNotification = enlistmentNotification;
        State = OletxEnlistmentState.Active;

        // Do this before we do any tracing because it will affect the trace identifiers that we generate.
        Debug.Assert(prepareInfoByteArray != null,
                     "OletxEnlistment.ctor - null oletxTransaction without a prepareInfoByteArray");

        int prepareInfoLength = prepareInfoByteArray.Length;

        _proxyPrepareInfoByteArray = new byte[prepareInfoLength];
        Array.Copy(prepareInfoByteArray, _proxyPrepareInfoByteArray, prepareInfoLength);

        byte[] txGuidByteArray = new byte[16];
        Array.Copy(_proxyPrepareInfoByteArray, txGuidByteArray, 16);

        _transactionGuid      = new Guid(txGuidByteArray);
        TransactionGuidString = _transactionGuid.ToString();

        TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;

        // If this is being created as part of a Reenlist and we already know the
        // outcome, then tell the application.
        switch (xactStatus)
        {
        case OletxTransactionStatus.OLETX_TRANSACTION_STATUS_ABORTED:
        {
            State = OletxEnlistmentState.Aborting;
            if (etwLog.IsEnabled())
            {
                etwLog.EnlistmentStatus(TraceSourceType.TraceSourceOleTx, InternalTraceIdentifier, NotificationCall.Rollback);
            }

            _iEnlistmentNotification.Rollback(this);
            break;
        }

        case OletxTransactionStatus.OLETX_TRANSACTION_STATUS_COMMITTED:
        {
            State = OletxEnlistmentState.Committing;
            // We are going to send the notification to the RM.  We need to put the
            // enlistment on the reenlistPendingList.  We lock the reenlistList because
            // we have decided that is the lock that protects both lists.  The entry will
            // be taken off the reenlistPendingList when the enlistment has
            // EnlistmentDone called on it.  The enlistment will call
            // RemoveFromReenlistPending.
            lock (oletxResourceManager.ReenlistList)
            {
                oletxResourceManager.ReenlistPendingList.Add(this);
            }

            if (etwLog.IsEnabled())
            {
                etwLog.EnlistmentStatus(TraceSourceType.TraceSourceOleTx, InternalTraceIdentifier, NotificationCall.Commit);
            }

            _iEnlistmentNotification.Commit(this);
            break;
        }

        case OletxTransactionStatus.OLETX_TRANSACTION_STATUS_PREPARED:
        {
            State = OletxEnlistmentState.Prepared;
            lock (oletxResourceManager.ReenlistList)
            {
                oletxResourceManager.ReenlistList.Add(this);
                oletxResourceManager.StartReenlistThread();
            }
            break;
        }

        default:
        {
            if (etwLog.IsEnabled())
            {
                etwLog.InternalError(SR.OletxEnlistmentUnexpectedTransactionStatus);
            }

            throw TransactionException.Create(
                      SR.OletxEnlistmentUnexpectedTransactionStatus, null, DistributedTxId);
        }
        }

        if (etwLog.IsEnabled())
        {
            etwLog.EnlistmentCreated(TraceSourceType.TraceSourceOleTx, InternalTraceIdentifier, EnlistmentType.Durable, EnlistmentOptions.None);
        }

        // Always do this last in case anything prior to this fails.
        AddToEnlistmentTable();
    }
Example #5
0
        internal OletxEnlistment Reenlist(int prepareInfoLength, byte[] prepareInfo, IEnlistmentNotificationInternal enlistmentNotification)
        {
            OletxRecoveryInformation information;
            OletxTransactionOutcome  notKnownYet         = OletxTransactionOutcome.NotKnownYet;
            OletxTransactionStatus   xactStatus          = OletxTransactionStatus.OLETX_TRANSACTION_STATUS_NONE;
            MemoryStream             serializationStream = new MemoryStream(prepareInfo);
            IFormatter formatter = new BinaryFormatter();

            try
            {
                information = formatter.Deserialize(serializationStream) as OletxRecoveryInformation;
            }
            catch (SerializationException exception2)
            {
                throw new ArgumentException(System.Transactions.SR.GetString("InvalidArgument"), "prepareInfo", exception2);
            }
            if (information == null)
            {
                throw new ArgumentException(System.Transactions.SR.GetString("InvalidArgument"), "prepareInfo");
            }
            byte[] b = new byte[0x10];
            for (int i = 0; i < 0x10; i++)
            {
                b[i] = information.proxyRecoveryInformation[i + 0x10];
            }
            Guid guid = new Guid(b);

            if (guid != this.resourceManagerIdentifier)
            {
                throw TransactionException.Create(System.Transactions.SR.GetString("TraceSourceOletx"), System.Transactions.SR.GetString("ResourceManagerIdDoesNotMatchRecoveryInformation"), null);
            }
            IResourceManagerShim resourceManagerShim = null;

            try
            {
                resourceManagerShim = this.ResourceManagerShim;
                if (resourceManagerShim == null)
                {
                    throw new COMException(System.Transactions.SR.GetString("DtcTransactionManagerUnavailable"), System.Transactions.Oletx.NativeMethods.XACT_E_CONNECTION_DOWN);
                }
                resourceManagerShim.Reenlist(Convert.ToUInt32(information.proxyRecoveryInformation.Length, CultureInfo.InvariantCulture), information.proxyRecoveryInformation, out notKnownYet);
                if (OletxTransactionOutcome.Committed == notKnownYet)
                {
                    xactStatus = OletxTransactionStatus.OLETX_TRANSACTION_STATUS_COMMITTED;
                }
                else if (OletxTransactionOutcome.Aborted == notKnownYet)
                {
                    xactStatus = OletxTransactionStatus.OLETX_TRANSACTION_STATUS_ABORTED;
                }
                else
                {
                    xactStatus = OletxTransactionStatus.OLETX_TRANSACTION_STATUS_PREPARED;
                    this.StartReenlistThread();
                }
            }
            catch (COMException exception)
            {
                if (System.Transactions.Oletx.NativeMethods.XACT_E_CONNECTION_DOWN != exception.ErrorCode)
                {
                    throw;
                }
                xactStatus = OletxTransactionStatus.OLETX_TRANSACTION_STATUS_PREPARED;
                this.ResourceManagerShim = null;
                this.StartReenlistThread();
                if (DiagnosticTrace.Verbose)
                {
                    ExceptionConsumedTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), exception);
                }
            }
            finally
            {
                resourceManagerShim = null;
            }
            return(new OletxEnlistment(enlistmentNotification, xactStatus, information.proxyRecoveryInformation, this));
        }
    internal OletxEnlistment Reenlist(byte[] prepareInfo, IEnlistmentNotificationInternal enlistmentNotification)
    {
        OletxTransactionOutcome outcome    = OletxTransactionOutcome.NotKnownYet;
        OletxTransactionStatus  xactStatus = OletxTransactionStatus.OLETX_TRANSACTION_STATUS_NONE;

        if (prepareInfo == null)
        {
            throw new ArgumentException(SR.InvalidArgument, nameof(prepareInfo));
        }

        // Verify that the resource manager guid in the recovery info matches that of the calling resource manager.
        byte[] rmGuidArray = new byte[16];
        for (int i = 0; i < 16; i++)
        {
            rmGuidArray[i] = prepareInfo[i + 16];
        }
        Guid rmGuid = new(rmGuidArray);

        if (rmGuid != ResourceManagerIdentifier)
        {
            throw TransactionException.Create(TraceSourceType.TraceSourceOleTx, SR.ResourceManagerIdDoesNotMatchRecoveryInformation, null);
        }

        // Ask the proxy resource manager to reenlist.
        ResourceManagerShim?localResourceManagerShim = null;

        try
        {
            localResourceManagerShim = ResourceManagerShim;
            if (localResourceManagerShim == null)
            {
                // The TM must be down.  Throw the exception that will get caught below and will cause
                // the enlistment to start the ReenlistThread.  The TMDown thread will be trying to reestablish
                // connection with the TM and will start the reenlist thread when it does.
                throw new COMException(SR.DtcTransactionManagerUnavailable, OletxHelper.XACT_E_CONNECTION_DOWN);
            }

            // Only wait for 5 milliseconds.  If the TM doesn't have the outcome now, we will
            // put the enlistment on the reenlistList for later processing.
            localResourceManagerShim.Reenlist(prepareInfo, out outcome);

            if (OletxTransactionOutcome.Committed == outcome)
            {
                xactStatus = OletxTransactionStatus.OLETX_TRANSACTION_STATUS_COMMITTED;
            }
            else if (OletxTransactionOutcome.Aborted == outcome)
            {
                xactStatus = OletxTransactionStatus.OLETX_TRANSACTION_STATUS_ABORTED;
            }
            else  // we must not know the outcome yet.
            {
                xactStatus = OletxTransactionStatus.OLETX_TRANSACTION_STATUS_PREPARED;
                StartReenlistThread();
            }
        }
        catch (COMException ex) when(ex.ErrorCode == OletxHelper.XACT_E_CONNECTION_DOWN)
        {
            xactStatus          = OletxTransactionStatus.OLETX_TRANSACTION_STATUS_PREPARED;
            ResourceManagerShim = null;
            StartReenlistThread();

            TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;

            if (etwLog.IsEnabled())
            {
                etwLog.ExceptionConsumed(TraceSourceType.TraceSourceOleTx, ex);
            }
        }
        finally
        {
            localResourceManagerShim = null;
        }

        // Now create our enlistment to tell the client the outcome.
        return(new OletxEnlistment(enlistmentNotification, xactStatus, prepareInfo, this));
    }