From c879a1acb5358090c2939a3f3f590d876200c358 Mon Sep 17 00:00:00 2001 From: buyaa-n Date: Tue, 12 Nov 2019 21:59:33 -0800 Subject: [PATCH] Annotate System.Transactions.Local for nullable (dotnet/corefx#42465) * Annotate System.Transactions.Local for nullable * Reverting assert on Transaction.State property and make it nullabe * Small udpates * Applying feedback * Applying feedback * Update src/System.Transactions.Local/src/System/Transactions/Transaction.cs Co-Authored-By: Santiago Fernandez Madero Commit migrated from https://github.com/dotnet/corefx/commit/8f8b895f843e2b659c8a722c3e38548cfecdb271 --- .../ref/System.Transactions.Local.cs | 59 ++-- .../ref/System.Transactions.Local.csproj | 1 + .../src/System.Transactions.Local.csproj | 1 + .../System/Transactions/CommittableTransaction.cs | 13 +- .../System/Transactions/DependentTransaction.cs | 3 + .../System/Transactions/DistributedTransaction.cs | 10 +- .../System/Transactions/DurableEnlistmentState.cs | 31 +- .../src/System/Transactions/Enlistment.cs | 52 +-- .../src/System/Transactions/EnlistmentState.cs | 23 +- .../Transactions/EnlistmentTraceIdentifier.cs | 2 +- .../src/System/Transactions/EnterpriseServices.cs | 4 +- .../System/Transactions/ITransactionPromoter.cs | 2 +- .../src/System/Transactions/InternalTransaction.cs | 51 +-- .../src/System/Transactions/PreparingEnlistment.cs | 2 +- .../System/Transactions/SinglePhaseEnlistment.cs | 4 +- .../src/System/Transactions/Transaction.cs | 103 +++--- .../System/Transactions/TransactionException.cs | 70 ++-- .../System/Transactions/TransactionInformation.cs | 4 + .../src/System/Transactions/TransactionInterop.cs | 6 +- .../src/System/Transactions/TransactionManager.cs | 61 ++-- .../src/System/Transactions/TransactionOptions.cs | 2 +- .../src/System/Transactions/TransactionScope.cs | 55 ++-- .../src/System/Transactions/TransactionState.cs | 362 +++++++++++---------- .../src/System/Transactions/TransactionTable.cs | 72 ++-- .../Transactions/TransactionTraceIdentifier.cs | 2 +- .../System/Transactions/TransactionsEtwProvider.cs | 56 ++-- .../Transactions/VolatileEnlistmentMultiplexing.cs | 40 ++- .../System/Transactions/VolatileEnlistmentState.cs | 43 ++- 28 files changed, 615 insertions(+), 519 deletions(-) diff --git a/src/libraries/System.Transactions.Local/ref/System.Transactions.Local.cs b/src/libraries/System.Transactions.Local/ref/System.Transactions.Local.cs index 00ef78a..4ca3840 100644 --- a/src/libraries/System.Transactions.Local/ref/System.Transactions.Local.cs +++ b/src/libraries/System.Transactions.Local/ref/System.Transactions.Local.cs @@ -12,11 +12,11 @@ namespace System.Transactions public CommittableTransaction() { } public CommittableTransaction(System.TimeSpan timeout) { } public CommittableTransaction(System.Transactions.TransactionOptions options) { } - object System.IAsyncResult.AsyncState { get { throw null; } } + object? System.IAsyncResult.AsyncState { get { throw null; } } System.Threading.WaitHandle System.IAsyncResult.AsyncWaitHandle { get { throw null; } } bool System.IAsyncResult.CompletedSynchronously { get { throw null; } } bool System.IAsyncResult.IsCompleted { get { throw null; } } - public System.IAsyncResult BeginCommit(System.AsyncCallback asyncCallback, object asyncState) { throw null; } + public System.IAsyncResult BeginCommit(System.AsyncCallback? asyncCallback, object? asyncState) { throw null; } public void Commit() { } public void EndCommit(System.IAsyncResult asyncResult) { } } @@ -47,7 +47,7 @@ namespace System.Transactions Automatic = 1, Full = 2, } - public delegate System.Transactions.Transaction HostCurrentTransactionCallback(); + public delegate System.Transactions.Transaction? HostCurrentTransactionCallback(); [System.Runtime.InteropServices.InterfaceTypeAttribute(System.Runtime.InteropServices.ComInterfaceType.InterfaceIsIUnknown)] public partial interface IDtcTransaction { @@ -88,13 +88,13 @@ namespace System.Transactions } public partial interface ITransactionPromoter { - byte[] Promote(); + byte[]? Promote(); } public partial class PreparingEnlistment : System.Transactions.Enlistment { internal PreparingEnlistment() { } public void ForceRollback() { } - public void ForceRollback(System.Exception e) { } + public void ForceRollback(System.Exception? e) { } public void Prepared() { } public byte[] RecoveryInformation() { throw null; } } @@ -102,10 +102,10 @@ namespace System.Transactions { internal SinglePhaseEnlistment() { } public void Aborted() { } - public void Aborted(System.Exception e) { } + public void Aborted(System.Exception? e) { } public void Committed() { } public void InDoubt() { } - public void InDoubt(System.Exception e) { } + public void InDoubt(System.Exception? e) { } } public sealed partial class SubordinateTransaction : System.Transactions.Transaction { @@ -114,11 +114,11 @@ namespace System.Transactions public partial class Transaction : System.IDisposable, System.Runtime.Serialization.ISerializable { internal Transaction() { } - public static System.Transactions.Transaction Current { get { throw null; } set { } } + public static System.Transactions.Transaction? Current { get { throw null; } set { } } public System.Transactions.IsolationLevel IsolationLevel { get { throw null; } } public System.Guid PromoterType { get { throw null; } } public System.Transactions.TransactionInformation TransactionInformation { get { throw null; } } - public event System.Transactions.TransactionCompletedEventHandler TransactionCompleted { add { } remove { } } + public event System.Transactions.TransactionCompletedEventHandler? TransactionCompleted { add { } remove { } } public System.Transactions.Transaction Clone() { throw null; } public System.Transactions.DependentTransaction DependentClone(System.Transactions.DependentCloneOption cloneOption) { throw null; } public void Dispose() { } @@ -128,14 +128,14 @@ namespace System.Transactions public bool EnlistPromotableSinglePhase(System.Transactions.IPromotableSinglePhaseNotification promotableSinglePhaseNotification, System.Guid promoterType) { throw null; } public System.Transactions.Enlistment EnlistVolatile(System.Transactions.IEnlistmentNotification enlistmentNotification, System.Transactions.EnlistmentOptions enlistmentOptions) { throw null; } public System.Transactions.Enlistment EnlistVolatile(System.Transactions.ISinglePhaseNotification singlePhaseNotification, System.Transactions.EnlistmentOptions enlistmentOptions) { throw null; } - public override bool Equals(object obj) { throw null; } + public override bool Equals(object? obj) { throw null; } public override int GetHashCode() { throw null; } public byte[] GetPromotedToken() { throw null; } - public static bool operator ==(System.Transactions.Transaction x, System.Transactions.Transaction y) { throw null; } - public static bool operator !=(System.Transactions.Transaction x, System.Transactions.Transaction y) { throw null; } + public static bool operator ==(System.Transactions.Transaction? x, System.Transactions.Transaction? y) { throw null; } + public static bool operator !=(System.Transactions.Transaction? x, System.Transactions.Transaction? y) { throw null; } public System.Transactions.Enlistment PromoteAndEnlistDurable(System.Guid resourceManagerIdentifier, System.Transactions.IPromotableSinglePhaseNotification promotableNotification, System.Transactions.ISinglePhaseNotification enlistmentNotification, System.Transactions.EnlistmentOptions enlistmentOptions) { throw null; } public void Rollback() { } - public void Rollback(System.Exception e) { } + public void Rollback(System.Exception? e) { } public void SetDistributedTransactionIdentifier(System.Transactions.IPromotableSinglePhaseNotification promotableNotification, System.Guid distributedTransactionIdentifier) { } void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo serializationInfo, System.Runtime.Serialization.StreamingContext context) { } } @@ -143,28 +143,28 @@ namespace System.Transactions { public TransactionAbortedException() { } protected TransactionAbortedException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { } - public TransactionAbortedException(string message) { } - public TransactionAbortedException(string message, System.Exception innerException) { } + public TransactionAbortedException(string? message) { } + public TransactionAbortedException(string? message, System.Exception? innerException) { } } - public delegate void TransactionCompletedEventHandler(object sender, System.Transactions.TransactionEventArgs e); + public delegate void TransactionCompletedEventHandler(object? sender, System.Transactions.TransactionEventArgs e); public partial class TransactionEventArgs : System.EventArgs { public TransactionEventArgs() { } - public System.Transactions.Transaction Transaction { get { throw null; } } + public System.Transactions.Transaction? Transaction { get { throw null; } } } public partial class TransactionException : System.SystemException { public TransactionException() { } protected TransactionException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { } - public TransactionException(string message) { } - public TransactionException(string message, System.Exception innerException) { } + public TransactionException(string? message) { } + public TransactionException(string? message, System.Exception? innerException) { } } public partial class TransactionInDoubtException : System.Transactions.TransactionException { public TransactionInDoubtException() { } protected TransactionInDoubtException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { } - public TransactionInDoubtException(string message) { } - public TransactionInDoubtException(string message, System.Exception innerException) { } + public TransactionInDoubtException(string? message) { } + public TransactionInDoubtException(string? message, System.Exception? innerException) { } } public partial class TransactionInformation { @@ -188,9 +188,10 @@ namespace System.Transactions public static partial class TransactionManager { public static System.TimeSpan DefaultTimeout { get { throw null; } } - public static System.Transactions.HostCurrentTransactionCallback HostCurrentCallback { get { throw null; } set { } } + [System.Diagnostics.CodeAnalysis.DisallowNullAttribute] + public static System.Transactions.HostCurrentTransactionCallback? HostCurrentCallback { get { throw null; } set { } } public static System.TimeSpan MaximumTimeout { get { throw null; } } - public static event System.Transactions.TransactionStartedEventHandler DistributedTransactionStarted { add { } remove { } } + public static event System.Transactions.TransactionStartedEventHandler? DistributedTransactionStarted { add { } remove { } } public static void RecoveryComplete(System.Guid resourceManagerIdentifier) { } public static System.Transactions.Enlistment Reenlist(System.Guid resourceManagerIdentifier, byte[] recoveryInformation, System.Transactions.IEnlistmentNotification enlistmentNotification) { throw null; } } @@ -198,15 +199,15 @@ namespace System.Transactions { public TransactionManagerCommunicationException() { } protected TransactionManagerCommunicationException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { } - public TransactionManagerCommunicationException(string message) { } - public TransactionManagerCommunicationException(string message, System.Exception innerException) { } + public TransactionManagerCommunicationException(string? message) { } + public TransactionManagerCommunicationException(string? message, System.Exception? innerException) { } } public partial struct TransactionOptions { private int _dummyPrimitive; public System.Transactions.IsolationLevel IsolationLevel { get { throw null; } set { } } public System.TimeSpan Timeout { get { throw null; } set { } } - public override bool Equals(object obj) { throw null; } + public override bool Equals(object? obj) { throw null; } public override int GetHashCode() { throw null; } public static bool operator ==(System.Transactions.TransactionOptions x, System.Transactions.TransactionOptions y) { throw null; } public static bool operator !=(System.Transactions.TransactionOptions x, System.Transactions.TransactionOptions y) { throw null; } @@ -215,8 +216,8 @@ namespace System.Transactions { public TransactionPromotionException() { } protected TransactionPromotionException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { } - public TransactionPromotionException(string message) { } - public TransactionPromotionException(string message, System.Exception innerException) { } + public TransactionPromotionException(string? message) { } + public TransactionPromotionException(string? message, System.Exception? innerException) { } } public sealed partial class TransactionScope : System.IDisposable { @@ -248,7 +249,7 @@ namespace System.Transactions RequiresNew = 1, Suppress = 2, } - public delegate void TransactionStartedEventHandler(object sender, System.Transactions.TransactionEventArgs e); + public delegate void TransactionStartedEventHandler(object? sender, System.Transactions.TransactionEventArgs e); public enum TransactionStatus { Active = 0, diff --git a/src/libraries/System.Transactions.Local/ref/System.Transactions.Local.csproj b/src/libraries/System.Transactions.Local/ref/System.Transactions.Local.csproj index 33cd04b..5de24ad 100644 --- a/src/libraries/System.Transactions.Local/ref/System.Transactions.Local.csproj +++ b/src/libraries/System.Transactions.Local/ref/System.Transactions.Local.csproj @@ -2,6 +2,7 @@ Library netcoreapp-Debug;netcoreapp-Release + enable diff --git a/src/libraries/System.Transactions.Local/src/System.Transactions.Local.csproj b/src/libraries/System.Transactions.Local/src/System.Transactions.Local.csproj index f275f2a..6f8fdc1 100644 --- a/src/libraries/System.Transactions.Local/src/System.Transactions.Local.csproj +++ b/src/libraries/System.Transactions.Local/src/System.Transactions.Local.csproj @@ -3,6 +3,7 @@ true true netcoreapp-Debug;netcoreapp-Release + enable diff --git a/src/libraries/System.Transactions.Local/src/System/Transactions/CommittableTransaction.cs b/src/libraries/System.Transactions.Local/src/System/Transactions/CommittableTransaction.cs index 68d8eb6..f564ba4 100644 --- a/src/libraries/System.Transactions.Local/src/System/Transactions/CommittableTransaction.cs +++ b/src/libraries/System.Transactions.Local/src/System/Transactions/CommittableTransaction.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Diagnostics; using System.Threading; namespace System.Transactions @@ -26,7 +27,7 @@ namespace System.Transactions { } - internal CommittableTransaction(IsolationLevel isoLevel, TimeSpan timeout) : base(isoLevel, (InternalTransaction)null) + internal CommittableTransaction(IsolationLevel isoLevel, TimeSpan timeout) : base(isoLevel, (InternalTransaction?)null) { // object to use for synchronization rather than locking on a public object _internalTransaction = new InternalTransaction(timeout, this); @@ -42,7 +43,7 @@ namespace System.Transactions } } - public IAsyncResult BeginCommit(AsyncCallback asyncCallback, object asyncState) + public IAsyncResult BeginCommit(AsyncCallback? asyncCallback, object? asyncState) { TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log; if (etwLog.IsEnabled()) @@ -63,6 +64,7 @@ namespace System.Transactions throw TransactionException.CreateTransactionCompletedException(DistributedTxId); } + Debug.Assert(_internalTransaction.State != null); // this.complete will get set to true when the transaction enters a state that is // beyond Phase0. _internalTransaction.State.BeginCommit(_internalTransaction, true, asyncCallback, asyncState); @@ -99,6 +101,7 @@ namespace System.Transactions throw TransactionException.CreateTransactionCompletedException(DistributedTxId); } + Debug.Assert(_internalTransaction.State != null); _internalTransaction.State.BeginCommit(_internalTransaction, false, null, null); // now that commit has started wait for the monitor on the transaction to know @@ -134,6 +137,7 @@ namespace System.Transactions return; } + Debug.Assert(_internalTransaction.State != null); if (_internalTransaction.State.get_Status(_internalTransaction) == TransactionStatus.Active) { lock (_internalTransaction) @@ -173,6 +177,7 @@ namespace System.Transactions { do { + Debug.Assert(_internalTransaction.State != null); if (_internalTransaction.State.IsCompleted(_internalTransaction)) { break; @@ -188,7 +193,7 @@ namespace System.Transactions } } - object IAsyncResult.AsyncState => _internalTransaction._asyncState; + object? IAsyncResult.AsyncState => _internalTransaction._asyncState; bool IAsyncResult.CompletedSynchronously => _completedSynchronously; @@ -202,6 +207,7 @@ namespace System.Transactions { if (_internalTransaction._asyncResultEvent == null) { + Debug.Assert(_internalTransaction.State != null); // Demand create an event that is already signaled if the transaction has completed. ManualResetEvent temp = new ManualResetEvent( _internalTransaction.State.get_Status(_internalTransaction) != TransactionStatus.Active); @@ -221,6 +227,7 @@ namespace System.Transactions { lock (_internalTransaction) { + Debug.Assert(_internalTransaction.State != null); return _internalTransaction.State.get_Status(_internalTransaction) != TransactionStatus.Active; } } diff --git a/src/libraries/System.Transactions.Local/src/System/Transactions/DependentTransaction.cs b/src/libraries/System.Transactions.Local/src/System/Transactions/DependentTransaction.cs index 1a86259..4ca8232 100644 --- a/src/libraries/System.Transactions.Local/src/System/Transactions/DependentTransaction.cs +++ b/src/libraries/System.Transactions.Local/src/System/Transactions/DependentTransaction.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Diagnostics; namespace System.Transactions { @@ -18,6 +19,7 @@ namespace System.Transactions _blocking = blocking; lock (_internalTransaction) { + Debug.Assert(_internalTransaction.State != null); if (blocking) { _internalTransaction.State.CreateBlockingClone(_internalTransaction); @@ -51,6 +53,7 @@ namespace System.Transactions _complete = true; + Debug.Assert(_internalTransaction.State != null); if (_blocking) { _internalTransaction.State.CompleteBlockingClone(_internalTransaction); diff --git a/src/libraries/System.Transactions.Local/src/System/Transactions/DistributedTransaction.cs b/src/libraries/System.Transactions.Local/src/System/Transactions/DistributedTransaction.cs index c814e35..3735d51 100644 --- a/src/libraries/System.Transactions.Local/src/System/Transactions/DistributedTransaction.cs +++ b/src/libraries/System.Transactions.Local/src/System/Transactions/DistributedTransaction.cs @@ -8,7 +8,7 @@ namespace System.Transactions.Distributed { internal sealed class DistributedTransactionManager { - internal object NodeName { get; set; } + internal object? NodeName { get; set; } internal IPromotedEnlistment ReenlistTransaction(Guid resourceManagerIdentifier, byte[] resourceManagerRecoveryInformation, RecoveringInternalEnlistment internalEnlistment) { @@ -74,12 +74,12 @@ namespace System.Transactions.Distributed throw new PlatformNotSupportedException(); } - internal Exception InnerException { get; set; } + internal Exception? InnerException { get; set; } internal Guid Identifier { get; set; } - internal RealDistributedTransaction RealTransaction { get; set; } + internal RealDistributedTransaction? RealTransaction { get; set; } internal TransactionTraceIdentifier TransactionTraceId { get; set; } internal IsolationLevel IsolationLevel { get; set; } - internal Transaction SavedLtmPromotedTransaction { get; set; } + internal Transaction? SavedLtmPromotedTransaction { get; set; } internal void Dispose() { @@ -149,7 +149,7 @@ namespace System.Transactions.Distributed internal class RealDistributedTransaction { - internal InternalTransaction InternalTransaction { get; set; } + internal InternalTransaction? InternalTransaction { get; set; } } } diff --git a/src/libraries/System.Transactions.Local/src/System/Transactions/DurableEnlistmentState.cs b/src/libraries/System.Transactions.Local/src/System/Transactions/DurableEnlistmentState.cs index 0b7dbea..1afd579 100644 --- a/src/libraries/System.Transactions.Local/src/System/Transactions/DurableEnlistmentState.cs +++ b/src/libraries/System.Transactions.Local/src/System/Transactions/DurableEnlistmentState.cs @@ -10,14 +10,14 @@ namespace System.Transactions // Base class for all durable enlistment states internal abstract class DurableEnlistmentState : EnlistmentState { - private static DurableEnlistmentActive s_durableEnlistmentActive; - private static DurableEnlistmentAborting s_durableEnlistmentAborting; - private static DurableEnlistmentCommitting s_durableEnlistmentCommitting; - private static DurableEnlistmentDelegated s_durableEnlistmentDelegated; - private static DurableEnlistmentEnded s_durableEnlistmentEnded; + private static DurableEnlistmentActive? s_durableEnlistmentActive; + private static DurableEnlistmentAborting? s_durableEnlistmentAborting; + private static DurableEnlistmentCommitting? s_durableEnlistmentCommitting; + private static DurableEnlistmentDelegated? s_durableEnlistmentDelegated; + private static DurableEnlistmentEnded? s_durableEnlistmentEnded; // Object for synchronizing access to the entire class( avoiding lock( typeof( ... )) ) - private static object s_classSyncObject; + private static object? s_classSyncObject; internal static DurableEnlistmentActive DurableEnlistmentActive => LazyInitializer.EnsureInitialized(ref s_durableEnlistmentActive, ref s_classSyncObject, () => new DurableEnlistmentActive()); @@ -116,7 +116,7 @@ namespace System.Transactions } } - internal override void Aborted(InternalEnlistment enlistment, Exception e) + internal override void Aborted(InternalEnlistment enlistment, Exception? e) { if (enlistment.Transaction._innerException == null) { @@ -183,6 +183,7 @@ namespace System.Transactions // Transition to the ended state DurableEnlistmentEnded.EnterState(enlistment); + Debug.Assert(enlistment.Transaction.State != null); // Make the transaction commit enlistment.Transaction.State.ChangeStateTransactionCommitted(enlistment.Transaction); } @@ -192,20 +193,22 @@ namespace System.Transactions // Transition to the ended state DurableEnlistmentEnded.EnterState(enlistment); + Debug.Assert(enlistment.Transaction.State != null); // Make the transaction commit enlistment.Transaction.State.ChangeStateTransactionCommitted(enlistment.Transaction); } - internal override void Aborted(InternalEnlistment enlistment, Exception e) + internal override void Aborted(InternalEnlistment enlistment, Exception? e) { // Transition to the ended state DurableEnlistmentEnded.EnterState(enlistment); + Debug.Assert(enlistment.Transaction.State != null); // Start the transaction aborting enlistment.Transaction.State.ChangeStateTransactionAborted(enlistment.Transaction, e); } - internal override void InDoubt(InternalEnlistment enlistment, Exception e) + internal override void InDoubt(InternalEnlistment enlistment, Exception? e) { // Transition to the ended state DurableEnlistmentEnded.EnterState(enlistment); @@ -215,6 +218,7 @@ namespace System.Transactions enlistment.Transaction._innerException = e; } + Debug.Assert(enlistment.Transaction.State != null); // Make the transaction in dobut enlistment.Transaction.State.InDoubtFromEnlistment(enlistment.Transaction); } @@ -239,11 +243,12 @@ namespace System.Transactions // Transition to the ended state DurableEnlistmentEnded.EnterState(enlistment); + Debug.Assert(enlistment.Transaction.State != null); // Change the transaction to committed. enlistment.Transaction.State.ChangeStatePromotedCommitted(enlistment.Transaction); } - internal override void Aborted(InternalEnlistment enlistment, Exception e) + internal override void Aborted(InternalEnlistment enlistment, Exception? e) { // Transition to the ended state DurableEnlistmentEnded.EnterState(enlistment); @@ -253,11 +258,12 @@ namespace System.Transactions enlistment.Transaction._innerException = e; } + Debug.Assert(enlistment.Transaction.State != null); // Start the transaction aborting enlistment.Transaction.State.ChangeStatePromotedAborted(enlistment.Transaction); } - internal override void InDoubt(InternalEnlistment enlistment, Exception e) + internal override void InDoubt(InternalEnlistment enlistment, Exception? e) { // Transition to the ended state DurableEnlistmentEnded.EnterState(enlistment); @@ -267,6 +273,7 @@ namespace System.Transactions enlistment.Transaction._innerException = e; } + Debug.Assert(enlistment.Transaction.State != null); // Tell the transaction that the enlistment is InDoubt. Note that // for a transaction that has been delegated and then promoted there // are two chances to get a better answer than indoubt. So it may be that @@ -292,7 +299,7 @@ namespace System.Transactions // it already knows. Eat this message. } - internal override void InDoubt(InternalEnlistment enlistment, Exception e) + internal override void InDoubt(InternalEnlistment enlistment, Exception? e) { // Ignore this in case the enlistment gets here before // the transaction tells it to do so diff --git a/src/libraries/System.Transactions.Local/src/System/Transactions/Enlistment.cs b/src/libraries/System.Transactions.Local/src/System/Transactions/Enlistment.cs index 6ead235..c9372f0 100644 --- a/src/libraries/System.Transactions.Local/src/System/Transactions/Enlistment.cs +++ b/src/libraries/System.Transactions.Local/src/System/Transactions/Enlistment.cs @@ -16,17 +16,17 @@ namespace System.Transactions void ForceRollback(); - void ForceRollback(Exception e); + void ForceRollback(Exception? e); void Committed(); void Aborted(); - void Aborted(Exception e); + void Aborted(Exception? e); void InDoubt(); - void InDoubt(Exception e); + void InDoubt(Exception? e); byte[] GetRecoveryInformation(); @@ -45,20 +45,20 @@ namespace System.Transactions internal class InternalEnlistment : ISinglePhaseNotificationInternal { // Storage for the state of the enlistment. - internal EnlistmentState _twoPhaseState; + internal EnlistmentState? _twoPhaseState; // Interface implemented by the enlistment owner for notifications - protected IEnlistmentNotification _twoPhaseNotifications; + protected IEnlistmentNotification? _twoPhaseNotifications; // Store a reference to the single phase notification interface in case // the enlisment supports it. - protected ISinglePhaseNotification _singlePhaseNotifications; + protected ISinglePhaseNotification? _singlePhaseNotifications; // Reference to the containing transaction. - protected InternalTransaction _transaction; + protected InternalTransaction _transaction = null!; // Reference to the lightweight transaction. - private readonly Transaction _atomicTransaction; + private readonly Transaction? _atomicTransaction; // The EnlistmentTraceIdentifier for this enlistment. private EnlistmentTraceIdentifier _traceIdentifier; @@ -82,11 +82,11 @@ namespace System.Transactions // Parent Enlistment Object private readonly Enlistment _enlistment; - private PreparingEnlistment _preparingEnlistment; - private SinglePhaseEnlistment _singlePhaseEnlistment; + private PreparingEnlistment? _preparingEnlistment; + private SinglePhaseEnlistment? _singlePhaseEnlistment; // If this enlistment is promoted store the object it delegates to. - private IPromotedEnlistment _promotedEnlistment; + private IPromotedEnlistment? _promotedEnlistment; // For Recovering Enlistments protected InternalEnlistment(Enlistment enlistment, IEnlistmentNotification twoPhaseNotifications) @@ -113,7 +113,7 @@ namespace System.Transactions Enlistment enlistment, InternalTransaction transaction, IEnlistmentNotification twoPhaseNotifications, - ISinglePhaseNotification singlePhaseNotifications, + ISinglePhaseNotification? singlePhaseNotifications, Transaction atomicTransaction) { _enlistment = enlistment; @@ -139,7 +139,10 @@ namespace System.Transactions internal EnlistmentState State { - get { return _twoPhaseState; } + get { + Debug.Assert(_twoPhaseState != null); + return _twoPhaseState; + } set { _twoPhaseState = value; } } @@ -182,9 +185,9 @@ namespace System.Transactions } } - internal IEnlistmentNotification EnlistmentNotification => _twoPhaseNotifications; + internal IEnlistmentNotification? EnlistmentNotification => _twoPhaseNotifications; - internal ISinglePhaseNotification SinglePhaseNotification => _singlePhaseNotifications; + internal ISinglePhaseNotification? SinglePhaseNotification => _singlePhaseNotifications; internal virtual IPromotableSinglePhaseNotification PromotableSinglePhaseNotification { @@ -195,7 +198,7 @@ namespace System.Transactions } } - internal IPromotedEnlistment PromotedEnlistment + internal IPromotedEnlistment? PromotedEnlistment { get { return _promotedEnlistment; } set { _promotedEnlistment = value; } @@ -255,7 +258,7 @@ namespace System.Transactions if (Transaction._phase0Volatiles._preparedVolatileEnlistments == Transaction._phase0VolatileWaveCount + Transaction._phase0Volatiles._dependentClones) { - Transaction.State.Phase0VolatilePrepareDone(Transaction); + Transaction.State!.Phase0VolatilePrepareDone(Transaction); } } @@ -274,6 +277,7 @@ namespace System.Transactions _promotedEnlistment = singlePhaseEnlistment; try { + Debug.Assert(_singlePhaseNotifications != null); _singlePhaseNotifications.SinglePhaseCommit(SinglePhaseEnlistment); spcCommitted = true; } @@ -290,6 +294,7 @@ namespace System.Transactions IPromotedEnlistment preparingEnlistment ) { + Debug.Assert(_twoPhaseNotifications != null); _promotedEnlistment = preparingEnlistment; _twoPhaseNotifications.Prepare(PreparingEnlistment); } @@ -298,6 +303,7 @@ namespace System.Transactions IPromotedEnlistment enlistment ) { + Debug.Assert(_twoPhaseNotifications != null); _promotedEnlistment = enlistment; _twoPhaseNotifications.Commit(Enlistment); } @@ -306,6 +312,7 @@ namespace System.Transactions IPromotedEnlistment enlistment ) { + Debug.Assert(_twoPhaseNotifications != null); _promotedEnlistment = enlistment; _twoPhaseNotifications.Rollback(Enlistment); } @@ -314,6 +321,7 @@ namespace System.Transactions IPromotedEnlistment enlistment ) { + Debug.Assert(_twoPhaseNotifications != null); _promotedEnlistment = enlistment; _twoPhaseNotifications.InDoubt(Enlistment); } @@ -329,7 +337,7 @@ namespace System.Transactions Guid resourceManagerIdentifier, InternalTransaction transaction, IEnlistmentNotification twoPhaseNotifications, - ISinglePhaseNotification singlePhaseNotifications, + ISinglePhaseNotification? singlePhaseNotifications, Transaction atomicTransaction) : base(enlistment, transaction, twoPhaseNotifications, singlePhaseNotifications, atomicTransaction) { @@ -389,7 +397,7 @@ namespace System.Transactions Enlistment enlistment, InternalTransaction transaction, IEnlistmentNotification twoPhaseNotifications, - ISinglePhaseNotification singlePhaseNotifications, + ISinglePhaseNotification? singlePhaseNotifications, Transaction atomicTransaction) : base(enlistment, transaction, twoPhaseNotifications, singlePhaseNotifications, atomicTransaction) { @@ -414,7 +422,7 @@ namespace System.Transactions _transaction._phase1Volatiles._volatileEnlistmentCount + _transaction._phase1Volatiles._dependentClones) { - _transaction.State.Phase1VolatilePrepareDone(_transaction); + _transaction.State!.Phase1VolatilePrepareDone(_transaction); } } } @@ -433,7 +441,7 @@ namespace System.Transactions Guid resourceManagerIdentifier, InternalTransaction transaction, IEnlistmentNotification twoPhaseNotifications, - ISinglePhaseNotification singlePhaseNotifications, + ISinglePhaseNotification? singlePhaseNotifications, Transaction atomicTransaction) { _internalEnlistment = new DurableInternalEnlistment( @@ -449,7 +457,7 @@ namespace System.Transactions internal Enlistment( InternalTransaction transaction, IEnlistmentNotification twoPhaseNotifications, - ISinglePhaseNotification singlePhaseNotifications, + ISinglePhaseNotification? singlePhaseNotifications, Transaction atomicTransaction, EnlistmentOptions enlistmentOptions) { diff --git a/src/libraries/System.Transactions.Local/src/System/Transactions/EnlistmentState.cs b/src/libraries/System.Transactions.Local/src/System/Transactions/EnlistmentState.cs index e1a6f78..b9256f2 100644 --- a/src/libraries/System.Transactions.Local/src/System/Transactions/EnlistmentState.cs +++ b/src/libraries/System.Transactions.Local/src/System/Transactions/EnlistmentState.cs @@ -12,10 +12,10 @@ namespace System.Transactions { internal abstract void EnterState(InternalEnlistment enlistment); - internal static EnlistmentStatePromoted _enlistmentStatePromoted; + internal static EnlistmentStatePromoted? _enlistmentStatePromoted; // Object for synchronizing access to the entire class( avoiding lock( typeof( ... )) ) - private static object s_classSyncObject; + private static object? s_classSyncObject; internal static EnlistmentStatePromoted EnlistmentStatePromoted => LazyInitializer.EnsureInitialized(ref _enlistmentStatePromoted, ref s_classSyncObject, () => new EnlistmentStatePromoted()); @@ -30,7 +30,7 @@ namespace System.Transactions throw TransactionException.CreateEnlistmentStateException(null, enlistment == null ? Guid.Empty : enlistment.DistributedTxId); } - internal virtual void ForceRollback(InternalEnlistment enlistment, Exception e) + internal virtual void ForceRollback(InternalEnlistment enlistment, Exception? e) { throw TransactionException.CreateEnlistmentStateException(null, enlistment == null ? Guid.Empty : enlistment.DistributedTxId); } @@ -40,12 +40,12 @@ namespace System.Transactions throw TransactionException.CreateEnlistmentStateException(null, enlistment == null ? Guid.Empty : enlistment.DistributedTxId); } - internal virtual void Aborted(InternalEnlistment enlistment, Exception e) + internal virtual void Aborted(InternalEnlistment enlistment, Exception? e) { throw TransactionException.CreateEnlistmentStateException(null, enlistment == null ? Guid.Empty : enlistment.DistributedTxId); } - internal virtual void InDoubt(InternalEnlistment enlistment, Exception e) + internal virtual void InDoubt(InternalEnlistment enlistment, Exception? e) { throw TransactionException.CreateEnlistmentStateException(null, enlistment == null ? Guid.Empty : enlistment.DistributedTxId); } @@ -116,6 +116,7 @@ namespace System.Transactions Monitor.Exit(enlistment.SyncRoot); try { + Debug.Assert(enlistment.PromotedEnlistment != null); enlistment.PromotedEnlistment.EnlistmentDone(); } finally @@ -129,6 +130,7 @@ namespace System.Transactions Monitor.Exit(enlistment.SyncRoot); try { + Debug.Assert(enlistment.PromotedEnlistment != null); enlistment.PromotedEnlistment.Prepared(); } finally @@ -137,11 +139,12 @@ namespace System.Transactions } } - internal override void ForceRollback(InternalEnlistment enlistment, Exception e) + internal override void ForceRollback(InternalEnlistment enlistment, Exception? e) { Monitor.Exit(enlistment.SyncRoot); try { + Debug.Assert(enlistment.PromotedEnlistment != null); enlistment.PromotedEnlistment.ForceRollback(e); } finally @@ -155,6 +158,7 @@ namespace System.Transactions Monitor.Exit(enlistment.SyncRoot); try { + Debug.Assert(enlistment.PromotedEnlistment != null); enlistment.PromotedEnlistment.Committed(); } finally @@ -163,11 +167,12 @@ namespace System.Transactions } } - internal override void Aborted(InternalEnlistment enlistment, Exception e) + internal override void Aborted(InternalEnlistment enlistment, Exception? e) { Monitor.Exit(enlistment.SyncRoot); try { + Debug.Assert(enlistment.PromotedEnlistment != null); enlistment.PromotedEnlistment.Aborted(e); } finally @@ -176,11 +181,12 @@ namespace System.Transactions } } - internal override void InDoubt(InternalEnlistment enlistment, Exception e) + internal override void InDoubt(InternalEnlistment enlistment, Exception? e) { Monitor.Exit(enlistment.SyncRoot); try { + Debug.Assert(enlistment.PromotedEnlistment != null); enlistment.PromotedEnlistment.InDoubt(e); } finally @@ -194,6 +200,7 @@ namespace System.Transactions Monitor.Exit(enlistment.SyncRoot); try { + Debug.Assert(enlistment.PromotedEnlistment != null); return enlistment.PromotedEnlistment.GetRecoveryInformation(); } finally diff --git a/src/libraries/System.Transactions.Local/src/System/Transactions/EnlistmentTraceIdentifier.cs b/src/libraries/System.Transactions.Local/src/System/Transactions/EnlistmentTraceIdentifier.cs index c5b6410..0570040 100644 --- a/src/libraries/System.Transactions.Local/src/System/Transactions/EnlistmentTraceIdentifier.cs +++ b/src/libraries/System.Transactions.Local/src/System/Transactions/EnlistmentTraceIdentifier.cs @@ -47,7 +47,7 @@ namespace System.Transactions public override int GetHashCode() => base.GetHashCode(); // Don't have anything better to do. - public override bool Equals(object obj) => obj is EnlistmentTraceIdentifier && Equals((EnlistmentTraceIdentifier)obj); + public override bool Equals(object? obj) => obj is EnlistmentTraceIdentifier enlistmentTraceId && Equals(enlistmentTraceId); public bool Equals(EnlistmentTraceIdentifier other) => _enlistmentIdentifier == other._enlistmentIdentifier && diff --git a/src/libraries/System.Transactions.Local/src/System/Transactions/EnterpriseServices.cs b/src/libraries/System.Transactions.Local/src/System/Transactions/EnterpriseServices.cs index 637ec20..3e04af4 100644 --- a/src/libraries/System.Transactions.Local/src/System/Transactions/EnterpriseServices.cs +++ b/src/libraries/System.Transactions.Local/src/System/Transactions/EnterpriseServices.cs @@ -16,7 +16,7 @@ namespace System.Transactions } } - internal static Transaction GetContextTransaction(ContextData contextData) + internal static Transaction? GetContextTransaction(ContextData contextData) { if (EnterpriseServicesOk) { @@ -30,7 +30,7 @@ namespace System.Transactions internal static bool UseServiceDomainForCurrent() => false; - internal static void PushServiceDomain(Transaction newCurrent) + internal static void PushServiceDomain(Transaction? newCurrent) { ThrowNotSupported(); } diff --git a/src/libraries/System.Transactions.Local/src/System/Transactions/ITransactionPromoter.cs b/src/libraries/System.Transactions.Local/src/System/Transactions/ITransactionPromoter.cs index 5ef3874..3432da3 100644 --- a/src/libraries/System.Transactions.Local/src/System/Transactions/ITransactionPromoter.cs +++ b/src/libraries/System.Transactions.Local/src/System/Transactions/ITransactionPromoter.cs @@ -6,6 +6,6 @@ namespace System.Transactions { public interface ITransactionPromoter { - byte[] Promote(); + byte[]? Promote(); } } diff --git a/src/libraries/System.Transactions.Local/src/System/Transactions/InternalTransaction.cs b/src/libraries/System.Transactions.Local/src/System/Transactions/InternalTransaction.cs index 6b385bf..8071fac 100644 --- a/src/libraries/System.Transactions.Local/src/System/Transactions/InternalTransaction.cs +++ b/src/libraries/System.Transactions.Local/src/System/Transactions/InternalTransaction.cs @@ -17,9 +17,9 @@ namespace System.Transactions { // This variable manages the state of the transaction it should be one of the // static elements of TransactionState derived from TransactionState. - protected TransactionState _transactionState; + protected TransactionState? _transactionState; - internal TransactionState State + internal TransactionState? State { get { return _transactionState; } set { _transactionState = value; } @@ -39,7 +39,7 @@ namespace System.Transactions // The promoted token for the transaction. // This is set when the transaction is promoted. For an MSDTC transaction, it is the // same as the DTC propagation token. - internal byte[] promotedToken; + internal byte[]? promotedToken; // This is only used if the promoter type is different than TransactionInterop.PromoterTypeDtc. // The promoter is supposed to tell us what the distributed transaction id after promoting it. @@ -54,7 +54,7 @@ namespace System.Transactions #endif // Finalized object see class definition for the use of this object - internal FinalizedObject _finalizedObject; + internal FinalizedObject? _finalizedObject; internal readonly int _transactionHash; internal int TransactionHash => _transactionHash; @@ -84,7 +84,7 @@ namespace System.Transactions // operation repeatedly for a given type of transaction. So if a transaction of a specific // type continually causes the array size to be increased the LTM could start // allocating a larger array initially for transactions of that type. - internal InternalEnlistment _durableEnlistment; + internal InternalEnlistment? _durableEnlistment; internal VolatileEnlistmentSet _phase0Volatiles; internal VolatileEnlistmentSet _phase1Volatiles; @@ -94,7 +94,7 @@ namespace System.Transactions // These members are used for promoted waves of dependent blocking clones. The Ltm // does not register individually for each blocking clone created in phase 0. Instead // it multiplexes a single phase 0 blocking clone only created after phase 0 has started. - internal DistributedDependentTransaction _phase0WaveDependentClone; + internal DistributedDependentTransaction? _phase0WaveDependentClone; internal int _phase0WaveDependentCloneCount; // These members are used for keeping track of aborting dependent clones if we promote @@ -106,22 +106,22 @@ namespace System.Transactions // on the distributed TM takes care of checking to make sure all the aborting dependent // clones have completed as part of its Prepare processing. These are used in conjunction with // phase1volatiles.dependentclones. - internal DistributedDependentTransaction _abortingDependentClone; + internal DistributedDependentTransaction? _abortingDependentClone; internal int _abortingDependentCloneCount; // When the size of the volatile enlistment array grows increase it by this amount. internal const int VolatileArrayIncrement = 8; // Data maintained for TransactionTable participation - internal Bucket _tableBucket; + internal Bucket? _tableBucket; internal int _bucketIndex; // Delegate to fire on transaction completion - internal TransactionCompletedEventHandler _transactionCompletedDelegate; + internal TransactionCompletedEventHandler? _transactionCompletedDelegate; // If this transaction get's promoted keep a reference to the promoted transaction - private DistributedTransaction _promotedTransaction; - internal DistributedTransaction PromotedTransaction + private DistributedTransaction? _promotedTransaction; + internal DistributedTransaction? PromotedTransaction { get { return _promotedTransaction; } set @@ -133,7 +133,7 @@ namespace System.Transactions // If there was an exception that happened during promotion save that exception so that it // can be used as an inner exception to the transaciton aborted exception. - internal Exception _innerException = null; + internal Exception? _innerException = null; // Note the number of Transaction objects supported by this object internal int _cloneCount; @@ -143,31 +143,31 @@ namespace System.Transactions // Double-checked locking pattern requires volatile for read/write synchronization // Manual Reset event for IAsyncResult support - internal volatile ManualResetEvent _asyncResultEvent; + internal volatile ManualResetEvent? _asyncResultEvent; // Store the callback and state for the caller of BeginCommit internal bool _asyncCommit; - internal AsyncCallback _asyncCallback; - internal object _asyncState; + internal AsyncCallback? _asyncCallback; + internal object? _asyncState; // Flag to indicate if we need to be pulsed for tx completion internal bool _needPulse; // Store the transaction information object - internal TransactionInformation _transactionInformation; + internal TransactionInformation? _transactionInformation; // Store a reference to the owning Committable Transaction - internal readonly CommittableTransaction _committableTransaction; + internal readonly CommittableTransaction? _committableTransaction; // Store a reference to the outcome source internal readonly Transaction _outcomeSource; // Object for synchronizing access to the entire class( avoiding lock( typeof( ... )) ) - private static object s_classSyncObject; + private static object? s_classSyncObject; - internal Guid DistributedTxId => State.get_Identifier(this); + internal Guid DistributedTxId => State!.get_Identifier(this); - private static string s_instanceIdentifier; + private static string? s_instanceIdentifier; internal static string InstanceIdentifier => LazyInitializer.EnsureInitialized(ref s_instanceIdentifier, ref s_classSyncObject, () => Guid.NewGuid().ToString() + ":"); @@ -198,7 +198,7 @@ namespace System.Transactions } } - internal ITransactionPromoter _promoter; + internal ITransactionPromoter? _promoter; // This member is used to allow a PSPE enlistment to call Transaction.PSPEPromoteAndConvertToEnlistDurable when it is // asked to promote a transaction. The value is set to true in TransactionStatePSPEOperation.PSPEPromote before the @@ -291,15 +291,17 @@ namespace System.Transactions internal static void DistributedTransactionOutcome(InternalTransaction tx, TransactionStatus status) { - FinalizedObject fo = null; + FinalizedObject? fo = null; lock (tx) { if (null == tx._innerException) { + Debug.Assert(tx.PromotedTransaction != null); tx._innerException = tx.PromotedTransaction.InnerException; } + Debug.Assert(tx.State! != null); switch (status) { case TransactionStatus.Committed: @@ -356,6 +358,7 @@ namespace System.Transactions Monitor.Exit(this); // Don't hold a lock calling user code. try { + Debug.Assert(_committableTransaction != null); _asyncCallback(_committableTransaction); } finally @@ -368,7 +371,7 @@ namespace System.Transactions // Fire completion to anyone registered for outcome internal void FireCompletion() { - TransactionCompletedEventHandler eventHandlers = _transactionCompletedDelegate; + TransactionCompletedEventHandler? eventHandlers = _transactionCompletedDelegate; if (eventHandlers != null) { @@ -429,7 +432,7 @@ namespace System.Transactions Hashtable promotedTransactionTable = TransactionManager.PromotedTransactionTable; lock (promotedTransactionTable) { - WeakReference weakRef = (WeakReference)promotedTransactionTable[_identifier]; + WeakReference? weakRef = (WeakReference?)promotedTransactionTable[_identifier]; if (null != weakRef) { if (weakRef.Target != null) diff --git a/src/libraries/System.Transactions.Local/src/System/Transactions/PreparingEnlistment.cs b/src/libraries/System.Transactions.Local/src/System/Transactions/PreparingEnlistment.cs index c3e1017..5c148c3 100644 --- a/src/libraries/System.Transactions.Local/src/System/Transactions/PreparingEnlistment.cs +++ b/src/libraries/System.Transactions.Local/src/System/Transactions/PreparingEnlistment.cs @@ -52,7 +52,7 @@ namespace System.Transactions } } - public void ForceRollback(Exception e) + public void ForceRollback(Exception? e) { TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log; if (etwLog.IsEnabled()) diff --git a/src/libraries/System.Transactions.Local/src/System/Transactions/SinglePhaseEnlistment.cs b/src/libraries/System.Transactions.Local/src/System/Transactions/SinglePhaseEnlistment.cs index 4b831f7..412b142 100644 --- a/src/libraries/System.Transactions.Local/src/System/Transactions/SinglePhaseEnlistment.cs +++ b/src/libraries/System.Transactions.Local/src/System/Transactions/SinglePhaseEnlistment.cs @@ -30,7 +30,7 @@ namespace System.Transactions } } - public void Aborted(Exception e) + public void Aborted(Exception? e) { TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log; if (etwLog.IsEnabled()) @@ -97,7 +97,7 @@ namespace System.Transactions } - public void InDoubt(Exception e) + public void InDoubt(Exception? e) { TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log; if (etwLog.IsEnabled()) diff --git a/src/libraries/System.Transactions.Local/src/System/Transactions/Transaction.cs b/src/libraries/System.Transactions.Local/src/System/Transactions/Transaction.cs index 38e1085..66b94ca 100644 --- a/src/libraries/System.Transactions.Local/src/System/Transactions/Transaction.cs +++ b/src/libraries/System.Transactions.Local/src/System/Transactions/Transaction.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.Serialization; using System.Threading; @@ -12,11 +13,11 @@ namespace System.Transactions { public class TransactionEventArgs : EventArgs { - internal Transaction _transaction; - public Transaction Transaction => _transaction; + internal Transaction? _transaction; + public Transaction? Transaction => _transaction; } - public delegate void TransactionCompletedEventHandler(object sender, TransactionEventArgs e); + public delegate void TransactionCompletedEventHandler(object? sender, TransactionEventArgs e); public enum IsolationLevel { @@ -67,7 +68,7 @@ namespace System.Transactions // This property figures out the current interop mode based on the // top of the transaction scope stack as well as the default mode // from config. - internal static EnterpriseServicesInteropOption InteropMode(TransactionScope currentScope) + internal static EnterpriseServicesInteropOption InteropMode(TransactionScope? currentScope) { if (currentScope != null) { @@ -77,9 +78,9 @@ namespace System.Transactions return EnterpriseServicesInteropOption.None; } - internal static Transaction FastGetTransaction(TransactionScope currentScope, ContextData contextData, out Transaction contextTransaction) + internal static Transaction? FastGetTransaction(TransactionScope? currentScope, ContextData contextData, out Transaction? contextTransaction) { - Transaction current = null; + Transaction? current = null; contextTransaction = null; contextTransaction = contextData.CurrentTransaction; @@ -97,7 +98,7 @@ namespace System.Transactions // Otherwise check for an external current. if (TransactionManager.s_currentDelegateSet) { - current = TransactionManager.s_currentDelegate(); + current = TransactionManager.s_currentDelegate!(); } else { @@ -132,9 +133,9 @@ namespace System.Transactions // in TransactionScope because it is required to get both of them in several cases. internal static void GetCurrentTransactionAndScope( TxLookup defaultLookup, - out Transaction current, - out TransactionScope currentScope, - out Transaction contextTransaction) + out Transaction? current, + out TransactionScope? currentScope, + out Transaction? contextTransaction) { current = null; currentScope = null; @@ -148,7 +149,7 @@ namespace System.Transactions } } - public static Transaction Current + public static Transaction? Current { get { @@ -158,10 +159,7 @@ namespace System.Transactions etwLog.MethodEnter(TraceSourceType.TraceSourceBase, "Transaction.get_Current"); } - Transaction current = null; - TransactionScope currentScope = null; - Transaction contextValue = null; - GetCurrentTransactionAndScope(TxLookup.Default, out current, out currentScope, out contextValue); + GetCurrentTransactionAndScope(TxLookup.Default, out Transaction? current, out TransactionScope? currentScope, out Transaction? contextValue); if (currentScope != null) { @@ -242,7 +240,7 @@ namespace System.Transactions // Internal synchronization object for transactions. It is not safe to lock on the // transaction object because it is public and users of the object may lock it for // other purposes. - internal InternalTransaction _internalTransaction; + internal InternalTransaction _internalTransaction = null!; // The TransactionTraceIdentifier for the transaction instance. internal TransactionTraceIdentifier _traceIdentifier; @@ -252,7 +250,7 @@ namespace System.Transactions // Create a transaction with the given settings // - internal Transaction(IsolationLevel isoLevel, InternalTransaction internalTransaction) + internal Transaction(IsolationLevel isoLevel, InternalTransaction? internalTransaction) { TransactionManager.ValidateIsolationLevel(isoLevel); @@ -319,37 +317,29 @@ namespace System.Transactions // Don't allow equals to get the identifier // - public override bool Equals(object obj) + public override bool Equals(object? obj) { - Transaction transaction = obj as Transaction; - // If we can't cast the object as a Transaction, it must not be equal - // to this, which is a Transaction. - if (null == transaction) - { - return false; - } - - // Check the internal transaction object for equality. - return _internalTransaction.TransactionHash == transaction._internalTransaction.TransactionHash; + // to this, which is a Transaction. Check the internal transaction object for equality. + return obj is Transaction transaction && _internalTransaction.TransactionHash == transaction._internalTransaction.TransactionHash; } - public static bool operator ==(Transaction x, Transaction y) + public static bool operator ==(Transaction? x, Transaction? y) { - if (((object)x) != null) + if (((object?)x) != null) { return x.Equals(y); } - return ((object)y) == null; + return ((object?)y) == null; } - public static bool operator !=(Transaction x, Transaction y) + public static bool operator !=(Transaction? x, Transaction? y) { - if (((object)x) != null) + if (((object?)x) != null) { return !x.Equals(y); } - return ((object)y) != null; + return ((object?)y) != null; } @@ -370,7 +360,7 @@ namespace System.Transactions throw new ObjectDisposedException(nameof(Transaction)); } - TransactionInformation txInfo = _internalTransaction._transactionInformation; + TransactionInformation? txInfo = _internalTransaction._transactionInformation; if (txInfo == null) { // A race would only result in an extra allocation @@ -483,6 +473,7 @@ namespace System.Transactions byte[] internalPromotedToken; lock (_internalTransaction) { + Debug.Assert(_internalTransaction.State != null); internalPromotedToken = _internalTransaction.State.PromotedToken(_internalTransaction); } @@ -529,6 +520,7 @@ namespace System.Transactions lock (_internalTransaction) { + Debug.Assert(_internalTransaction.State != null); Enlistment enlistment = _internalTransaction.State.EnlistDurable(_internalTransaction, resourceManagerIdentifier, enlistmentNotification, enlistmentOptions, this); @@ -582,6 +574,7 @@ namespace System.Transactions lock (_internalTransaction) { + Debug.Assert(_internalTransaction.State != null); Enlistment enlistment = _internalTransaction.State.EnlistDurable(_internalTransaction, resourceManagerIdentifier, singlePhaseNotification, enlistmentOptions, this); @@ -621,7 +614,7 @@ namespace System.Transactions } - public void Rollback(Exception e) + public void Rollback(Exception? e) { TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log; if (etwLog.IsEnabled()) @@ -680,6 +673,7 @@ namespace System.Transactions lock (_internalTransaction) { + Debug.Assert(_internalTransaction.State != null); Enlistment enlistment = _internalTransaction.State.EnlistVolatile(_internalTransaction, enlistmentNotification, enlistmentOptions, this); @@ -724,6 +718,7 @@ namespace System.Transactions lock (_internalTransaction) { + Debug.Assert(_internalTransaction.State != null); Enlistment enlistment = _internalTransaction.State.EnlistVolatile(_internalTransaction, singlePhaseNotification, enlistmentOptions, this); @@ -842,7 +837,7 @@ namespace System.Transactions // Forward request to the state machine to take the appropriate action. // - public event TransactionCompletedEventHandler TransactionCompleted + public event TransactionCompletedEventHandler? TransactionCompleted { add { @@ -853,6 +848,7 @@ namespace System.Transactions lock (_internalTransaction) { + Debug.Assert(_internalTransaction.State != null); // Register for completion with the inner transaction _internalTransaction.State.AddOutcomeRegistrant(_internalTransaction, value); } @@ -862,7 +858,7 @@ namespace System.Transactions { lock (_internalTransaction) { - _internalTransaction._transactionCompletedDelegate = (TransactionCompletedEventHandler) + _internalTransaction._transactionCompletedDelegate = (TransactionCompletedEventHandler?) System.Delegate.Remove(_internalTransaction._transactionCompletedDelegate, value); } } @@ -1012,6 +1008,7 @@ namespace System.Transactions lock (_internalTransaction) { + Debug.Assert(_internalTransaction.State != null); succeeded = _internalTransaction.State.EnlistPromotableSinglePhase(_internalTransaction, promotableSinglePhaseNotification, this, promoterType); } @@ -1066,6 +1063,7 @@ namespace System.Transactions lock (_internalTransaction) { + Debug.Assert(_internalTransaction.State != null); Enlistment enlistment = _internalTransaction.State.PromoteAndEnlistDurable(_internalTransaction, resourceManagerIdentifier, promotableNotification, enlistmentNotification, enlistmentOptions, this); @@ -1109,6 +1107,7 @@ namespace System.Transactions lock (_internalTransaction) { + Debug.Assert(_internalTransaction.State != null); _internalTransaction.State.SetDistributedTransactionId(_internalTransaction, promotableNotification, distributedTransactionIdentifier); @@ -1121,10 +1120,11 @@ namespace System.Transactions } } - internal DistributedTransaction Promote() + internal DistributedTransaction? Promote() { lock (_internalTransaction) { + Debug.Assert(_internalTransaction.State != null); // This method is only called when we expect to be promoting to MSDTC. _internalTransaction.ThrowIfPromoterTypeIsNotMSDTC(); _internalTransaction.State.Promote(_internalTransaction); @@ -1166,7 +1166,7 @@ namespace System.Transactions // internal static class CallContextCurrentData { - private static readonly AsyncLocal s_currentTransaction = new AsyncLocal(); + private static readonly AsyncLocal s_currentTransaction = new AsyncLocal(); // ConditionalWeakTable is used to automatically remove the entries that are no longer referenced. This will help prevent leaks in async nested TransactionScope // usage and when child nested scopes are not syncronized properly. @@ -1182,17 +1182,17 @@ namespace System.Transactions return s_contextDataTable.GetValue(contextKey, (env) => new ContextData(true)); } - public static void ClearCurrentData(ContextKey contextKey, bool removeContextData) + public static void ClearCurrentData(ContextKey? contextKey, bool removeContextData) { // Get the current ambient CallContext. - ContextKey key = s_currentTransaction.Value; + ContextKey? key = s_currentTransaction.Value; if (contextKey != null || key != null) { // removeContextData flag is used for perf optimization to avoid removing from the table in certain nested TransactionScope usage. if (removeContextData) { // if context key is passed in remove that from the contextDataTable, otherwise remove the default context key. - s_contextDataTable.Remove(contextKey ?? key); + s_contextDataTable.Remove(contextKey ?? key!); } if (key != null) @@ -1202,10 +1202,10 @@ namespace System.Transactions } } - public static bool TryGetCurrentData(out ContextData currentData) + public static bool TryGetCurrentData([NotNullWhen(true)] out ContextData? currentData) { currentData = null; - ContextKey contextKey = s_currentTransaction.Value; + ContextKey? contextKey = s_currentTransaction.Value; if (contextKey == null) { return false; @@ -1226,27 +1226,28 @@ namespace System.Transactions internal class ContextData { - internal TransactionScope CurrentScope; - internal Transaction CurrentTransaction; + internal TransactionScope? CurrentScope; + internal Transaction? CurrentTransaction; internal DefaultComContextState DefaultComContextState; - internal WeakReference WeakDefaultComContext; + internal WeakReference? WeakDefaultComContext; internal bool _asyncFlow; [ThreadStatic] - private static ContextData t_staticData; + private static ContextData? t_staticData; internal ContextData(bool asyncFlow) { _asyncFlow = asyncFlow; } + [AllowNull] internal static ContextData TLSCurrentData { get { - ContextData data = t_staticData; + ContextData? data = t_staticData; if (data == null) { data = new ContextData(false); @@ -1274,7 +1275,7 @@ namespace System.Transactions internal static ContextData LookupContextData(TxLookup defaultLookup) { - ContextData currentData = null; + ContextData? currentData = null; if (CallContextCurrentData.TryGetCurrentData(out currentData)) { if (currentData.CurrentScope == null && currentData.CurrentTransaction == null && defaultLookup != TxLookup.DefaultCallContext) diff --git a/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionException.cs b/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionException.cs index 469a1a2..b88fdd4 100644 --- a/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionException.cs +++ b/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionException.cs @@ -19,7 +19,7 @@ namespace System.Transactions return (distributedTxId != Guid.Empty && AppSettings.IncludeDistributedTxIdInExceptionMessage); } - internal static TransactionException Create(string message, Exception innerException) + internal static TransactionException Create(string? message, Exception? innerException) { TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log; if (etwLog.IsEnabled()) @@ -30,7 +30,7 @@ namespace System.Transactions return new TransactionException(message, innerException); } - internal static TransactionException Create(TraceSourceType traceSource, string message, Exception innerException) + internal static TransactionException Create(TraceSourceType traceSource, string? message, Exception? innerException) { TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log; if (etwLog.IsEnabled()) @@ -40,12 +40,12 @@ namespace System.Transactions return new TransactionException(message, innerException); } - internal static TransactionException CreateTransactionStateException(Exception innerException) + internal static TransactionException CreateTransactionStateException(Exception? innerException) { return Create(SR.TransactionStateException, innerException); } - internal static Exception CreateEnlistmentStateException(Exception innerException, Guid distributedTxId) + internal static Exception CreateEnlistmentStateException(Exception? innerException, Guid distributedTxId) { string messagewithTxId = SR.EnlistmentStateException; if (IncludeDistributedTxId(distributedTxId)) @@ -59,7 +59,7 @@ namespace System.Transactions return new InvalidOperationException(messagewithTxId, innerException); } - internal static Exception CreateInvalidOperationException(TraceSourceType traceSource, string message, Exception innerException) + internal static Exception CreateInvalidOperationException(TraceSourceType traceSource, string? message, Exception? innerException) { TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log; if (etwLog.IsEnabled()) @@ -81,7 +81,7 @@ namespace System.Transactions /// /// /// - public TransactionException(string message) : base(message) + public TransactionException(string? message) : base(message) { } @@ -90,7 +90,7 @@ namespace System.Transactions /// /// /// - public TransactionException(string message, Exception innerException) : base(message, innerException) + public TransactionException(string? message, Exception? innerException) : base(message, innerException) { } @@ -103,7 +103,7 @@ namespace System.Transactions { } - internal static TransactionException Create(string message, Guid distributedTxId) + internal static TransactionException Create(string? message, Guid distributedTxId) { if (IncludeDistributedTxId(distributedTxId)) { @@ -112,25 +112,25 @@ namespace System.Transactions return new TransactionException(message); } - internal static TransactionException Create(string message, Exception innerException, Guid distributedTxId) + internal static TransactionException Create(string? message, Exception? innerException, Guid distributedTxId) { - string messagewithTxId = message; + string? messagewithTxId = message; if (IncludeDistributedTxId(distributedTxId)) messagewithTxId = SR.Format(SR.DistributedTxIDInTransactionException, messagewithTxId, distributedTxId); return Create(messagewithTxId, innerException); } - internal static TransactionException Create(TraceSourceType traceSource, string message, Exception innerException, Guid distributedTxId) + internal static TransactionException Create(TraceSourceType traceSource, string? message, Exception? innerException, Guid distributedTxId) { - string messagewithTxId = message; + string? messagewithTxId = message; if (IncludeDistributedTxId(distributedTxId)) messagewithTxId = SR.Format(SR.DistributedTxIDInTransactionException, messagewithTxId, distributedTxId); return Create(traceSource, messagewithTxId, innerException); } - internal static TransactionException Create(TraceSourceType traceSource, string message, Guid distributedTxId) + internal static TransactionException Create(TraceSourceType traceSource, string? message, Guid distributedTxId) { if (IncludeDistributedTxId(distributedTxId)) { @@ -139,7 +139,7 @@ namespace System.Transactions return new TransactionException(message); } - internal static TransactionException CreateTransactionStateException(Exception innerException, Guid distributedTxId) + internal static TransactionException CreateTransactionStateException(Exception? innerException, Guid distributedTxId) { return Create(SR.TransactionStateException, innerException, distributedTxId); } @@ -159,9 +159,9 @@ namespace System.Transactions return new InvalidOperationException(messagewithTxId); } - internal static Exception CreateInvalidOperationException(TraceSourceType traceSource, string message, Exception innerException, Guid distributedTxId) + internal static Exception CreateInvalidOperationException(TraceSourceType traceSource, string? message, Exception? innerException, Guid distributedTxId) { - string messagewithTxId = message; + string? messagewithTxId = message; if (IncludeDistributedTxId(distributedTxId)) messagewithTxId = SR.Format(SR.DistributedTxIDInTransactionException, messagewithTxId, distributedTxId); @@ -177,16 +177,16 @@ namespace System.Transactions [System.Runtime.CompilerServices.TypeForwardedFrom("System.Transactions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] public class TransactionAbortedException : TransactionException { - internal static new TransactionAbortedException Create(string message, Exception innerException, Guid distributedTxId) + internal static new TransactionAbortedException Create(string? message, Exception? innerException, Guid distributedTxId) { - string messagewithTxId = message; + string? messagewithTxId = message; if (IncludeDistributedTxId(distributedTxId)) messagewithTxId = SR.Format(SR.DistributedTxIDInTransactionException, messagewithTxId, distributedTxId); return TransactionAbortedException.Create(messagewithTxId, innerException); } - internal static new TransactionAbortedException Create(string message, Exception innerException) + internal static new TransactionAbortedException Create(string? message, Exception? innerException) { TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log; if (etwLog.IsEnabled()) @@ -207,7 +207,7 @@ namespace System.Transactions /// /// /// - public TransactionAbortedException(string message) : base(message) + public TransactionAbortedException(string? message) : base(message) { } @@ -216,7 +216,7 @@ namespace System.Transactions /// /// /// - public TransactionAbortedException(string message, Exception innerException) : base(message, innerException) + public TransactionAbortedException(string? message, Exception? innerException) : base(message, innerException) { } @@ -224,11 +224,11 @@ namespace System.Transactions /// /// /// - internal TransactionAbortedException(Exception innerException) : base(SR.TransactionAborted, innerException) + internal TransactionAbortedException(Exception? innerException) : base(SR.TransactionAborted, innerException) { } - internal TransactionAbortedException(Exception innerException, Guid distributedTxId) : + internal TransactionAbortedException(Exception? innerException, Guid distributedTxId) : base(IncludeDistributedTxId(distributedTxId) ? SR.Format(SR.DistributedTxIDInTransactionException, SR.TransactionAborted, distributedTxId) : SR.TransactionAborted, innerException) @@ -252,16 +252,16 @@ namespace System.Transactions [System.Runtime.CompilerServices.TypeForwardedFrom("System.Transactions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] public class TransactionInDoubtException : TransactionException { - internal static new TransactionInDoubtException Create(TraceSourceType traceSource, string message, Exception innerException, Guid distributedTxId) + internal static new TransactionInDoubtException Create(TraceSourceType traceSource, string? message, Exception? innerException, Guid distributedTxId) { - string messagewithTxId = message; + string? messagewithTxId = message; if (IncludeDistributedTxId(distributedTxId)) messagewithTxId = SR.Format(SR.DistributedTxIDInTransactionException, messagewithTxId, distributedTxId); return TransactionInDoubtException.Create(traceSource, messagewithTxId, innerException); } - internal static new TransactionInDoubtException Create(TraceSourceType traceSource, string message, Exception innerException) + internal static new TransactionInDoubtException Create(TraceSourceType traceSource, string? message, Exception? innerException) { TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log; if (etwLog.IsEnabled()) @@ -283,7 +283,7 @@ namespace System.Transactions /// /// /// - public TransactionInDoubtException(string message) : base(message) + public TransactionInDoubtException(string? message) : base(message) { } @@ -292,7 +292,7 @@ namespace System.Transactions /// /// /// - public TransactionInDoubtException(string message, Exception innerException) : base(message, innerException) + public TransactionInDoubtException(string? message, Exception? innerException) : base(message, innerException) { } @@ -313,7 +313,7 @@ namespace System.Transactions [System.Runtime.CompilerServices.TypeForwardedFrom("System.Transactions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] public class TransactionManagerCommunicationException : TransactionException { - internal static new TransactionManagerCommunicationException Create(string message, Exception innerException) + internal static new TransactionManagerCommunicationException Create(string? message, Exception? innerException) { TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log; if (etwLog.IsEnabled()) @@ -324,7 +324,7 @@ namespace System.Transactions return new TransactionManagerCommunicationException(message, innerException); } - internal static TransactionManagerCommunicationException Create(Exception innerException) + internal static TransactionManagerCommunicationException Create(Exception? innerException) { return Create(SR.TransactionManagerCommunicationException, innerException); } @@ -340,7 +340,7 @@ namespace System.Transactions /// /// /// - public TransactionManagerCommunicationException(string message) : base(message) + public TransactionManagerCommunicationException(string? message) : base(message) { } @@ -350,8 +350,8 @@ namespace System.Transactions /// /// public TransactionManagerCommunicationException( - string message, - Exception innerException + string? message, + Exception? innerException ) : base(message, innerException) { } @@ -381,7 +381,7 @@ namespace System.Transactions /// /// /// - public TransactionPromotionException(string message) : base(message) + public TransactionPromotionException(string? message) : base(message) { } @@ -390,7 +390,7 @@ namespace System.Transactions /// /// /// - public TransactionPromotionException(string message, Exception innerException) : base(message, innerException) + public TransactionPromotionException(string? message, Exception? innerException) : base(message, innerException) { } diff --git a/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionInformation.cs b/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionInformation.cs index 020903b..8c3ce9f 100644 --- a/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionInformation.cs +++ b/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionInformation.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Diagnostics; + namespace System.Transactions { public class TransactionInformation @@ -55,6 +57,7 @@ namespace System.Transactions lock (_internalTransaction) { + Debug.Assert(_internalTransaction.State != null); return _internalTransaction.State.get_Identifier(_internalTransaction); } } @@ -83,6 +86,7 @@ namespace System.Transactions try { + Debug.Assert(_internalTransaction.State != null); return _internalTransaction.State.get_Status(_internalTransaction); } finally diff --git a/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionInterop.cs b/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionInterop.cs index c5e85d1..2219525 100644 --- a/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionInterop.cs +++ b/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionInterop.cs @@ -38,7 +38,7 @@ namespace System.Transactions throw TransactionException.CreateTransactionCompletedException(transaction.DistributedTxId); } - DistributedTransaction distributedTx = transaction.Promote(); + DistributedTransaction? distributedTx = transaction.Promote(); if (distributedTx == null) { throw DistributedTransaction.NotSupported(); @@ -123,7 +123,7 @@ namespace System.Transactions // First check to see if there is a promoted LTM transaction with the same ID. If there // is, just return that. - Transaction transaction = TransactionManager.FindPromotedTransaction(txId); + Transaction? transaction = TransactionManager.FindPromotedTransaction(txId); if (transaction != null) { if (etwLog.IsEnabled()) @@ -194,7 +194,7 @@ namespace System.Transactions var txId = new Guid(propagationToken.AsSpan(8, 16)); // First check to see if there is a promoted LTM transaction with the same ID. If there is, just return that. - Transaction tx = TransactionManager.FindPromotedTransaction(txId); + Transaction? tx = TransactionManager.FindPromotedTransaction(txId); if (null != tx) { if (etwLog.IsEnabled()) diff --git a/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionManager.cs b/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionManager.cs index 5c02a86..a6f3d00 100644 --- a/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionManager.cs +++ b/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionManager.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Collections; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.Runtime.Serialization; @@ -13,9 +14,9 @@ using System.Transactions.Distributed; namespace System.Transactions { - public delegate Transaction HostCurrentTransactionCallback(); + public delegate Transaction? HostCurrentTransactionCallback(); - public delegate void TransactionStartedEventHandler(object sender, TransactionEventArgs e); + public delegate void TransactionStartedEventHandler(object? sender, TransactionEventArgs e); public static class TransactionManager { @@ -26,19 +27,19 @@ namespace System.Transactions // Hashtable of promoted transactions, keyed by identifier guid. This is used by // FindPromotedTransaction to support transaction equivalence when a transaction is // serialized and then deserialized back in this app-domain. - private static Hashtable s_promotedTransactionTable; + private static Hashtable? s_promotedTransactionTable; // Sorted Table of transaction timeouts - private static TransactionTable s_transactionTable; + private static TransactionTable? s_transactionTable; - private static TransactionStartedEventHandler s_distributedTransactionStartedDelegate; - public static event TransactionStartedEventHandler DistributedTransactionStarted + private static TransactionStartedEventHandler? s_distributedTransactionStartedDelegate; + public static event TransactionStartedEventHandler? DistributedTransactionStarted { add { lock (ClassSyncObject) { - s_distributedTransactionStartedDelegate = (TransactionStartedEventHandler)System.Delegate.Combine(s_distributedTransactionStartedDelegate, value); + s_distributedTransactionStartedDelegate = (TransactionStartedEventHandler?)System.Delegate.Combine(s_distributedTransactionStartedDelegate, value); if (value != null) { ProcessExistingTransactions(value); @@ -50,7 +51,7 @@ namespace System.Transactions { lock (ClassSyncObject) { - s_distributedTransactionStartedDelegate = (TransactionStartedEventHandler)System.Delegate.Remove(s_distributedTransactionStartedDelegate, value); + s_distributedTransactionStartedDelegate = (TransactionStartedEventHandler?)System.Delegate.Remove(s_distributedTransactionStartedDelegate, value); } } } @@ -63,9 +64,9 @@ namespace System.Transactions IDictionaryEnumerator e = PromotedTransactionTable.GetEnumerator(); while (e.MoveNext()) { - WeakReference weakRef = (WeakReference)e.Value; - Transaction tx = (Transaction)weakRef.Target; - if (tx != null) + WeakReference weakRef = (WeakReference)e.Value!; + + if (weakRef.Target is Transaction tx) { TransactionEventArgs args = new TransactionEventArgs(); args._transaction = tx.InternalClone(); @@ -77,7 +78,7 @@ namespace System.Transactions internal static void FireDistributedTransactionStarted(Transaction transaction) { - TransactionStartedEventHandler localStartedEventHandler = null; + TransactionStartedEventHandler? localStartedEventHandler = null; lock (ClassSyncObject) { localStartedEventHandler = s_distributedTransactionStartedDelegate; @@ -92,13 +93,14 @@ namespace System.Transactions } // Data storage for current delegate - internal static HostCurrentTransactionCallback s_currentDelegate = null; + internal static HostCurrentTransactionCallback? s_currentDelegate = null; internal static bool s_currentDelegateSet = false; // CurrentDelegate // // Store a delegate to be used to query for an external current transaction. - public static HostCurrentTransactionCallback HostCurrentCallback + [DisallowNull] + public static HostCurrentTransactionCallback? HostCurrentCallback { // get_HostCurrentCallback is used from get_CurrentTransaction, which doesn't have any permission requirements. // We don't expose what is returned from this property in that case. But we don't want just anybody being able @@ -161,8 +163,8 @@ namespace System.Transactions // Put the recovery information into a stream. MemoryStream stream = new MemoryStream(recoveryInformation); int recoveryInformationVersion = 0; - string nodeName = null; - byte[] resourceManagerRecoveryInformation = null; + string? nodeName = null; + byte[]? resourceManagerRecoveryInformation = null; try { @@ -229,7 +231,7 @@ namespace System.Transactions } - private static DistributedTransactionManager CheckTransactionManager(string nodeName) + private static DistributedTransactionManager CheckTransactionManager(string? nodeName) { DistributedTransactionManager tm = DistributedTransactionManager; if (!((tm.NodeName == null && (nodeName == null || nodeName.Length == 0)) || @@ -264,7 +266,7 @@ namespace System.Transactions // Object for synchronizing access to the entire class( avoiding lock( typeof( ... )) ) - private static object s_classSyncObject; + private static object? s_classSyncObject; // Helper object for static synchronization private static object ClassSyncObject => LazyInitializer.EnsureInitialized(ref s_classSyncObject); @@ -285,7 +287,7 @@ namespace System.Transactions } - private static DefaultSettingsSection s_defaultSettings; + private static DefaultSettingsSection? s_defaultSettings; private static DefaultSettingsSection DefaultSettings { get @@ -300,7 +302,7 @@ namespace System.Transactions } - private static MachineSettingsSection s_machineSettings; + private static MachineSettingsSection? s_machineSettings; private static MachineSettingsSection MachineSettings { get @@ -377,7 +379,7 @@ namespace System.Transactions // type of the calling object and its provided parameter collection. This information // we be read back by the static Reenlist method to create the necessary transaction // manager object with the right parameters in order to do a ReenlistTransaction call. - internal static byte[] GetRecoveryInformation(string startupInfo, byte[] resourceManagerRecoveryInformation) + internal static byte[] GetRecoveryInformation(string? startupInfo, byte[] resourceManagerRecoveryInformation) { TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log; if (etwLog.IsEnabled()) @@ -386,7 +388,7 @@ namespace System.Transactions } MemoryStream stream = new MemoryStream(); - byte[] returnValue = null; + byte[]? returnValue = null; try { @@ -422,7 +424,7 @@ namespace System.Transactions internal static byte[] ConvertToByteArray(object thingToConvert) { MemoryStream streamToWrite = new MemoryStream(); - byte[] returnValue = null; + byte[]? returnValue = null; try { @@ -493,14 +495,13 @@ namespace System.Transactions return transactionTimeout; } - internal static Transaction FindPromotedTransaction(Guid transactionIdentifier) + internal static Transaction? FindPromotedTransaction(Guid transactionIdentifier) { Hashtable promotedTransactionTable = PromotedTransactionTable; - WeakReference weakRef = (WeakReference)promotedTransactionTable[transactionIdentifier]; + WeakReference? weakRef = (WeakReference?)promotedTransactionTable[transactionIdentifier]; if (null != weakRef) { - Transaction tx = weakRef.Target as Transaction; - if (null != tx) + if (weakRef.Target is Transaction tx) { return tx.InternalClone(); } @@ -518,11 +519,11 @@ namespace System.Transactions internal static Transaction FindOrCreatePromotedTransaction(Guid transactionIdentifier, DistributedTransaction dtx) { - Transaction tx = null; + Transaction? tx = null; Hashtable promotedTransactionTable = PromotedTransactionTable; lock (promotedTransactionTable) { - WeakReference weakRef = (WeakReference)promotedTransactionTable[transactionIdentifier]; + WeakReference? weakRef = (WeakReference?)promotedTransactionTable[transactionIdentifier]; if (null != weakRef) { tx = weakRef.Target as Transaction; @@ -566,7 +567,7 @@ namespace System.Transactions LazyInitializer.EnsureInitialized(ref s_transactionTable, ref s_classSyncObject, () => new TransactionTable()); // Fault in a DistributedTransactionManager if one has not already been created. - internal static DistributedTransactionManager distributedTransactionManager; + internal static DistributedTransactionManager? distributedTransactionManager; internal static DistributedTransactionManager DistributedTransactionManager => // If the distributed transaction manager is not configured, throw an exception LazyInitializer.EnsureInitialized(ref distributedTransactionManager, ref s_classSyncObject, () => new DistributedTransactionManager()); diff --git a/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionOptions.cs b/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionOptions.cs index 6a964a5..7ed59f3 100644 --- a/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionOptions.cs +++ b/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionOptions.cs @@ -23,7 +23,7 @@ namespace System.Transactions public override int GetHashCode() => base.GetHashCode(); // Don't have anything better to do. - public override bool Equals(object obj) => obj is TransactionOptions && Equals((TransactionOptions)obj); + public override bool Equals(object? obj) => obj is TransactionOptions transactionOptions && Equals(transactionOptions); private bool Equals(TransactionOptions other) => _timeout == other._timeout && diff --git a/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionScope.cs b/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionScope.cs index 280ed9b..71e2285 100644 --- a/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionScope.cs +++ b/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionScope.cs @@ -530,21 +530,22 @@ namespace System.Transactions throw new InvalidOperationException(SR.InvalidScopeThread); } - Exception exToThrow = null; + Exception? exToThrow = null; try { // Single threaded from this point _disposed = true; + Debug.Assert(_threadContextData != null); // First, lets pop the "stack" of TransactionScopes and dispose each one that is above us in // the stack, making sure they are NOT consistent before disposing them. // Optimize the first lookup by getting both the actual current scope and actual current // transaction at the same time. - TransactionScope actualCurrentScope = _threadContextData.CurrentScope; - Transaction contextTransaction = null; - Transaction current = Transaction.FastGetTransaction(actualCurrentScope, _threadContextData, out contextTransaction); + TransactionScope? actualCurrentScope = _threadContextData.CurrentScope; + Transaction? contextTransaction = null; + Transaction? current = Transaction.FastGetTransaction(actualCurrentScope, _threadContextData, out contextTransaction); if (!Equals(actualCurrentScope)) { @@ -556,7 +557,7 @@ namespace System.Transactions // Something must have gone wrong trying to clean up a bad scope // stack previously. // Make a best effort to abort the active transaction. - Transaction rollbackTransaction = _committableTransaction; + Transaction? rollbackTransaction = _committableTransaction; if (rollbackTransaction == null) { rollbackTransaction = _dependentTransaction; @@ -633,7 +634,7 @@ namespace System.Transactions current == null ? Guid.Empty : current.DistributedTxId); } - if (null == actualCurrentScope._expectedCurrent) + if (null == actualCurrentScope!._expectedCurrent) { if (etwLog.IsEnabled()) { @@ -793,7 +794,7 @@ namespace System.Transactions // Note: Rollback is not called on expected current because someone could conceiveably // dispose expectedCurrent out from under the transaction scope. // - Transaction rollbackTransaction = _committableTransaction; + Transaction? rollbackTransaction = _committableTransaction; if (rollbackTransaction == null) { rollbackTransaction = _dependentTransaction; @@ -827,6 +828,7 @@ namespace System.Transactions { _committableTransaction.Dispose(); + Debug.Assert(_expectedCurrent != null); // If we created the committable transaction then we placed a clone in expectedCurrent // and it needs to be disposed as well. _expectedCurrent.Dispose(); @@ -863,9 +865,9 @@ namespace System.Transactions } } - private static void TimerCallback(object state) + private static void TimerCallback(object? state) { - TransactionScope scope = state as TransactionScope; + TransactionScope? scope = state as TransactionScope; if (null == scope) { TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log; @@ -952,6 +954,7 @@ namespace System.Transactions if (AsyncFlowEnabled) { + Debug.Assert(ContextKey != null); // Async Flow is enabled and CallContext will be used for ambient transaction. _threadContextData = CallContextCurrentData.CreateOrGetCurrentData(ContextKey); @@ -998,6 +1001,7 @@ namespace System.Transactions { if (_savedCurrentScope.AsyncFlowEnabled) { + Debug.Assert(_savedCurrentScope.ContextKey != null); _threadContextData = CallContextCurrentData.CreateOrGetCurrentData(_savedCurrentScope.ContextKey); } else @@ -1039,6 +1043,7 @@ namespace System.Transactions // prevent restoring the context in an unexpected thread due to thread switch during TransactionScope's Dispose if (shouldRestoreContextData) { + Debug.Assert(_threadContextData != null); _threadContextData.CurrentScope = _savedCurrentScope; RestoreCurrent(); } @@ -1047,7 +1052,7 @@ namespace System.Transactions // SetCurrent // // Place the given value in current by whatever means necessary for interop mode. - private void SetCurrent(Transaction newCurrent) + private void SetCurrent(Transaction? newCurrent) { // Keep a dependent clone of current if we don't have one and we are not committable if (_dependentTransaction == null && _committableTransaction == null) @@ -1061,7 +1066,7 @@ namespace System.Transactions switch (_interopOption) { case EnterpriseServicesInteropOption.None: - _threadContextData.CurrentTransaction = newCurrent; + _threadContextData!.CurrentTransaction = newCurrent; break; case EnterpriseServicesInteropOption.Automatic: @@ -1072,7 +1077,7 @@ namespace System.Transactions } else { - _threadContextData.CurrentTransaction = newCurrent; + _threadContextData!.CurrentTransaction = newCurrent; } break; @@ -1118,7 +1123,7 @@ namespace System.Transactions } // Only restore the value that was actually in the context. - _threadContextData.CurrentTransaction = _contextTransaction; + _threadContextData!.CurrentTransaction = _contextTransaction; } @@ -1137,7 +1142,7 @@ namespace System.Transactions // ValidateScopeTimeout // // Scope timeouts are not governed by MaxTimeout and therefore need a special validate function - private void ValidateScopeTimeout(string paramName, TimeSpan scopeTimeout) + private void ValidateScopeTimeout(string? paramName, TimeSpan scopeTimeout) { if (scopeTimeout < TimeSpan.Zero) { @@ -1189,41 +1194,41 @@ namespace System.Transactions } // Storage location for the previous current transaction. - private Transaction _savedCurrent; + private Transaction? _savedCurrent; // To ensure that we don't restore a value for current that was // returned to us by an external entity keep the value that was actually // in TLS when the scope was created. - private Transaction _contextTransaction; + private Transaction? _contextTransaction; // Storage for the value to restore to current - private TransactionScope _savedCurrentScope; + private TransactionScope? _savedCurrentScope; // Store a reference to the context data object for this scope. - private ContextData _threadContextData; + private ContextData? _threadContextData; - private ContextData _savedTLSContextData; + private ContextData? _savedTLSContextData; // Store a reference to the value that this scope expects for current - private Transaction _expectedCurrent; + private Transaction? _expectedCurrent; // Store a reference to the committable form of this transaction if // the scope made one. - private CommittableTransaction _committableTransaction; + private CommittableTransaction? _committableTransaction; // Store a reference to the scopes transaction guard. - private DependentTransaction _dependentTransaction; + private DependentTransaction? _dependentTransaction; // Note when the scope is disposed. private bool _disposed; // BUGBUG: A shared timer should be used. // Individual timer for this scope. - private Timer _scopeTimer; + private Timer? _scopeTimer; // Store a reference to the thread on which the scope was created so that we can // check to make sure that the dispose pattern for scope is being used correctly. - private Thread _scopeThread; + private Thread? _scopeThread; // Store the interop mode for this transaction scope. private bool _interopModeSpecified = false; @@ -1236,7 +1241,7 @@ namespace System.Transactions } } - internal ContextKey ContextKey + internal ContextKey? ContextKey { get; private set; diff --git a/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionState.cs b/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionState.cs index 2d911c0..cb49abc 100644 --- a/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionState.cs +++ b/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionState.cs @@ -20,45 +20,45 @@ namespace System.Transactions // The state machines themselves are designed to be internally consistent. So the only externally visable // state transition is to active. All other state transitions must happen within the state machines // themselves. - private static TransactionStateActive s_transactionStateActive; - private static TransactionStateSubordinateActive s_transactionStateSubordinateActive; - private static TransactionStatePhase0 s_transactionStatePhase0; - private static TransactionStateVolatilePhase1 s_transactionStateVolatilePhase1; - private static TransactionStateVolatileSPC s_transactionStateVolatileSPC; - private static TransactionStateSPC s_transactionStateSPC; - private static TransactionStateAborted s_transactionStateAborted; - private static TransactionStateCommitted s_transactionStateCommitted; - private static TransactionStateInDoubt s_transactionStateInDoubt; - - private static TransactionStatePromoted s_transactionStatePromoted; - private static TransactionStateNonCommittablePromoted s_transactionStateNonCommittablePromoted; - private static TransactionStatePromotedP0Wave s_transactionStatePromotedP0Wave; - private static TransactionStatePromotedCommitting s_transactionStatePromotedCommitting; - private static TransactionStatePromotedPhase0 s_transactionStatePromotedPhase0; - private static TransactionStatePromotedPhase1 s_transactionStatePromotedPhase1; - private static TransactionStatePromotedP0Aborting s_transactionStatePromotedP0Aborting; - private static TransactionStatePromotedP1Aborting s_transactionStatePromotedP1Aborting; - private static TransactionStatePromotedAborted s_transactionStatePromotedAborted; - private static TransactionStatePromotedCommitted s_transactionStatePromotedCommitted; - private static TransactionStatePromotedIndoubt s_transactionStatePromotedIndoubt; - - private static TransactionStateDelegated s_transactionStateDelegated; - private static TransactionStateDelegatedSubordinate s_transactionStateDelegatedSubordinate; - private static TransactionStateDelegatedP0Wave s_transactionStateDelegatedP0Wave; - private static TransactionStateDelegatedCommitting s_transactionStateDelegatedCommitting; - private static TransactionStateDelegatedAborting s_transactionStateDelegatedAborting; - private static TransactionStatePSPEOperation s_transactionStatePSPEOperation; - - private static TransactionStateDelegatedNonMSDTC s_transactionStateDelegatedNonMSDTC; - private static TransactionStatePromotedNonMSDTCPhase0 s_transactionStatePromotedNonMSDTCPhase0; - private static TransactionStatePromotedNonMSDTCVolatilePhase1 s_transactionStatePromotedNonMSDTCVolatilePhase1; - private static TransactionStatePromotedNonMSDTCSinglePhaseCommit s_transactionStatePromotedNonMSDTCSinglePhaseCommit; - private static TransactionStatePromotedNonMSDTCAborted s_transactionStatePromotedNonMSDTCAborted; - private static TransactionStatePromotedNonMSDTCCommitted s_transactionStatePromotedNonMSDTCCommitted; - private static TransactionStatePromotedNonMSDTCIndoubt s_transactionStatePromotedNonMSDTCIndoubt; + private static TransactionStateActive? s_transactionStateActive; + private static TransactionStateSubordinateActive? s_transactionStateSubordinateActive; + private static TransactionStatePhase0? s_transactionStatePhase0; + private static TransactionStateVolatilePhase1? s_transactionStateVolatilePhase1; + private static TransactionStateVolatileSPC? s_transactionStateVolatileSPC; + private static TransactionStateSPC? s_transactionStateSPC; + private static TransactionStateAborted? s_transactionStateAborted; + private static TransactionStateCommitted? s_transactionStateCommitted; + private static TransactionStateInDoubt? s_transactionStateInDoubt; + + private static TransactionStatePromoted? s_transactionStatePromoted; + private static TransactionStateNonCommittablePromoted? s_transactionStateNonCommittablePromoted; + private static TransactionStatePromotedP0Wave? s_transactionStatePromotedP0Wave; + private static TransactionStatePromotedCommitting? s_transactionStatePromotedCommitting; + private static TransactionStatePromotedPhase0? s_transactionStatePromotedPhase0; + private static TransactionStatePromotedPhase1? s_transactionStatePromotedPhase1; + private static TransactionStatePromotedP0Aborting? s_transactionStatePromotedP0Aborting; + private static TransactionStatePromotedP1Aborting? s_transactionStatePromotedP1Aborting; + private static TransactionStatePromotedAborted? s_transactionStatePromotedAborted; + private static TransactionStatePromotedCommitted? s_transactionStatePromotedCommitted; + private static TransactionStatePromotedIndoubt? s_transactionStatePromotedIndoubt; + + private static TransactionStateDelegated? s_transactionStateDelegated; + private static TransactionStateDelegatedSubordinate? s_transactionStateDelegatedSubordinate; + private static TransactionStateDelegatedP0Wave? s_transactionStateDelegatedP0Wave; + private static TransactionStateDelegatedCommitting? s_transactionStateDelegatedCommitting; + private static TransactionStateDelegatedAborting? s_transactionStateDelegatedAborting; + private static TransactionStatePSPEOperation? s_transactionStatePSPEOperation; + + private static TransactionStateDelegatedNonMSDTC? s_transactionStateDelegatedNonMSDTC; + private static TransactionStatePromotedNonMSDTCPhase0? s_transactionStatePromotedNonMSDTCPhase0; + private static TransactionStatePromotedNonMSDTCVolatilePhase1? s_transactionStatePromotedNonMSDTCVolatilePhase1; + private static TransactionStatePromotedNonMSDTCSinglePhaseCommit? s_transactionStatePromotedNonMSDTCSinglePhaseCommit; + private static TransactionStatePromotedNonMSDTCAborted? s_transactionStatePromotedNonMSDTCAborted; + private static TransactionStatePromotedNonMSDTCCommitted? s_transactionStatePromotedNonMSDTCCommitted; + private static TransactionStatePromotedNonMSDTCIndoubt? s_transactionStatePromotedNonMSDTCIndoubt; // Object for synchronizing access to the entire class( avoiding lock( typeof( ... )) ) - internal static object s_classSyncObject; + internal static object? s_classSyncObject; internal static TransactionStateActive TransactionStateActive => LazyInitializer.EnsureInitialized(ref s_transactionStateActive, ref s_classSyncObject, () => new TransactionStateActive()); @@ -176,7 +176,7 @@ namespace System.Transactions // Every state must override EnterState internal abstract void EnterState(InternalTransaction tx); - internal virtual void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback asyncCallback, object asyncState) + internal virtual void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback? asyncCallback, object? asyncState) { throw TransactionException.CreateTransactionStateException(tx._innerException, tx.DistributedTxId); } @@ -188,7 +188,7 @@ namespace System.Transactions throw TransactionException.CreateTransactionStateException(tx._innerException, tx.DistributedTxId); } - internal virtual void Rollback(InternalTransaction tx, Exception e) + internal virtual void Rollback(InternalTransaction tx, Exception? e) { throw TransactionException.CreateTransactionStateException(tx._innerException, tx.DistributedTxId); } @@ -256,7 +256,7 @@ namespace System.Transactions // Every state derived from the base must override status internal abstract TransactionStatus get_Status(InternalTransaction tx); - internal virtual void AddOutcomeRegistrant(InternalTransaction tx, TransactionCompletedEventHandler transactionCompletedDelegate) + internal virtual void AddOutcomeRegistrant(InternalTransaction tx, TransactionCompletedEventHandler? transactionCompletedDelegate) { throw TransactionException.CreateTransactionStateException(tx._innerException, tx.DistributedTxId); } @@ -295,7 +295,7 @@ namespace System.Transactions throw TransactionException.CreateTransactionStateException(tx._innerException, tx.DistributedTxId); } - internal virtual void ChangeStateTransactionAborted(InternalTransaction tx, Exception e) + internal virtual void ChangeStateTransactionAborted(InternalTransaction tx, Exception? e) { Debug.Fail($"Invalid Event for State; Current State: {GetType()}"); TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log; @@ -524,9 +524,9 @@ namespace System.Transactions return TransactionStatus.Active; } - internal override void AddOutcomeRegistrant(InternalTransaction tx, TransactionCompletedEventHandler transactionCompletedDelegate) + internal override void AddOutcomeRegistrant(InternalTransaction tx, TransactionCompletedEventHandler? transactionCompletedDelegate) { - tx._transactionCompletedDelegate = (TransactionCompletedEventHandler) + tx._transactionCompletedDelegate = (TransactionCompletedEventHandler?) System.Delegate.Combine(tx._transactionCompletedDelegate, transactionCompletedDelegate); } } @@ -550,7 +550,7 @@ namespace System.Transactions tx._promoteState.EnterState(tx); // Note that just because we did an EnterState above does not mean that the state will be // the same when the next method is called. - return tx.State.EnlistDurable(tx, resourceManagerIdentifier, enlistmentNotification, enlistmentOptions, atomicTransaction); + return tx.State!.EnlistDurable(tx, resourceManagerIdentifier, enlistmentNotification, enlistmentOptions, atomicTransaction); } internal override Enlistment EnlistDurable( @@ -566,7 +566,7 @@ namespace System.Transactions { // These circumstances cause promotion tx._promoteState.EnterState(tx); - return tx.State.EnlistDurable(tx, resourceManagerIdentifier, enlistmentNotification, enlistmentOptions, atomicTransaction); + return tx.State!.EnlistDurable(tx, resourceManagerIdentifier, enlistmentNotification, enlistmentOptions, atomicTransaction); } // Create a durable enlistment @@ -604,7 +604,7 @@ namespace System.Transactions tx._promoteState.EnterState(tx); // Forward this call - tx.State.GetObjectData(tx, serializationInfo, context); + tx.State!.GetObjectData(tx, serializationInfo, context); } internal override void CompleteBlockingClone(InternalTransaction tx) @@ -623,7 +623,7 @@ namespace System.Transactions if (tx._phase0Volatiles._preparedVolatileEnlistments == tx._phase0VolatileWaveCount + tx._phase0Volatiles._dependentClones) { - tx.State.Phase0VolatilePrepareDone(tx); + tx.State!.Phase0VolatilePrepareDone(tx); } } @@ -652,7 +652,7 @@ namespace System.Transactions internal override void Promote(InternalTransaction tx) { tx._promoteState.EnterState(tx); - tx.State.CheckForFinishedTransaction(tx); + tx.State!.CheckForFinishedTransaction(tx); } internal override byte[] PromotedToken(InternalTransaction tx) @@ -660,9 +660,9 @@ namespace System.Transactions if (tx.promotedToken == null) { tx._promoteState.EnterState(tx); - tx.State.CheckForFinishedTransaction(tx); + tx.State!.CheckForFinishedTransaction(tx); } - + Debug.Assert(tx.promotedToken != null); return tx.promotedToken; } } @@ -682,7 +682,7 @@ namespace System.Transactions // Yeah it's active. } - internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback asyncCallback, object asyncState) + internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback? asyncCallback, object? asyncState) { // Store the given values tx._asyncCommit = asyncCommit; @@ -693,7 +693,7 @@ namespace System.Transactions TransactionStatePhase0.EnterState(tx); } - internal override void Rollback(InternalTransaction tx, Exception e) + internal override void Rollback(InternalTransaction tx, Exception? e) { // Start the process for abort. From the active state we can transition directly // to the aborted state. @@ -820,7 +820,7 @@ namespace System.Transactions internal override void DisposeRoot(InternalTransaction tx) { - tx.State.Rollback(tx, null); + tx.State!.Rollback(tx, null); } } @@ -839,7 +839,7 @@ namespace System.Transactions Debug.Assert(tx._promoter != null, "Transaction Promoter is Null entering SubordinateActive"); } - internal override void Rollback(InternalTransaction tx, Exception e) + internal override void Rollback(InternalTransaction tx, Exception? e) { // Start the process for abort. From the active state we can transition directly // to the aborted state. @@ -849,6 +849,7 @@ namespace System.Transactions tx._innerException = e; } + Debug.Assert(tx._promoter != null); ((ISimpleTransactionSuperior)tx._promoter).Rollback(); TransactionStateAborted.EnterState(tx); } @@ -861,7 +862,7 @@ namespace System.Transactions ) { tx._promoteState.EnterState(tx); - return tx.State.EnlistVolatile(tx, enlistmentNotification, enlistmentOptions, atomicTransaction); + return tx.State!.EnlistVolatile(tx, enlistmentNotification, enlistmentOptions, atomicTransaction); } internal override Enlistment EnlistVolatile( @@ -872,20 +873,20 @@ namespace System.Transactions ) { tx._promoteState.EnterState(tx); - return tx.State.EnlistVolatile(tx, enlistmentNotification, enlistmentOptions, atomicTransaction); + return tx.State!.EnlistVolatile(tx, enlistmentNotification, enlistmentOptions, atomicTransaction); } // Every state derived from the base must override status internal override TransactionStatus get_Status(InternalTransaction tx) { tx._promoteState.EnterState(tx); - return tx.State.get_Status(tx); + return tx.State!.get_Status(tx); } - internal override void AddOutcomeRegistrant(InternalTransaction tx, TransactionCompletedEventHandler transactionCompletedDelegate) + internal override void AddOutcomeRegistrant(InternalTransaction tx, TransactionCompletedEventHandler? transactionCompletedDelegate) { tx._promoteState.EnterState(tx); - tx.State.AddOutcomeRegistrant(tx, transactionCompletedDelegate); + tx.State!.AddOutcomeRegistrant(tx, transactionCompletedDelegate); } internal override bool EnlistPromotableSinglePhase( @@ -901,14 +902,14 @@ namespace System.Transactions internal override void CreateBlockingClone(InternalTransaction tx) { tx._promoteState.EnterState(tx); - tx.State.CreateBlockingClone(tx); + tx.State!.CreateBlockingClone(tx); } internal override void CreateAbortingClone(InternalTransaction tx) { tx._promoteState.EnterState(tx); - tx.State.CreateAbortingClone(tx); + tx.State!.CreateAbortingClone(tx); } } @@ -937,8 +938,8 @@ namespace System.Transactions // Broadcast prepare to the phase 0 enlistments for (int i = 0; i < volatileCount; i++) { - tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState.ChangeStatePreparing(tx._phase0Volatiles._volatileEnlistments[i]); - if (!tx.State.ContinuePhase0Prepares()) + tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState!.ChangeStatePreparing(tx._phase0Volatiles._volatileEnlistments[i]); + if (!tx.State!.ContinuePhase0Prepares()) { break; } @@ -965,7 +966,7 @@ namespace System.Transactions enlistmentOptions, atomicTransaction); // Calling durable enlist in Phase0 may cause the transaction to promote. Leverage the promoted - tx.State.RestartCommitIfNeeded(tx); + tx.State!.RestartCommitIfNeeded(tx); return en; } @@ -983,7 +984,7 @@ namespace System.Transactions enlistmentOptions, atomicTransaction); // Calling durable enlist in Phase0 may cause the transaction to promote. Leverage the promoted - tx.State.RestartCommitIfNeeded(tx); + tx.State!.RestartCommitIfNeeded(tx); return en; } @@ -1040,7 +1041,7 @@ namespace System.Transactions return enlistment; } - internal override void Rollback(InternalTransaction tx, Exception e) + internal override void Rollback(InternalTransaction tx, Exception? e) { ChangeStateTransactionAborted(tx, e); } @@ -1117,8 +1118,8 @@ namespace System.Transactions // Broadcast prepare to the phase 0 enlistments for (int i = 0; i < volatileCount; i++) { - tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState.ChangeStatePreparing(tx._phase0Volatiles._volatileEnlistments[i]); - if (!tx.State.ContinuePhase0Prepares()) + tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState!.ChangeStatePreparing(tx._phase0Volatiles._volatileEnlistments[i]); + if (!tx.State!.ContinuePhase0Prepares()) { break; } @@ -1149,11 +1150,11 @@ namespace System.Transactions internal override void Promote(InternalTransaction tx) { tx._promoteState.EnterState(tx); - tx.State.CheckForFinishedTransaction(tx); + tx.State!.CheckForFinishedTransaction(tx); tx.State.RestartCommitIfNeeded(tx); } - internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception e) + internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception? e) { if (tx._innerException == null) { @@ -1172,7 +1173,7 @@ namespace System.Transactions tx._promoteState.EnterState(tx); // Forward this call - tx.State.GetObjectData(tx, serializationInfo, context); + tx.State!.GetObjectData(tx, serializationInfo, context); // Restart the commit process. tx.State.RestartCommitIfNeeded(tx); @@ -1189,6 +1190,7 @@ namespace System.Transactions // Set the transaction state CommonEnterState(tx); + Debug.Assert(tx._committableTransaction != null); // Mark the committable transaction as complete. tx._committableTransaction._complete = true; @@ -1210,8 +1212,8 @@ namespace System.Transactions // Broadcast prepare to the phase 0 enlistments for (int i = 0; i < tx._phase1Volatiles._volatileEnlistmentCount; i++) { - tx._phase1Volatiles._volatileEnlistments[i]._twoPhaseState.ChangeStatePreparing(tx._phase1Volatiles._volatileEnlistments[i]); - if (!tx.State.ContinuePhase1Prepares()) + tx._phase1Volatiles._volatileEnlistments[i]._twoPhaseState!.ChangeStatePreparing(tx._phase1Volatiles._volatileEnlistments[i]); + if (!tx.State!.ContinuePhase1Prepares()) { break; } @@ -1224,12 +1226,12 @@ namespace System.Transactions } } - internal override void Rollback(InternalTransaction tx, Exception e) + internal override void Rollback(InternalTransaction tx, Exception? e) { ChangeStateTransactionAborted(tx, e); } - internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception e) + internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception? e) { if (tx._innerException == null) { @@ -1277,7 +1279,7 @@ namespace System.Transactions Debug.Assert(tx._phase1Volatiles._volatileEnlistmentCount == 1, "There must be exactly 1 phase 1 volatile enlistment for TransactionStateVolatileSPC"); - tx._phase1Volatiles._volatileEnlistments[0]._twoPhaseState.ChangeStateSinglePhaseCommit( + tx._phase1Volatiles._volatileEnlistments[0]._twoPhaseState!.ChangeStateSinglePhaseCommit( tx._phase1Volatiles._volatileEnlistments[0]); } @@ -1293,7 +1295,7 @@ namespace System.Transactions TransactionStateInDoubt.EnterState(tx); } - internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception e) + internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception? e) { if (tx._innerException == null) { @@ -1340,7 +1342,7 @@ namespace System.Transactions TransactionStateInDoubt.EnterState(tx); } - internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception e) + internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception? e) { if (tx._innerException == null) { @@ -1366,7 +1368,7 @@ namespace System.Transactions } } - internal override void AddOutcomeRegistrant(InternalTransaction tx, TransactionCompletedEventHandler transactionCompletedDelegate) + internal override void AddOutcomeRegistrant(InternalTransaction tx, TransactionCompletedEventHandler? transactionCompletedDelegate) { if (transactionCompletedDelegate != null) { @@ -1401,12 +1403,12 @@ namespace System.Transactions // Notify the enlistments that the transaction has aborted for (int i = 0; i < tx._phase0Volatiles._volatileEnlistmentCount; i++) { - tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState.InternalAborted(tx._phase0Volatiles._volatileEnlistments[i]); + tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState!.InternalAborted(tx._phase0Volatiles._volatileEnlistments[i]); } for (int i = 0; i < tx._phase1Volatiles._volatileEnlistmentCount; i++) { - tx._phase1Volatiles._volatileEnlistments[i]._twoPhaseState.InternalAborted(tx._phase1Volatiles._volatileEnlistments[i]); + tx._phase1Volatiles._volatileEnlistments[i]._twoPhaseState!.InternalAborted(tx._phase1Volatiles._volatileEnlistments[i]); } // Notify the durable enlistment @@ -1440,12 +1442,12 @@ namespace System.Transactions } - internal override void Rollback(InternalTransaction tx, Exception e) + internal override void Rollback(InternalTransaction tx, Exception? e) { // Abort is itempotent. Ignore this if the transaction is already aborted. } - internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback asyncCallback, object asyncState) + internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback? asyncCallback, object? asyncState) { // End Commit Must throw a TransactionAbortedException to let the caller know that the tx aborted. throw CreateTransactionAbortedException(tx); @@ -1478,7 +1480,7 @@ namespace System.Transactions // Since the transaction is aborted ignore it. } - internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception e) + internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception? e) { // Yes, yes, yes... I already know. } @@ -1537,13 +1539,13 @@ namespace System.Transactions // Notify the phase 0 enlistments that the transaction has aborted for (int i = 0; i < tx._phase0Volatiles._volatileEnlistmentCount; i++) { - tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState.InternalCommitted(tx._phase0Volatiles._volatileEnlistments[i]); + tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState!.InternalCommitted(tx._phase0Volatiles._volatileEnlistments[i]); } // Notify the phase 1 enlistments that the transaction has aborted for (int i = 0; i < tx._phase1Volatiles._volatileEnlistmentCount; i++) { - tx._phase1Volatiles._volatileEnlistments[i]._twoPhaseState.InternalCommitted(tx._phase1Volatiles._volatileEnlistments[i]); + tx._phase1Volatiles._volatileEnlistments[i]._twoPhaseState!.InternalCommitted(tx._phase1Volatiles._volatileEnlistments[i]); } // Remove this from the timeout list @@ -1572,7 +1574,7 @@ namespace System.Transactions } - internal override void Rollback(InternalTransaction tx, Exception e) + internal override void Rollback(InternalTransaction tx, Exception? e) { throw TransactionException.CreateTransactionStateException(tx._innerException, tx.DistributedTxId); } @@ -1600,13 +1602,13 @@ namespace System.Transactions // Notify the phase 0 enlistments that the transaction has aborted for (int i = 0; i < tx._phase0Volatiles._volatileEnlistmentCount; i++) { - tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState.InternalIndoubt(tx._phase0Volatiles._volatileEnlistments[i]); + tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState!.InternalIndoubt(tx._phase0Volatiles._volatileEnlistments[i]); } // Notify the phase 1 enlistments that the transaction has aborted for (int i = 0; i < tx._phase1Volatiles._volatileEnlistmentCount; i++) { - tx._phase1Volatiles._volatileEnlistments[i]._twoPhaseState.InternalIndoubt(tx._phase1Volatiles._volatileEnlistments[i]); + tx._phase1Volatiles._volatileEnlistments[i]._twoPhaseState!.InternalIndoubt(tx._phase1Volatiles._volatileEnlistments[i]); } // Remove this from the timeout list @@ -1635,7 +1637,7 @@ namespace System.Transactions } - internal override void Rollback(InternalTransaction tx, Exception e) + internal override void Rollback(InternalTransaction tx, Exception? e) { throw TransactionException.CreateTransactionStateException(tx._innerException, tx.DistributedTxId); } @@ -1818,7 +1820,7 @@ namespace System.Transactions } - internal override void Rollback(InternalTransaction tx, Exception e) + internal override void Rollback(InternalTransaction tx, Exception? e) { Debug.Assert(tx.PromotedTransaction != null, "Promoted state not valid for transaction."); // Forward this on to the promoted transaction. @@ -1841,7 +1843,7 @@ namespace System.Transactions } - internal override Guid get_Identifier(InternalTransaction tx) + internal override Guid get_Identifier(InternalTransaction? tx) { if (tx != null && tx.PromotedTransaction != null) { @@ -1854,15 +1856,15 @@ namespace System.Transactions } - internal override void AddOutcomeRegistrant(InternalTransaction tx, TransactionCompletedEventHandler transactionCompletedDelegate) + internal override void AddOutcomeRegistrant(InternalTransaction tx, TransactionCompletedEventHandler? transactionCompletedDelegate) { // Add this guy to the list of people to be notified of the outcome. - tx._transactionCompletedDelegate = (TransactionCompletedEventHandler) + tx._transactionCompletedDelegate = (TransactionCompletedEventHandler?) System.Delegate.Combine(tx._transactionCompletedDelegate, transactionCompletedDelegate); } - internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback asyncCallback, object asyncState) + internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback? asyncCallback, object? asyncState) { // Store the given values tx._asyncCommit = asyncCommit; @@ -1907,7 +1909,7 @@ namespace System.Transactions if (tx._phase0Volatiles._preparedVolatileEnlistments == tx._phase0VolatileWaveCount + tx._phase0Volatiles._dependentClones) { - tx.State.Phase0VolatilePrepareDone(tx); + tx.State!.Phase0VolatilePrepareDone(tx); } } else @@ -1917,7 +1919,7 @@ namespace System.Transactions Debug.Assert(tx._phase0WaveDependentCloneCount >= 0); if (tx._phase0WaveDependentCloneCount == 0) { - DistributedDependentTransaction dtx = tx._phase0WaveDependentClone; + DistributedDependentTransaction dtx = tx._phase0WaveDependentClone!; tx._phase0WaveDependentClone = null; Monitor.Exit(tx); @@ -1961,7 +1963,7 @@ namespace System.Transactions { // We need to complete our dependent clone on the promoted transaction and null it out // so if we get a new one, a new one will be created on the promoted transaction. - DistributedDependentTransaction dtx = tx._abortingDependentClone; + DistributedDependentTransaction dtx = tx._abortingDependentClone!; tx._abortingDependentClone = null; Monitor.Exit(tx); @@ -1992,6 +1994,7 @@ namespace System.Transactions // will handle phase 0 waves. if (tx._phase0WaveDependentClone == null) { + Debug.Assert(tx.PromotedTransaction != null); tx._phase0WaveDependentClone = tx.PromotedTransaction.DependentClone(true); } @@ -2013,6 +2016,7 @@ namespace System.Transactions { if (null == tx._abortingDependentClone) { + Debug.Assert(tx.PromotedTransaction != null); tx._abortingDependentClone = tx.PromotedTransaction.DependentClone(false); } tx._abortingDependentCloneCount++; @@ -2044,7 +2048,7 @@ namespace System.Transactions // Before forwarding this call to the promoted tx make sure to change // the full type info so that only if the promoted tx does not set this // then it should be set correctly. - serializationInfo.FullTypeName = tx.PromotedTransaction.GetType().FullName; + serializationInfo.FullTypeName = tx.PromotedTransaction.GetType().FullName!; // Now forward the call. serializableTx.GetObjectData(serializationInfo, context); @@ -2088,8 +2092,8 @@ namespace System.Transactions if (tx._innerException == null) { tx._innerException = new TimeoutException(SR.TraceTransactionTimeout); - ; } + Debug.Assert(tx.PromotedTransaction != null); tx.PromotedTransaction.Rollback(); TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log; @@ -2155,6 +2159,7 @@ namespace System.Transactions // Set the transaction state CommonEnterState(tx); + Debug.Assert(tx.PromotedTransaction != null && tx.PromotedTransaction.RealTransaction != null); // Let the distributed transaction know that we want to know about the outcome. tx.PromotedTransaction.RealTransaction.InternalTransaction = tx; } @@ -2182,7 +2187,7 @@ namespace System.Transactions CommonEnterState(tx); // Create a transaction with the distributed transaction manager - DistributedCommittableTransaction distributedTx = null; + DistributedCommittableTransaction? distributedTx = null; try { TimeSpan newTimeout; @@ -2235,7 +2240,7 @@ namespace System.Transactions { // There was an exception trying to create the distributed transaction abort // the local transaction and exit. - tx.State.ChangeStateAbortedDuringPromotion(tx); + tx.State!.ChangeStateAbortedDuringPromotion(tx); } } @@ -2278,6 +2283,7 @@ namespace System.Transactions volatiles.VolatileDemux = new Phase1VolatileDemultiplexer(tx); } + Debug.Assert(tx.PromotedTransaction != null); volatiles.VolatileDemux._promotedEnlistment = tx.PromotedTransaction.EnlistVolatile(volatiles.VolatileDemux, phase0 ? EnlistmentOptions.EnlistDuringPrepareRequired : EnlistmentOptions.None); } @@ -2293,6 +2299,7 @@ namespace System.Transactions { // Directly enlist the durable enlistment with the resource manager. InternalEnlistment enlistment = tx._durableEnlistment; + Debug.Assert(tx.PromotedTransaction != null); IPromotedEnlistment promotedEnlistment = tx.PromotedTransaction.EnlistDurable( enlistment.ResourceManagerIdentifier, (DurableInternalEnlistment)enlistment, @@ -2317,9 +2324,11 @@ namespace System.Transactions bool enlistmentsPromoted = false; + Debug.Assert(tx.PromotedTransaction != null && tx.PromotedTransaction.RealTransaction != null); // Tell the real transaction that we want a callback for the outcome. tx.PromotedTransaction.RealTransaction.InternalTransaction = tx; + Debug.Assert(tx.State != null); // Promote Phase 0 Volatiles try { @@ -2411,7 +2420,7 @@ namespace System.Transactions internal override void DisposeRoot(InternalTransaction tx) { - tx.State.Rollback(tx, null); + tx.State!.Rollback(tx, null); } } @@ -2429,7 +2438,7 @@ namespace System.Transactions } - internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback asyncCallback, object asyncState) + internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback? asyncCallback, object? asyncState) { // Don't allow this again. throw TransactionException.CreateTransactionStateException(tx._innerException, tx.DistributedTxId); @@ -2467,7 +2476,7 @@ namespace System.Transactions } - internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception e) + internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception? e) { if (tx._innerException == null) { @@ -2491,12 +2500,12 @@ namespace System.Transactions CommonEnterState(tx); // Use the asynchronous commit provided by the promoted transaction - var ctx = (DistributedCommittableTransaction)tx.PromotedTransaction; + var ctx = (DistributedCommittableTransaction)tx.PromotedTransaction!; ctx.BeginCommit(tx); } - internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback asyncCallback, object asyncState) + internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback? asyncCallback, object? asyncState) { // Don't allow this again. throw TransactionException.CreateTransactionStateException(tx._innerException, tx.DistributedTxId); @@ -2543,10 +2552,10 @@ namespace System.Transactions // Broadcast preprepare to the volatile subordinates for (int i = 0; i < volatileCount; i++) { - tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState.ChangeStatePreparing( + tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState!.ChangeStatePreparing( tx._phase0Volatiles._volatileEnlistments[i]); - if (!tx.State.ContinuePhase0Prepares()) + if (!tx.State!.ContinuePhase0Prepares()) { break; } @@ -2566,6 +2575,7 @@ namespace System.Transactions Monitor.Exit(tx); try { + Debug.Assert(tx._phase0Volatiles.VolatileDemux._promotedEnlistment != null); // Tell the distributed TM that the volatile enlistments are prepared tx._phase0Volatiles.VolatileDemux._promotedEnlistment.Prepared(); } @@ -2582,7 +2592,7 @@ namespace System.Transactions } - internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception e) + internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception? e) { if (tx._innerException == null) { @@ -2616,7 +2626,7 @@ namespace System.Transactions // If at this point there are phase1 dependent clones abort the transaction if (tx._phase1Volatiles._dependentClones != 0) { - tx.State.ChangeStateTransactionAborted(tx, null); + tx.State!.ChangeStateTransactionAborted(tx, null); return; } @@ -2632,9 +2642,9 @@ namespace System.Transactions // Broadcast preprepare to the volatile subordinates for (int i = 0; i < volatileCount; i++) { - tx._phase1Volatiles._volatileEnlistments[i]._twoPhaseState.ChangeStatePreparing( + tx._phase1Volatiles._volatileEnlistments[i]._twoPhaseState!.ChangeStatePreparing( tx._phase1Volatiles._volatileEnlistments[i]); - if (!tx.State.ContinuePhase1Prepares()) + if (!tx.State!.ContinuePhase1Prepares()) { break; } @@ -2659,7 +2669,7 @@ namespace System.Transactions } - internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception e) + internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception? e) { if (tx._innerException == null) { @@ -2679,6 +2689,7 @@ namespace System.Transactions Monitor.Exit(tx); try { + Debug.Assert(tx._phase1Volatiles.VolatileDemux._promotedEnlistment != null); // Tell the distributed TM that the volatile enlistments are prepared tx._phase1Volatiles.VolatileDemux._promotedEnlistment.Prepared(); } @@ -2739,7 +2750,7 @@ namespace System.Transactions } - internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback asyncCallback, object asyncState) + internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback? asyncCallback, object? asyncState) { // Don't allow this again. throw TransactionException.CreateTransactionStateException(tx._innerException, tx.DistributedTxId); @@ -2764,7 +2775,7 @@ namespace System.Transactions } - internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception e) + internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception? e) { // Don't do this yet wait until all of the notifications come back. } @@ -2795,6 +2806,7 @@ namespace System.Transactions Monitor.Exit(tx); try { + Debug.Assert(tx._phase0Volatiles.VolatileDemux._promotedEnlistment != null); // Tell the distributed TM that the tx aborted. tx._phase0Volatiles.VolatileDemux._promotedEnlistment.ForceRollback(); } @@ -2805,6 +2817,7 @@ namespace System.Transactions } else { + Debug.Assert(tx.PromotedTransaction != null); // Otherwise make sure that the transaction rolls back. tx.PromotedTransaction.Rollback(); } @@ -2835,6 +2848,7 @@ namespace System.Transactions Monitor.Exit(tx); try { + Debug.Assert(tx._phase1Volatiles.VolatileDemux._promotedEnlistment != null); // Tell the distributed TM that the tx aborted. tx._phase1Volatiles.VolatileDemux._promotedEnlistment.ForceRollback(); } @@ -2876,7 +2890,7 @@ namespace System.Transactions } - internal override void AddOutcomeRegistrant(InternalTransaction tx, TransactionCompletedEventHandler transactionCompletedDelegate) + internal override void AddOutcomeRegistrant(InternalTransaction tx, TransactionCompletedEventHandler? transactionCompletedDelegate) { if (transactionCompletedDelegate != null) { @@ -2920,6 +2934,7 @@ namespace System.Transactions internal override Guid get_Identifier(InternalTransaction tx) { + Debug.Assert(tx.PromotedTransaction != null); return tx.PromotedTransaction.Identifier; } @@ -2930,8 +2945,8 @@ namespace System.Transactions protected abstract void PromotedTransactionOutcome(InternalTransaction tx); - private static WaitCallback s_signalMethod; - private static WaitCallback SignalMethod => LazyInitializer.EnsureInitialized(ref s_signalMethod, ref s_classSyncObject, () => new WaitCallback(SignalCallback)); + private static WaitCallback? s_signalMethod; + private static WaitCallback SignalMethod => LazyInitializer.EnsureInitialized(ref s_signalMethod, ref s_classSyncObject, () => new WaitCallback(SignalCallback!)); private static void SignalCallback(object state) @@ -2985,13 +3000,13 @@ namespace System.Transactions } - internal override void Rollback(InternalTransaction tx, Exception e) + internal override void Rollback(InternalTransaction tx, Exception? e) { // Already done. } - internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback asyncCallback, object asyncState) + internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback? asyncCallback, object? asyncState) { throw TransactionAbortedException.Create(SR.TransactionAborted, tx._innerException, tx.DistributedTxId); } @@ -3043,7 +3058,7 @@ namespace System.Transactions } - internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception e) + internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception? e) { // This may come from a promotable single phase enlistments abort response. } @@ -3289,7 +3304,7 @@ namespace System.Transactions CommonEnterState(tx); // Create a transaction with the distributed transaction manager - DistributedTransaction distributedTx = null; + DistributedTransaction? distributedTx = null; try { // Ask the delegation interface to promote the transaction. @@ -3316,15 +3331,15 @@ namespace System.Transactions } finally { - if (((object)distributedTx) == null) + if (((object?)distributedTx) == null) { // There was an exception trying to create the distributed transaction abort // the local transaction and exit. - tx.State.ChangeStateAbortedDuringPromotion(tx); + tx.State!.ChangeStateAbortedDuringPromotion(tx); } } - if (((object)distributedTx) == null) + if (((object?)distributedTx) == null) { return; } @@ -3375,7 +3390,7 @@ namespace System.Transactions // except for the way that commit happens. internal class TransactionStateDelegated : TransactionStateDelegatedBase { - internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback asyncCallback, object asyncState) + internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback? asyncCallback, object? asyncState) { // Store the given values tx._asyncCommit = asyncCommit; @@ -3389,6 +3404,7 @@ namespace System.Transactions internal override bool PromoteDurable(InternalTransaction tx) { + Debug.Assert(tx._durableEnlistment != null); // Let the enlistment know that it has been delegated. For this type of enlistment that // is really all that needs to be done. tx._durableEnlistment.State.ChangeStateDelegated(tx._durableEnlistment); @@ -3403,7 +3419,7 @@ namespace System.Transactions } - internal override void Rollback(InternalTransaction tx, Exception e) + internal override void Rollback(InternalTransaction tx, Exception? e) { // Pass the Rollback through the promotable single phase enlistment to be // certain it is notified. @@ -3516,7 +3532,7 @@ namespace System.Transactions return false; } - internal override void Rollback(InternalTransaction tx, Exception e) + internal override void Rollback(InternalTransaction tx, Exception? e) { // Start the process for abort. Transitioning to the Aborted state will cause // the tx.durableEnlistment to get aborted, which is how the non-MSDTC @@ -3538,16 +3554,16 @@ namespace System.Transactions } - internal override void AddOutcomeRegistrant(InternalTransaction tx, TransactionCompletedEventHandler transactionCompletedDelegate) + internal override void AddOutcomeRegistrant(InternalTransaction tx, TransactionCompletedEventHandler? transactionCompletedDelegate) { // Add this guy to the list of people to be notified of the outcome. - tx._transactionCompletedDelegate = (TransactionCompletedEventHandler) + tx._transactionCompletedDelegate = (TransactionCompletedEventHandler?) System.Delegate.Combine(tx._transactionCompletedDelegate, transactionCompletedDelegate); } // Start the commit processing by transitioning to TransactionStatePromotedNonMSDTCPhase0. - internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback asyncCallback, object asyncState) + internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback? asyncCallback, object? asyncState) { tx._asyncCommit = asyncCommit; tx._asyncCallback = asyncCallback; @@ -3572,7 +3588,7 @@ namespace System.Transactions if (tx._phase0Volatiles._preparedVolatileEnlistments == tx._phase0VolatileWaveCount + tx._phase0Volatiles._dependentClones) { - tx.State.Phase0VolatilePrepareDone(tx); + tx.State!.Phase0VolatilePrepareDone(tx); } } } @@ -3610,7 +3626,7 @@ namespace System.Transactions tx._innerException); } - internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception e) + internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception? e) { // Just transition to Aborted. The PSPE will be told to rollback thru the durableEnlistment. // This is also overridden in TransactionStatePromotedNonMSDTCSinglePhaseCommit @@ -3672,7 +3688,7 @@ namespace System.Transactions internal override void DisposeRoot(InternalTransaction tx) { - tx.State.Rollback(tx, null); + tx.State!.Rollback(tx, null); } } @@ -3700,8 +3716,8 @@ namespace System.Transactions // Broadcast prepare to the phase 0 enlistments for (int i = 0; i < volatileCount; i++) { - tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState.ChangeStatePreparing(tx._phase0Volatiles._volatileEnlistments[i]); - if (!tx.State.ContinuePhase0Prepares()) + tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState!.ChangeStatePreparing(tx._phase0Volatiles._volatileEnlistments[i]); + if (!tx.State!.ContinuePhase0Prepares()) { break; } @@ -3714,12 +3730,12 @@ namespace System.Transactions } } - internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback asyncCallback, object asyncState) + internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback? asyncCallback, object? asyncState) { throw TransactionException.CreateTransactionStateException(tx._innerException, tx.DistributedTxId); } - internal override void Rollback(InternalTransaction tx, Exception e) + internal override void Rollback(InternalTransaction tx, Exception? e) { ChangeStateTransactionAborted(tx, e); } @@ -3744,8 +3760,8 @@ namespace System.Transactions // Broadcast prepare to the phase 0 enlistments for (int i = 0; i < volatileCount; i++) { - tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState.ChangeStatePreparing(tx._phase0Volatiles._volatileEnlistments[i]); - if (!tx.State.ContinuePhase0Prepares()) + tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState!.ChangeStatePreparing(tx._phase0Volatiles._volatileEnlistments[i]); + if (!tx.State!.ContinuePhase0Prepares()) { break; } @@ -3779,6 +3795,7 @@ namespace System.Transactions // Set the transaction state CommonEnterState(tx); + Debug.Assert(tx._committableTransaction != null); // Mark the committable transaction as complete. tx._committableTransaction._complete = true; @@ -3794,8 +3811,8 @@ namespace System.Transactions // Broadcast prepare to the phase 0 enlistments for (int i = 0; i < tx._phase1Volatiles._volatileEnlistmentCount; i++) { - tx._phase1Volatiles._volatileEnlistments[i]._twoPhaseState.ChangeStatePreparing(tx._phase1Volatiles._volatileEnlistments[i]); - if (!tx.State.ContinuePhase1Prepares()) + tx._phase1Volatiles._volatileEnlistments[i]._twoPhaseState!.ChangeStatePreparing(tx._phase1Volatiles._volatileEnlistments[i]); + if (!tx.State!.ContinuePhase1Prepares()) { break; } @@ -3809,12 +3826,12 @@ namespace System.Transactions } - internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback asyncCallback, object asyncState) + internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback? asyncCallback, object? asyncState) { throw TransactionException.CreateTransactionStateException(tx._innerException, tx.DistributedTxId); } - internal override void Rollback(InternalTransaction tx, Exception e) + internal override void Rollback(InternalTransaction tx, Exception? e) { ChangeStateTransactionAborted(tx, e); } @@ -3879,6 +3896,7 @@ namespace System.Transactions { CommonEnterState(tx); + Debug.Assert(tx._durableEnlistment != null); TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log; if (etwLog.IsEnabled()) { @@ -3892,12 +3910,12 @@ namespace System.Transactions tx._durableEnlistment.State.ChangeStateCommitting(tx._durableEnlistment); } - internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback asyncCallback, object asyncState) + internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback? asyncCallback, object? asyncState) { throw TransactionException.CreateTransactionStateException(tx._innerException, tx.DistributedTxId); } - internal override void Rollback(InternalTransaction tx, Exception e) + internal override void Rollback(InternalTransaction tx, Exception? e) { // We have told the PSPE enlistment to do a single phase commit. It's too late to rollback. throw TransactionException.CreateTransactionStateException(tx._innerException, tx.DistributedTxId); @@ -3915,7 +3933,7 @@ namespace System.Transactions TransactionStatePromotedNonMSDTCIndoubt.EnterState(tx); } - internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception e) + internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception? e) { if (tx._innerException == null) { @@ -3994,7 +4012,7 @@ namespace System.Transactions } } - internal override void AddOutcomeRegistrant(InternalTransaction tx, TransactionCompletedEventHandler transactionCompletedDelegate) + internal override void AddOutcomeRegistrant(InternalTransaction tx, TransactionCompletedEventHandler? transactionCompletedDelegate) { if (transactionCompletedDelegate != null) { @@ -4043,8 +4061,8 @@ namespace System.Transactions protected abstract void PromotedTransactionOutcome(InternalTransaction tx); - private static WaitCallback s_signalMethod; - private static WaitCallback SignalMethod => LazyInitializer.EnsureInitialized(ref s_signalMethod, ref s_classSyncObject, () => new WaitCallback(SignalCallback)); + private static WaitCallback? s_signalMethod; + private static WaitCallback SignalMethod => LazyInitializer.EnsureInitialized(ref s_signalMethod, ref s_classSyncObject, () => new WaitCallback(SignalCallback!)); private static void SignalCallback(object state) { @@ -4069,12 +4087,12 @@ namespace System.Transactions // Notify the enlistments that the transaction has aborted for (int i = 0; i < tx._phase0Volatiles._volatileEnlistmentCount; i++) { - tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState.InternalAborted(tx._phase0Volatiles._volatileEnlistments[i]); + tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState!.InternalAborted(tx._phase0Volatiles._volatileEnlistments[i]); } for (int i = 0; i < tx._phase1Volatiles._volatileEnlistmentCount; i++) { - tx._phase1Volatiles._volatileEnlistments[i]._twoPhaseState.InternalAborted(tx._phase1Volatiles._volatileEnlistments[i]); + tx._phase1Volatiles._volatileEnlistments[i]._twoPhaseState!.InternalAborted(tx._phase1Volatiles._volatileEnlistments[i]); } // Notify the durable enlistment @@ -4099,12 +4117,12 @@ namespace System.Transactions return TransactionStatus.Aborted; } - internal override void Rollback(InternalTransaction tx, Exception e) + internal override void Rollback(InternalTransaction tx, Exception? e) { // Already done. } - internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback asyncCallback, object asyncState) + internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback? asyncCallback, object? asyncState) { throw TransactionAbortedException.Create(SR.TransactionAborted, tx._innerException, tx.DistributedTxId); } @@ -4129,7 +4147,7 @@ namespace System.Transactions // Since the transaction is aborted ignore it. } - internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception e) + internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception? e) { // This may come from a promotable single phase enlistments abort response. } @@ -4167,13 +4185,13 @@ namespace System.Transactions // Notify the phase 0 enlistments that the transaction has committed for (int i = 0; i < tx._phase0Volatiles._volatileEnlistmentCount; i++) { - tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState.InternalCommitted(tx._phase0Volatiles._volatileEnlistments[i]); + tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState!.InternalCommitted(tx._phase0Volatiles._volatileEnlistments[i]); } // Notify the phase 1 enlistments that the transaction has committed for (int i = 0; i < tx._phase1Volatiles._volatileEnlistmentCount; i++) { - tx._phase1Volatiles._volatileEnlistments[i]._twoPhaseState.InternalCommitted(tx._phase1Volatiles._volatileEnlistments[i]); + tx._phase1Volatiles._volatileEnlistments[i]._twoPhaseState!.InternalCommitted(tx._phase1Volatiles._volatileEnlistments[i]); } // Fire Completion for anyone listening @@ -4211,13 +4229,13 @@ namespace System.Transactions // Notify the phase 0 enlistments that the transaction is indoubt for (int i = 0; i < tx._phase0Volatiles._volatileEnlistmentCount; i++) { - tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState.InternalIndoubt(tx._phase0Volatiles._volatileEnlistments[i]); + tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState!.InternalIndoubt(tx._phase0Volatiles._volatileEnlistments[i]); } // Notify the phase 1 enlistments that the transaction is indoubt for (int i = 0; i < tx._phase1Volatiles._volatileEnlistmentCount; i++) { - tx._phase1Volatiles._volatileEnlistments[i]._twoPhaseState.InternalIndoubt(tx._phase1Volatiles._volatileEnlistments[i]); + tx._phase1Volatiles._volatileEnlistments[i]._twoPhaseState!.InternalIndoubt(tx._phase1Volatiles._volatileEnlistments[i]); } // Fire Completion for anyone listening @@ -4287,7 +4305,7 @@ namespace System.Transactions CommonEnterState(tx); // We are never going to have an DistributedTransaction for this one. - DistributedTransaction distributedTx = null; + DistributedTransaction? distributedTx = null; try { // Ask the delegation interface to promote the transaction. @@ -4319,7 +4337,7 @@ namespace System.Transactions if (tx.promotedToken == null) { // There was an exception trying to promote the transaction. - tx.State.ChangeStateAbortedDuringPromotion(tx); + tx.State!.ChangeStateAbortedDuringPromotion(tx); } } } @@ -4337,7 +4355,7 @@ namespace System.Transactions } - internal override void Rollback(InternalTransaction tx, Exception e) + internal override void Rollback(InternalTransaction tx, Exception? e) { // Pass the Rollback through the promotable single phase enlistment to be // certain it is notified. @@ -4347,6 +4365,7 @@ namespace System.Transactions tx._innerException = e; } + Debug.Assert(tx.PromotedTransaction != null); tx.PromotedTransaction.Rollback(); TransactionStatePromotedAborted.EnterState(tx); } @@ -4435,18 +4454,18 @@ namespace System.Transactions } } - internal DistributedTransaction PSPEPromote(InternalTransaction tx) + internal DistributedTransaction? PSPEPromote(InternalTransaction tx) { bool changeToReturnState = true; - TransactionState returnState = tx.State; + TransactionState? returnState = tx.State; Debug.Assert(returnState == TransactionStateDelegated || returnState == TransactionStateDelegatedSubordinate || returnState == TransactionStateDelegatedNonMSDTC, "PSPEPromote called from state other than TransactionStateDelegated[NonMSDTC]"); CommonEnterState(tx); - DistributedTransaction distributedTx = null; + DistributedTransaction? distributedTx = null; try { if (tx._attemptingPSPEPromote) @@ -4461,7 +4480,8 @@ namespace System.Transactions } tx._attemptingPSPEPromote = true; - byte[] propagationToken = tx._promoter.Promote(); + Debug.Assert(tx._promoter != null); + byte[]? propagationToken = tx._promoter.Promote(); // If the PromoterType is NOT MSDTC, then we can't assume that the returned // byte[] is an MSDTC propagation token and we can't create an DistributedTransaction from it. @@ -4513,7 +4533,7 @@ namespace System.Transactions try { distributedTx = TransactionInterop.GetDistributedTransactionFromTransmitterPropagationToken( - propagationToken + propagationToken! ); } catch (ArgumentException e) @@ -4595,7 +4615,7 @@ namespace System.Transactions // Now we need to create the durable enlistment that will replace the PSPE enlistment. Use the internalEnlistment of // this newly created durable enlistment as the tx.durableEnlistment. - enlistment = tx.State.EnlistDurable(tx, resourceManagerIdentifier, enlistmentNotification, enlistmentOptions, atomicTransaction); + enlistment = tx.State!.EnlistDurable(tx, resourceManagerIdentifier, enlistmentNotification, enlistmentOptions, atomicTransaction); tx._durableEnlistment = enlistment.InternalEnlistment; return enlistment; @@ -4655,6 +4675,7 @@ namespace System.Transactions // Forward this on to the promotable single phase enlisment Monitor.Exit(tx); + Debug.Assert(tx._durableEnlistment != null); TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log; if (etwLog.IsEnabled()) { @@ -4691,6 +4712,7 @@ namespace System.Transactions Monitor.Exit(tx); try { + Debug.Assert(tx._durableEnlistment != null); TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log; if (etwLog.IsEnabled()) { @@ -4707,7 +4729,7 @@ namespace System.Transactions } - internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback asyncCallback, object asyncState) + internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback? asyncCallback, object? asyncState) { // Initiate the commit process. throw TransactionException.CreateTransactionStateException(tx._innerException, tx.DistributedTxId); diff --git a/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionTable.cs b/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionTable.cs index d712b88..d79a269 100644 --- a/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionTable.cs +++ b/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionTable.cs @@ -9,13 +9,13 @@ namespace System.Transactions { internal class CheapUnfairReaderWriterLock { - private object _writerFinishedEvent; + private object? _writerFinishedEvent; private int _readersIn; private int _readersOut; private bool _writerPresent; - private object _syncRoot; + private object? _syncRoot; // Spin lock params private const int MAX_SPIN_COUNT = 100; @@ -283,14 +283,14 @@ namespace System.Transactions while (currentBucketSet.AbsoluteTimeout != txNew.AbsoluteTimeout) { - BucketSet lastBucketSet = null; + BucketSet? lastBucketSet = null; do { - WeakReference nextSetWeak = (WeakReference)currentBucketSet.nextSetWeak; - BucketSet nextBucketSet = null; + WeakReference? nextSetWeak = (WeakReference?)currentBucketSet.nextSetWeak; + BucketSet? nextBucketSet = null; if (nextSetWeak != null) { - nextBucketSet = (BucketSet)nextSetWeak.Target; + nextBucketSet = (BucketSet?)nextSetWeak.Target; } if (nextBucketSet == null) @@ -303,7 +303,7 @@ namespace System.Transactions BucketSet newBucketSet = new BucketSet(this, txNew.AbsoluteTimeout); WeakReference newSetWeak = new WeakReference(newBucketSet); - WeakReference oldNextSetWeak = (WeakReference)Interlocked.CompareExchange( + WeakReference? oldNextSetWeak = (WeakReference?)Interlocked.CompareExchange( ref currentBucketSet.nextSetWeak, newSetWeak, nextSetWeak); if (oldNextSetWeak == nextSetWeak) { @@ -330,15 +330,16 @@ namespace System.Transactions BucketSet newBucketSet = new BucketSet(this, txNew.AbsoluteTimeout); WeakReference newSetWeak = new WeakReference(newBucketSet); + Debug.Assert(lastBucketSet != null); newBucketSet.nextSetWeak = lastBucketSet.nextSetWeak; - WeakReference oldNextSetWeak = (WeakReference)Interlocked.CompareExchange( + WeakReference? oldNextSetWeak = (WeakReference?)Interlocked.CompareExchange( ref lastBucketSet.nextSetWeak, newSetWeak, newBucketSet.nextSetWeak); if (oldNextSetWeak == newBucketSet.nextSetWeak) { // Ladies and Gentlemen we have a winner. if (oldNextSetWeak != null) { - BucketSet oldSet = (BucketSet)oldNextSetWeak.Target; + BucketSet? oldSet = (BucketSet?)oldNextSetWeak.Target; if (oldSet != null) { // prev references are just there to root things for the GC. If this object is @@ -375,13 +376,14 @@ namespace System.Transactions // Remove a transaction from the table. internal void Remove(InternalTransaction tx) { + Debug.Assert(tx._tableBucket != null); tx._tableBucket.Remove(tx); tx._tableBucket = null; } // Process a timer event - private void ThreadTimer(object state) + private void ThreadTimer(object? state) { // // Theory of operation. @@ -409,20 +411,20 @@ namespace System.Transactions // that point will timeout so once we've found it then it is just a matter of traversing the // structure. // - BucketSet lastBucketSet = null; + BucketSet? lastBucketSet = null; BucketSet currentBucketSet = _headBucketSet; // The list always has a head. // Acquire a writer lock before checking to see if we should disable the timer. // Adding of transactions acquires a reader lock and might insert a new BucketSet. // If that races with our check for a BucketSet existing, we may not timeout that // transaction that is being added. - WeakReference nextWeakSet = null; - BucketSet nextBucketSet = null; + WeakReference? nextWeakSet = null; + BucketSet? nextBucketSet = null; - nextWeakSet = (WeakReference)currentBucketSet.nextSetWeak; + nextWeakSet = (WeakReference?)currentBucketSet.nextSetWeak; if (nextWeakSet != null) { - nextBucketSet = (BucketSet)nextWeakSet.Target; + nextBucketSet = (BucketSet?)nextWeakSet.Target; } if (nextBucketSet == null) @@ -431,10 +433,10 @@ namespace System.Transactions try { // Access the nextBucketSet again in writer lock to account for any race before disabling the timeout. - nextWeakSet = (WeakReference)currentBucketSet.nextSetWeak; + nextWeakSet = (WeakReference?)currentBucketSet.nextSetWeak; if (nextWeakSet != null) { - nextBucketSet = (BucketSet)nextWeakSet.Target; + nextBucketSet = (BucketSet?)nextWeakSet.Target; } if (nextBucketSet == null) @@ -470,14 +472,14 @@ namespace System.Transactions { do { - nextWeakSet = (WeakReference)currentBucketSet.nextSetWeak; + nextWeakSet = (WeakReference?)currentBucketSet.nextSetWeak; if (nextWeakSet == null) { // Nothing more to do. return; } - nextBucketSet = (BucketSet)nextWeakSet.Target; + nextBucketSet = (BucketSet?)nextWeakSet.Target; if (nextBucketSet == null) { // Again nothing more to do. @@ -498,19 +500,19 @@ namespace System.Transactions // expires, the thread will walk the list again, find the appropriate BucketSet to pinch off, and // then time out the transactions. This means that it is possible for a transaction to live a bit longer, // but not much. - WeakReference abortingSetsWeak = - (WeakReference)Interlocked.CompareExchange(ref lastBucketSet.nextSetWeak, null, nextWeakSet); + WeakReference? abortingSetsWeak = + (WeakReference?)Interlocked.CompareExchange(ref lastBucketSet.nextSetWeak, null, nextWeakSet); if (abortingSetsWeak == nextWeakSet) { // Yea - now proceed to abort the transactions. - BucketSet abortingBucketSets = null; + BucketSet? abortingBucketSets = null; do { if (abortingSetsWeak != null) { - abortingBucketSets = (BucketSet)abortingSetsWeak.Target; + abortingBucketSets = (BucketSet?)abortingSetsWeak.Target; } else { @@ -519,7 +521,7 @@ namespace System.Transactions if (abortingBucketSets != null) { abortingBucketSets.TimeoutTransactions(); - abortingSetsWeak = (WeakReference)abortingBucketSets.nextSetWeak; + abortingSetsWeak = (WeakReference?)abortingBucketSets.nextSetWeak; } } while (abortingBucketSets != null); @@ -539,8 +541,8 @@ namespace System.Transactions internal class BucketSet { // Buckets are kept in sets. Each element of a set will have the same absoluteTimeout. - internal object nextSetWeak; - internal BucketSet prevSet; + internal object? nextSetWeak; + internal BucketSet? prevSet; private readonly TransactionTable _table; @@ -573,16 +575,16 @@ namespace System.Transactions internal void TimeoutTransactions() { - Bucket currentBucket = headBucket; + Bucket? currentBucket = headBucket; // It will always have a head. do { currentBucket.TimeoutTransactions(); - WeakReference nextWeakBucket = (WeakReference)currentBucket.nextBucketWeak; + WeakReference? nextWeakBucket = (WeakReference?)currentBucket.nextBucketWeak; if (nextWeakBucket != null) { - currentBucket = (Bucket)nextWeakBucket.Target; + currentBucket = (Bucket?)nextWeakBucket.Target; } else { @@ -599,9 +601,9 @@ namespace System.Transactions private bool _timedOut; private int _index; private readonly int _size; - private readonly InternalTransaction[] _transactions; - internal WeakReference nextBucketWeak; - private Bucket _previous; + private readonly InternalTransaction?[] _transactions; + internal WeakReference? nextBucketWeak; + private Bucket? _previous; private readonly BucketSet _owningSet; @@ -630,7 +632,7 @@ namespace System.Transactions { lock (tx) { - tx.State.Timeout(tx); + tx.State!.Timeout(tx); } } } @@ -669,12 +671,12 @@ namespace System.Transactions for (i = 0; i <= transactionCount && i < _size; i++) { Debug.Assert(transactionCount == _index, "Index changed timing out transactions"); - InternalTransaction tx = _transactions[i]; + InternalTransaction? tx = _transactions[i]; if (tx != null) { lock (tx) { - tx.State.Timeout(tx); + tx.State!.Timeout(tx); } } } diff --git a/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionTraceIdentifier.cs b/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionTraceIdentifier.cs index 0dfd048..164f2b1 100644 --- a/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionTraceIdentifier.cs +++ b/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionTraceIdentifier.cs @@ -34,7 +34,7 @@ namespace System.Transactions public override int GetHashCode() => base.GetHashCode(); // Don't have anything better to do. - public override bool Equals(object obj) => obj is TransactionTraceIdentifier && Equals((TransactionTraceIdentifier)obj); + public override bool Equals(object? obj) => obj is TransactionTraceIdentifier transactionTraceId && Equals(transactionTraceId); public bool Equals(TransactionTraceIdentifier other) => _cloneIdentifier == other._cloneIdentifier && diff --git a/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionsEtwProvider.cs b/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionsEtwProvider.cs index f751767..c6fd036 100644 --- a/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionsEtwProvider.cs +++ b/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionsEtwProvider.cs @@ -177,17 +177,17 @@ namespace System.Transactions // Transactions Events // [NonEvent] - public static string IdOf(object value) => value != null ? value.GetType().Name + "#" + GetHashCode(value) : NullInstance; + public static string IdOf(object? value) => value != null ? value.GetType().Name + "#" + GetHashCode(value) : NullInstance; [NonEvent] - public static int GetHashCode(object value) => value?.GetHashCode() ?? 0; + public static int GetHashCode(object? value) => value?.GetHashCode() ?? 0; #region Transaction Creation /// Trace an event when a new transaction is created. /// The transaction that was created. /// The type of transaction.Method [NonEvent] - internal void TransactionCreated(Transaction transaction, string type) + internal void TransactionCreated(Transaction transaction, string? type) { Debug.Assert(transaction != null, "Transaction needed for the ETW event."); @@ -201,7 +201,7 @@ namespace System.Transactions } [Event(TRANSACTION_CREATED_EVENTID, Keywords = Keywords.TraceLtm, Level = EventLevel.Informational, Task = Tasks.Transaction, Opcode = Opcodes.Create, Message = "Transaction Created. ID is {0}, type is {1}")] - private void TransactionCreated(string transactionIdentifier, string type) + private void TransactionCreated(string transactionIdentifier, string? type) { SetActivityId(transactionIdentifier); WriteEvent(TRANSACTION_CREATED_EVENTID, transactionIdentifier, type); @@ -267,7 +267,7 @@ namespace System.Transactions /// The message for the exception. /// The inner exception. [NonEvent] - internal void TransactionExceptionTrace(TraceSourceType traceSource, TransactionExceptionType type, string message, string innerExceptionStr) + internal void TransactionExceptionTrace(TraceSourceType traceSource, TransactionExceptionType type, string? message, string? innerExceptionStr) { if (IsEnabled(EventLevel.Error, ALL_KEYWORDS)) { @@ -287,7 +287,7 @@ namespace System.Transactions /// The message for the exception. /// The inner exception. [NonEvent] - internal void TransactionExceptionTrace(TransactionExceptionType type, string message, string innerExceptionStr) + internal void TransactionExceptionTrace(TransactionExceptionType type, string? message, string? innerExceptionStr) { if (IsEnabled(EventLevel.Error, ALL_KEYWORDS)) { @@ -296,14 +296,14 @@ namespace System.Transactions } [Event(TRANSACTION_EXCEPTION_BASE_EVENTID, Keywords = Keywords.TraceBase, Level = EventLevel.Error, Task = Tasks.TransactionException, Message = "Transaction Exception. Type is {0}, message is {1}, InnerException is {2}")] - private void TransactionExceptionBase(string type, string message, string innerExceptionStr) + private void TransactionExceptionBase(string? type, string? message, string? innerExceptionStr) { SetActivityId(string.Empty); WriteEvent(TRANSACTION_EXCEPTION_BASE_EVENTID, type, message, innerExceptionStr); } [Event(TRANSACTION_EXCEPTION_LTM_EVENTID, Keywords = Keywords.TraceLtm, Level = EventLevel.Error, Task = Tasks.TransactionException, Message = "Transaction Exception. Type is {0}, message is {1}, InnerException is {2}")] - private void TransactionExceptionLtm(string type, string message, string innerExceptionStr) + private void TransactionExceptionLtm(string? type, string? message, string? innerExceptionStr) { SetActivityId(string.Empty); WriteEvent(TRANSACTION_EXCEPTION_LTM_EVENTID, type, message, innerExceptionStr); @@ -315,7 +315,7 @@ namespace System.Transactions /// The type of transaction. /// The operationont the transaction. [NonEvent] - internal void InvalidOperation(string type, string operation) + internal void InvalidOperation(string? type, string? operation) { if (IsEnabled(EventLevel.Error, ALL_KEYWORDS)) { @@ -324,7 +324,7 @@ namespace System.Transactions } } [Event(TRANSACTION_INVALID_OPERATION_EVENTID, Keywords = Keywords.TraceBase, Level = EventLevel.Error, Task = Tasks.Transaction, Opcode = Opcodes.InvalidOperation, Message = "Transaction Invalid Operation. ID is {0}, type is {1} and operation is {2}")] - private void TransactionInvalidOperation(string transactionIdentifier, string type, string operation) + private void TransactionInvalidOperation(string? transactionIdentifier, string? type, string? operation) { SetActivityId(string.Empty); WriteEvent(TRANSACTION_INVALID_OPERATION_EVENTID, transactionIdentifier, type, operation); @@ -336,7 +336,7 @@ namespace System.Transactions /// The transaction to rollback. /// The type of transaction. [NonEvent] - internal void TransactionRollback(Transaction transaction, string type) + internal void TransactionRollback(Transaction transaction, string? type) { Debug.Assert(transaction != null, "Transaction needed for the ETW event."); @@ -350,7 +350,7 @@ namespace System.Transactions } [Event(TRANSACTION_ROLLBACK_EVENTID, Keywords = Keywords.TraceLtm, Level = EventLevel.Warning, Task = Tasks.Transaction, Opcode = Opcodes.Rollback, Message = "Transaction Rollback. ID is {0}, type is {1}")] - private void TransactionRollback(string transactionIdentifier, string type) + private void TransactionRollback(string transactionIdentifier, string? type) { SetActivityId(transactionIdentifier); WriteEvent(TRANSACTION_ROLLBACK_EVENTID, transactionIdentifier, type); @@ -362,7 +362,7 @@ namespace System.Transactions /// The transaction that do dependent clone. /// The type of transaction. [NonEvent] - internal void TransactionDependentCloneComplete(Transaction transaction, string type) + internal void TransactionDependentCloneComplete(Transaction transaction, string? type) { Debug.Assert(transaction != null, "Transaction needed for the ETW event."); @@ -376,7 +376,7 @@ namespace System.Transactions } [Event(TRANSACTION_DEPENDENT_CLONE_COMPLETE_EVENTID, Keywords = Keywords.TraceLtm, Level = EventLevel.Informational, Task = Tasks.Transaction, Opcode = Opcodes.DependentCloneComplete, Message = "Transaction Dependent Clone Completed. ID is {0}, type is {1}")] - private void TransactionDependentCloneComplete(string transactionIdentifier, string type) + private void TransactionDependentCloneComplete(string transactionIdentifier, string? type) { SetActivityId(transactionIdentifier); WriteEvent(TRANSACTION_DEPENDENT_CLONE_COMPLETE_EVENTID, transactionIdentifier, type); @@ -388,7 +388,7 @@ namespace System.Transactions /// The transaction to commit. /// The type of transaction. [NonEvent] - internal void TransactionCommit(Transaction transaction, string type) + internal void TransactionCommit(Transaction transaction, string? type) { Debug.Assert(transaction != null, "Transaction needed for the ETW event."); @@ -402,7 +402,7 @@ namespace System.Transactions } [Event(TRANSACTION_COMMIT_EVENTID, Keywords = Keywords.TraceLtm, Level = EventLevel.Verbose, Task = Tasks.Transaction, Opcode = Opcodes.Commit, Message = "Transaction Commit: ID is {0}, type is {1}")] - private void TransactionCommit(string transactionIdentifier, string type) + private void TransactionCommit(string transactionIdentifier, string? type) { SetActivityId(transactionIdentifier); WriteEvent(TRANSACTION_COMMIT_EVENTID, transactionIdentifier, type); @@ -592,7 +592,7 @@ namespace System.Transactions /// 'this', or another object that serves to provide context for the operation. /// The name of method. [NonEvent] - internal void MethodEnter(TraceSourceType traceSource, object thisOrContextObject, [CallerMemberName] string methodname = null) + internal void MethodEnter(TraceSourceType traceSource, object? thisOrContextObject, [CallerMemberName] string? methodname = null) { if (IsEnabled(EventLevel.Verbose, ALL_KEYWORDS)) { @@ -615,7 +615,7 @@ namespace System.Transactions /// trace source /// The name of method. [NonEvent] - internal void MethodEnter(TraceSourceType traceSource, [CallerMemberName] string methodname = null) + internal void MethodEnter(TraceSourceType traceSource, [CallerMemberName] string? methodname = null) { if (IsEnabled(EventLevel.Verbose, ALL_KEYWORDS)) { @@ -635,19 +635,19 @@ namespace System.Transactions } [Event(METHOD_ENTER_LTM_EVENTID, Keywords = Keywords.TraceLtm, Level = EventLevel.Verbose, Task = Tasks.Method, Opcode = Opcodes.Enter, Message = "Enter method : {0}.{1}")] - private void MethodEnterTraceLtm(string thisOrContextObject, string methodname) + private void MethodEnterTraceLtm(string thisOrContextObject, string? methodname) { SetActivityId(string.Empty); WriteEvent(METHOD_ENTER_LTM_EVENTID, thisOrContextObject, methodname); } [Event(METHOD_ENTER_BASE_EVENTID, Keywords = Keywords.TraceBase, Level = EventLevel.Verbose, Task = Tasks.Method, Opcode = Opcodes.Enter, Message = "Enter method : {0}.{1}")] - private void MethodEnterTraceBase(string thisOrContextObject, string methodname) + private void MethodEnterTraceBase(string thisOrContextObject, string? methodname) { SetActivityId(string.Empty); WriteEvent(METHOD_ENTER_BASE_EVENTID, thisOrContextObject, methodname); } [Event(METHOD_ENTER_DISTRIBUTED_EVENTID, Keywords = Keywords.TraceDistributed, Level = EventLevel.Verbose, Task = Tasks.Method, Opcode = Opcodes.Enter, Message = "Enter method : {0}.{1}")] - private void MethodEnterTraceDistributed(string thisOrContextObject, string methodname) + private void MethodEnterTraceDistributed(string thisOrContextObject, string? methodname) { SetActivityId(string.Empty); WriteEvent(METHOD_ENTER_DISTRIBUTED_EVENTID, thisOrContextObject, methodname); @@ -660,7 +660,7 @@ namespace System.Transactions /// 'this', or another object that serves to provide context for the operation. /// The name of method. [NonEvent] - internal void MethodExit(TraceSourceType traceSource, object thisOrContextObject, [CallerMemberName] string methodname = null) + internal void MethodExit(TraceSourceType traceSource, object? thisOrContextObject, [CallerMemberName] string? methodname = null) { if (IsEnabled(EventLevel.Verbose, ALL_KEYWORDS)) { @@ -683,7 +683,7 @@ namespace System.Transactions /// trace source /// The name of method. [NonEvent] - internal void MethodExit(TraceSourceType traceSource, [CallerMemberName] string methodname = null) + internal void MethodExit(TraceSourceType traceSource, [CallerMemberName] string? methodname = null) { if (IsEnabled(EventLevel.Verbose, ALL_KEYWORDS)) { @@ -703,19 +703,19 @@ namespace System.Transactions } [Event(METHOD_EXIT_LTM_EVENTID, Keywords = Keywords.TraceLtm, Level = EventLevel.Verbose, Task = Tasks.Method, Opcode = Opcodes.Exit, Message = "Exit method: {0}.{1}")] - private void MethodExitTraceLtm(string thisOrContextObject, string methodname) + private void MethodExitTraceLtm(string thisOrContextObject, string? methodname) { SetActivityId(string.Empty); WriteEvent(METHOD_EXIT_LTM_EVENTID, thisOrContextObject, methodname); } [Event(METHOD_EXIT_BASE_EVENTID, Keywords = Keywords.TraceBase, Level = EventLevel.Verbose, Task = Tasks.Method, Opcode = Opcodes.Exit, Message = "Exit method: {0}.{1}")] - private void MethodExitTraceBase(string thisOrContextObject, string methodname) + private void MethodExitTraceBase(string thisOrContextObject, string? methodname) { SetActivityId(string.Empty); WriteEvent(METHOD_EXIT_BASE_EVENTID, thisOrContextObject, methodname); } [Event(METHOD_EXIT_DISTRIBUTED_EVENTID, Keywords = Keywords.TraceDistributed, Level = EventLevel.Verbose, Task = Tasks.Method, Opcode = Opcodes.Exit, Message = "Exit method: {0}.{1}")] - private void MethodExitTraceDistributed(string thisOrContextObject, string methodname) + private void MethodExitTraceDistributed(string thisOrContextObject, string? methodname) { SetActivityId(string.Empty); WriteEvent(METHOD_EXIT_DISTRIBUTED_EVENTID, thisOrContextObject, methodname); @@ -942,7 +942,7 @@ namespace System.Transactions /// Trace an event when there is an internal error on transactionscope. /// The error information. [NonEvent] - internal void TransactionScopeInternalError(string error) + internal void TransactionScopeInternalError(string? error) { if (IsEnabled(EventLevel.Critical, ALL_KEYWORDS)) { @@ -951,7 +951,7 @@ namespace System.Transactions } [Event(TRANSACTIONSCOPE_INTERNAL_ERROR_EVENTID, Keywords = Keywords.TraceBase, Level = EventLevel.Critical, Task = Tasks.TransactionScope, Opcode = Opcodes.InternalError, Message = "Transactionscope internal error: {0}")] - private void TransactionScopeInternalErrorTrace(string error) + private void TransactionScopeInternalErrorTrace(string? error) { SetActivityId(string.Empty); WriteEvent(TRANSACTIONSCOPE_INTERNAL_ERROR_EVENTID, error); diff --git a/src/libraries/System.Transactions.Local/src/System/Transactions/VolatileEnlistmentMultiplexing.cs b/src/libraries/System.Transactions.Local/src/System/Transactions/VolatileEnlistmentMultiplexing.cs index 5056341..534e4ab 100644 --- a/src/libraries/System.Transactions.Local/src/System/Transactions/VolatileEnlistmentMultiplexing.cs +++ b/src/libraries/System.Transactions.Local/src/System/Transactions/VolatileEnlistmentMultiplexing.cs @@ -19,8 +19,8 @@ namespace System.Transactions protected InternalTransaction _transaction; // Store the IVolatileEnlistment interface to call back to the Distributed TM - internal IPromotedEnlistment _promotedEnlistment; - internal IPromotedEnlistment _preparingEnlistment; + internal IPromotedEnlistment? _promotedEnlistment; + internal IPromotedEnlistment? _preparingEnlistment; public VolatileDemultiplexer(InternalTransaction transaction) { @@ -32,7 +32,7 @@ namespace System.Transactions // Broadcast preprepare to the volatile subordinates for (int i = 0; i < volatiles._volatileEnlistmentCount; i++) { - volatiles._volatileEnlistments[i]._twoPhaseState.InternalCommitted( + volatiles._volatileEnlistments[i]._twoPhaseState!.InternalCommitted( volatiles._volatileEnlistments[i]); } } @@ -43,7 +43,7 @@ namespace System.Transactions // Broadcast preprepare to the volatile subordinates for (int i = 0; i < volatiles._volatileEnlistmentCount; i++) { - volatiles._volatileEnlistments[i]._twoPhaseState.InternalAborted( + volatiles._volatileEnlistments[i]._twoPhaseState!.InternalAborted( volatiles._volatileEnlistments[i]); } } @@ -53,13 +53,13 @@ namespace System.Transactions // Broadcast preprepare to the volatile subordinates for (int i = 0; i < volatiles._volatileEnlistmentCount; i++) { - volatiles._volatileEnlistments[i]._twoPhaseState.InternalIndoubt( + volatiles._volatileEnlistments[i]._twoPhaseState!.InternalIndoubt( volatiles._volatileEnlistments[i]); } } // Object for synchronizing access to the entire class( avoiding lock( typeof( ... )) ) - private static object s_classSyncObject; + private static object? s_classSyncObject; internal static object ClassSyncObject { get @@ -73,8 +73,8 @@ namespace System.Transactions } } - private static WaitCallback s_prepareCallback; - private static WaitCallback PrepareCallback => LazyInitializer.EnsureInitialized(ref s_prepareCallback, ref s_classSyncObject, () => new WaitCallback(PoolablePrepare)); + private static WaitCallback? s_prepareCallback; + private static WaitCallback PrepareCallback => LazyInitializer.EnsureInitialized(ref s_prepareCallback, ref s_classSyncObject, () => new WaitCallback(PoolablePrepare!)); protected static void PoolablePrepare(object state) { @@ -112,8 +112,8 @@ namespace System.Transactions } } - private static WaitCallback s_commitCallback; - private static WaitCallback CommitCallback => LazyInitializer.EnsureInitialized(ref s_commitCallback, ref s_classSyncObject, () => new WaitCallback(PoolableCommit)); + private static WaitCallback? s_commitCallback; + private static WaitCallback CommitCallback => LazyInitializer.EnsureInitialized(ref s_commitCallback, ref s_classSyncObject, () => new WaitCallback(PoolableCommit!)); protected static void PoolableCommit(object state) { @@ -151,8 +151,8 @@ namespace System.Transactions } } - private static WaitCallback s_rollbackCallback; - private static WaitCallback RollbackCallback => LazyInitializer.EnsureInitialized(ref s_rollbackCallback, ref s_classSyncObject, () => new WaitCallback(PoolableRollback)); + private static WaitCallback? s_rollbackCallback; + private static WaitCallback RollbackCallback => LazyInitializer.EnsureInitialized(ref s_rollbackCallback, ref s_classSyncObject, () => new WaitCallback(PoolableRollback!)); protected static void PoolableRollback(object state) { @@ -190,8 +190,8 @@ namespace System.Transactions } } - private static WaitCallback s_inDoubtCallback; - private static WaitCallback InDoubtCallback => LazyInitializer.EnsureInitialized(ref s_inDoubtCallback, ref s_classSyncObject, () => new WaitCallback(PoolableInDoubt)); + private static WaitCallback? s_inDoubtCallback; + private static WaitCallback InDoubtCallback => LazyInitializer.EnsureInitialized(ref s_inDoubtCallback, ref s_classSyncObject, () => new WaitCallback(PoolableInDoubt!)); protected static void PoolableInDoubt(object state) { @@ -256,6 +256,7 @@ namespace System.Transactions protected override void InternalPrepare() { + Debug.Assert(_promotedEnlistment != null && _transaction.State != null); try { _transaction.State.ChangeStatePromotedPhase0(_transaction); @@ -282,6 +283,8 @@ namespace System.Transactions protected override void InternalCommit() { + Debug.Assert(_promotedEnlistment != null && _transaction.State != null); + // Respond immediately to the TM _promotedEnlistment.EnlistmentDone(); @@ -290,6 +293,8 @@ namespace System.Transactions protected override void InternalRollback() { + Debug.Assert(_promotedEnlistment != null && _transaction.State != null); + // Respond immediately to the TM _promotedEnlistment.EnlistmentDone(); @@ -298,6 +303,7 @@ namespace System.Transactions protected override void InternalInDoubt() { + Debug.Assert(_transaction.State != null); _transaction.State.InDoubtFromDtc(_transaction); } @@ -341,6 +347,7 @@ namespace System.Transactions protected override void InternalPrepare() { + Debug.Assert(_promotedEnlistment != null && _transaction.State != null); try { _transaction.State.ChangeStatePromotedPhase1(_transaction); @@ -368,6 +375,8 @@ namespace System.Transactions protected override void InternalCommit() { + Debug.Assert(_promotedEnlistment != null && _transaction.State != null); + // Respond immediately to the TM _promotedEnlistment.EnlistmentDone(); @@ -377,6 +386,8 @@ namespace System.Transactions protected override void InternalRollback() { + Debug.Assert(_promotedEnlistment != null && _transaction.State != null); + // Respond immediately to the TM _promotedEnlistment.EnlistmentDone(); @@ -386,6 +397,7 @@ namespace System.Transactions protected override void InternalInDoubt() { + Debug.Assert(_transaction.State != null); _transaction.State.InDoubtFromDtc(_transaction); } diff --git a/src/libraries/System.Transactions.Local/src/System/Transactions/VolatileEnlistmentState.cs b/src/libraries/System.Transactions.Local/src/System/Transactions/VolatileEnlistmentState.cs index 1d926ee..88c9490 100644 --- a/src/libraries/System.Transactions.Local/src/System/Transactions/VolatileEnlistmentState.cs +++ b/src/libraries/System.Transactions.Local/src/System/Transactions/VolatileEnlistmentState.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Diagnostics; using System.Threading; namespace System.Transactions @@ -11,19 +12,19 @@ namespace System.Transactions // Base class for all volatile enlistment states internal abstract class VolatileEnlistmentState : EnlistmentState { - private static VolatileEnlistmentActive s_volatileEnlistmentActive; - private static VolatileEnlistmentPreparing s_volatileEnlistmentPreparing; - private static VolatileEnlistmentPrepared s_volatileEnlistmentPrepared; - private static VolatileEnlistmentSPC s_volatileEnlistmentSPC; - private static VolatileEnlistmentPreparingAborting s_volatileEnlistmentPreparingAborting; - private static VolatileEnlistmentAborting s_volatileEnlistmentAborting; - private static VolatileEnlistmentCommitting s_volatileEnlistmentCommitting; - private static VolatileEnlistmentInDoubt s_volatileEnlistmentInDoubt; - private static VolatileEnlistmentEnded s_volatileEnlistmentEnded; - private static VolatileEnlistmentDone s_volatileEnlistmentDone; + private static VolatileEnlistmentActive? s_volatileEnlistmentActive; + private static VolatileEnlistmentPreparing? s_volatileEnlistmentPreparing; + private static VolatileEnlistmentPrepared? s_volatileEnlistmentPrepared; + private static VolatileEnlistmentSPC? s_volatileEnlistmentSPC; + private static VolatileEnlistmentPreparingAborting? s_volatileEnlistmentPreparingAborting; + private static VolatileEnlistmentAborting? s_volatileEnlistmentAborting; + private static VolatileEnlistmentCommitting? s_volatileEnlistmentCommitting; + private static VolatileEnlistmentInDoubt? s_volatileEnlistmentInDoubt; + private static VolatileEnlistmentEnded? s_volatileEnlistmentEnded; + private static VolatileEnlistmentDone? s_volatileEnlistmentDone; // Object for synchronizing access to the entire class( avoiding lock( typeof( ... )) ) - private static object s_classSyncObject; + private static object? s_classSyncObject; internal static VolatileEnlistmentActive VolatileEnlistmentActive => LazyInitializer.EnsureInitialized(ref s_volatileEnlistmentActive, ref s_classSyncObject, () => new VolatileEnlistmentActive()); @@ -144,6 +145,7 @@ namespace System.Transactions etwLog.EnlistmentStatus(enlistment, NotificationCall.Prepare); } + Debug.Assert(enlistment.EnlistmentNotification != null); enlistment.EnlistmentNotification.Prepare(enlistment.PreparingEnlistment); } finally @@ -170,11 +172,12 @@ namespace System.Transactions } // The enlistment says to abort start the abort sequence. - internal override void ForceRollback(InternalEnlistment enlistment, Exception e) + internal override void ForceRollback(InternalEnlistment enlistment, Exception? e) { // Change enlistment state to aborting VolatileEnlistmentEnded.EnterState(enlistment); + Debug.Assert(enlistment.Transaction.State != null); // Start the transaction aborting enlistment.Transaction.State.ChangeStateTransactionAborted(enlistment.Transaction, e); @@ -217,6 +220,7 @@ namespace System.Transactions Monitor.Exit(enlistment.Transaction); try // Don't hold this lock while calling into the application code. { + Debug.Assert(enlistment.SinglePhaseNotification != null); enlistment.SinglePhaseNotification.SinglePhaseCommit(enlistment.SinglePhaseEnlistment); spcCommitted = true; } @@ -235,23 +239,26 @@ namespace System.Transactions internal override void EnlistmentDone(InternalEnlistment enlistment) { VolatileEnlistmentEnded.EnterState(enlistment); + Debug.Assert(enlistment.Transaction.State != null); enlistment.Transaction.State.ChangeStateTransactionCommitted(enlistment.Transaction); } internal override void Committed(InternalEnlistment enlistment) { VolatileEnlistmentEnded.EnterState(enlistment); + Debug.Assert(enlistment.Transaction.State != null); enlistment.Transaction.State.ChangeStateTransactionCommitted(enlistment.Transaction); } - internal override void Aborted(InternalEnlistment enlistment, Exception e) + internal override void Aborted(InternalEnlistment enlistment, Exception? e) { VolatileEnlistmentEnded.EnterState(enlistment); + Debug.Assert(enlistment.Transaction.State != null); enlistment.Transaction.State.ChangeStateTransactionAborted(enlistment.Transaction, e); } - internal override void InDoubt(InternalEnlistment enlistment, Exception e) + internal override void InDoubt(InternalEnlistment enlistment, Exception? e) { VolatileEnlistmentEnded.EnterState(enlistment); @@ -260,6 +267,7 @@ namespace System.Transactions enlistment.Transaction._innerException = e; } + Debug.Assert(enlistment.Transaction.State != null); enlistment.Transaction.State.InDoubtFromEnlistment(enlistment.Transaction); } } @@ -324,7 +332,7 @@ namespace System.Transactions } // The enlistment says to abort start the abort sequence. - internal override void ForceRollback(InternalEnlistment enlistment, Exception e) + internal override void ForceRollback(InternalEnlistment enlistment, Exception? e) { // Change enlistment state to aborting VolatileEnlistmentEnded.EnterState(enlistment); @@ -365,6 +373,7 @@ namespace System.Transactions etwLog.EnlistmentStatus(enlistment, NotificationCall.Rollback); } + Debug.Assert(enlistment.EnlistmentNotification != null); enlistment.EnlistmentNotification.Rollback(enlistment.SinglePhaseEnlistment); } finally @@ -407,6 +416,7 @@ namespace System.Transactions etwLog.EnlistmentStatus(enlistment, NotificationCall.Commit); } + Debug.Assert(enlistment.EnlistmentNotification != null); // Forward the notification to the enlistment enlistment.EnlistmentNotification.Commit(enlistment.Enlistment); } @@ -440,6 +450,7 @@ namespace System.Transactions etwLog.EnlistmentStatus(enlistment, NotificationCall.InDoubt); } + Debug.Assert(enlistment.EnlistmentNotification != null); // Forward the notification to the enlistment enlistment.EnlistmentNotification.InDoubt(enlistment.PreparingEnlistment); } @@ -492,7 +503,7 @@ namespace System.Transactions // the transaction tells it to do so } - internal override void InDoubt(InternalEnlistment enlistment, Exception e) + internal override void InDoubt(InternalEnlistment enlistment, Exception? e) { // Ignore this in case the enlistment gets here before // the transaction tells it to do so -- 2.7.4