public object GetRealObject(StreamingContext context) { if (DiagnosticTrace.Verbose) { MethodEnteredTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), "IObjectReference.GetRealObject"); } if (this.propagationTokenForDeserialize == null) { if (DiagnosticTrace.Critical) { InternalErrorTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), System.Transactions.SR.GetString("UnableToDeserializeTransaction")); } throw TransactionException.Create(System.Transactions.SR.GetString("TraceSourceOletx"), System.Transactions.SR.GetString("UnableToDeserializeTransactionInternalError"), null); } if (null != this.savedLtmPromotedTransaction) { if (DiagnosticTrace.Verbose) { MethodExitedTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), "IObjectReference.GetRealObject"); } return(this.savedLtmPromotedTransaction); } Transaction transactionFromTransmitterPropagationToken = TransactionInterop.GetTransactionFromTransmitterPropagationToken(this.propagationTokenForDeserialize); this.savedLtmPromotedTransaction = transactionFromTransmitterPropagationToken; if (DiagnosticTrace.Verbose) { TransactionDeserializedTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), transactionFromTransmitterPropagationToken.internalTransaction.PromotedTransaction.TransactionTraceId); } if (DiagnosticTrace.Verbose) { MethodExitedTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), "IObjectReference.GetRealObject"); } return(transactionFromTransmitterPropagationToken); }
internal void Commit() { try { this.transactionShim.Commit(); } catch (COMException exception) { if ((System.Transactions.Oletx.NativeMethods.XACT_E_ABORTED == exception.ErrorCode) || (System.Transactions.Oletx.NativeMethods.XACT_E_INDOUBT == exception.ErrorCode)) { Interlocked.CompareExchange <Exception>(ref this.innerException, exception, null); if (DiagnosticTrace.Verbose) { ExceptionConsumedTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), exception); } } else { if (System.Transactions.Oletx.NativeMethods.XACT_E_ALREADYINPROGRESS == exception.ErrorCode) { throw TransactionException.Create(System.Transactions.SR.GetString("TraceSourceOletx"), System.Transactions.SR.GetString("TransactionAlreadyOver"), exception); } OletxTransactionManager.ProxyException(exception); throw; } } }
internal OletxDependentTransaction DependentClone(bool delayCommit) { OletxDependentTransaction transaction = null; if (DiagnosticTrace.Verbose) { MethodEnteredTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), "OletxTransaction.DependentClone"); } if (TransactionStatus.Aborted == this.Status) { throw TransactionAbortedException.Create(System.Transactions.SR.GetString("TraceSourceOletx"), this.realOletxTransaction.innerException); } if (TransactionStatus.InDoubt == this.Status) { throw TransactionInDoubtException.Create(System.Transactions.SR.GetString("TraceSourceOletx"), this.realOletxTransaction.innerException); } if (this.Status != TransactionStatus.Active) { throw TransactionException.Create(System.Transactions.SR.GetString("TraceSourceOletx"), System.Transactions.SR.GetString("TransactionAlreadyOver"), null); } transaction = new OletxDependentTransaction(this.realOletxTransaction, delayCommit); if (DiagnosticTrace.Verbose) { MethodExitedTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), "OletxTransaction.DependentClone"); } return(transaction); }
internal void Rollback() { lock (this) { if ((TransactionStatus.Aborted != this.status) && (this.status != TransactionStatus.Active)) { throw TransactionException.Create(System.Transactions.SR.GetString("TraceSourceOletx"), System.Transactions.SR.GetString("TransactionAlreadyOver"), null); } if (TransactionStatus.Aborted == this.status) { return; } if (0 < this.undecidedEnlistmentCount) { this.doomed = true; } else if (this.tooLateForEnlistments) { throw TransactionException.Create(System.Transactions.SR.GetString("TraceSourceOletx"), System.Transactions.SR.GetString("TransactionAlreadyOver"), null); } if (this.phase0EnlistVolatilementContainerList != null) { foreach (OletxPhase0VolatileEnlistmentContainer container in this.phase0EnlistVolatilementContainerList) { container.RollbackFromTransaction(); } } if (this.phase1EnlistVolatilementContainer != null) { this.phase1EnlistVolatilementContainer.RollbackFromTransaction(); } } try { this.transactionShim.Abort(); } catch (COMException exception) { if (System.Transactions.Oletx.NativeMethods.XACT_E_ALREADYINPROGRESS == exception.ErrorCode) { if (!this.doomed) { throw TransactionException.Create(System.Transactions.SR.GetString("TraceSourceOletx"), System.Transactions.SR.GetString("TransactionAlreadyOver"), exception); } if (DiagnosticTrace.Verbose) { ExceptionConsumedTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), exception); } } else { OletxTransactionManager.ProxyException(exception); throw; } } }
internal void AddEnlistment(OletxVolatileEnlistment enlistment) { lock (this) { if (-1 != base.phase) { throw TransactionException.Create(System.Transactions.SR.GetString("TraceSourceOletx"), System.Transactions.SR.GetString("TooLate"), null); } base.enlistmentList.Add(enlistment); } }
internal IPromotedEnlistment EnlistDurable(Guid resourceManagerIdentifier, ISinglePhaseNotificationInternal singlePhaseNotification, bool canDoSinglePhase, EnlistmentOptions enlistmentOptions) { if (DiagnosticTrace.Verbose) { MethodEnteredTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), "OletxTransaction.EnlistDurable( ISinglePhaseNotificationInternal )"); } if ((this.realOletxTransaction == null) || this.realOletxTransaction.TooLateForEnlistments) { throw TransactionException.Create(System.Transactions.SR.GetString("TraceSourceOletx"), System.Transactions.SR.GetString("TooLate"), null); } OletxEnlistment enlistment = this.realOletxTransaction.OletxTransactionManagerInstance.FindOrRegisterResourceManager(resourceManagerIdentifier).EnlistDurable(this, canDoSinglePhase, singlePhaseNotification, enlistmentOptions); if (DiagnosticTrace.Verbose) { MethodExitedTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), "OletxTransaction.EnlistDurable( ISinglePhaseNotificationInternal )"); } return(enlistment); }
internal IPromotedEnlistment EnlistVolatile(ISinglePhaseNotificationInternal singlePhaseNotification, EnlistmentOptions enlistmentOptions) { if (DiagnosticTrace.Verbose) { MethodEnteredTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), "OletxTransaction.EnlistVolatile( ISinglePhaseNotificationInternal )"); } if ((this.realOletxTransaction == null) || this.realOletxTransaction.TooLateForEnlistments) { throw TransactionException.Create(System.Transactions.SR.GetString("TraceSourceOletx"), System.Transactions.SR.GetString("TooLate"), null); } IPromotedEnlistment enlistment = this.realOletxTransaction.EnlistVolatile(singlePhaseNotification, enlistmentOptions, this); if (DiagnosticTrace.Verbose) { MethodExitedTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), "OletxTransaction.EnlistVolatile( ISinglePhaseNotificationInternal )"); } return(enlistment); }
internal static void ProxyException( COMException comException ) { if ((NativeMethods.XACT_E_CONNECTION_DOWN == comException.ErrorCode) || (NativeMethods.XACT_E_TMNOTAVAILABLE == comException.ErrorCode) ) { throw TransactionManagerCommunicationException.Create( SR.GetString(SR.TraceSourceOletx), SR.GetString(SR.TransactionManagerCommunicationException), comException ); } if ((NativeMethods.XACT_E_NETWORK_TX_DISABLED == comException.ErrorCode)) { throw TransactionManagerCommunicationException.Create( SR.GetString(SR.TraceSourceOletx), SR.GetString(SR.NetworkTransactionsDisabled), comException ); } // Else if the error is a transaction oriented error, throw a TransactionException else if ((NativeMethods.XACT_E_FIRST <= comException.ErrorCode) && (NativeMethods.XACT_E_LAST >= comException.ErrorCode)) { // Special casing XACT_E_NOTRANSACTION if (NativeMethods.XACT_E_NOTRANSACTION == comException.ErrorCode) { throw TransactionException.Create( SR.GetString(SR.TraceSourceOletx), SR.GetString(SR.TransactionAlreadyOver), comException ); } throw TransactionException.Create( SR.GetString(SR.TraceSourceOletx), comException.Message, comException ); } }
internal static void ProxyException(COMException comException) { if ((System.Transactions.Oletx.NativeMethods.XACT_E_CONNECTION_DOWN == comException.ErrorCode) || (System.Transactions.Oletx.NativeMethods.XACT_E_TMNOTAVAILABLE == comException.ErrorCode)) { throw TransactionManagerCommunicationException.Create(System.Transactions.SR.GetString("TraceSourceOletx"), System.Transactions.SR.GetString("TransactionManagerCommunicationException"), comException); } if (System.Transactions.Oletx.NativeMethods.XACT_E_NETWORK_TX_DISABLED == comException.ErrorCode) { throw TransactionManagerCommunicationException.Create(System.Transactions.SR.GetString("TraceSourceOletx"), System.Transactions.SR.GetString("NetworkTransactionsDisabled"), comException); } if ((System.Transactions.Oletx.NativeMethods.XACT_E_FIRST <= comException.ErrorCode) && (System.Transactions.Oletx.NativeMethods.XACT_E_LAST >= comException.ErrorCode)) { if (System.Transactions.Oletx.NativeMethods.XACT_E_NOTRANSACTION == comException.ErrorCode) { throw TransactionException.Create(System.Transactions.SR.GetString("TraceSourceOletx"), System.Transactions.SR.GetString("TransactionAlreadyOver"), comException); } throw TransactionException.Create(System.Transactions.SR.GetString("TraceSourceOletx"), comException.Message, comException); } }
internal OletxTransactionManager(string nodeName) { lock (ClassSyncObject) { if (proxyShimFactory == null) { if (System.Transactions.Oletx.NativeMethods.GetNotificationFactory(ShimWaitHandle.SafeWaitHandle, out proxyShimFactory) != 0) { throw TransactionException.Create(System.Transactions.SR.GetString("TraceSourceOletx"), System.Transactions.SR.GetString("UnableToGetNotificationShimFactory"), null); } ThreadPool.UnsafeRegisterWaitForSingleObject(ShimWaitHandle, new WaitOrTimerCallback(OletxTransactionManager.ShimNotificationCallback), null, -1, false); } } this.dtcTransactionManagerLock = new ReaderWriterLock(); this.nodeNameField = nodeName; if ((this.nodeNameField != null) && (this.nodeNameField.Length == 0)) { this.nodeNameField = null; } if (DiagnosticTrace.Verbose) { DistributedTransactionManagerCreatedTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), base.GetType(), this.nodeNameField); } this.configuredTransactionOptions.IsolationLevel = this.isolationLevelProperty = TransactionManager.DefaultIsolationLevel; this.configuredTransactionOptions.Timeout = this.timeoutProperty = TransactionManager.DefaultTimeout; this.internalResourceManager = new OletxInternalResourceManager(this); this.dtcTransactionManagerLock.AcquireWriterLock(-1); try { this.dtcTransactionManager = new System.Transactions.Oletx.DtcTransactionManager(this.nodeNameField, this); } finally { this.dtcTransactionManagerLock.ReleaseWriterLock(); } if (resourceManagerHashTable == null) { resourceManagerHashTable = new Hashtable(2); resourceManagerHashTableLock = new ReaderWriterLock(); } }
internal OletxEnlistment EnlistDurable( OletxTransaction oletxTransaction, bool canDoSinglePhase, IEnlistmentNotificationInternal enlistmentNotification, EnlistmentOptions enlistmentOptions) { ResourceManagerShim?localResourceManagerShim; Debug.Assert(oletxTransaction != null, "Argument is null"); Debug.Assert(enlistmentNotification != null, "Argument is null"); EnlistmentShim enlistmentShim; Phase0EnlistmentShim phase0Shim; Guid txUow = Guid.Empty; bool undecidedEnlistmentsIncremented = false; // Create our enlistment object. OletxEnlistment enlistment = new( canDoSinglePhase, enlistmentNotification, oletxTransaction.RealTransaction.TxGuid, enlistmentOptions, this, oletxTransaction); bool enlistmentSucceeded = false; try { if ((enlistmentOptions & EnlistmentOptions.EnlistDuringPrepareRequired) != 0) { oletxTransaction.RealTransaction.IncrementUndecidedEnlistments(); undecidedEnlistmentsIncremented = true; } // This entire sequence needs to be executed before we can go on. lock (enlistment) { try { // Do the enlistment on the proxy. localResourceManagerShim = ResourceManagerShim; if (localResourceManagerShim == null) { // The TM must be down. Throw the appropriate exception. throw TransactionManagerCommunicationException.Create(SR.TraceSourceOletx, null); } if ((enlistmentOptions & EnlistmentOptions.EnlistDuringPrepareRequired) != 0) { oletxTransaction.RealTransaction.TransactionShim.Phase0Enlist(enlistment, out phase0Shim); enlistment.Phase0EnlistmentShim = phase0Shim; } localResourceManagerShim.Enlist(oletxTransaction.RealTransaction.TransactionShim, enlistment, out enlistmentShim); enlistment.EnlistmentShim = enlistmentShim; } catch (COMException comException) { // There is no string mapping for XACT_E_TOOMANY_ENLISTMENTS, so we need to do it here. if (comException.ErrorCode == OletxHelper.XACT_E_TOOMANY_ENLISTMENTS) { throw TransactionException.Create( SR.OletxTooManyEnlistments, comException, enlistment == null ? Guid.Empty : enlistment.DistributedTxId); } OletxTransactionManager.ProxyException(comException); throw; } } enlistmentSucceeded = true; } finally { if (!enlistmentSucceeded && (enlistmentOptions & EnlistmentOptions.EnlistDuringPrepareRequired) != 0 && undecidedEnlistmentsIncremented) { oletxTransaction.RealTransaction.DecrementUndecidedEnlistments(); } } return(enlistment); }
internal void ReenlistThread(object?state) { int localLoopCount; bool done; OletxEnlistment? localEnlistment; ResourceManagerShim?localResourceManagerShim; bool success; Timer? localTimer = null; bool disposeLocalTimer = false; OletxResourceManager resourceManager = (OletxResourceManager)state !; try { TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log; if (etwLog.IsEnabled()) { etwLog.MethodEnter(TraceSourceType.TraceSourceOleTx, this, $"{nameof(OletxResourceManager)}.{nameof(ReenlistThread)}"); } lock (resourceManager) { localResourceManagerShim = resourceManager.ResourceManagerShim; localTimer = resourceManager.ReenlistThreadTimer; resourceManager.ReenlistThreadTimer = null; resourceManager.reenlistThread = Thread.CurrentThread; } // We only want to do work if we have a resourceManagerShim. if (localResourceManagerShim != null) { lock (resourceManager.ReenlistList) { // Get the current count on the list. localLoopCount = resourceManager.ReenlistList.Count; } done = false; while (!done && localLoopCount > 0 && localResourceManagerShim != null) { lock (resourceManager.ReenlistList) { localEnlistment = null; localLoopCount--; if (resourceManager.ReenlistList.Count == 0) { done = true; } else { localEnlistment = resourceManager.ReenlistList[0] as OletxEnlistment; if (localEnlistment == null) { if (etwLog.IsEnabled()) { etwLog.InternalError(); } throw TransactionException.Create(SR.InternalError, null); } resourceManager.ReenlistList.RemoveAt(0); object syncRoot = localEnlistment; lock (syncRoot) { if (OletxEnlistment.OletxEnlistmentState.Done == localEnlistment.State) { // We may be racing with a RecoveryComplete here. Just forget about this // enlistment. localEnlistment = null; } else if (OletxEnlistment.OletxEnlistmentState.Prepared != localEnlistment.State) { // The app hasn't yet responded to Prepare, so we don't know // if it is indoubt or not yet. So just re-add it to the end // of the list. resourceManager.ReenlistList.Add(localEnlistment); localEnlistment = null; } } } } if (localEnlistment != null) { OletxTransactionOutcome localOutcome = OletxTransactionOutcome.NotKnownYet; try { Debug.Assert(localResourceManagerShim != null, "ReenlistThread - localResourceManagerShim is null"); // Make sure we have a prepare info. if (localEnlistment.ProxyPrepareInfoByteArray == null) { Debug.Assert(false, string.Format(null, "this.prepareInfoByteArray == null in RecoveryInformation()")); if (etwLog.IsEnabled()) { etwLog.InternalError(); } throw TransactionException.Create(SR.InternalError, null); } localResourceManagerShim.Reenlist(localEnlistment.ProxyPrepareInfoByteArray, out localOutcome); if (localOutcome == OletxTransactionOutcome.NotKnownYet) { object syncRoot = localEnlistment; lock (syncRoot) { if (OletxEnlistment.OletxEnlistmentState.Done == localEnlistment.State) { // We may be racing with a RecoveryComplete here. Just forget about this // enlistment. localEnlistment = null; } else { // Put the enlistment back on the end of the list for retry later. lock (resourceManager.ReenlistList) { resourceManager.ReenlistList.Add(localEnlistment); localEnlistment = null; } } } } } catch (COMException ex) when(ex.ErrorCode == OletxHelper.XACT_E_CONNECTION_DOWN) { if (etwLog.IsEnabled()) { etwLog.ExceptionConsumed(TraceSourceType.TraceSourceOleTx, ex); } // Release the resource manager so we can create a new one. resourceManager.ResourceManagerShim = null; // Now create a new resource manager with the proxy. localResourceManagerShim = resourceManager.ResourceManagerShim; } // If we get here and we still have localEnlistment, then we got the outcome. if (localEnlistment != null) { object syncRoot = localEnlistment; lock (syncRoot) { if (OletxEnlistment.OletxEnlistmentState.Done == localEnlistment.State) { // We may be racing with a RecoveryComplete here. Just forget about this // enlistment. localEnlistment = null; } else { // 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 (resourceManager.ReenlistList) { resourceManager.ReenlistPendingList.Add(localEnlistment); } if (localOutcome == OletxTransactionOutcome.Committed) { localEnlistment.State = OletxEnlistment.OletxEnlistmentState.Committing; if (etwLog.IsEnabled()) { etwLog.EnlistmentStatus(TraceSourceType.TraceSourceOleTx, localEnlistment.EnlistmentTraceId, NotificationCall.Commit); } localEnlistment.EnlistmentNotification !.Commit(localEnlistment); } else if (localOutcome == OletxTransactionOutcome.Aborted) { localEnlistment.State = OletxEnlistment.OletxEnlistmentState.Aborting; if (etwLog.IsEnabled()) { etwLog.EnlistmentStatus(TraceSourceType.TraceSourceOleTx, localEnlistment.EnlistmentTraceId, NotificationCall.Rollback); } localEnlistment.EnlistmentNotification !.Rollback(localEnlistment); } else { if (etwLog.IsEnabled()) { etwLog.InternalError(); } throw TransactionException.Create(SR.InternalError, null); } } } } // end of if null != localEnlistment } // end of if null != localEnlistment } } localResourceManagerShim = null; // Check to see if there is more work to do. lock (resourceManager.ReenlistList) { lock (resourceManager) { // Get the current count on the list. localLoopCount = resourceManager.ReenlistList.Count; if (localLoopCount <= 0 && resourceManager.ReenlistPendingList.Count <= 0) { // No more entries on the list. Try calling ReenlistComplete on the proxy, if // appropriate. // If the application has called RecoveryComplete, // we are responsible for calling ReenlistComplete on the // proxy. success = resourceManager.CallProxyReenlistComplete(); if (success) { // Okay, the reenlist thread is done and we don't need to schedule another one. disposeLocalTimer = true; } else { // We couldn't talk to the proxy to do ReenlistComplete, so schedule // the thread again for 10 seconds from now. resourceManager.ReenlistThreadTimer = localTimer; if (!localTimer !.Change(10000, Timeout.Infinite)) { throw TransactionException.CreateInvalidOperationException( TraceSourceType.TraceSourceLtm, SR.UnexpectedTimerFailure, null); } } } else { // There are still entries on the list, so they must not be // resovled, yet. Schedule the thread again in 10 seconds. resourceManager.ReenlistThreadTimer = localTimer; if (!localTimer !.Change(10000, Timeout.Infinite)) { throw TransactionException.CreateInvalidOperationException( TraceSourceType.TraceSourceLtm, SR.UnexpectedTimerFailure, null); } } resourceManager.reenlistThread = null; } if (etwLog.IsEnabled()) { etwLog.MethodExit(TraceSourceType.TraceSourceOleTx, this, $"{nameof(OletxResourceManager)}.{nameof(ReenlistThread)}"); } } } // end of outer-most try finally { localResourceManagerShim = null; if (disposeLocalTimer && localTimer != null) { localTimer.Dispose(); } } } // end of ReenlistThread method;
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 void ReenlistThread(object state) { int count = 0; bool flag = false; OletxEnlistment enlistment = null; IResourceManagerShim resourceManagerShim = null; Timer reenlistThreadTimer = null; bool flag2 = false; OletxResourceManager manager = (OletxResourceManager)state; try { if (DiagnosticTrace.Information) { MethodEnteredTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), "OletxResourceManager.ReenlistThread"); } lock (manager) { resourceManagerShim = manager.ResourceManagerShim; reenlistThreadTimer = manager.reenlistThreadTimer; manager.reenlistThreadTimer = null; manager.reenlistThread = Thread.CurrentThread; } if (resourceManagerShim != null) { lock (manager.reenlistList) { count = manager.reenlistList.Count; } flag = false; while ((!flag && (count > 0)) && (resourceManagerShim != null)) { lock (manager.reenlistList) { enlistment = null; count--; if (manager.reenlistList.Count == 0) { flag = true; } else { enlistment = manager.reenlistList[0] as OletxEnlistment; if (enlistment == null) { if (DiagnosticTrace.Critical) { InternalErrorTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), ""); } throw TransactionException.Create(System.Transactions.SR.GetString("TraceSourceOletx"), System.Transactions.SR.GetString("InternalError"), null); } manager.reenlistList.RemoveAt(0); object obj7 = enlistment; lock (obj7) { if (OletxEnlistment.OletxEnlistmentState.Done == enlistment.State) { enlistment = null; } else if (OletxEnlistment.OletxEnlistmentState.Prepared != enlistment.State) { manager.reenlistList.Add(enlistment); enlistment = null; } } } } if (enlistment != null) { OletxTransactionOutcome notKnownYet = OletxTransactionOutcome.NotKnownYet; try { if (enlistment.ProxyPrepareInfoByteArray == null) { if (DiagnosticTrace.Critical) { InternalErrorTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), ""); } throw TransactionException.Create(System.Transactions.SR.GetString("TraceSourceOletx"), System.Transactions.SR.GetString("InternalError"), null); } resourceManagerShim.Reenlist((uint)enlistment.ProxyPrepareInfoByteArray.Length, enlistment.ProxyPrepareInfoByteArray, out notKnownYet); if (notKnownYet == OletxTransactionOutcome.NotKnownYet) { object obj5 = enlistment; lock (obj5) { if (OletxEnlistment.OletxEnlistmentState.Done == enlistment.State) { enlistment = null; } else { lock (manager.reenlistList) { manager.reenlistList.Add(enlistment); enlistment = null; } } } } } catch (COMException exception) { if (System.Transactions.Oletx.NativeMethods.XACT_E_CONNECTION_DOWN != exception.ErrorCode) { throw; } if (DiagnosticTrace.Verbose) { ExceptionConsumedTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), exception); } if (System.Transactions.Oletx.NativeMethods.XACT_E_CONNECTION_DOWN == exception.ErrorCode) { manager.ResourceManagerShim = null; resourceManagerShim = manager.ResourceManagerShim; } } if (enlistment != null) { object obj3 = enlistment; lock (obj3) { if (OletxEnlistment.OletxEnlistmentState.Done != enlistment.State) { lock (manager.reenlistList) { manager.reenlistPendingList.Add(enlistment); } if (OletxTransactionOutcome.Committed != notKnownYet) { if (OletxTransactionOutcome.Aborted != notKnownYet) { if (DiagnosticTrace.Critical) { InternalErrorTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), ""); } throw TransactionException.Create(System.Transactions.SR.GetString("TraceSourceOletx"), System.Transactions.SR.GetString("InternalError"), null); } enlistment.State = OletxEnlistment.OletxEnlistmentState.Aborting; if (DiagnosticTrace.Verbose) { EnlistmentNotificationCallTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), enlistment.EnlistmentTraceId, NotificationCall.Rollback); } enlistment.EnlistmentNotification.Rollback(enlistment); } else { enlistment.State = OletxEnlistment.OletxEnlistmentState.Committing; if (DiagnosticTrace.Verbose) { EnlistmentNotificationCallTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), enlistment.EnlistmentTraceId, NotificationCall.Commit); } enlistment.EnlistmentNotification.Commit(enlistment); } } else { enlistment = null; } continue; } } } } } resourceManagerShim = null; lock (manager.reenlistList) { lock (manager) { count = manager.reenlistList.Count; if ((0 >= count) && (0 >= manager.reenlistPendingList.Count)) { if (!manager.CallProxyReenlistComplete()) { manager.reenlistThreadTimer = reenlistThreadTimer; if (!reenlistThreadTimer.Change(0x2710, -1)) { throw TransactionException.CreateInvalidOperationException(System.Transactions.SR.GetString("TraceSourceLtm"), System.Transactions.SR.GetString("UnexpectedTimerFailure"), null); } } else { flag2 = true; } } else { manager.reenlistThreadTimer = reenlistThreadTimer; if (!reenlistThreadTimer.Change(0x2710, -1)) { throw TransactionException.CreateInvalidOperationException(System.Transactions.SR.GetString("TraceSourceLtm"), System.Transactions.SR.GetString("UnexpectedTimerFailure"), null); } } manager.reenlistThread = null; } if (DiagnosticTrace.Information) { MethodExitedTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), "OletxResourceManager.ReenlistThread"); } } } finally { resourceManagerShim = null; if (flag2 && (reenlistThreadTimer != null)) { reenlistThreadTimer.Dispose(); } } }
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(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)); }
internal OletxEnlistment EnlistDurable(OletxTransaction oletxTransaction, bool canDoSinglePhase, IEnlistmentNotificationInternal enlistmentNotification, EnlistmentOptions enlistmentOptions) { IResourceManagerShim resourceManagerShim = null; IPhase0EnlistmentShim shim2 = null; IEnlistmentShim enlistmentShim = null; IntPtr zero = IntPtr.Zero; bool flag3 = false; bool flag2 = false; OletxEnlistment target = new OletxEnlistment(canDoSinglePhase, enlistmentNotification, oletxTransaction.RealTransaction.TxGuid, enlistmentOptions, this, oletxTransaction); bool flag = false; RuntimeHelpers.PrepareConstrainedRegions(); try { if ((enlistmentOptions & EnlistmentOptions.EnlistDuringPrepareRequired) != EnlistmentOptions.None) { RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { oletxTransaction.RealTransaction.IncrementUndecidedEnlistments(); flag2 = true; } } lock (target) { RuntimeHelpers.PrepareConstrainedRegions(); try { resourceManagerShim = this.ResourceManagerShim; if (resourceManagerShim == null) { throw TransactionManagerCommunicationException.Create(System.Transactions.SR.GetString("TraceSourceOletx"), null); } if ((enlistmentOptions & EnlistmentOptions.EnlistDuringPrepareRequired) != EnlistmentOptions.None) { zero = HandleTable.AllocHandle(target); RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { oletxTransaction.RealTransaction.TransactionShim.Phase0Enlist(zero, out shim2); flag3 = true; } target.Phase0EnlistmentShim = shim2; } target.phase1Handle = HandleTable.AllocHandle(target); resourceManagerShim.Enlist(oletxTransaction.RealTransaction.TransactionShim, target.phase1Handle, out enlistmentShim); target.EnlistmentShim = enlistmentShim; } catch (COMException exception) { if (System.Transactions.Oletx.NativeMethods.XACT_E_TOOMANY_ENLISTMENTS == exception.ErrorCode) { throw TransactionException.Create(System.Transactions.SR.GetString("TraceSourceOletx"), System.Transactions.SR.GetString("OletxTooManyEnlistments"), exception); } OletxTransactionManager.ProxyException(exception); throw; } finally { if (target.EnlistmentShim == null) { if ((zero != IntPtr.Zero) && !flag3) { HandleTable.FreeHandle(zero); } if (target.phase1Handle != IntPtr.Zero) { HandleTable.FreeHandle(target.phase1Handle); } } } } flag = true; } finally { if ((!flag && ((enlistmentOptions & EnlistmentOptions.EnlistDuringPrepareRequired) != EnlistmentOptions.None)) && flag2) { oletxTransaction.RealTransaction.DecrementUndecidedEnlistments(); } } return(target); }
internal OletxTransactionManager( string nodeName ) { lock ( ClassSyncObject ) { // If we have not already initialized the shim factory and started the notification // thread, do so now. if (null == OletxTransactionManager.proxyShimFactory) { Int32 error = NativeMethods.GetNotificationFactory( OletxTransactionManager.ShimWaitHandle.SafeWaitHandle, out OletxTransactionManager.proxyShimFactory ); if (0 != error) { throw TransactionException.Create(SR.GetString(SR.TraceSourceOletx), SR.GetString(SR.UnableToGetNotificationShimFactory), null); } ThreadPool.UnsafeRegisterWaitForSingleObject( OletxTransactionManager.ShimWaitHandle, new WaitOrTimerCallback(OletxTransactionManager.ShimNotificationCallback), null, -1, false ); } } this.dtcTransactionManagerLock = new ReaderWriterLock(); this.nodeNameField = nodeName; // The DTC proxy doesn't like an empty string for node name on 64-bit platforms when // running as WOW64. It treats any non-null node name as a "remote" node and turns off // the WOW64 bit, causing problems when reading the registry. So if we got on empty // string for the node name, just treat it as null. if ((null != this.nodeNameField) && (0 == this.nodeNameField.Length)) { this.nodeNameField = null; } if (DiagnosticTrace.Verbose) { DistributedTransactionManagerCreatedTraceRecord.Trace(SR.GetString(SR.TraceSourceOletx), this.GetType(), this.nodeNameField ); } // Initialize the properties from config. configuredTransactionOptions.IsolationLevel = isolationLevelProperty = TransactionManager.DefaultIsolationLevel; configuredTransactionOptions.Timeout = timeoutProperty = TransactionManager.DefaultTimeout; this.internalResourceManager = new OletxInternalResourceManager(this); dtcTransactionManagerLock.AcquireWriterLock(-1); try { this.dtcTransactionManager = new DtcTransactionManager(this.nodeNameField, this); } finally { dtcTransactionManagerLock.ReleaseWriterLock(); } if (resourceManagerHashTable == null) { resourceManagerHashTable = new Hashtable(2); resourceManagerHashTableLock = new System.Threading.ReaderWriterLock(); } }