internal void RemoveFromReenlistPending(OletxEnlistment enlistment) { lock (this.reenlistList) { this.reenlistPendingList.Remove(enlistment); lock (this) { if (((this.reenlistThreadTimer != null) && (this.reenlistList.Count == 0)) && ((this.reenlistPendingList.Count == 0) && !this.reenlistThreadTimer.Change(0, -1))) { throw TransactionException.CreateInvalidOperationException(System.Transactions.SR.GetString("TraceSourceLtm"), System.Transactions.SR.GetString("UnexpectedTimerFailure"), null); } } } }
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 void TMDownFromInternalRM(OletxTransactionManager oletxTM) { OletxEnlistment enlistment = null; IDictionaryEnumerator enumerator = null; Hashtable hashtable = null; this.ResourceManagerShim = null; lock (this.enlistmentHashtable.SyncRoot) { hashtable = (Hashtable)this.enlistmentHashtable.Clone(); } enumerator = hashtable.GetEnumerator(); while (enumerator.MoveNext()) { enlistment = enumerator.Value as OletxEnlistment; if (enlistment != null) { enlistment.TMDownFromInternalRM(oletxTM); } } }
internal OletxEnlistment ReenlistTransaction( Guid resourceManagerIdentifier, byte[] recoveryInformation, IEnlistmentNotificationInternal enlistmentNotification ) { if (null == recoveryInformation) { throw new ArgumentNullException("recoveryInformation"); } if (null == enlistmentNotification) { throw new ArgumentNullException("enlistmentNotification"); } // Now go find the resource manager in the collection. OletxResourceManager oletxResourceManager = RegisterResourceManager(resourceManagerIdentifier); if (null == oletxResourceManager) { throw new ArgumentException(SR.GetString(SR.InvalidArgument), "resourceManagerIdentifier"); } if (oletxResourceManager.RecoveryCompleteCalledByApplication) { throw new InvalidOperationException(SR.GetString(SR.ReenlistAfterRecoveryComplete)); } // Now ask the resource manager to reenlist. OletxEnlistment returnValue = oletxResourceManager.Reenlist( recoveryInformation.Length, recoveryInformation, enlistmentNotification ); return(returnValue); }
internal static void ShimNotificationCallback(object state, bool timeout) { IntPtr zero = IntPtr.Zero; ShimNotificationType none = ShimNotificationType.None; bool isSinglePhase = false; bool abortingHint = false; uint prepareInfoSize = 0; CoTaskMemHandle prepareInfo = null; bool releaseRequired = false; bool flag3 = false; IDtcProxyShimFactory factory = null; if (DiagnosticTrace.Verbose) { MethodEnteredTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), "OletxTransactionManager.ShimNotificationCallback"); } Thread.BeginCriticalRegion(); try { Label_003D: factory = proxyShimFactory; try { object obj2; OletxResourceManager manager2; byte[] buffer; Thread.BeginThreadAffinity(); RuntimeHelpers.PrepareConstrainedRegions(); try { factory.GetNotification(out zero, out none, out isSinglePhase, out abortingHint, out releaseRequired, out prepareInfoSize, out prepareInfo); } finally { if (releaseRequired) { if (HandleTable.FindHandle(zero) is OletxInternalResourceManager) { processingTmDown = true; Monitor.Enter(proxyShimFactory); } else { releaseRequired = false; } factory.ReleaseNotificationLock(); } Thread.EndThreadAffinity(); } if (processingTmDown) { lock (proxyShimFactory) { } } if (none != ShimNotificationType.None) { obj2 = HandleTable.FindHandle(zero); switch (none) { case ShimNotificationType.Phase0RequestNotify: try { OletxPhase0VolatileEnlistmentContainer container5 = obj2 as OletxPhase0VolatileEnlistmentContainer; if (container5 != null) { DiagnosticTrace.SetActivityId(container5.TransactionIdentifier); container5.Phase0Request(abortingHint); } else { OletxEnlistment enlistment8 = obj2 as OletxEnlistment; if (enlistment8 != null) { DiagnosticTrace.SetActivityId(enlistment8.TransactionIdentifier); enlistment8.Phase0Request(abortingHint); } else { Environment.FailFast(System.Transactions.SR.GetString("InternalError")); } } goto Label_0444; } finally { HandleTable.FreeHandle(zero); } break; case ShimNotificationType.VoteRequestNotify: break; case ShimNotificationType.PrepareRequestNotify: goto Label_02B0; case ShimNotificationType.CommitRequestNotify: goto Label_031A; case ShimNotificationType.AbortRequestNotify: goto Label_0358; case ShimNotificationType.CommittedNotify: try { OutcomeEnlistment enlistment7 = obj2 as OutcomeEnlistment; if (enlistment7 != null) { DiagnosticTrace.SetActivityId(enlistment7.TransactionIdentifier); enlistment7.Committed(); } else { OletxPhase1VolatileEnlistmentContainer container3 = obj2 as OletxPhase1VolatileEnlistmentContainer; if (container3 != null) { DiagnosticTrace.SetActivityId(container3.TransactionIdentifier); container3.Committed(); } else { Environment.FailFast(System.Transactions.SR.GetString("InternalError")); } } goto Label_0444; } finally { HandleTable.FreeHandle(zero); } goto Label_0203; case ShimNotificationType.AbortedNotify: goto Label_0203; case ShimNotificationType.InDoubtNotify: goto Label_0251; case ShimNotificationType.EnlistmentTmDownNotify: goto Label_0396; case ShimNotificationType.ResourceManagerTmDownNotify: goto Label_03CD; default: goto Label_0410; } OletxPhase1VolatileEnlistmentContainer container4 = obj2 as OletxPhase1VolatileEnlistmentContainer; if (container4 != null) { DiagnosticTrace.SetActivityId(container4.TransactionIdentifier); container4.VoteRequest(); } else { Environment.FailFast(System.Transactions.SR.GetString("InternalError")); } } goto Label_0444; Label_0203 :; try { OutcomeEnlistment enlistment6 = obj2 as OutcomeEnlistment; if (enlistment6 != null) { DiagnosticTrace.SetActivityId(enlistment6.TransactionIdentifier); enlistment6.Aborted(); } else { OletxPhase1VolatileEnlistmentContainer container2 = obj2 as OletxPhase1VolatileEnlistmentContainer; if (container2 != null) { DiagnosticTrace.SetActivityId(container2.TransactionIdentifier); container2.Aborted(); } } goto Label_0444; } finally { HandleTable.FreeHandle(zero); } Label_0251 :; try { OutcomeEnlistment enlistment5 = obj2 as OutcomeEnlistment; if (enlistment5 != null) { DiagnosticTrace.SetActivityId(enlistment5.TransactionIdentifier); enlistment5.InDoubt(); } else { OletxPhase1VolatileEnlistmentContainer container = obj2 as OletxPhase1VolatileEnlistmentContainer; if (container != null) { DiagnosticTrace.SetActivityId(container.TransactionIdentifier); container.InDoubt(); } else { Environment.FailFast(System.Transactions.SR.GetString("InternalError")); } } goto Label_0444; } finally { HandleTable.FreeHandle(zero); } Label_02B0: buffer = new byte[prepareInfoSize]; Marshal.Copy(prepareInfo.DangerousGetHandle(), buffer, 0, Convert.ToInt32(prepareInfoSize)); bool flag2 = true; try { OletxEnlistment enlistment4 = obj2 as OletxEnlistment; if (enlistment4 != null) { DiagnosticTrace.SetActivityId(enlistment4.TransactionIdentifier); flag2 = enlistment4.PrepareRequest(isSinglePhase, buffer); } else { Environment.FailFast(System.Transactions.SR.GetString("InternalError")); } goto Label_0444; } finally { if (flag2) { HandleTable.FreeHandle(zero); } } Label_031A :; try { OletxEnlistment enlistment3 = obj2 as OletxEnlistment; if (enlistment3 != null) { DiagnosticTrace.SetActivityId(enlistment3.TransactionIdentifier); enlistment3.CommitRequest(); } else { Environment.FailFast(System.Transactions.SR.GetString("InternalError")); } goto Label_0444; } finally { HandleTable.FreeHandle(zero); } Label_0358 :; try { OletxEnlistment enlistment2 = obj2 as OletxEnlistment; if (enlistment2 != null) { DiagnosticTrace.SetActivityId(enlistment2.TransactionIdentifier); enlistment2.AbortRequest(); } else { Environment.FailFast(System.Transactions.SR.GetString("InternalError")); } goto Label_0444; } finally { HandleTable.FreeHandle(zero); } Label_0396 :; try { OletxEnlistment enlistment = obj2 as OletxEnlistment; if (enlistment != null) { DiagnosticTrace.SetActivityId(enlistment.TransactionIdentifier); enlistment.TMDown(); } else { Environment.FailFast(System.Transactions.SR.GetString("InternalError")); } goto Label_0444; } finally { HandleTable.FreeHandle(zero); } Label_03CD: manager2 = obj2 as OletxResourceManager; try { if (manager2 != null) { manager2.TMDown(); } else { OletxInternalResourceManager manager = obj2 as OletxInternalResourceManager; if (manager != null) { manager.TMDown(); } else { Environment.FailFast(System.Transactions.SR.GetString("InternalError")); } } goto Label_0444; } finally { HandleTable.FreeHandle(zero); } Label_0410: Environment.FailFast(System.Transactions.SR.GetString("InternalError")); } finally { if (prepareInfo != null) { prepareInfo.Close(); } if (releaseRequired) { releaseRequired = false; processingTmDown = false; Monitor.Exit(proxyShimFactory); } } Label_0444: if (none != ShimNotificationType.None) { goto Label_003D; } flag3 = true; } finally { if (releaseRequired) { releaseRequired = false; processingTmDown = false; Monitor.Exit(proxyShimFactory); } if (!flag3 && (zero != IntPtr.Zero)) { HandleTable.FreeHandle(zero); } Thread.EndCriticalRegion(); } if (DiagnosticTrace.Verbose) { MethodExitedTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), "OletxTransactionManager.ShimNotificationCallback"); } }
// This routine searches the reenlistPendingList for the specified enlistment and if it finds // it, removes it from the list. An enlistment calls this routine when it is "finishing" because // the RM has called EnlistmentDone or it was InDoubt. But it only calls it if the enlistment does NOT // have a WrappedTransactionEnlistmentAsync value, indicating that it is a recovery enlistment. internal void RemoveFromReenlistPending( OletxEnlistment enlistment ) { // We lock the reenlistList because we have decided to lock that list when accessing either // the reenlistList or the reenlistPendingList. lock ( reenlistList ) { // This will do a linear search of the list, but that is what we need to do because // the enlistments may change indicies while notifications are outstanding. Also, // this does not throw if the enlistment isn't on the list. reenlistPendingList.Remove( enlistment ); lock ( this ) { // If we have a ReenlistThread timer and both the reenlistList and the reenlistPendingList // are empty, kick the ReenlistThread now. if ( ( null != this.reenlistThreadTimer ) && ( 0 == this.reenlistList.Count ) && ( 0 == this.reenlistPendingList.Count ) ) { if ( !this.reenlistThreadTimer.Change( 0, Timeout.Infinite )) { throw TransactionException.CreateInvalidOperationException( SR.GetString( SR.TraceSourceLtm ), SR.GetString(SR.UnexpectedTimerFailure), null ); } } } } }
internal OletxEnlistment Reenlist( int prepareInfoLength, byte[] prepareInfo, IEnlistmentNotificationInternal enlistmentNotification ) { OletxTransactionOutcome outcome = OletxTransactionOutcome.NotKnownYet; OletxTransactionStatus xactStatus = OletxTransactionStatus.OLETX_TRANSACTION_STATUS_NONE; // Put the recovery information into a stream. MemoryStream stream = new MemoryStream( prepareInfo ); // First extract the OletxRecoveryInformation from the stream. IFormatter formatter = new BinaryFormatter(); OletxRecoveryInformation oletxRecoveryInformation; try { oletxRecoveryInformation = formatter.Deserialize( stream ) as OletxRecoveryInformation; } catch (SerializationException se) { throw new ArgumentException( SR.GetString( SR.InvalidArgument ), "prepareInfo", se ); } if ( null == oletxRecoveryInformation ) { throw new ArgumentException( SR.GetString( SR.InvalidArgument ), "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] = oletxRecoveryInformation.proxyRecoveryInformation[i + 16]; } Guid rmGuid = new Guid( rmGuidArray ); if ( rmGuid != this.resourceManagerIdentifier ) { throw TransactionException.Create( SR.GetString( SR.TraceSourceOletx ), SR.GetString( SR.ResourceManagerIdDoesNotMatchRecoveryInformation ), null ); } // Ask the proxy resource manager to reenlist. IResourceManagerShim localResourceManagerShim = null; try { localResourceManagerShim = this.ResourceManagerShim; if ( null == localResourceManagerShim ) { // 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.GetString( SR.DtcTransactionManagerUnavailable ), NativeMethods.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( Convert.ToUInt32( oletxRecoveryInformation.proxyRecoveryInformation.Length, CultureInfo.InvariantCulture ), oletxRecoveryInformation.proxyRecoveryInformation, 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 ) { if ( NativeMethods.XACT_E_CONNECTION_DOWN == ex.ErrorCode ) { xactStatus = OletxTransactionStatus.OLETX_TRANSACTION_STATUS_PREPARED; this.ResourceManagerShim = null; StartReenlistThread(); if ( DiagnosticTrace.Verbose ) { ExceptionConsumedTraceRecord.Trace( SR.GetString( SR.TraceSourceOletx ), ex ); } } else { throw; } } finally { localResourceManagerShim = null; } // Now create our enlistment to tell the client the outcome. OletxEnlistment enlistment = new OletxEnlistment( enlistmentNotification, xactStatus, oletxRecoveryInformation.proxyRecoveryInformation, this ); return enlistment; }
internal OletxEnlistment EnlistDurable( OletxTransaction oletxTransaction, bool canDoSinglePhase, IEnlistmentNotificationInternal enlistmentNotification, EnlistmentOptions enlistmentOptions ) { IResourceManagerShim localResourceManagerShim = null; Debug.Assert( null != oletxTransaction, "Argument is null" ); Debug.Assert( null != enlistmentNotification, "Argument is null" ); IEnlistmentShim enlistmentShim = null; IPhase0EnlistmentShim phase0Shim = null; Guid txUow = Guid.Empty; IntPtr handlePhase0 = IntPtr.Zero; bool phase0EnlistSucceeded = false; bool undecidedEnlistmentsIncremented = false; // Create our enlistment object. OletxEnlistment enlistment = new OletxEnlistment( canDoSinglePhase, enlistmentNotification, oletxTransaction.RealTransaction.TxGuid, enlistmentOptions, this, oletxTransaction ); bool enlistmentSucceeded = false; RuntimeHelpers.PrepareConstrainedRegions(); try { if ( (enlistmentOptions & EnlistmentOptions.EnlistDuringPrepareRequired) != 0 ) { RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { oletxTransaction.RealTransaction.IncrementUndecidedEnlistments(); undecidedEnlistmentsIncremented = true; } } // This entire sequense needs to be executed before we can go on. lock ( enlistment ) { RuntimeHelpers.PrepareConstrainedRegions(); try { // Do the enlistment on the proxy. localResourceManagerShim = this.ResourceManagerShim; if ( null == localResourceManagerShim ) { // The TM must be down. Throw the appropriate exception. throw TransactionManagerCommunicationException.Create( SR.GetString( SR.TraceSourceOletx), null ); } if ( (enlistmentOptions & EnlistmentOptions.EnlistDuringPrepareRequired) != 0 ) { // We need to create an EnlistmentNotifyShim if native threads are not allowed to enter managed code. handlePhase0 = HandleTable.AllocHandle( enlistment ); RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { oletxTransaction.RealTransaction.TransactionShim.Phase0Enlist( handlePhase0, out phase0Shim ); phase0EnlistSucceeded = true; } enlistment.Phase0EnlistmentShim = phase0Shim; } enlistment.phase1Handle = HandleTable.AllocHandle( enlistment ); localResourceManagerShim.Enlist( oletxTransaction.RealTransaction.TransactionShim, enlistment.phase1Handle, 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 ( NativeMethods.XACT_E_TOOMANY_ENLISTMENTS == comException.ErrorCode ) { throw TransactionException.Create( SR.GetString( SR.TraceSourceOletx ), SR.GetString( SR.OletxTooManyEnlistments ), comException ); } OletxTransactionManager.ProxyException( comException ); throw; } finally { if ( enlistment.EnlistmentShim == null ) { // If the enlistment shim was never assigned then something blew up. // Perform some cleanup. if ( handlePhase0 != IntPtr.Zero && !phase0EnlistSucceeded ) { // Only clean up the phase0 handle if the phase 0 enlistment did not succeed. // This is because the notification processing code expects it to exist. HandleTable.FreeHandle( handlePhase0 ); } if ( enlistment.phase1Handle != IntPtr.Zero ) { HandleTable.FreeHandle( enlistment.phase1Handle ); } // Note this code used to call unenlist however this allows race conditions where // it is unclear if the handlePhase0 should be freed or not. The notification // thread should get a phase0Request and it will free the Handle at that point. } } } enlistmentSucceeded = true; } finally { if ( !enlistmentSucceeded && ((enlistmentOptions & EnlistmentOptions.EnlistDuringPrepareRequired) != 0) && undecidedEnlistmentsIncremented ) { oletxTransaction.RealTransaction.DecrementUndecidedEnlistments(); } } return enlistment; }
internal static void ShimNotificationCallback(object state, bool timeout) { // First we need to get the notification from the shim factory. IntPtr enlistmentHandleIntPtr = IntPtr.Zero; ShimNotificationType shimNotificationType = ShimNotificationType.None; bool isSinglePhase = false; bool abortingHint = false; UInt32 prepareInfoSize = 0; CoTaskMemHandle prepareInfoBuffer = null; bool holdingNotificationLock = false; bool cleanExit = false; IDtcProxyShimFactory localProxyShimFactory = null; if (DiagnosticTrace.Verbose) { MethodEnteredTraceRecord.Trace(SR.GetString(SR.TraceSourceOletx), "OletxTransactionManager.ShimNotificationCallback" ); } // This lock doesn't really protect any of our data. It is here so that if an exception occurs // while calling out to the app, we get an escalation to AppDomainUnload. Thread.BeginCriticalRegion(); try { do { // Take a local copy of the proxyShimFactory because if we get an RM TMDown notification, // we will still hold the critical section in that factory, but processing of the TMDown will // cause replacement of the OletxTransactionManager.proxyShimFactory. localProxyShimFactory = OletxTransactionManager.proxyShimFactory; try { Thread.BeginThreadAffinity(); RuntimeHelpers.PrepareConstrainedRegions(); try { localProxyShimFactory.GetNotification( out enlistmentHandleIntPtr, out shimNotificationType, out isSinglePhase, out abortingHint, out holdingNotificationLock, out prepareInfoSize, out prepareInfoBuffer ); } finally { if (holdingNotificationLock) { if ((HandleTable.FindHandle(enlistmentHandleIntPtr)) is OletxInternalResourceManager) { // In this case we know that the TM has gone down and we need to exchange // the native lock for a managed lock. processingTmDown = true; #pragma warning disable 0618 //@ System.Threading.Monitor.Enter(OletxTransactionManager.proxyShimFactory); #pragma warning restore 0618 } else { holdingNotificationLock = false; } localProxyShimFactory.ReleaseNotificationLock(); } Thread.EndThreadAffinity(); } // If a TM down is being processed it is possible that the native lock // has been exchanged for a managed lock. In that case we need to attempt // to take a lock to hold up processing more events until the TM down // processing is complete. if (processingTmDown) { lock (OletxTransactionManager.proxyShimFactory) { // We don't do any work under this lock just make sure that we // can take it. } } if (ShimNotificationType.None != shimNotificationType) { Object target = HandleTable.FindHandle(enlistmentHandleIntPtr); // Next, based on the notification type, cast the Handle accordingly and make // the appropriate call on the enlistment. switch (shimNotificationType) { case ShimNotificationType.Phase0RequestNotify: { try { OletxPhase0VolatileEnlistmentContainer ph0VolEnlistContainer = target as OletxPhase0VolatileEnlistmentContainer; if (null != ph0VolEnlistContainer) { DiagnosticTrace.SetActivityId( ph0VolEnlistContainer.TransactionIdentifier); //CSDMain 91509 - We now synchronize this call with the AddDependentClone call in RealOleTxTransaction ph0VolEnlistContainer.Phase0Request(abortingHint); } else { OletxEnlistment enlistment = target as OletxEnlistment; if (null != enlistment) { DiagnosticTrace.SetActivityId( enlistment.TransactionIdentifier); enlistment.Phase0Request(abortingHint); } else { Environment.FailFast(SR.GetString(SR.InternalError)); } } } finally { // We aren't going to get any more notifications on this. HandleTable.FreeHandle(enlistmentHandleIntPtr); } break; } case ShimNotificationType.VoteRequestNotify: { OletxPhase1VolatileEnlistmentContainer ph1VolEnlistContainer = target as OletxPhase1VolatileEnlistmentContainer; if (null != ph1VolEnlistContainer) { DiagnosticTrace.SetActivityId( ph1VolEnlistContainer.TransactionIdentifier); ph1VolEnlistContainer.VoteRequest(); } else { Environment.FailFast(SR.GetString(SR.InternalError)); } break; } case ShimNotificationType.CommittedNotify: { try { OutcomeEnlistment outcomeEnlistment = target as OutcomeEnlistment; if (null != outcomeEnlistment) { DiagnosticTrace.SetActivityId( outcomeEnlistment.TransactionIdentifier); outcomeEnlistment.Committed(); } else { OletxPhase1VolatileEnlistmentContainer ph1VolEnlistContainer = target as OletxPhase1VolatileEnlistmentContainer; if (null != ph1VolEnlistContainer) { DiagnosticTrace.SetActivityId( ph1VolEnlistContainer.TransactionIdentifier); ph1VolEnlistContainer.Committed(); } else { Environment.FailFast(SR.GetString(SR.InternalError)); } } } finally { // We aren't going to get any more notifications on this. HandleTable.FreeHandle(enlistmentHandleIntPtr); } break; } case ShimNotificationType.AbortedNotify: { try { OutcomeEnlistment outcomeEnlistment = target as OutcomeEnlistment; if (null != outcomeEnlistment) { DiagnosticTrace.SetActivityId( outcomeEnlistment.TransactionIdentifier); outcomeEnlistment.Aborted(); } else { OletxPhase1VolatileEnlistmentContainer ph1VolEnlistContainer = target as OletxPhase1VolatileEnlistmentContainer; if (null != ph1VolEnlistContainer) { DiagnosticTrace.SetActivityId( ph1VolEnlistContainer.TransactionIdentifier); ph1VolEnlistContainer.Aborted(); } // else // Voters may receive notifications even // in cases where they therwise respond // negatively to the vote request. It is // also not guaranteed that we will get a // notification if we do respond negatively. // The only safe thing to do is to free the // Handle when we abort the transaction // with a voter. These two things together // mean that we cannot guarantee that this // Handle will be alive when we get this // notification. } } finally { // We aren't going to get any more notifications on this. HandleTable.FreeHandle(enlistmentHandleIntPtr); } break; } case ShimNotificationType.InDoubtNotify: { try { OutcomeEnlistment outcomeEnlistment = target as OutcomeEnlistment; if (null != outcomeEnlistment) { DiagnosticTrace.SetActivityId( outcomeEnlistment.TransactionIdentifier); outcomeEnlistment.InDoubt(); } else { OletxPhase1VolatileEnlistmentContainer ph1VolEnlistContainer = target as OletxPhase1VolatileEnlistmentContainer; if (null != ph1VolEnlistContainer) { DiagnosticTrace.SetActivityId( ph1VolEnlistContainer.TransactionIdentifier); ph1VolEnlistContainer.InDoubt(); } else { Environment.FailFast(SR.GetString(SR.InternalError)); } } } finally { // We aren't going to get any more notifications on this. HandleTable.FreeHandle(enlistmentHandleIntPtr); } break; } case ShimNotificationType.PrepareRequestNotify: { byte[] prepareInfo = new byte[prepareInfoSize]; Marshal.Copy(prepareInfoBuffer.DangerousGetHandle(), prepareInfo, 0, Convert.ToInt32(prepareInfoSize)); bool enlistmentDone = true; try { OletxEnlistment enlistment = target as OletxEnlistment; if (null != enlistment) { DiagnosticTrace.SetActivityId( enlistment.TransactionIdentifier); enlistmentDone = enlistment.PrepareRequest( isSinglePhase, prepareInfo ); } else { Environment.FailFast(SR.GetString(SR.InternalError)); } } finally { if (enlistmentDone) { HandleTable.FreeHandle(enlistmentHandleIntPtr); } } break; } case ShimNotificationType.CommitRequestNotify: { try { OletxEnlistment enlistment = target as OletxEnlistment; if (null != enlistment) { DiagnosticTrace.SetActivityId( enlistment.TransactionIdentifier); enlistment.CommitRequest(); } else { Environment.FailFast(SR.GetString(SR.InternalError)); } } finally { // We aren't going to get any more notifications on this. HandleTable.FreeHandle(enlistmentHandleIntPtr); } break; } case ShimNotificationType.AbortRequestNotify: { try { OletxEnlistment enlistment = target as OletxEnlistment; if (null != enlistment) { DiagnosticTrace.SetActivityId( enlistment.TransactionIdentifier); enlistment.AbortRequest(); } else { Environment.FailFast(SR.GetString(SR.InternalError)); } } finally { // We aren't going to get any more notifications on this. HandleTable.FreeHandle(enlistmentHandleIntPtr); } break; } case ShimNotificationType.EnlistmentTmDownNotify: { try { OletxEnlistment enlistment = target as OletxEnlistment; if (null != enlistment) { DiagnosticTrace.SetActivityId( enlistment.TransactionIdentifier); enlistment.TMDown(); } else { Environment.FailFast(SR.GetString(SR.InternalError)); } } finally { // We aren't going to get any more notifications on this. HandleTable.FreeHandle(enlistmentHandleIntPtr); } break; } case ShimNotificationType.ResourceManagerTmDownNotify: { OletxResourceManager resourceManager = target as OletxResourceManager; try { if (null != resourceManager) { resourceManager.TMDown(); } else { OletxInternalResourceManager internalResourceManager = target as OletxInternalResourceManager; if (null != internalResourceManager) { internalResourceManager.TMDown(); } else { Environment.FailFast(SR.GetString(SR.InternalError)); } } } finally { HandleTable.FreeHandle(enlistmentHandleIntPtr); } // Note that we don't free the gchandle on the OletxResourceManager. These objects // are not going to go away. break; } default: { Environment.FailFast(SR.GetString(SR.InternalError)); break; } } } } finally { if (null != prepareInfoBuffer) { prepareInfoBuffer.Close(); } if (holdingNotificationLock) { holdingNotificationLock = false; processingTmDown = false; System.Threading.Monitor.Exit(OletxTransactionManager.proxyShimFactory); } } }while (ShimNotificationType.None != shimNotificationType); cleanExit = true; } finally { if (holdingNotificationLock) { holdingNotificationLock = false; processingTmDown = false; System.Threading.Monitor.Exit(OletxTransactionManager.proxyShimFactory); } if (!cleanExit && enlistmentHandleIntPtr != IntPtr.Zero) { HandleTable.FreeHandle(enlistmentHandleIntPtr); } Thread.EndCriticalRegion(); } if (DiagnosticTrace.Verbose) { MethodExitedTraceRecord.Trace(SR.GetString(SR.TraceSourceOletx), "OletxTransactionManager.ShimNotificationCallback" ); } }
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 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 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; }