Skip to content

Commit

Permalink
Add setter to TransactionManager.DefaultTimeout and MaxTimeout. (#71703)
Browse files Browse the repository at this point in the history
* Add setter to TransactionManager.DefaultTimeout and MaxTimeout.
* Address review feedback.
* Interlocked access timespan to avoid data tear on x86 machine.
* Remove redundant Interlocked.Read.
  • Loading branch information
imcarolwang authored Aug 2, 2022
1 parent a413e87 commit 8fc905e
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -187,10 +187,10 @@ public static partial class TransactionInterop
}
public static partial class TransactionManager
{
public static System.TimeSpan DefaultTimeout { get { throw null; } }
public static System.TimeSpan DefaultTimeout { 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 System.TimeSpan MaximumTimeout { get { throw null; } set { } }
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; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ internal static IsolationLevel DefaultIsolationLevel
private static MachineSettingsSection MachineSettings => s_machineSettings ??= MachineSettingsSection.GetSection();

private static bool s_defaultTimeoutValidated;
private static TimeSpan s_defaultTimeout;
private static long s_defaultTimeoutTicks;
public static TimeSpan DefaultTimeout
{
get
Expand All @@ -292,23 +292,45 @@ public static TimeSpan DefaultTimeout

if (!s_defaultTimeoutValidated)
{
s_defaultTimeout = ValidateTimeout(DefaultSettingsSection.Timeout);
// If the timeout value got adjusted, it must have been greater than MaximumTimeout.
if (s_defaultTimeout != DefaultSettingsSection.Timeout)
LazyInitializer.EnsureInitialized(ref s_defaultTimeoutTicks, ref s_defaultTimeoutValidated, ref s_classSyncObject, () => ValidateTimeout(DefaultSettingsSection.Timeout).Ticks);
if (Interlocked.Read(ref s_defaultTimeoutTicks) != DefaultSettingsSection.Timeout.Ticks)
{
if (etwLog.IsEnabled())
{
etwLog.ConfiguredDefaultTimeoutAdjusted();
}
}
s_defaultTimeoutValidated = true;
}

if (etwLog.IsEnabled())
{
etwLog.MethodExit(TraceSourceType.TraceSourceBase, "TransactionManager.get_DefaultTimeout");
}
return s_defaultTimeout;
return new TimeSpan(Interlocked.Read(ref s_defaultTimeoutTicks));
}
set
{
TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;
if (etwLog.IsEnabled())
{
etwLog.MethodEnter(TraceSourceType.TraceSourceBase, "TransactionManager.set_DefaultTimeout");
}

Interlocked.Exchange(ref s_defaultTimeoutTicks, ValidateTimeout(value).Ticks);
if (Interlocked.Read(ref s_defaultTimeoutTicks) != value.Ticks)
{
if (etwLog.IsEnabled())
{
etwLog.ConfiguredDefaultTimeoutAdjusted();
}
}

s_defaultTimeoutValidated = true;

if (etwLog.IsEnabled())
{
etwLog.MethodExit(TraceSourceType.TraceSourceBase, "TransactionManager.set_DefaultTimeout");
}
}
}

Expand All @@ -325,7 +347,7 @@ public static TimeSpan MaximumTimeout
etwLog.MethodEnter(TraceSourceType.TraceSourceBase, "TransactionManager.get_DefaultMaximumTimeout");
}

LazyInitializer.EnsureInitialized(ref s_maximumTimeout, ref s_cachedMaxTimeout, ref s_classSyncObject, () => DefaultSettingsSection.Timeout);
LazyInitializer.EnsureInitialized(ref s_maximumTimeout, ref s_cachedMaxTimeout, ref s_classSyncObject, () => MachineSettingsSection.MaxTimeout);

if (etwLog.IsEnabled())
{
Expand All @@ -334,6 +356,38 @@ public static TimeSpan MaximumTimeout

return s_maximumTimeout;
}
set
{
TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;
if (etwLog.IsEnabled())
{
etwLog.MethodEnter(TraceSourceType.TraceSourceBase, "TransactionManager.set_DefaultMaximumTimeout");
}

if (value < TimeSpan.Zero)
{
throw new ArgumentOutOfRangeException(nameof(value));
}

s_cachedMaxTimeout = true;
s_maximumTimeout = value;
LazyInitializer.EnsureInitialized(ref s_defaultTimeoutTicks, ref s_defaultTimeoutValidated, ref s_classSyncObject, () => DefaultSettingsSection.Timeout.Ticks);

long defaultTimeoutTicks = Interlocked.Read(ref s_defaultTimeoutTicks);
Interlocked.Exchange(ref s_defaultTimeoutTicks, ValidateTimeout(new TimeSpan(defaultTimeoutTicks)).Ticks);
if (Interlocked.Read(ref s_defaultTimeoutTicks) != defaultTimeoutTicks)
{
if (etwLog.IsEnabled())
{
etwLog.ConfiguredDefaultTimeoutAdjusted();
}
}

if (etwLog.IsEnabled())
{
etwLog.MethodExit(TraceSourceType.TraceSourceBase, "TransactionManager.set_DefaultMaximumTimeout");
}
}
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<Compile Include="NonMsdtcPromoterTests.cs" />
<Compile Include="AsyncTransactionScopeTests.cs" />
<Compile Include="IntResourceManager.cs" />
<Compile Include="TransactionManagerTest.cs" />
<Compile Include="TransactionScopeTest.cs" />
<Compile Include="AsyncTest.cs" />
<Compile Include="EnlistTest.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Xunit;

namespace System.Transactions.Tests
{
public class TransactionManagerTest
{
[Fact]
public void DefaultTimeout_MaxTimeout_Set_Get()
{
TimeSpan tsDefault = TimeSpan.Parse("00:02:00");
TransactionManager.DefaultTimeout = tsDefault;
Assert.Equal(tsDefault, TransactionManager.DefaultTimeout);

TimeSpan tsMax = TimeSpan.Parse("00:30:00");
TransactionManager.MaximumTimeout = tsMax;
Assert.Equal(tsMax, TransactionManager.MaximumTimeout);

TimeSpan ts = TransactionManager.MaximumTimeout.Add(TimeSpan.FromMinutes(10));
TransactionManager.DefaultTimeout = ts;
Assert.Equal(tsMax, TransactionManager.MaximumTimeout);
Assert.Equal(TransactionManager.DefaultTimeout, TransactionManager.MaximumTimeout);

ts = TimeSpan.Parse("-00:01:00");
Assert.Throws<ArgumentOutOfRangeException>(() => TransactionManager.DefaultTimeout = ts);
Assert.Throws<ArgumentOutOfRangeException>(() => TransactionManager.MaximumTimeout = ts);
}
}
}

0 comments on commit 8fc905e

Please sign in to comment.