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 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(); }
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)); }