Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cache all appcontext switches #2227

Merged
merged 6 commits into from Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -8,15 +8,23 @@ namespace Microsoft.Data.SqlClient
{
internal static partial class LocalAppContextSwitches
{
private enum Tristate : byte
{
NotInitialized = 0,
False = 1,
True = 2
}

internal const string MakeReadAsyncBlockingString = @"Switch.Microsoft.Data.SqlClient.MakeReadAsyncBlocking";
internal const string LegacyRowVersionNullString = @"Switch.Microsoft.Data.SqlClient.LegacyRowVersionNullBehavior";
internal const string SuppressInsecureTLSWarningString = @"Switch.Microsoft.Data.SqlClient.SuppressInsecureTLSWarning";
internal const string UseMinimumLoginTimeoutString = @"Switch.Microsoft.Data.SqlClient.UseOneSecFloorInTimeoutCalculationDuringLogin";

private static bool? s_legacyRowVersionNullBehavior;
private static bool? s_suppressInsecureTLSWarning;
private static bool s_makeReadAsyncBlocking;
private static bool s_useMinimumLoginTimeout;
// this field is accessed through reflection in tests and should not be renamed or have the type changed without refactoring NullRow related tests
private static Tristate s_legacyRowVersionNullBehavior;
private static Tristate s_suppressInsecureTLSWarning;
private static Tristate s_makeReadAsyncBlocking;
private static Tristate s_useMinimumLoginTimeout;

#if !NETFRAMEWORK
static LocalAppContextSwitches()
Expand All @@ -36,7 +44,7 @@ static LocalAppContextSwitches()

#if NETFRAMEWORK
internal const string DisableTNIRByDefaultString = @"Switch.Microsoft.Data.SqlClient.DisableTNIRByDefaultInConnectionString";
private static bool s_disableTNIRByDefault;
private static Tristate s_disableTNIRByDefault;

/// <summary>
/// Transparent Network IP Resolution (TNIR) is a revision of the existing MultiSubnetFailover feature.
Expand All @@ -54,7 +62,23 @@ static LocalAppContextSwitches()
/// This app context switch defaults to 'false'.
/// </summary>
public static bool DisableTNIRByDefault
=> AppContext.TryGetSwitch(DisableTNIRByDefaultString, out s_disableTNIRByDefault) && s_disableTNIRByDefault;
{
get
{
if (s_disableTNIRByDefault == Tristate.NotInitialized)
{
if (AppContext.TryGetSwitch(DisableTNIRByDefaultString, out bool returnedValue) && returnedValue)
{
s_disableTNIRByDefault = Tristate.True;
}
else
{
s_disableTNIRByDefault = Tristate.False;
}
}
return s_disableTNIRByDefault == Tristate.True;
}
}
#endif

/// <summary>
Expand All @@ -66,13 +90,18 @@ public static bool SuppressInsecureTLSWarning
{
get
{
if (s_suppressInsecureTLSWarning is null)
if (s_suppressInsecureTLSWarning == Tristate.NotInitialized)
{
bool result;
result = AppContext.TryGetSwitch(SuppressInsecureTLSWarningString, out result) && result;
s_suppressInsecureTLSWarning = result;
if (AppContext.TryGetSwitch(SuppressInsecureTLSWarningString, out bool returnedValue) && returnedValue)
{
s_suppressInsecureTLSWarning = Tristate.True;
}
else
{
s_suppressInsecureTLSWarning = Tristate.False;
}
}
return s_suppressInsecureTLSWarning.Value;
return s_suppressInsecureTLSWarning == Tristate.True;
}
}

Expand All @@ -86,13 +115,18 @@ public static bool LegacyRowVersionNullBehavior
{
get
{
if (s_legacyRowVersionNullBehavior is null)
if (s_legacyRowVersionNullBehavior == Tristate.NotInitialized)
{
bool result;
result = AppContext.TryGetSwitch(LegacyRowVersionNullString, out result) && result;
s_legacyRowVersionNullBehavior = result;
if (AppContext.TryGetSwitch(LegacyRowVersionNullString, out bool returnedValue) && returnedValue)
{
s_legacyRowVersionNullBehavior = Tristate.True;
}
else
{
s_legacyRowVersionNullBehavior = Tristate.False;
}
}
return s_legacyRowVersionNullBehavior.Value;
return s_legacyRowVersionNullBehavior == Tristate.True;
}
}

Expand All @@ -101,14 +135,46 @@ public static bool LegacyRowVersionNullBehavior
/// This app context switch defaults to 'false'.
/// </summary>
public static bool MakeReadAsyncBlocking
=> AppContext.TryGetSwitch(MakeReadAsyncBlockingString, out s_makeReadAsyncBlocking) && s_makeReadAsyncBlocking;
{
get
{
if (s_makeReadAsyncBlocking == Tristate.NotInitialized)
{
if (AppContext.TryGetSwitch(MakeReadAsyncBlockingString, out bool returnedValue) && returnedValue)
{
s_makeReadAsyncBlocking = Tristate.True;
}
else
{
s_makeReadAsyncBlocking = Tristate.False;
}
}
return s_makeReadAsyncBlocking == Tristate.True;
}
}

/// <summary>
/// Specifies minimum login timeout to be set to 1 second instead of 0 seconds,
/// to prevent a login attempt from waiting indefinitely.
/// This app context switch defaults to 'true'.
/// </summary>
public static bool UseMinimumLoginTimeout
=> !AppContext.TryGetSwitch(UseMinimumLoginTimeoutString, out s_useMinimumLoginTimeout) || s_useMinimumLoginTimeout;
{
get
{
if (s_useMinimumLoginTimeout == Tristate.NotInitialized)
{
if (AppContext.TryGetSwitch(UseMinimumLoginTimeoutString, out bool returnedValue) && returnedValue)
{
s_useMinimumLoginTimeout = Tristate.True;
}
else
{
s_useMinimumLoginTimeout = Tristate.False;
}
}
return s_useMinimumLoginTimeout == Tristate.True;
}
}
}
}
Expand Up @@ -17,6 +17,14 @@ public static class DataReaderTest
{
private static readonly object s_rowVersionLock = new();

// this enum must mirror the definition in LocalAppContextSwitches
private enum Tristate : byte
{
NotInitialized = 0,
False = 1,
True = 2
}

[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))]
public static void LoadReaderIntoDataTableToTestGetSchemaTable()
{
Expand Down Expand Up @@ -261,7 +269,7 @@ public static void CheckNullRowVersionIsBDNull()
{
lock (s_rowVersionLock)
{
bool? originalValue = SetLegacyRowVersionNullBehavior(false);
Tristate originalValue = SetLegacyRowVersionNullBehavior(Tristate.False);
try
{
using SqlConnection con = new(DataTestUtility.TCPConnectionString);
Expand Down Expand Up @@ -298,7 +306,7 @@ public static void CheckLegacyNullRowVersionIsEmptyArray()
{
lock (s_rowVersionLock)
{
bool? originalValue = SetLegacyRowVersionNullBehavior(true);
Tristate originalValue = SetLegacyRowVersionNullBehavior(Tristate.True);
try
{
using SqlConnection con = new(DataTestUtility.TCPConnectionString);
Expand All @@ -323,11 +331,11 @@ public static void CheckLegacyNullRowVersionIsEmptyArray()
}
}

private static bool? SetLegacyRowVersionNullBehavior(bool? value)
private static Tristate SetLegacyRowVersionNullBehavior(Tristate value)
{
Type switchesType = typeof(SqlCommand).Assembly.GetType("Microsoft.Data.SqlClient.LocalAppContextSwitches");
FieldInfo switchField = switchesType.GetField("s_legacyRowVersionNullBehavior", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
bool? originalValue = (bool?)switchField.GetValue(null);
Tristate originalValue = (Tristate)switchField.GetValue(null);
switchField.SetValue(null, value);
return originalValue;
}
Expand Down