Skip to content

Commit

Permalink
Merge pull request dotnet/corefx#29697 from AfsanehR/PoolBlockingPeriod
Browse files Browse the repository at this point in the history
Added PoolBlockingPeriod connection property

Commit migrated from dotnet/corefx@f487a4c
  • Loading branch information
AfsanehR-zz committed Jun 27, 2018
2 parents 053f9da + f3298c1 commit 93f1441
Show file tree
Hide file tree
Showing 17 changed files with 526 additions and 11 deletions.
2 changes: 1 addition & 1 deletion src/libraries/System.Data.SqlClient/dir.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\dir.props" />
<PropertyGroup>
<AssemblyVersion>4.4.1.0</AssemblyVersion>
<AssemblyVersion>4.5.0.0</AssemblyVersion>
<AssemblyKey>MSFT</AssemblyKey>
<IsUAP>true</IsUAP>
</PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,17 @@ public partial class SqlDataReader : System.Data.Common.IDbColumnSchemaGenerator
{
public System.Collections.ObjectModel.ReadOnlyCollection<System.Data.Common.DbColumn> GetColumnSchema() { throw null; }
}

public enum PoolBlockingPeriod
{
Auto = 0,
AlwaysBlock = 1,
NeverBlock = 2,
}

public sealed partial class SqlConnectionStringBuilder : System.Data.Common.DbConnectionStringBuilder
{
public PoolBlockingPeriod PoolBlockingPeriod { get { throw null; } set { } }
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@
# netstandard dll has been shipped with IDbColumnSchemaGenerator inherited and SqlDataReader.GetColumnScheme() implemented in source, but not exposed in ref contract.
# Removing SqlDataReader.GetColumnScheme() from netstandard implementation potentially breaks existing customer source code
# that utilizes SqlDataReader.GetColumnScheme() indirectly by casting SqlDataReader to IDbColumnSchemaGenerator type.
# In order to prevent it, the API needs to be kept in public, and following 2 error message should be remaining in this baseline file.
# In order to prevent it, the API needs to be kept in public, and following 5 error message should be remaining in this baseline file.
#
# PoolBlockingPeriod was not added until .NET Framework 4.6.2, hence, the respective APIs are netcoreapp specific only.
Compat issues with assembly System.Data.SqlClient:
CannotRemoveBaseTypeOrInterface : Type 'System.Data.SqlClient.SqlDataReader' does not implement interface 'System.Data.Common.IDbColumnSchemaGenerator' in the reference but it does in the implementation.
MembersMustExist : Member 'System.Data.SqlClient.SqlDataReader.GetColumnSchema()' does not exist in the reference but it does exist in the implementation.
Total Issues: 2
TypesMustExist : Type 'System.Data.SqlClient.PoolBlockingPeriod' does not exist in the reference but it does exist in the implementation.
MembersMustExist : Member 'System.Data.SqlClient.SqlConnectionStringBuilder.PoolBlockingPeriod.get()' does not exist in the reference but it does exist in the implementation.
MembersMustExist : Member 'System.Data.SqlClient.SqlConnectionStringBuilder.PoolBlockingPeriod.set(System.Data.SqlClient.PoolBlockingPeriod)' does not exist in the reference but it does exist in the implementation.
Total Issues: 5
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
<AssemblyVersion Condition="'$(TargetGroup)' == 'netstandard1.2'">4.0.0.0</AssemblyVersion>
<AssemblyVersion Condition="'$(TargetGroup)' == 'netstandard1.3'">4.1.0.0</AssemblyVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetGroup)'=='netcoreapp'">
<DefineConstants>$(DefineConstants);netcoreapp</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Debug|AnyCPU'" />
Expand All @@ -36,6 +39,9 @@
<ItemGroup Condition="'$(TargetGroup)' == 'netstandard' OR '$(TargetGroup)' == 'netcoreapp' OR '$(IsUAPAssembly)' == 'true' ">
<Compile Include="System.Data.SqlClient.TypeForwards.cs" />
</ItemGroup>
<ItemGroup Condition="'$(IsPartialFacadeAssembly)' != 'true' AND '$(OSGroup)' != 'AnyOS' AND '$(TargetGroup)' == 'netcoreapp'">
<Compile Include="System\Data\SqlClient\PoolBlockingPeriod.cs" />
</ItemGroup>
<ItemGroup Condition="'$(IsPartialFacadeAssembly)' != 'true' AND '$(OSGroup)' != 'AnyOS'">
<Compile Include="Microsoft\SqlServer\Server\ITypedGetters.cs" />
<Compile Include="Microsoft\SqlServer\Server\ITypedGettersV3.cs" />
Expand Down Expand Up @@ -229,6 +235,12 @@
<Compile Include="Interop\SNINativeMethodWrapper.Common.cs" />
<Compile Include="System\Data\SqlClient\SqlCredential.cs" />
</ItemGroup>
<ItemGroup Condition="'$(IsPartialFacadeAssembly)' != 'true' AND '$(OSGroup)' != 'AnyOS' AND '$(TargetGroup)' == 'netcoreapp'">
<Compile Include="System\Data\Common\DbConnectionStringCommon.NetCoreApp.cs"/>
<Compile Include="System\Data\ProviderBase\DbConnectionPool.NetCoreApp.cs" />
<Compile Include="System\Data\SqlClient\SqlConnectionString.NetCoreApp.cs" />
<Compile Include="System\Data\SqlClient\SqlConnectionStringBuilder.NetCoreApp.cs" />
</ItemGroup>
<!-- Manage the SNI toggle for Windows netstandard and UWP -->
<ItemGroup Condition="('$(TargetGroup)' == 'netstandard' OR '$(TargetGroup)' == 'netcoreapp') AND '$(TargetsWindows)' == 'true'">
<Compile Include="System\Data\SqlClient\TdsParserStateObjectFactory.Windows.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
// Licensed to the .NET Foundation under one or more agreements.
// 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.Data.SqlClient;

namespace System.Data.Common
{
internal static partial class DbConnectionStringBuilderUtil
{
#region <<PoolBlockingPeriod Utility>>
internal static bool TryConvertToPoolBlockingPeriod(string value, out PoolBlockingPeriod result)
{
Debug.Assert(Enum.GetNames(typeof(PoolBlockingPeriod)).Length == 3, "PoolBlockingPeriod enum has changed, update needed");
Debug.Assert(null != value, "TryConvertToPoolBlockingPeriod(null,...)");

if (StringComparer.OrdinalIgnoreCase.Equals(value, nameof(PoolBlockingPeriod.Auto)))
{
result = PoolBlockingPeriod.Auto;
return true;
}
else if (StringComparer.OrdinalIgnoreCase.Equals(value, nameof(PoolBlockingPeriod.AlwaysBlock)))
{
result = PoolBlockingPeriod.AlwaysBlock;
return true;
}
else if (StringComparer.OrdinalIgnoreCase.Equals(value, nameof(PoolBlockingPeriod.NeverBlock)))
{
result = PoolBlockingPeriod.NeverBlock;
return true;
}
else
{
result = DbConnectionStringDefaults.PoolBlockingPeriod;
return false;
}
}

internal static bool IsValidPoolBlockingPeriodValue(PoolBlockingPeriod value)
{
Debug.Assert(Enum.GetNames(typeof(PoolBlockingPeriod)).Length == 3, "PoolBlockingPeriod enum has changed, update needed");
return (uint)value <= (uint)PoolBlockingPeriod.NeverBlock;
}

internal static string PoolBlockingPeriodToString(PoolBlockingPeriod value)
{
Debug.Assert(IsValidPoolBlockingPeriodValue(value));

switch (value)
{
case PoolBlockingPeriod.AlwaysBlock:
return nameof(PoolBlockingPeriod.AlwaysBlock);
case PoolBlockingPeriod.NeverBlock:
return nameof(PoolBlockingPeriod.NeverBlock);
default:
return nameof(PoolBlockingPeriod.Auto);
}
}

/// <summary>
/// This method attempts to convert the given value to a PoolBlockingPeriod enum. The algorithm is:
/// * if the value is from type string, it will be matched against PoolBlockingPeriod enum names only, using ordinal, case-insensitive comparer
/// * if the value is from type PoolBlockingPeriod, it will be used as is
/// * if the value is from integral type (SByte, Int16, Int32, Int64, Byte, UInt16, UInt32, or UInt64), it will be converted to enum
/// * if the value is another enum or any other type, it will be blocked with an appropriate ArgumentException
///
/// in any case above, if the conerted value is out of valid range, the method raises ArgumentOutOfRangeException.
/// </summary>
/// <returns>PoolBlockingPeriod value in the valid range</returns>
internal static PoolBlockingPeriod ConvertToPoolBlockingPeriod(string keyword, object value)
{
Debug.Assert(null != value, "ConvertToPoolBlockingPeriod(null)");
string sValue = (value as string);
PoolBlockingPeriod result;
if (null != sValue)
{
// We could use Enum.TryParse<PoolBlockingPeriod> here, but it accepts value combinations like
// "ReadOnly, ReadWrite" which are unwelcome here
// Also, Enum.TryParse is 100x slower than plain StringComparer.OrdinalIgnoreCase.Equals method.
if (TryConvertToPoolBlockingPeriod(sValue, out result))
{
return result;
}

// try again after remove leading & trailing whitespaces.
sValue = sValue.Trim();
if (TryConvertToPoolBlockingPeriod(sValue, out result))
{
return result;
}

// string values must be valid
throw ADP.InvalidConnectionOptionValue(keyword);
}
else
{
// the value is not string, try other options
PoolBlockingPeriod eValue;

if (value is PoolBlockingPeriod)
{
// quick path for the most common case
eValue = (PoolBlockingPeriod)value;
}
else if (value.GetType().IsEnum)
{
// explicitly block scenarios in which user tries to use wrong enum types, like:
// builder["PoolBlockingPeriod"] = EnvironmentVariableTarget.Process;
// workaround: explicitly cast non-PoolBlockingPeriod enums to int
throw ADP.ConvertFailed(value.GetType(), typeof(PoolBlockingPeriod), null);
}
else
{
try
{
// Enum.ToObject allows only integral and enum values (enums are blocked above), rasing ArgumentException for the rest
eValue = (PoolBlockingPeriod)Enum.ToObject(typeof(PoolBlockingPeriod), value);
}
catch (ArgumentException e)
{
// to be consistent with the messages we send in case of wrong type usage, replace
// the error with our exception, and keep the original one as inner one for troubleshooting
throw ADP.ConvertFailed(value.GetType(), typeof(PoolBlockingPeriod), e);
}
}

// ensure value is in valid range
if (IsValidPoolBlockingPeriodValue(eValue))
{
return eValue;
}
else
{
throw ADP.InvalidEnumerationValue(typeof(ApplicationIntent), (int)eValue);
}
}
}
#endregion
}

internal static partial class DbConnectionStringDefaults
{
internal const PoolBlockingPeriod PoolBlockingPeriod = System.Data.SqlClient.PoolBlockingPeriod.Auto;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

namespace System.Data.Common
{
internal static class DbConnectionStringBuilderUtil
internal static partial class DbConnectionStringBuilderUtil
{
internal static bool ConvertToBoolean(object value)
{
Expand Down Expand Up @@ -306,6 +306,7 @@ internal static partial class DbConnectionStringKeywords
internal const string MaxPoolSize = "Max Pool Size";
internal const string Pooling = "Pooling";
internal const string MinPoolSize = "Min Pool Size";
internal const string PoolBlockingPeriod = "PoolBlockingPeriod";
}

internal static class DbConnectionStringSynonyms
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Licensed to the .NET Foundation under one or more agreements.
// 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.Data.Common;
using System.Data.SqlClient;

namespace System.Data.ProviderBase
{
sealed internal partial class DbConnectionPool
{
partial void CheckPoolBlockingPeriod(Exception e)
{
if (!IsBlockingPeriodEnabled())
{
throw e;
}
}

private bool IsBlockingPeriodEnabled()
{
var poolGroupConnectionOptions = _connectionPoolGroup.ConnectionOptions as SqlConnectionString;
if (poolGroupConnectionOptions == null)
{
return true;
}
var policy = poolGroupConnectionOptions.PoolBlockingPeriod;

switch (policy)
{
case System.Data.SqlClient.PoolBlockingPeriod.Auto:
{
return !ADP.IsAzureSqlServerEndpoint(poolGroupConnectionOptions.DataSource);
}
case System.Data.SqlClient.PoolBlockingPeriod.AlwaysBlock:
{
return true; //Enabled
}
case System.Data.SqlClient.PoolBlockingPeriod.NeverBlock:
{
return false; //Disabled
}
default:
{
//we should never get into this path.
Debug.Fail("Unknown PoolBlockingPeriod. Please specify explicit results in above switch case statement.");
return true;
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

namespace System.Data.ProviderBase
{
sealed internal class DbConnectionPool
sealed internal partial class DbConnectionPool
{
private enum State
{
Expand Down Expand Up @@ -719,6 +719,9 @@ private DbConnectionInternal CreateObject(DbConnection owningObject, DbConnectio
{
throw;
}

CheckPoolBlockingPeriod(e);

newObj = null; // set to null, so we do not return bad new object
// Failed to create instance
_resError = e;
Expand Down Expand Up @@ -757,6 +760,9 @@ private DbConnectionInternal CreateObject(DbConnection owningObject, DbConnectio
return newObj;
}

//This method is implemented in DbConnectionPool.NetCoreApp
partial void CheckPoolBlockingPeriod(Exception e);

private void DeactivateObject(DbConnectionInternal obj)
{
obj.DeactivateConnection();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.


namespace System.Data.SqlClient
{
public enum PoolBlockingPeriod
{
Auto = 0, // Blocking period OFF for Azure SQL servers, but ON for all other SQL servers.
AlwaysBlock = 1, // Blocking period ON for all SQL servers including Azure SQL servers.
NeverBlock = 2, // Blocking period OFF for all SQL servers including Azure SQL servers.
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Licensed to the .NET Foundation under one or more agreements.
// 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.Data.Common;

namespace System.Data.SqlClient
{
internal sealed partial class SqlConnectionString : DbConnectionOptions
{
internal static partial class DEFAULT
{
internal const PoolBlockingPeriod PoolBlockingPeriod = DbConnectionStringDefaults.PoolBlockingPeriod;
}

private readonly PoolBlockingPeriod _poolBlockingPeriod;

internal PoolBlockingPeriod PoolBlockingPeriod { get { return _poolBlockingPeriod; } }

internal System.Data.SqlClient.PoolBlockingPeriod ConvertValueToPoolBlockingPeriod()
{
string value;
if (!TryGetParsetableValue(KEY.PoolBlockingPeriod, out value))
{
return DEFAULT.PoolBlockingPeriod;
}

try
{
return DbConnectionStringBuilderUtil.ConvertToPoolBlockingPeriod(KEY.PoolBlockingPeriod, value);
}
catch (Exception e) when (e is FormatException || e is OverflowException)
{
throw ADP.InvalidConnectionOptionValue(KEY.PoolBlockingPeriod, e);
}
}
}
}
Loading

0 comments on commit 93f1441

Please sign in to comment.