From cb00f2839170499b609197b48cc825e35fc2ff15 Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Fri, 28 Aug 2020 17:37:43 -0700 Subject: [PATCH 01/12] Add event counters --- .../Data/ProviderBase/DbConnectionFactory.cs | 10 +- .../Data/ProviderBase/DbConnectionInternal.cs | 1 + .../ProviderBase/DbConnectionPoolGroup.cs | 3 + .../src/Microsoft.Data.SqlClient.csproj | 1 + .../Data/ProviderBase/DbConnectionFactory.cs | 5 + .../Data/ProviderBase/DbConnectionInternal.cs | 6 + .../Data/ProviderBase/DbConnectionPool.cs | 19 +- .../SqlClientEventSource.NetCoreApp.cs | 389 ++++++++++++++++++ .../Data/SqlClient/SqlClientEventSource.cs | 2 +- 9 files changed, 432 insertions(+), 4 deletions(-) create mode 100644 src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp.cs diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbConnectionFactory.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbConnectionFactory.cs index cfbdd659eb..8134d042bc 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbConnectionFactory.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbConnectionFactory.cs @@ -124,6 +124,7 @@ internal DbConnectionInternal CreateNonPooledConnection(DbConnection owningConne DbConnectionInternal newConnection = CreateConnection(connectionOptions, poolKey, poolGroupProviderInfo, null, owningConnection, userOptions); if (null != newConnection) { + SqlClientEventSource.Log.HardConnectRequest(); newConnection.MakeNonPooledObject(owningConnection); } SqlClientEventSource.Log.TraceEvent(" {0}, Non-pooled database connection created.", ObjectID); @@ -138,6 +139,7 @@ internal DbConnectionInternal CreatePooledConnection(DbConnectionPool pool, DbCo DbConnectionInternal newConnection = CreateConnection(options, poolKey, poolGroupProviderInfo, pool, owningObject, userOptions); if (null != newConnection) { + SqlClientEventSource.Log.HardConnectRequest(); newConnection.MakePooledConnection(pool); } SqlClientEventSource.Log.TraceEvent(" {0}, Pooled database connection created.", ObjectID); @@ -281,6 +283,7 @@ internal DbConnectionPoolGroup GetConnectionPoolGroup(DbConnectionPoolKey key, D // lock prevents race condition with PruneConnectionPoolGroups newConnectionPoolGroups.Add(key, newConnectionPoolGroup); + SqlClientEventSource.Log.ActiveConnectionPoolGroupRequest(); connectionPoolGroup = newConnectionPoolGroup; _connectionPoolGroups = newConnectionPoolGroups; } @@ -304,7 +307,7 @@ private void PruneConnectionPoolGroups(object state) { // when debugging this method, expect multiple threads at the same time SqlClientEventSource.Log.AdvancedTraceEvent(" {0}", ObjectID); - + // First, walk the pool release list and attempt to clear each // pool, when the pool is finally empty, we dispose of it. If the // pool isn't empty, it's because there are active connections or @@ -324,6 +327,7 @@ private void PruneConnectionPoolGroups(object state) { _poolsToRelease.Remove(pool); SqlClientEventSource.Log.AdvancedTraceEvent(" {0}, ReleasePool={1}", ObjectID, pool.ObjectID); + SqlClientEventSource.Log.InactiveConnectionPoolRequest(false); } } } @@ -348,6 +352,7 @@ private void PruneConnectionPoolGroups(object state) { _poolGroupsToRelease.Remove(poolGroup); SqlClientEventSource.Log.AdvancedTraceEvent(" {0}, ReleasePoolGroup={1}", ObjectID, poolGroup.ObjectID); + SqlClientEventSource.Log.InactiveConnectionPoolGroupRequest(false); } } } @@ -373,6 +378,7 @@ private void PruneConnectionPoolGroups(object state) // otherwise process entry which may move it from active to idle if (entry.Value.Prune()) { // may add entries to _poolsToRelease + SqlClientEventSource.Log.ActiveConnectionPoolGroupRequest(false); QueuePoolGroupForRelease(entry.Value); } else @@ -405,6 +411,7 @@ internal void QueuePoolForRelease(DbConnectionPool pool, bool clearing) } _poolsToRelease.Add(pool); } + SqlClientEventSource.Log.InactiveConnectionPoolRequest(); } internal void QueuePoolGroupForRelease(DbConnectionPoolGroup poolGroup) @@ -416,6 +423,7 @@ internal void QueuePoolGroupForRelease(DbConnectionPoolGroup poolGroup) { _poolGroupsToRelease.Add(poolGroup); } + SqlClientEventSource.Log.InactiveConnectionPoolGroupRequest(); } virtual protected DbConnectionInternal CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection, DbConnectionOptions userOptions) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs index fdb2042b54..7847996b36 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs @@ -231,6 +231,7 @@ internal void DeactivateConnection() int activateCount = Interlocked.Decrement(ref _activateCount); #endif // DEBUG + SqlClientEventSource.Log.ActiveConnectionRequest(false); if (!_connectionIsDoomed && Pool.UseLoadBalancing) { diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbConnectionPoolGroup.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbConnectionPoolGroup.cs index 4c8e9adec6..a88bd0374e 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbConnectionPoolGroup.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbConnectionPoolGroup.cs @@ -129,6 +129,7 @@ internal int Clear() if (pool != null) { DbConnectionFactory connectionFactory = pool.ConnectionFactory; + SqlClientEventSource.Log.ActiveConnectionPoolRequest(false); connectionFactory.QueuePoolForRelease(pool, true); } } @@ -187,6 +188,7 @@ internal DbConnectionPool GetConnectionPool(DbConnectionFactory connectionFactor newPool.Startup(); // must start pool before usage bool addResult = _poolCollection.TryAdd(currentIdentity, newPool); Debug.Assert(addResult, "No other pool with current identity should exist at this point"); + SqlClientEventSource.Log.ActiveConnectionPoolRequest(); pool = newPool; } else @@ -264,6 +266,7 @@ internal bool Prune() DbConnectionFactory connectionFactory = pool.ConnectionFactory; connectionFactory.QueuePoolForRelease(pool, false); + SqlClientEventSource.Log.ActiveConnectionPoolRequest(false); } else { diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj index 9232078830..05e00854f1 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -36,6 +36,7 @@ Microsoft\Data\SqlClient\SqlClientEventSource.cs + Microsoft\Data\SqlClient\SqlClientLogger.cs diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/ProviderBase/DbConnectionFactory.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/ProviderBase/DbConnectionFactory.cs index eed3ff6970..434abf92ff 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/ProviderBase/DbConnectionFactory.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/ProviderBase/DbConnectionFactory.cs @@ -108,6 +108,7 @@ internal bool TryGetConnection(DbConnection owningConnection, TaskCompletionSour } connection = CreateNonPooledConnection(owningConnection, poolGroup, userOptions); + SqlClientEventSource.Log.NonPooledConnectionRequest(); } else { @@ -209,6 +210,10 @@ private static void TryGetConnectionCompletedContinuation(Task {0}, Non-Pooled Connection has Delegated Transaction, waiting to Dispose.", ObjectID); + SqlClientEventSource.Log.StasisConnectionRequest(); } private void TerminateStasis(bool returningToPool) @@ -494,6 +499,7 @@ private void TerminateStasis(bool returningToPool) { SqlClientEventSource.Log.PoolerTraceEvent(" {0}, Delegated Transaction has ended, connection is closed/leaked. Disposing.", ObjectID); } + SqlClientEventSource.Log.StasisConnectionRequest(false); _isInStasis = false; } } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/ProviderBase/DbConnectionPool.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/ProviderBase/DbConnectionPool.cs index 90ada93ff3..53b4f177fc 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/ProviderBase/DbConnectionPool.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/ProviderBase/DbConnectionPool.cs @@ -231,6 +231,7 @@ internal void PutTransactedObject(Transaction transaction, DbConnectionInternal } SqlClientEventSource.Log.PoolerTraceEvent(" {0}, Transaction {1}, Connection {2}, Added.", ObjectID, transaction.GetHashCode(), transactedObject.ObjectID); } + SqlClientEventSource.Log.FreeConnectionRequest(); } internal void TransactionEnded(Transaction transaction, DbConnectionInternal transactedObject) @@ -293,6 +294,7 @@ internal void TransactionEnded(Transaction transaction, DbConnectionInternal tra // connections, we'll put it back... if (0 <= entry) { + SqlClientEventSource.Log.FreeConnectionRequest(); Pool.PutObjectFromTransactedPool(transactedObject); } } @@ -600,6 +602,7 @@ private void CleanupCallback(object state) { Debug.Assert(obj != null, "null connection is not expected"); // If we obtained one from the old stack, destroy it. + SqlClientEventSource.Log.FreeConnectionRequest(false); // Transaction roots must survive even aging out (TxEnd event will clean them up). bool shouldDestroy = true; @@ -696,11 +699,13 @@ internal void Clear() while (_stackNew.TryPop(out obj)) { Debug.Assert(obj != null, "null connection is not expected"); + SqlClientEventSource.Log.FreeConnectionRequest(false); DestroyObject(obj); } while (_stackOld.TryPop(out obj)) { Debug.Assert(obj != null, "null connection is not expected"); + SqlClientEventSource.Log.FreeConnectionRequest(false); DestroyObject(obj); } @@ -742,6 +747,7 @@ private DbConnectionInternal CreateObject(DbConnection owningObject, DbConnectio } _objectList.Add(newObj); _totalObjects = _objectList.Count; + SqlClientEventSource.Log.PooledConnectionRequest(); } // If the old connection belonged to another pool, we need to remove it from that @@ -967,9 +973,11 @@ internal void DestroyObject(DbConnectionInternal obj) if (removed) { SqlClientEventSource.Log.PoolerTraceEvent(" {0}, Connection {1}, Removed from pool.", ObjectID, obj.ObjectID); + SqlClientEventSource.Log.PooledConnectionRequest(false); } obj.Dispose(); SqlClientEventSource.Log.PoolerTraceEvent(" {0}, Connection {1}, Disposed.", ObjectID, obj.ObjectID); + SqlClientEventSource.Log.HardDisconnectRequest(); } } @@ -1287,7 +1295,7 @@ private bool TryGetConnection(DbConnection owningObject, uint waitForMultipleObj } // Do not use this pooled connection if access token is about to expire soon before we can connect. - if(null != obj && obj.IsAccessTokenExpired) + if (null != obj && obj.IsAccessTokenExpired) { DestroyObject(obj); obj = null; @@ -1301,6 +1309,7 @@ private bool TryGetConnection(DbConnection owningObject, uint waitForMultipleObj } connection = obj; + SqlClientEventSource.Log.SoftConnectRequest(); return true; } @@ -1337,6 +1346,7 @@ internal DbConnectionInternal ReplaceConnection(DbConnection owningObject, DbCon if (newConnection != null) { + SqlClientEventSource.Log.SoftConnectRequest(); PrepareConnection(owningObject, newConnection, oldConnection.EnlistedTransaction); oldConnection.PrepareForReplaceConnection(); oldConnection.DeactivateConnection(); @@ -1374,6 +1384,7 @@ private DbConnectionInternal GetFromGeneralPool() if (null != obj) { SqlClientEventSource.Log.PoolerTraceEvent(" {0}, Connection {1}, Popped from general pool.", ObjectID, obj.ObjectID); + SqlClientEventSource.Log.FreeConnectionRequest(false); } return (obj); } @@ -1390,6 +1401,7 @@ private DbConnectionInternal GetFromTransactedPool(out Transaction transaction) if (null != obj) { SqlClientEventSource.Log.PoolerTraceEvent(" {0}, Connection {1}, Popped from transacted pool.", ObjectID, obj.ObjectID); + SqlClientEventSource.Log.FreeConnectionRequest(false); if (obj.IsTransactionRoot) { @@ -1544,12 +1556,13 @@ internal void PutNewObject(DbConnectionInternal obj) _stackNew.Push(obj); _waitHandles.PoolSemaphore.Release(1); + SqlClientEventSource.Log.FreeConnectionRequest(); } internal void PutObject(DbConnectionInternal obj, object owningObject) { Debug.Assert(null != obj, "null obj?"); - + SqlClientEventSource.Log.SoftDisconnectRequest(); // Once a connection is closing (which is the state that we're in at // this point in time) you cannot delegate a transaction to or enlist @@ -1662,6 +1675,8 @@ private bool ReclaimEmancipatedObjects() { DbConnectionInternal obj = reclaimedObjects[i]; SqlClientEventSource.Log.PoolerTraceEvent(" {0}, Connection {1}, Reclaiming.", ObjectID, obj.ObjectID); + SqlClientEventSource.Log.ReclaimedConnectionRequest(); + emancipatedObjectFound = true; obj.DetachCurrentTransactionIfEnded(); diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp.cs new file mode 100644 index 0000000000..88f2c05e80 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp.cs @@ -0,0 +1,389 @@ +// 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.Tracing; +using System.Threading; + +namespace Microsoft.Data.SqlClient +{ + internal partial class SqlClientEventSource : EventSource + { + private EventCounter _activeHardConnections; + private EventCounter _hardConnectsPerSecond; + private EventCounter _hardDisconnectsPerSecond; + + private EventCounter _activeSoftConnections; + private EventCounter _softConnects; + private EventCounter _softDisconnects; + + private EventCounter _numberOfNonPooledConnections; + private EventCounter _numberOfPooledConnections; + + private EventCounter _numberOfActiveConnectionPoolGroups; + private EventCounter _numberOfInactiveConnectionPoolGroups; + + private EventCounter _numberOfActiveConnectionPools; + private EventCounter _numberOfInactiveConnectionPools; + + private EventCounter _numberOfActiveConnections; + private EventCounter _numberOfFreeConnections; + private EventCounter _numberOfStasisConnections; + private EventCounter _numberOfReclaimedConnections; + + private long _activeHardConnectionsCounter = 0; + private long _hardConnectsCounter = 0; + private long _hardDisconnectsCounter = 0; + + private long _activeSoftConnectionsCounter = 0; + private long _softConnectsCounter = 0; + private long _softDisconnectsCounter = 0; + + private long _nonPooledConnectionsCounter = 0; + private long _pooledConnectionsCounter = 0; + + private long _activeConnectionPoolGroupsCounter = 0; + private long _inactiveConnectionPoolGroupsCounter = 0; + + private long _activeConnectionPoolsCounter = 0; + private long _inactiveConnectionPoolsCounter = 0; + + private long _activeConnectionsCounter = 0; + private long _freeConnectionsCounter = 0; + private long _stasisConnectionsCounter = 0; + private long _reclaimedConnectionsCounter = 0; + + protected override void OnEventCommand(EventCommandEventArgs command) + { + if (command.Command != EventCommand.Enable) + { + return; + } + + _activeHardConnections = _activeHardConnections ?? + new EventCounter("active-hard-connections", this) + { +#if NETCORE3 + DisplayName = "Actual active connections are made to servers", + DisplayUnits = "count" +#endif + }; + + _hardConnectsPerSecond = _hardConnectsPerSecond ?? + new EventCounter("hard-connects", this) + { +#if NETCORE3 + DisplayName = "Actual connections are made to servers", + DisplayUnits = "count / sec" +#endif + }; + + _hardDisconnectsPerSecond = _hardDisconnectsPerSecond ?? + new EventCounter("hard-disconnects", this) + { +#if NETCORE3 + DisplayName = "Actual disconnections are made to servers", + DisplayUnits = "count / sec" +#endif + }; + + _activeSoftConnections = _activeSoftConnections ?? + new EventCounter("active-soft-connects", this) + { +#if NETCORE3 + DisplayName = "Active connections got from connection pool", + DisplayUnits = "count" +#endif + }; + + _softConnects = _softConnects ?? + new EventCounter("soft-connects", this) + { +#if NETCORE3 + DisplayName = "Connections got from connection pool", + DisplayUnits = "count / sec" +#endif + }; + + _softDisconnects = _softDisconnects ?? + new EventCounter("soft-disconnects", this) + { +#if NETCORE3 + DisplayName = "Connections returned to the connection pool", + DisplayUnits = "count / sec" +#endif + }; + + _numberOfNonPooledConnections = _numberOfNonPooledConnections ?? + new EventCounter("number-of-non-pooled-connections", this) + { +#if NETCORE3 + DisplayName = "Number of connections are not using connection pooling", + DisplayUnits = "count / sec" +#endif + }; + + _numberOfPooledConnections = _numberOfPooledConnections ?? + new EventCounter("number-of-pooled-connections", this) + { +#if NETCORE3 + DisplayName = "Number of connections are managed by connection pooler", + DisplayUnits = "count / sec" +#endif + }; + + _numberOfActiveConnectionPoolGroups = _numberOfActiveConnectionPoolGroups ?? + new EventCounter("number-of-active-connection-pool-groups", this) + { +#if NETCORE3 + DisplayName = "Number of active unique connection strings", + DisplayUnits = "count" +#endif + }; + + _numberOfInactiveConnectionPoolGroups = _numberOfInactiveConnectionPoolGroups ?? + new EventCounter("number-of-inactive-connection-pool-groups", this) + { +#if NETCORE3 + DisplayName = "Number of unique connection strings waiting for pruning", + DisplayUnits = "count" +#endif + }; + + _numberOfActiveConnectionPools = _numberOfActiveConnectionPools ?? + new EventCounter("number-of-active-connection-pools", this) + { +#if NETCORE3 + DisplayName = "Number of active connection pools", + DisplayUnits = "count" +#endif + }; + + _numberOfInactiveConnectionPools = _numberOfInactiveConnectionPools ?? + new EventCounter("number-of-inactive-connection-pools", this) + { +#if NETCORE3 + DisplayName = "Number of inactive connection pools", + DisplayUnits = "count" +#endif + }; + + _numberOfActiveConnections = _numberOfActiveConnections ?? + new EventCounter("number-of-active-connections", this) + { +#if NETCORE3 + DisplayName = "Number of active connections", + DisplayUnits = "count" +#endif + }; + + _numberOfFreeConnections = _numberOfFreeConnections ?? + new EventCounter("number-of-free-connections", this) + { +#if NETCORE3 + DisplayName = "Number of free-ready connections", + DisplayUnits = "count" +#endif + }; + + _numberOfStasisConnections = _numberOfStasisConnections ?? + new EventCounter("number-of-stasis-connections", this) + { +#if NETCORE3 + DisplayName = "Number of connections currently waiting to be ready", + DisplayUnits = "count" +#endif + }; + + _numberOfReclaimedConnections = _numberOfReclaimedConnections ?? + new EventCounter("number-of-reclaimed-connections", this) + { +#if NETCORE3 + DisplayName = "Number of reclaimed connections from GC", + DisplayUnits = "count" +#endif + }; + } + + /// + /// The number of actual connections that are being made to servers + /// + [NonEvent] + internal void HardConnectRequest() + { + if (IsEnabled()) + { + var counter = Interlocked.Increment(ref _activeHardConnectionsCounter); + _activeHardConnections.WriteMetric(counter); + + counter = Interlocked.Increment(ref _hardConnectsCounter); + _hardConnectsPerSecond.WriteMetric(counter); + } + } + + /// + /// The number of actual disconnects that are being made to servers + /// + [NonEvent] + internal void HardDisconnectRequest() + { + if (IsEnabled()) + { + var counter = Interlocked.Decrement(ref _activeHardConnectionsCounter); + _activeHardConnections.WriteMetric(counter); + + counter = Interlocked.Increment(ref _hardDisconnectsCounter); + _hardDisconnectsPerSecond.WriteMetric(counter); + } + } + + /// + /// The number of connections we get from the pool + /// + [NonEvent] + internal void SoftConnectRequest() + { + if (IsEnabled()) + { + var counter = Interlocked.Increment(ref _activeSoftConnectionsCounter); + _activeSoftConnections.WriteMetric(counter); + + counter = Interlocked.Increment(ref _softConnectsCounter); + _softConnects.WriteMetric(counter); + } + } + + /// + /// The number of connections we return to the pool + /// + [NonEvent] + internal void SoftDisconnectRequest() + { + if (IsEnabled()) + { + var counter = Interlocked.Decrement(ref _activeSoftConnectionsCounter); + _activeSoftConnections.WriteMetric(counter); + + counter = Interlocked.Increment(ref _softDisconnectsCounter); + _softDisconnects.WriteMetric(counter); + } + } + + /// + /// The number of connections that are not using connection pooling + /// + /// + [NonEvent] + internal void NonPooledConnectionRequest(bool increment = true) + { + Request(ref _numberOfNonPooledConnections, ref _nonPooledConnectionsCounter, increment); + } + + /// + /// The number of connections that are managed by the connection pooler + /// + /// + [NonEvent] + internal void PooledConnectionRequest(bool increment = true) + { + Request(ref _numberOfPooledConnections, ref _pooledConnectionsCounter, increment); + } + + /// + /// The number of unique connection strings + /// + /// + [NonEvent] + internal void ActiveConnectionPoolGroupRequest(bool increment = true) + { + Request(ref _numberOfActiveConnectionPoolGroups, ref _activeConnectionPoolGroupsCounter, increment); + } + + /// + /// The number of unique connection strings waiting for pruning + /// + /// + [NonEvent] + internal void InactiveConnectionPoolGroupRequest(bool increment = true) + { + Request(ref _numberOfInactiveConnectionPoolGroups, ref _inactiveConnectionPoolGroupsCounter, increment); + } + + /// + /// The number of connection pools + /// + /// + [NonEvent] + internal void ActiveConnectionPoolRequest(bool increment = true) + { + Request(ref _numberOfActiveConnectionPools, ref _activeConnectionPoolsCounter, increment); + } + + /// + /// The number of connection pools + /// + /// + [NonEvent] + internal void InactiveConnectionPoolRequest(bool increment = true) + { + Request(ref _numberOfInactiveConnectionPools, ref _inactiveConnectionPoolsCounter, increment); + } + + /// + /// The number of connections currently in-use + /// + /// + [NonEvent] + internal void ActiveConnectionRequest(bool increment = true) + { + Request(ref _numberOfActiveConnections, ref _activeConnectionsCounter, increment); + } + + /// + /// The number of connections currently available for use + /// + /// + [NonEvent] + internal void FreeConnectionRequest(bool increment = true) + { + Request(ref _numberOfFreeConnections, ref _freeConnectionsCounter, increment); + } + + /// + /// The number of connections currently waiting to be made ready for use + /// + /// + [NonEvent] + internal void StasisConnectionRequest(bool increment = true) + { + Request(ref _numberOfStasisConnections, ref _stasisConnectionsCounter, increment); + } + + /// + /// The number of connections we reclaim from GC'd external connections + /// + [NonEvent] + internal void ReclaimedConnectionRequest() + { + Request(ref _numberOfReclaimedConnections, ref _reclaimedConnectionsCounter, true); + } + + [NonEvent] + private void Request(ref EventCounter eventCounter, ref long counter, bool increment) + { + if (IsEnabled()) + { + long innerCounter; + if (increment) + { + innerCounter = Interlocked.Increment(ref counter); + } + else + { + innerCounter = Interlocked.Decrement(ref counter); + } + eventCounter.WriteMetric(innerCounter); + } + } + } +} diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.cs index 93e544a713..f9000f5d9f 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.cs @@ -8,7 +8,7 @@ namespace Microsoft.Data.SqlClient { [EventSource(Name = "Microsoft.Data.SqlClient.EventSource")] - internal class SqlClientEventSource : EventSource + internal partial class SqlClientEventSource : EventSource { // Defines the singleton instance for the Resources ETW provider internal static readonly SqlClientEventSource Log = new SqlClientEventSource(); From ada285a357a46a33cb49e8ab58d309099d4751ff Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Mon, 31 Aug 2020 16:35:18 -0700 Subject: [PATCH 02/12] Add support netstandard 2.1 & fix the conflict in event source --- .../src/Microsoft.Data.SqlClient.csproj | 3 ++ .../SqlClientEventSource.NetCoreApp.cs | 39 ++++++++----------- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj index a203a70b58..58772da574 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -28,6 +28,9 @@ $(DefineConstants);NETCORE3 + + $(DefineConstants);NETSTANDARD21 + portable true diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp.cs index 88f2c05e80..f15f691a42 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp.cs @@ -53,17 +53,12 @@ internal partial class SqlClientEventSource : EventSource private long _stasisConnectionsCounter = 0; private long _reclaimedConnectionsCounter = 0; - protected override void OnEventCommand(EventCommandEventArgs command) + public SqlClientEventSource() { - if (command.Command != EventCommand.Enable) - { - return; - } - _activeHardConnections = _activeHardConnections ?? new EventCounter("active-hard-connections", this) { -#if NETCORE3 +#if NETCORE3 || NETSTANDARD21 DisplayName = "Actual active connections are made to servers", DisplayUnits = "count" #endif @@ -72,7 +67,7 @@ protected override void OnEventCommand(EventCommandEventArgs command) _hardConnectsPerSecond = _hardConnectsPerSecond ?? new EventCounter("hard-connects", this) { -#if NETCORE3 +#if NETCORE3 || NETSTANDARD21 DisplayName = "Actual connections are made to servers", DisplayUnits = "count / sec" #endif @@ -81,7 +76,7 @@ protected override void OnEventCommand(EventCommandEventArgs command) _hardDisconnectsPerSecond = _hardDisconnectsPerSecond ?? new EventCounter("hard-disconnects", this) { -#if NETCORE3 +#if NETCORE3 || NETSTANDARD21 DisplayName = "Actual disconnections are made to servers", DisplayUnits = "count / sec" #endif @@ -90,7 +85,7 @@ protected override void OnEventCommand(EventCommandEventArgs command) _activeSoftConnections = _activeSoftConnections ?? new EventCounter("active-soft-connects", this) { -#if NETCORE3 +#if NETCORE3 || NETSTANDARD21 DisplayName = "Active connections got from connection pool", DisplayUnits = "count" #endif @@ -99,7 +94,7 @@ protected override void OnEventCommand(EventCommandEventArgs command) _softConnects = _softConnects ?? new EventCounter("soft-connects", this) { -#if NETCORE3 +#if NETCORE3 || NETSTANDARD21 DisplayName = "Connections got from connection pool", DisplayUnits = "count / sec" #endif @@ -108,7 +103,7 @@ protected override void OnEventCommand(EventCommandEventArgs command) _softDisconnects = _softDisconnects ?? new EventCounter("soft-disconnects", this) { -#if NETCORE3 +#if NETCORE3 || NETSTANDARD21 DisplayName = "Connections returned to the connection pool", DisplayUnits = "count / sec" #endif @@ -117,7 +112,7 @@ protected override void OnEventCommand(EventCommandEventArgs command) _numberOfNonPooledConnections = _numberOfNonPooledConnections ?? new EventCounter("number-of-non-pooled-connections", this) { -#if NETCORE3 +#if NETCORE3 || NETSTANDARD21 DisplayName = "Number of connections are not using connection pooling", DisplayUnits = "count / sec" #endif @@ -126,7 +121,7 @@ protected override void OnEventCommand(EventCommandEventArgs command) _numberOfPooledConnections = _numberOfPooledConnections ?? new EventCounter("number-of-pooled-connections", this) { -#if NETCORE3 +#if NETCORE3 || NETSTANDARD21 DisplayName = "Number of connections are managed by connection pooler", DisplayUnits = "count / sec" #endif @@ -135,7 +130,7 @@ protected override void OnEventCommand(EventCommandEventArgs command) _numberOfActiveConnectionPoolGroups = _numberOfActiveConnectionPoolGroups ?? new EventCounter("number-of-active-connection-pool-groups", this) { -#if NETCORE3 +#if NETCORE3 || NETSTANDARD21 DisplayName = "Number of active unique connection strings", DisplayUnits = "count" #endif @@ -144,7 +139,7 @@ protected override void OnEventCommand(EventCommandEventArgs command) _numberOfInactiveConnectionPoolGroups = _numberOfInactiveConnectionPoolGroups ?? new EventCounter("number-of-inactive-connection-pool-groups", this) { -#if NETCORE3 +#if NETCORE3 || NETSTANDARD21 DisplayName = "Number of unique connection strings waiting for pruning", DisplayUnits = "count" #endif @@ -153,7 +148,7 @@ protected override void OnEventCommand(EventCommandEventArgs command) _numberOfActiveConnectionPools = _numberOfActiveConnectionPools ?? new EventCounter("number-of-active-connection-pools", this) { -#if NETCORE3 +#if NETCORE3 || NETSTANDARD21 DisplayName = "Number of active connection pools", DisplayUnits = "count" #endif @@ -162,7 +157,7 @@ protected override void OnEventCommand(EventCommandEventArgs command) _numberOfInactiveConnectionPools = _numberOfInactiveConnectionPools ?? new EventCounter("number-of-inactive-connection-pools", this) { -#if NETCORE3 +#if NETCORE3 || NETSTANDARD21 DisplayName = "Number of inactive connection pools", DisplayUnits = "count" #endif @@ -171,7 +166,7 @@ protected override void OnEventCommand(EventCommandEventArgs command) _numberOfActiveConnections = _numberOfActiveConnections ?? new EventCounter("number-of-active-connections", this) { -#if NETCORE3 +#if NETCORE3 || NETSTANDARD21 DisplayName = "Number of active connections", DisplayUnits = "count" #endif @@ -180,7 +175,7 @@ protected override void OnEventCommand(EventCommandEventArgs command) _numberOfFreeConnections = _numberOfFreeConnections ?? new EventCounter("number-of-free-connections", this) { -#if NETCORE3 +#if NETCORE3 || NETSTANDARD21 DisplayName = "Number of free-ready connections", DisplayUnits = "count" #endif @@ -189,7 +184,7 @@ protected override void OnEventCommand(EventCommandEventArgs command) _numberOfStasisConnections = _numberOfStasisConnections ?? new EventCounter("number-of-stasis-connections", this) { -#if NETCORE3 +#if NETCORE3 || NETSTANDARD21 DisplayName = "Number of connections currently waiting to be ready", DisplayUnits = "count" #endif @@ -198,7 +193,7 @@ protected override void OnEventCommand(EventCommandEventArgs command) _numberOfReclaimedConnections = _numberOfReclaimedConnections ?? new EventCounter("number-of-reclaimed-connections", this) { -#if NETCORE3 +#if NETCORE3 || NETSTANDARD21 DisplayName = "Number of reclaimed connections from GC", DisplayUnits = "count" #endif From 0df6a558c077739dec9e49b73396c08812bc0f13 Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Tue, 1 Sep 2020 19:56:03 -0700 Subject: [PATCH 03/12] Support new event source types & add the test unit --- .../src/Microsoft.Data.SqlClient.csproj | 12 +- ...cs => SqlClientEventSource.NetCoreApp2.cs} | 173 ++------- .../SqlClientEventSource.NetCoreApp3.cs | 352 ++++++++++++++++++ .../netfx/src/Microsoft.Data.SqlClient.csproj | 20 +- .../SqlClient/SqlClientEventSource.Windows.cs | 3 +- .../Data/SqlClient/SqlClientEventSource.cs | 13 +- .../ManualTests/DataCommon/DataTestUtility.cs | 3 +- ....Data.SqlClient.ManualTesting.Tests.csproj | 1 + .../TracingTests/EventCounterTest.cs | 100 +++++ 9 files changed, 510 insertions(+), 167 deletions(-) rename src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/{SqlClientEventSource.NetCoreApp.cs => SqlClientEventSource.NetCoreApp2.cs} (65%) create mode 100644 src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp3.cs create mode 100644 src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/EventCounterTest.cs diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj index 58772da574..8e5d668070 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -28,9 +28,6 @@ $(DefineConstants);NETCORE3 - - $(DefineConstants);NETSTANDARD21 - portable true @@ -45,7 +42,6 @@ Microsoft\Data\SqlClient\SqlClientEventSource.cs - Microsoft\Data\SqlClient\SqlClientLogger.cs @@ -251,6 +247,14 @@ + + + + + + + + diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp2.cs similarity index 65% rename from src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp.cs rename to src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp2.cs index f15f691a42..da7a59b51b 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp2.cs @@ -7,7 +7,10 @@ namespace Microsoft.Data.SqlClient { - internal partial class SqlClientEventSource : EventSource + /// + /// supported frameworks: .Net core 2.1 and .Net standard 2.0 + /// + internal partial class SqlClientEventSource : SqlClientEventSourceBase { private EventCounter _activeHardConnections; private EventCounter _hardConnectsPerSecond; @@ -53,151 +56,31 @@ internal partial class SqlClientEventSource : EventSource private long _stasisConnectionsCounter = 0; private long _reclaimedConnectionsCounter = 0; - public SqlClientEventSource() + protected override void EventCommandMethodCall(EventCommandEventArgs command) { - _activeHardConnections = _activeHardConnections ?? - new EventCounter("active-hard-connections", this) - { -#if NETCORE3 || NETSTANDARD21 - DisplayName = "Actual active connections are made to servers", - DisplayUnits = "count" -#endif - }; - - _hardConnectsPerSecond = _hardConnectsPerSecond ?? - new EventCounter("hard-connects", this) - { -#if NETCORE3 || NETSTANDARD21 - DisplayName = "Actual connections are made to servers", - DisplayUnits = "count / sec" -#endif - }; - - _hardDisconnectsPerSecond = _hardDisconnectsPerSecond ?? - new EventCounter("hard-disconnects", this) - { -#if NETCORE3 || NETSTANDARD21 - DisplayName = "Actual disconnections are made to servers", - DisplayUnits = "count / sec" -#endif - }; - - _activeSoftConnections = _activeSoftConnections ?? - new EventCounter("active-soft-connects", this) - { -#if NETCORE3 || NETSTANDARD21 - DisplayName = "Active connections got from connection pool", - DisplayUnits = "count" -#endif - }; - - _softConnects = _softConnects ?? - new EventCounter("soft-connects", this) - { -#if NETCORE3 || NETSTANDARD21 - DisplayName = "Connections got from connection pool", - DisplayUnits = "count / sec" -#endif - }; - - _softDisconnects = _softDisconnects ?? - new EventCounter("soft-disconnects", this) - { -#if NETCORE3 || NETSTANDARD21 - DisplayName = "Connections returned to the connection pool", - DisplayUnits = "count / sec" -#endif - }; - - _numberOfNonPooledConnections = _numberOfNonPooledConnections ?? - new EventCounter("number-of-non-pooled-connections", this) - { -#if NETCORE3 || NETSTANDARD21 - DisplayName = "Number of connections are not using connection pooling", - DisplayUnits = "count / sec" -#endif - }; - - _numberOfPooledConnections = _numberOfPooledConnections ?? - new EventCounter("number-of-pooled-connections", this) - { -#if NETCORE3 || NETSTANDARD21 - DisplayName = "Number of connections are managed by connection pooler", - DisplayUnits = "count / sec" -#endif - }; - - _numberOfActiveConnectionPoolGroups = _numberOfActiveConnectionPoolGroups ?? - new EventCounter("number-of-active-connection-pool-groups", this) - { -#if NETCORE3 || NETSTANDARD21 - DisplayName = "Number of active unique connection strings", - DisplayUnits = "count" -#endif - }; - - _numberOfInactiveConnectionPoolGroups = _numberOfInactiveConnectionPoolGroups ?? - new EventCounter("number-of-inactive-connection-pool-groups", this) - { -#if NETCORE3 || NETSTANDARD21 - DisplayName = "Number of unique connection strings waiting for pruning", - DisplayUnits = "count" -#endif - }; - - _numberOfActiveConnectionPools = _numberOfActiveConnectionPools ?? - new EventCounter("number-of-active-connection-pools", this) - { -#if NETCORE3 || NETSTANDARD21 - DisplayName = "Number of active connection pools", - DisplayUnits = "count" -#endif - }; - - _numberOfInactiveConnectionPools = _numberOfInactiveConnectionPools ?? - new EventCounter("number-of-inactive-connection-pools", this) - { -#if NETCORE3 || NETSTANDARD21 - DisplayName = "Number of inactive connection pools", - DisplayUnits = "count" -#endif - }; - - _numberOfActiveConnections = _numberOfActiveConnections ?? - new EventCounter("number-of-active-connections", this) - { -#if NETCORE3 || NETSTANDARD21 - DisplayName = "Number of active connections", - DisplayUnits = "count" -#endif - }; - - _numberOfFreeConnections = _numberOfFreeConnections ?? - new EventCounter("number-of-free-connections", this) - { -#if NETCORE3 || NETSTANDARD21 - DisplayName = "Number of free-ready connections", - DisplayUnits = "count" -#endif - }; - - _numberOfStasisConnections = _numberOfStasisConnections ?? - new EventCounter("number-of-stasis-connections", this) - { -#if NETCORE3 || NETSTANDARD21 - DisplayName = "Number of connections currently waiting to be ready", - DisplayUnits = "count" -#endif - }; - - _numberOfReclaimedConnections = _numberOfReclaimedConnections ?? - new EventCounter("number-of-reclaimed-connections", this) - { -#if NETCORE3 || NETSTANDARD21 - DisplayName = "Number of reclaimed connections from GC", - DisplayUnits = "count" -#endif - }; + if (command.Command != EventCommand.Enable) + { + return; + } + + _activeHardConnections = _activeHardConnections ?? new EventCounter("active-hard-connections", this); + _hardConnectsPerSecond = _hardConnectsPerSecond ?? new EventCounter("hard-connects", this); + _hardDisconnectsPerSecond = _hardDisconnectsPerSecond ?? new EventCounter("hard-disconnects", this); + + _activeSoftConnections = _activeSoftConnections ?? new EventCounter("active-soft-connects", this); + _softConnects = _softConnects ?? new EventCounter("soft-connects", this); + _softDisconnects = _softDisconnects ?? new EventCounter("soft-disconnects", this); + + _numberOfNonPooledConnections = _numberOfNonPooledConnections ?? new EventCounter("number-of-non-pooled-connections", this); + _numberOfPooledConnections = _numberOfPooledConnections ?? new EventCounter("number-of-pooled-connections", this); + _numberOfActiveConnectionPoolGroups = _numberOfActiveConnectionPoolGroups ?? new EventCounter("number-of-active-connection-pool-groups", this); + _numberOfInactiveConnectionPoolGroups = _numberOfInactiveConnectionPoolGroups ?? new EventCounter("number-of-inactive-connection-pool-groups", this); + _numberOfActiveConnectionPools = _numberOfActiveConnectionPools ?? new EventCounter("number-of-active-connection-pools", this); + _numberOfInactiveConnectionPools = _numberOfInactiveConnectionPools ?? new EventCounter("number-of-inactive-connection-pools", this); + _numberOfActiveConnections = _numberOfActiveConnections ?? new EventCounter("number-of-active-connections", this); + _numberOfFreeConnections = _numberOfFreeConnections ?? new EventCounter("number-of-free-connections", this); + _numberOfStasisConnections = _numberOfStasisConnections ?? new EventCounter("number-of-stasis-connections", this); + _numberOfReclaimedConnections = _numberOfReclaimedConnections ?? new EventCounter("number-of-reclaimed-connections", this); } /// diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp3.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp3.cs new file mode 100644 index 0000000000..6d27a88cbe --- /dev/null +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp3.cs @@ -0,0 +1,352 @@ +// 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; +using System.Diagnostics.Tracing; +using System.Threading; + +namespace Microsoft.Data.SqlClient +{ + /// + /// supported frameworks: .Net core 3.1 and .Net standard 2.1 and above + /// + internal partial class SqlClientEventSource : SqlClientEventSourceBase + { + private PollingCounter _activeHardConnections; + private IncrementingPollingCounter _hardConnectsPerSecond; + private IncrementingPollingCounter _hardDisconnectsPerSecond; + + private PollingCounter _activeSoftConnections; + private IncrementingPollingCounter _softConnects; + private IncrementingPollingCounter _softDisconnects; + + private PollingCounter _numberOfNonPooledConnections; + private PollingCounter _numberOfPooledConnections; + + private PollingCounter _numberOfActiveConnectionPoolGroups; + private PollingCounter _numberOfInactiveConnectionPoolGroups; + + private PollingCounter _numberOfActiveConnectionPools; + private PollingCounter _numberOfInactiveConnectionPools; + + private PollingCounter _numberOfActiveConnections; + private PollingCounter _numberOfFreeConnections; + private PollingCounter _numberOfStasisConnections; + private IncrementingPollingCounter _numberOfReclaimedConnections; + + private long _activeHardConnectionsCounter = 0; + private long _hardConnectsCounter = 0; + private long _hardDisconnectsCounter = 0; + + private long _activeSoftConnectionsCounter = 0; + private long _softConnectsCounter = 0; + private long _softDisconnectsCounter = 0; + + private long _nonPooledConnectionsCounter = 0; + private long _pooledConnectionsCounter = 0; + + private long _activeConnectionPoolGroupsCounter = 0; + private long _inactiveConnectionPoolGroupsCounter = 0; + + private long _activeConnectionPoolsCounter = 0; + private long _inactiveConnectionPoolsCounter = 0; + + private long _activeConnectionsCounter = 0; + private long _freeConnectionsCounter = 0; + private long _stasisConnectionsCounter = 0; + private long _reclaimedConnectionsCounter = 0; + + protected override void EventCommandMethodCall(EventCommandEventArgs command) + { + if(command.Command != EventCommand.Enable) + { + return; + } + + _activeHardConnections = _activeHardConnections ?? + new PollingCounter("active-hard-connections", this, () => _activeHardConnectionsCounter) + { + DisplayName = "Actual active connections are made to servers", + DisplayUnits = "count" + }; + + _hardConnectsPerSecond = _hardConnectsPerSecond ?? + new IncrementingPollingCounter("hard-connects", this, () => _hardConnectsCounter) + { + DisplayName = "Actual connections are made to servers", + DisplayUnits = "count / sec", + DisplayRateTimeScale = TimeSpan.FromSeconds(1) + }; + + _hardDisconnectsPerSecond = _hardDisconnectsPerSecond ?? + new IncrementingPollingCounter("hard-disconnects", this, () => _hardDisconnectsCounter) + { + DisplayName = "Actual disconnections are made to servers", + DisplayUnits = "count / sec", + DisplayRateTimeScale = TimeSpan.FromSeconds(1) + }; + + _activeSoftConnections = _activeSoftConnections ?? + new PollingCounter("active-soft-connects", this, () => _activeSoftConnectionsCounter) + { + DisplayName = "Active connections got from connection pool", + DisplayUnits = "count" + }; + + _softConnects = _softConnects ?? + new IncrementingPollingCounter("soft-connects", this, () => _softConnectsCounter) + { + DisplayName = "Connections got from connection pool", + DisplayUnits = "count / sec", + DisplayRateTimeScale = TimeSpan.FromSeconds(1) + }; + + _softDisconnects = _softDisconnects ?? + new IncrementingPollingCounter("soft-disconnects", this, () => _softDisconnectsCounter) + { + DisplayName = "Connections returned to the connection pool", + DisplayUnits = "count / sec", + DisplayRateTimeScale = TimeSpan.FromSeconds(1) + }; + + _numberOfNonPooledConnections = _numberOfNonPooledConnections ?? + new PollingCounter("number-of-non-pooled-connections", this, () => _nonPooledConnectionsCounter) + { + DisplayName = "Number of connections are not using connection pooling", + DisplayUnits = "count / sec" + }; + + _numberOfPooledConnections = _numberOfPooledConnections ?? + new PollingCounter("number-of-pooled-connections", this, () => _pooledConnectionsCounter) + { + DisplayName = "Number of connections are managed by connection pooler", + DisplayUnits = "count / sec" + }; + + _numberOfActiveConnectionPoolGroups = _numberOfActiveConnectionPoolGroups ?? + new PollingCounter("number-of-active-connection-pool-groups", this, () => _activeConnectionPoolsCounter) + { + DisplayName = "Number of active unique connection strings", + DisplayUnits = "count" + }; + + _numberOfInactiveConnectionPoolGroups = _numberOfInactiveConnectionPoolGroups ?? + new PollingCounter("number-of-inactive-connection-pool-groups", this, () => _inactiveConnectionPoolGroupsCounter) + { + DisplayName = "Number of unique connection strings waiting for pruning", + DisplayUnits = "count" + }; + + _numberOfActiveConnectionPools = _numberOfActiveConnectionPools ?? + new PollingCounter("number-of-active-connection-pools", this, () => _activeConnectionPoolsCounter) + { + DisplayName = "Number of active connection pools", + DisplayUnits = "count" + }; + + _numberOfInactiveConnectionPools = _numberOfInactiveConnectionPools ?? + new PollingCounter("number-of-inactive-connection-pools", this, () => _inactiveConnectionPoolsCounter) + { + DisplayName = "Number of inactive connection pools", + DisplayUnits = "count" + }; + + _numberOfActiveConnections = _numberOfActiveConnections ?? + new PollingCounter("number-of-active-connections", this, () => _activeConnectionsCounter) + { + DisplayName = "Number of active connections", + DisplayUnits = "count" + }; + + _numberOfFreeConnections = _numberOfFreeConnections ?? + new PollingCounter("number-of-free-connections", this, () => _freeConnectionsCounter) + { + DisplayName = "Number of free-ready connections", + DisplayUnits = "count" + }; + + _numberOfStasisConnections = _numberOfStasisConnections ?? + new PollingCounter("number-of-stasis-connections", this, () => _stasisConnectionsCounter) + { + DisplayName = "Number of connections currently waiting to be ready", + DisplayUnits = "count" + }; + + _numberOfReclaimedConnections = _numberOfReclaimedConnections ?? + new IncrementingPollingCounter("number-of-reclaimed-connections", this, () => _reclaimedConnectionsCounter) + { + DisplayName = "Number of reclaimed connections from GC", + DisplayUnits = "count", + DisplayRateTimeScale = TimeSpan.FromSeconds(1) + }; + } + + /// + /// The number of actual connections that are being made to servers + /// + [NonEvent] + internal void HardConnectRequest() + { + if (IsEnabled()) + { + Interlocked.Increment(ref _activeHardConnectionsCounter); + Interlocked.Increment(ref _hardConnectsCounter); + } + } + + /// + /// The number of actual disconnects that are being made to servers + /// + [NonEvent] + internal void HardDisconnectRequest() + { + if (IsEnabled()) + { + Interlocked.Decrement(ref _activeHardConnectionsCounter); + Interlocked.Increment(ref _hardDisconnectsCounter); + } + } + + /// + /// The number of connections we get from the pool + /// + [NonEvent] + internal void SoftConnectRequest() + { + if (IsEnabled()) + { + Interlocked.Increment(ref _activeSoftConnectionsCounter); + Interlocked.Increment(ref _softConnectsCounter); + } + } + + /// + /// The number of connections we return to the pool + /// + [NonEvent] + internal void SoftDisconnectRequest() + { + if (IsEnabled()) + { + Interlocked.Decrement(ref _activeSoftConnectionsCounter); + Interlocked.Increment(ref _softDisconnectsCounter); + } + } + + /// + /// The number of connections that are not using connection pooling + /// + /// + [NonEvent] + internal void NonPooledConnectionRequest(bool increment = true) + { + Request(ref _nonPooledConnectionsCounter, increment); + } + + /// + /// The number of connections that are managed by the connection pooler + /// + /// + [NonEvent] + internal void PooledConnectionRequest(bool increment = true) + { + Request(ref _pooledConnectionsCounter, increment); + } + + /// + /// The number of unique connection strings + /// + /// + [NonEvent] + internal void ActiveConnectionPoolGroupRequest(bool increment = true) + { + Request(ref _activeConnectionPoolGroupsCounter, increment); + } + + /// + /// The number of unique connection strings waiting for pruning + /// + /// + [NonEvent] + internal void InactiveConnectionPoolGroupRequest(bool increment = true) + { + Request(ref _inactiveConnectionPoolGroupsCounter, increment); + } + + /// + /// The number of connection pools + /// + /// + [NonEvent] + internal void ActiveConnectionPoolRequest(bool increment = true) + { + Request(ref _activeConnectionPoolsCounter, increment); + } + + /// + /// The number of connection pools + /// + /// + [NonEvent] + internal void InactiveConnectionPoolRequest(bool increment = true) + { + Request(ref _inactiveConnectionPoolsCounter, increment); + } + + /// + /// The number of connections currently in-use + /// + /// + [NonEvent] + internal void ActiveConnectionRequest(bool increment = true) + { + Request(ref _activeConnectionsCounter, increment); + } + + /// + /// The number of connections currently available for use + /// + /// + [NonEvent] + internal void FreeConnectionRequest(bool increment = true) + { + Request(ref _freeConnectionsCounter, increment); + } + + /// + /// The number of connections currently waiting to be made ready for use + /// + /// + [NonEvent] + internal void StasisConnectionRequest(bool increment = true) + { + Request(ref _stasisConnectionsCounter, increment); + } + + /// + /// The number of connections we reclaim from GC'd external connections + /// + [NonEvent] + internal void ReclaimedConnectionRequest() + { + Request(ref _reclaimedConnectionsCounter, true); + } + + [NonEvent] + private void Request(ref long counter, bool increment) + { + if (IsEnabled()) + { + if (increment) + { + Interlocked.Increment(ref counter); + } + else + { + Interlocked.Decrement(ref counter); + } + } + } + } +} diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj index 927ddf3c95..a63ed87bce 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -318,16 +318,10 @@ - - Component - - - Component - + + - - Component - + @@ -335,9 +329,7 @@ - - Component - + @@ -407,9 +399,7 @@ - - Component - + diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.Windows.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.Windows.cs index f9af6024e4..cc5db8c738 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.Windows.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.Windows.cs @@ -8,7 +8,7 @@ namespace Microsoft.Data.SqlClient { - internal partial class SqlClientEventSource : EventSource + internal partial class SqlClientEventSource : SqlClientEventSourceBase { private bool _traceLoggingProviderEnabled = false; @@ -29,6 +29,7 @@ internal partial class SqlClientEventSource : EventSource protected override void OnEventCommand(EventCommandEventArgs e) { + base.OnEventCommand(e); // Internally, EventListener.EnableEvents sends an event command, with a reserved value of 0, -2, or -3. // When a command is sent via EnableEvents or SendCommand, check if it is a user-defined value // to enable or disable event tracing in sni.dll. diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.cs index a2d49e96c8..2febb4b5d9 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.cs @@ -7,8 +7,19 @@ namespace Microsoft.Data.SqlClient { + internal abstract class SqlClientEventSourceBase : EventSource + { + protected override void OnEventCommand(EventCommandEventArgs command) + { + base.OnEventCommand(command); + EventCommandMethodCall(command); + } + + protected virtual void EventCommandMethodCall(EventCommandEventArgs command){} + } + [EventSource(Name = "Microsoft.Data.SqlClient.EventSource")] - internal partial class SqlClientEventSource : EventSource + internal partial class SqlClientEventSource : SqlClientEventSourceBase { // Defines the singleton instance for the Resources ETW provider internal static readonly SqlClientEventSource Log = new SqlClientEventSource(); diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs index e65d4e6693..41b847b2b9 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs @@ -15,6 +15,7 @@ using Microsoft.Identity.Client; using Microsoft.Data.SqlClient.TestUtilities; using Xunit; +using System.Linq; namespace Microsoft.Data.SqlClient.ManualTesting.Tests { @@ -694,7 +695,7 @@ protected override void OnEventSourceCreated(EventSource eventSource) { if (eventSource.Name.Equals("Microsoft.Data.SqlClient.EventSource")) { - // Collect all traces for better code coverage + //// Collect all traces for better code coverage EnableEvents(eventSource, EventLevel.Informational, EventKeywords.All); } } diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj index 877791abe3..8f085ab21c 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj @@ -232,6 +232,7 @@ + diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/EventCounterTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/EventCounterTest.cs new file mode 100644 index 0000000000..0b9f971468 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/EventCounterTest.cs @@ -0,0 +1,100 @@ +// 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.Collections.Generic; +using System.Diagnostics.Tracing; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.Data.SqlClient.ManualTesting.Tests +{ + public class EventCounterTest + { + [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + public void EventCounterTestAll() + { + var stringBuilder = new SqlConnectionStringBuilder(DataTestUtility.TCPConnectionString) + { + Pooling = true, + MaxPoolSize = 20 + }; + + using (var TraceListener = new TraceEventCounterListener()) + { + OpenConnections(stringBuilder.ConnectionString); + stringBuilder.Pooling = false; + OpenConnections(stringBuilder.ConnectionString); + + Thread.Sleep(3000); //wait to complete sampling! + Assert.All(TraceListener.EventCounters, item => Assert.True(item.Value > 0)); + } + } + + private void OpenConnections(string cnnString) + { + List tasks = new List(); + + Enumerable.Range(1, 100).ToList().ForEach(i => + { + SqlConnection cnn = new SqlConnection(cnnString); + cnn.Open(); + int x = i; + tasks.Add(Task.Run(() => { Thread.Sleep(x); cnn.Close(); })); + }); + Task.WhenAll(tasks).Wait(); + } + } + + public class TraceEventCounterListener : EventListener + { + private const string Name = "Name"; + + public Dictionary EventCounters { get; private set; } + + public TraceEventCounterListener() + { + EventCounters = new Dictionary + { + { "active-hard-connections", 0 }, + { "hard-connects", 0 }, + { "hard-disconnects", 0 }, + { "active-soft-connects", 0 }, + { "soft-connects", 0 }, + { "soft-disconnects", 0 }, + { "number-of-non-pooled-connections", 0 }, + { "number-of-pooled-connections", 0 }, + { "number-of-active-connection-pool-groups", 0 }, + { "number-of-inactive-connection-pool-groups", 0 }, + { "number-of-active-connection-pools", 0 }, + { "number-of-inactive-connection-pools", 0 }, + { "number-of-active-connections", 0 }, + { "number-of-free-connections", 0 }, + { "number-of-stasis-connections", 0 }, + { "number-of-reclaimed-connections", 0 } + }; + } + + protected override void OnEventSourceCreated(EventSource eventSource) + { + if (eventSource.Name.Equals("Microsoft.Data.SqlClient.EventSource")) + { + var options = new Dictionary(); + options.Add("EventCounterIntervalSec", "1"); + EnableEvents(eventSource, EventLevel.Informational, EventKeywords.All, options); + } + } + + protected override void OnEventWritten(EventWrittenEventArgs eventData) + { + object counter = null; + eventData.Payload.FirstOrDefault(p => p is IDictionary x && x.TryGetValue(Name, out counter)); + if (counter is string cntName && EventCounters.ContainsKey(cntName)) + { + EventCounters[cntName] += 1; + } + } + } +} From 74bb4da75e80174780b0e6389d540df9926d9228 Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Wed, 2 Sep 2020 16:41:11 -0700 Subject: [PATCH 04/12] Remove supporting obsolete types --- .../SqlClientEventSource.NetCoreApp2.cs | 201 +++--------------- .../TracingTests/EventCounterTest.cs | 2 +- 2 files changed, 30 insertions(+), 173 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp2.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp2.cs index da7a59b51b..6201e739c5 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp2.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp2.cs @@ -2,266 +2,123 @@ // 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.Tracing; -using System.Threading; - namespace Microsoft.Data.SqlClient { /// - /// supported frameworks: .Net core 2.1 and .Net standard 2.0 + /// not implemented cause of low performance for .Net core 2.1 and .Net standard 2.0 /// internal partial class SqlClientEventSource : SqlClientEventSourceBase { - private EventCounter _activeHardConnections; - private EventCounter _hardConnectsPerSecond; - private EventCounter _hardDisconnectsPerSecond; - - private EventCounter _activeSoftConnections; - private EventCounter _softConnects; - private EventCounter _softDisconnects; - - private EventCounter _numberOfNonPooledConnections; - private EventCounter _numberOfPooledConnections; - - private EventCounter _numberOfActiveConnectionPoolGroups; - private EventCounter _numberOfInactiveConnectionPoolGroups; - - private EventCounter _numberOfActiveConnectionPools; - private EventCounter _numberOfInactiveConnectionPools; - - private EventCounter _numberOfActiveConnections; - private EventCounter _numberOfFreeConnections; - private EventCounter _numberOfStasisConnections; - private EventCounter _numberOfReclaimedConnections; - - private long _activeHardConnectionsCounter = 0; - private long _hardConnectsCounter = 0; - private long _hardDisconnectsCounter = 0; - - private long _activeSoftConnectionsCounter = 0; - private long _softConnectsCounter = 0; - private long _softDisconnectsCounter = 0; - - private long _nonPooledConnectionsCounter = 0; - private long _pooledConnectionsCounter = 0; - - private long _activeConnectionPoolGroupsCounter = 0; - private long _inactiveConnectionPoolGroupsCounter = 0; - - private long _activeConnectionPoolsCounter = 0; - private long _inactiveConnectionPoolsCounter = 0; - - private long _activeConnectionsCounter = 0; - private long _freeConnectionsCounter = 0; - private long _stasisConnectionsCounter = 0; - private long _reclaimedConnectionsCounter = 0; - - protected override void EventCommandMethodCall(EventCommandEventArgs command) - { - if (command.Command != EventCommand.Enable) - { - return; - } - - _activeHardConnections = _activeHardConnections ?? new EventCounter("active-hard-connections", this); - _hardConnectsPerSecond = _hardConnectsPerSecond ?? new EventCounter("hard-connects", this); - _hardDisconnectsPerSecond = _hardDisconnectsPerSecond ?? new EventCounter("hard-disconnects", this); - - _activeSoftConnections = _activeSoftConnections ?? new EventCounter("active-soft-connects", this); - _softConnects = _softConnects ?? new EventCounter("soft-connects", this); - _softDisconnects = _softDisconnects ?? new EventCounter("soft-disconnects", this); - - _numberOfNonPooledConnections = _numberOfNonPooledConnections ?? new EventCounter("number-of-non-pooled-connections", this); - _numberOfPooledConnections = _numberOfPooledConnections ?? new EventCounter("number-of-pooled-connections", this); - _numberOfActiveConnectionPoolGroups = _numberOfActiveConnectionPoolGroups ?? new EventCounter("number-of-active-connection-pool-groups", this); - _numberOfInactiveConnectionPoolGroups = _numberOfInactiveConnectionPoolGroups ?? new EventCounter("number-of-inactive-connection-pool-groups", this); - _numberOfActiveConnectionPools = _numberOfActiveConnectionPools ?? new EventCounter("number-of-active-connection-pools", this); - _numberOfInactiveConnectionPools = _numberOfInactiveConnectionPools ?? new EventCounter("number-of-inactive-connection-pools", this); - _numberOfActiveConnections = _numberOfActiveConnections ?? new EventCounter("number-of-active-connections", this); - _numberOfFreeConnections = _numberOfFreeConnections ?? new EventCounter("number-of-free-connections", this); - _numberOfStasisConnections = _numberOfStasisConnections ?? new EventCounter("number-of-stasis-connections", this); - _numberOfReclaimedConnections = _numberOfReclaimedConnections ?? new EventCounter("number-of-reclaimed-connections", this); - } - /// - /// The number of actual connections that are being made to servers + /// not implemented for .Net core 2.1, .Net standard 2.0 and lower /// - [NonEvent] internal void HardConnectRequest() { - if (IsEnabled()) - { - var counter = Interlocked.Increment(ref _activeHardConnectionsCounter); - _activeHardConnections.WriteMetric(counter); - - counter = Interlocked.Increment(ref _hardConnectsCounter); - _hardConnectsPerSecond.WriteMetric(counter); - } + //no-op } /// - /// The number of actual disconnects that are being made to servers + /// not implemented for .Net core 2.1, .Net standard 2.0 and lower /// - [NonEvent] internal void HardDisconnectRequest() { - if (IsEnabled()) - { - var counter = Interlocked.Decrement(ref _activeHardConnectionsCounter); - _activeHardConnections.WriteMetric(counter); - - counter = Interlocked.Increment(ref _hardDisconnectsCounter); - _hardDisconnectsPerSecond.WriteMetric(counter); - } + //no-op } /// - /// The number of connections we get from the pool + /// not implemented for .Net core 2.1, .Net standard 2.0 and lower /// - [NonEvent] internal void SoftConnectRequest() { - if (IsEnabled()) - { - var counter = Interlocked.Increment(ref _activeSoftConnectionsCounter); - _activeSoftConnections.WriteMetric(counter); - - counter = Interlocked.Increment(ref _softConnectsCounter); - _softConnects.WriteMetric(counter); - } + //no-op } /// - /// The number of connections we return to the pool + /// not implemented for .Net core 2.1, .Net standard 2.0 and lower /// - [NonEvent] internal void SoftDisconnectRequest() { - if (IsEnabled()) - { - var counter = Interlocked.Decrement(ref _activeSoftConnectionsCounter); - _activeSoftConnections.WriteMetric(counter); - - counter = Interlocked.Increment(ref _softDisconnectsCounter); - _softDisconnects.WriteMetric(counter); - } + //no-op } /// - /// The number of connections that are not using connection pooling + /// not implemented for .Net core 2.1, .Net standard 2.0 and lower /// - /// - [NonEvent] internal void NonPooledConnectionRequest(bool increment = true) { - Request(ref _numberOfNonPooledConnections, ref _nonPooledConnectionsCounter, increment); + //no-op } /// - /// The number of connections that are managed by the connection pooler + /// not implemented for .Net core 2.1, .Net standard 2.0 and lower /// - /// - [NonEvent] internal void PooledConnectionRequest(bool increment = true) { - Request(ref _numberOfPooledConnections, ref _pooledConnectionsCounter, increment); + //no-op } /// - /// The number of unique connection strings + /// not implemented for .Net core 2.1, .Net standard 2.0 and lower /// - /// - [NonEvent] internal void ActiveConnectionPoolGroupRequest(bool increment = true) { - Request(ref _numberOfActiveConnectionPoolGroups, ref _activeConnectionPoolGroupsCounter, increment); + //no-op } /// - /// The number of unique connection strings waiting for pruning + /// not implemented for .Net core 2.1, .Net standard 2.0 and lower /// - /// - [NonEvent] internal void InactiveConnectionPoolGroupRequest(bool increment = true) { - Request(ref _numberOfInactiveConnectionPoolGroups, ref _inactiveConnectionPoolGroupsCounter, increment); + //no-op } /// - /// The number of connection pools + /// not implemented for .Net core 2.1, .Net standard 2.0 and lower /// - /// - [NonEvent] internal void ActiveConnectionPoolRequest(bool increment = true) { - Request(ref _numberOfActiveConnectionPools, ref _activeConnectionPoolsCounter, increment); + //no-op } /// - /// The number of connection pools + /// not implemented for .Net core 2.1, .Net standard 2.0 and lower /// - /// - [NonEvent] internal void InactiveConnectionPoolRequest(bool increment = true) { - Request(ref _numberOfInactiveConnectionPools, ref _inactiveConnectionPoolsCounter, increment); + //no-op } /// - /// The number of connections currently in-use + /// not implemented for .Net core 2.1, .Net standard 2.0 and lower /// - /// - [NonEvent] internal void ActiveConnectionRequest(bool increment = true) { - Request(ref _numberOfActiveConnections, ref _activeConnectionsCounter, increment); + //no-op } /// - /// The number of connections currently available for use + /// not implemented for .Net core 2.1, .Net standard 2.0 and lower /// - /// - [NonEvent] internal void FreeConnectionRequest(bool increment = true) { - Request(ref _numberOfFreeConnections, ref _freeConnectionsCounter, increment); + //no-op } /// - /// The number of connections currently waiting to be made ready for use + /// not implemented for .Net core 2.1, .Net standard 2.0 and lower /// - /// - [NonEvent] internal void StasisConnectionRequest(bool increment = true) { - Request(ref _numberOfStasisConnections, ref _stasisConnectionsCounter, increment); + //no-op } /// - /// The number of connections we reclaim from GC'd external connections + /// not implemented for .Net core 2.1, .Net standard 2.0 and lower /// - [NonEvent] internal void ReclaimedConnectionRequest() { - Request(ref _numberOfReclaimedConnections, ref _reclaimedConnectionsCounter, true); - } - - [NonEvent] - private void Request(ref EventCounter eventCounter, ref long counter, bool increment) - { - if (IsEnabled()) - { - long innerCounter; - if (increment) - { - innerCounter = Interlocked.Increment(ref counter); - } - else - { - innerCounter = Interlocked.Decrement(ref counter); - } - eventCounter.WriteMetric(innerCounter); - } + //no-op } } } diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/EventCounterTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/EventCounterTest.cs index 0b9f971468..52c20e409c 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/EventCounterTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/EventCounterTest.cs @@ -28,7 +28,7 @@ public void EventCounterTestAll() stringBuilder.Pooling = false; OpenConnections(stringBuilder.ConnectionString); - Thread.Sleep(3000); //wait to complete sampling! + Thread.Sleep(3000); // wait to complete sampling! Assert.All(TraceListener.EventCounters, item => Assert.True(item.Value > 0)); } } From 7c2be9ec87b1ea8ed405aed854625e83a1b0de69 Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Wed, 2 Sep 2020 18:02:46 -0700 Subject: [PATCH 05/12] fix unit test --- .../src/Microsoft.Data.SqlClient.csproj | 4 - .../SqlClientEventSource.NetCoreApp2.cs | 124 ------------------ .../SqlClientEventSource.NetCoreApp3.cs | 28 ++-- .../Data/SqlClient/SqlClientEventSource.cs | 32 ++++- ....Data.SqlClient.ManualTesting.Tests.csproj | 3 + .../TracingTests/EventCounterTest.cs | 8 +- 6 files changed, 55 insertions(+), 144 deletions(-) delete mode 100644 src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp2.cs diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj index 8e5d668070..43dd66de36 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -247,10 +247,6 @@ - - - - diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp2.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp2.cs deleted file mode 100644 index 6201e739c5..0000000000 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp2.cs +++ /dev/null @@ -1,124 +0,0 @@ -// 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 Microsoft.Data.SqlClient -{ - /// - /// not implemented cause of low performance for .Net core 2.1 and .Net standard 2.0 - /// - internal partial class SqlClientEventSource : SqlClientEventSourceBase - { - /// - /// not implemented for .Net core 2.1, .Net standard 2.0 and lower - /// - internal void HardConnectRequest() - { - //no-op - } - - /// - /// not implemented for .Net core 2.1, .Net standard 2.0 and lower - /// - internal void HardDisconnectRequest() - { - //no-op - } - - /// - /// not implemented for .Net core 2.1, .Net standard 2.0 and lower - /// - internal void SoftConnectRequest() - { - //no-op - } - - /// - /// not implemented for .Net core 2.1, .Net standard 2.0 and lower - /// - internal void SoftDisconnectRequest() - { - //no-op - } - - /// - /// not implemented for .Net core 2.1, .Net standard 2.0 and lower - /// - internal void NonPooledConnectionRequest(bool increment = true) - { - //no-op - } - - /// - /// not implemented for .Net core 2.1, .Net standard 2.0 and lower - /// - internal void PooledConnectionRequest(bool increment = true) - { - //no-op - } - - /// - /// not implemented for .Net core 2.1, .Net standard 2.0 and lower - /// - internal void ActiveConnectionPoolGroupRequest(bool increment = true) - { - //no-op - } - - /// - /// not implemented for .Net core 2.1, .Net standard 2.0 and lower - /// - internal void InactiveConnectionPoolGroupRequest(bool increment = true) - { - //no-op - } - - /// - /// not implemented for .Net core 2.1, .Net standard 2.0 and lower - /// - internal void ActiveConnectionPoolRequest(bool increment = true) - { - //no-op - } - - /// - /// not implemented for .Net core 2.1, .Net standard 2.0 and lower - /// - internal void InactiveConnectionPoolRequest(bool increment = true) - { - //no-op - } - - /// - /// not implemented for .Net core 2.1, .Net standard 2.0 and lower - /// - internal void ActiveConnectionRequest(bool increment = true) - { - //no-op - } - - /// - /// not implemented for .Net core 2.1, .Net standard 2.0 and lower - /// - internal void FreeConnectionRequest(bool increment = true) - { - //no-op - } - - /// - /// not implemented for .Net core 2.1, .Net standard 2.0 and lower - /// - internal void StasisConnectionRequest(bool increment = true) - { - //no-op - } - - /// - /// not implemented for .Net core 2.1, .Net standard 2.0 and lower - /// - internal void ReclaimedConnectionRequest() - { - //no-op - } - } -} diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp3.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp3.cs index 6d27a88cbe..67521a1c36 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp3.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp3.cs @@ -186,7 +186,7 @@ protected override void EventCommandMethodCall(EventCommandEventArgs command) /// The number of actual connections that are being made to servers /// [NonEvent] - internal void HardConnectRequest() + internal override void HardConnectRequest() { if (IsEnabled()) { @@ -199,7 +199,7 @@ internal void HardConnectRequest() /// The number of actual disconnects that are being made to servers /// [NonEvent] - internal void HardDisconnectRequest() + internal override void HardDisconnectRequest() { if (IsEnabled()) { @@ -212,7 +212,7 @@ internal void HardDisconnectRequest() /// The number of connections we get from the pool /// [NonEvent] - internal void SoftConnectRequest() + internal override void SoftConnectRequest() { if (IsEnabled()) { @@ -225,7 +225,7 @@ internal void SoftConnectRequest() /// The number of connections we return to the pool /// [NonEvent] - internal void SoftDisconnectRequest() + internal override void SoftDisconnectRequest() { if (IsEnabled()) { @@ -239,7 +239,7 @@ internal void SoftDisconnectRequest() /// /// [NonEvent] - internal void NonPooledConnectionRequest(bool increment = true) + internal override void NonPooledConnectionRequest(bool increment = true) { Request(ref _nonPooledConnectionsCounter, increment); } @@ -249,7 +249,7 @@ internal void NonPooledConnectionRequest(bool increment = true) /// /// [NonEvent] - internal void PooledConnectionRequest(bool increment = true) + internal override void PooledConnectionRequest(bool increment = true) { Request(ref _pooledConnectionsCounter, increment); } @@ -259,7 +259,7 @@ internal void PooledConnectionRequest(bool increment = true) /// /// [NonEvent] - internal void ActiveConnectionPoolGroupRequest(bool increment = true) + internal override void ActiveConnectionPoolGroupRequest(bool increment = true) { Request(ref _activeConnectionPoolGroupsCounter, increment); } @@ -269,7 +269,7 @@ internal void ActiveConnectionPoolGroupRequest(bool increment = true) /// /// [NonEvent] - internal void InactiveConnectionPoolGroupRequest(bool increment = true) + internal override void InactiveConnectionPoolGroupRequest(bool increment = true) { Request(ref _inactiveConnectionPoolGroupsCounter, increment); } @@ -279,7 +279,7 @@ internal void InactiveConnectionPoolGroupRequest(bool increment = true) /// /// [NonEvent] - internal void ActiveConnectionPoolRequest(bool increment = true) + internal override void ActiveConnectionPoolRequest(bool increment = true) { Request(ref _activeConnectionPoolsCounter, increment); } @@ -289,7 +289,7 @@ internal void ActiveConnectionPoolRequest(bool increment = true) /// /// [NonEvent] - internal void InactiveConnectionPoolRequest(bool increment = true) + internal override void InactiveConnectionPoolRequest(bool increment = true) { Request(ref _inactiveConnectionPoolsCounter, increment); } @@ -299,7 +299,7 @@ internal void InactiveConnectionPoolRequest(bool increment = true) /// /// [NonEvent] - internal void ActiveConnectionRequest(bool increment = true) + internal override void ActiveConnectionRequest(bool increment = true) { Request(ref _activeConnectionsCounter, increment); } @@ -309,7 +309,7 @@ internal void ActiveConnectionRequest(bool increment = true) /// /// [NonEvent] - internal void FreeConnectionRequest(bool increment = true) + internal override void FreeConnectionRequest(bool increment = true) { Request(ref _freeConnectionsCounter, increment); } @@ -319,7 +319,7 @@ internal void FreeConnectionRequest(bool increment = true) /// /// [NonEvent] - internal void StasisConnectionRequest(bool increment = true) + internal override void StasisConnectionRequest(bool increment = true) { Request(ref _stasisConnectionsCounter, increment); } @@ -328,7 +328,7 @@ internal void StasisConnectionRequest(bool increment = true) /// The number of connections we reclaim from GC'd external connections /// [NonEvent] - internal void ReclaimedConnectionRequest() + internal override void ReclaimedConnectionRequest() { Request(ref _reclaimedConnectionsCounter, true); } diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.cs index 2febb4b5d9..f71ca6e667 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.cs @@ -15,7 +15,37 @@ protected override void OnEventCommand(EventCommandEventArgs command) EventCommandMethodCall(command); } - protected virtual void EventCommandMethodCall(EventCommandEventArgs command){} + protected virtual void EventCommandMethodCall(EventCommandEventArgs command) { } + + #region not implemented for .Net core 2.1, .Net standard 2.0 and lower + internal virtual void HardConnectRequest() { /*no-op*/ } + + internal virtual void HardDisconnectRequest() { /*no-op*/ } + + internal virtual void SoftConnectRequest() { /*no-op*/ } + + internal virtual void SoftDisconnectRequest() { /*no-op*/ } + + internal virtual void NonPooledConnectionRequest(bool increment = true) { /*no-op*/ } + + internal virtual void PooledConnectionRequest(bool increment = true) { /*no-op*/ } + + internal virtual void ActiveConnectionPoolGroupRequest(bool increment = true) { /*no-op*/ } + + internal virtual void InactiveConnectionPoolGroupRequest(bool increment = true) { /*no-op*/ } + + internal virtual void ActiveConnectionPoolRequest(bool increment = true) { /*no-op*/ } + + internal virtual void InactiveConnectionPoolRequest(bool increment = true) { /*no-op*/ } + + internal virtual void ActiveConnectionRequest(bool increment = true) { /*no-op*/ } + + internal virtual void FreeConnectionRequest(bool increment = true) { /*no-op*/ } + + internal virtual void StasisConnectionRequest(bool increment = true) { /*no-op*/ } + + internal virtual void ReclaimedConnectionRequest() { /*no-op*/ } + #endregion } [EventSource(Name = "Microsoft.Data.SqlClient.EventSource")] diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj index 8f085ab21c..6c5e6c3225 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj @@ -232,6 +232,9 @@ + + + diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/EventCounterTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/EventCounterTest.cs index 52c20e409c..ef2e1d7af3 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/EventCounterTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/EventCounterTest.cs @@ -11,6 +11,9 @@ namespace Microsoft.Data.SqlClient.ManualTesting.Tests { + /// + /// This unit test is just valid for .NetCore 3.0 and above + /// public class EventCounterTest { [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] @@ -82,8 +85,11 @@ protected override void OnEventSourceCreated(EventSource eventSource) if (eventSource.Name.Equals("Microsoft.Data.SqlClient.EventSource")) { var options = new Dictionary(); + // define time interval 1 second + // without defining this parameter event counters will not enabled options.Add("EventCounterIntervalSec", "1"); - EnableEvents(eventSource, EventLevel.Informational, EventKeywords.All, options); + // enable for the None keyword + EnableEvents(eventSource, EventLevel.Informational, EventKeywords.None, options); } } From 377fb33ea0681ddf26433f976c90d3df2a6a5985 Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Wed, 9 Sep 2020 17:53:01 -0700 Subject: [PATCH 06/12] Add snippet sample code --- doc/samples/SqlClientDiagnosticCounter.cs | 62 +++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 doc/samples/SqlClientDiagnosticCounter.cs diff --git a/doc/samples/SqlClientDiagnosticCounter.cs b/doc/samples/SqlClientDiagnosticCounter.cs new file mode 100644 index 0000000000..576563f6fd --- /dev/null +++ b/doc/samples/SqlClientDiagnosticCounter.cs @@ -0,0 +1,62 @@ +// +using System; +using System.Collections.Generic; +using System.Diagnostics.Tracing; +using System.Linq; + +// This listener class will listen for events from the SqlClientEventSource class. +// SqlClientEventSource is an implementation of the EventSource class which gives +// it the ability to create events. +public class EventCounterListener : EventListener +{ + protected override void OnEventSourceCreated(EventSource eventSource) + { + // Only enable events from SqlClientEventSource. + if (eventSource.Name.Equals("Microsoft.Data.SqlClient.EventSource")) + { + var options = new Dictionary(); + // define time interval 1 second + // without defining this parameter event counters will not enabled + options.Add("EventCounterIntervalSec", "1"); + // enable for the None keyword + EnableEvents(eventSource, EventLevel.Informational, EventKeywords.None, options); + } + } + + // This callback runs whenever an event is written by SqlClientEventSource. + // Event data is accessed through the EventWrittenEventArgs parameter. + protected override void OnEventWritten(EventWrittenEventArgs eventData) + { + if (eventData.Payload.FirstOrDefault(p => p is IDictionary x && x.ContainsKey("Name")) is IDictionary counters) + { + if (counters.TryGetValue("DisplayName", out object name) && name is string cntName + && counters.TryGetValue("Mean", out object value) && value is double cntValue) + { + // print event counter's name and mean value + Console.WriteLine($"{cntName}\t\t{cntValue}"); + } + } + } +} + +class Program +{ + static void Main(string[] args) + { + // Create a new event listener + using (var listener = new EventCounterListener()) + { + string connectionString = "Data Source=localhost; Integrated Security=true"; + + for (int i = 0; i < 50; i++) + { + // Open a connection + SqlConnection cnn = new SqlConnection(connectionString); + cnn.Open(); + // wait for sampling interval happens + System.Threading.Thread.Sleep(500); + } + } + } +} +// From fceefd9346022076b18fe5744d9433e5e0785e01 Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Fri, 11 Sep 2020 16:08:18 -0700 Subject: [PATCH 07/12] Address comments --- .../netcore/src/Microsoft.Data.SqlClient.csproj | 2 +- .../src/Microsoft/Data/ProviderBase/DbConnectionPool.cs | 2 +- ...ource.NetCoreApp3.cs => SqlClientEventSource.NetCoreApp.cs} | 0 .../tests/ManualTests/DataCommon/DataTestUtility.cs | 3 +-- 4 files changed, 3 insertions(+), 4 deletions(-) rename src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/{SqlClientEventSource.NetCoreApp3.cs => SqlClientEventSource.NetCoreApp.cs} (100%) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj index 43dd66de36..eb31614e5e 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -249,7 +249,7 @@ - + diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/ProviderBase/DbConnectionPool.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/ProviderBase/DbConnectionPool.cs index 4dc5af64bf..1399a57eaf 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/ProviderBase/DbConnectionPool.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/ProviderBase/DbConnectionPool.cs @@ -294,7 +294,7 @@ internal void TransactionEnded(Transaction transaction, DbConnectionInternal tra // connections, we'll put it back... if (0 <= entry) { - SqlClientEventSource.Log.FreeConnectionRequest(); + SqlClientEventSource.Log.FreeConnectionRequest(false); Pool.PutObjectFromTransactedPool(transactedObject); } } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp3.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp.cs similarity index 100% rename from src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp3.cs rename to src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp.cs diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs index 79e9adffb4..a3437647fa 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs @@ -15,7 +15,6 @@ using Microsoft.Identity.Client; using Microsoft.Data.SqlClient.TestUtilities; using Xunit; -using System.Linq; namespace Microsoft.Data.SqlClient.ManualTesting.Tests { @@ -695,7 +694,7 @@ protected override void OnEventSourceCreated(EventSource eventSource) { if (eventSource.Name.Equals("Microsoft.Data.SqlClient.EventSource")) { - //// Collect all traces for better code coverage + // Collect all traces for better code coverage EnableEvents(eventSource, EventLevel.Informational, EventKeywords.All); } } From 7ec5012ef4c36804a3250467963b2ed14c286d6e Mon Sep 17 00:00:00 2001 From: Karina Zhou Date: Thu, 7 Jan 2021 10:11:30 -0800 Subject: [PATCH 08/12] Fix minor typo (#3) --- .../Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp.cs index 67521a1c36..3b91e80e18 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp.cs @@ -125,7 +125,7 @@ protected override void EventCommandMethodCall(EventCommandEventArgs command) }; _numberOfActiveConnectionPoolGroups = _numberOfActiveConnectionPoolGroups ?? - new PollingCounter("number-of-active-connection-pool-groups", this, () => _activeConnectionPoolsCounter) + new PollingCounter("number-of-active-connection-pool-groups", this, () => _activeConnectionPoolGroupsCounter) { DisplayName = "Number of active unique connection strings", DisplayUnits = "count" From 6e264bc572ece17700df4af6816519e961579ad9 Mon Sep 17 00:00:00 2001 From: Karina Zhou Date: Tue, 12 Jan 2021 18:20:57 -0800 Subject: [PATCH 09/12] Reformatting counter methods * Fix minor typo * Removed IsEnabled condition and reformatted counter methods --- .../Data/ProviderBase/DbConnectionFactory.cs | 12 +- .../Data/ProviderBase/DbConnectionInternal.cs | 2 +- .../ProviderBase/DbConnectionPoolGroup.cs | 6 +- .../Data/ProviderBase/DbConnectionFactory.cs | 4 +- .../Data/ProviderBase/DbConnectionInternal.cs | 10 +- .../Data/ProviderBase/DbConnectionPool.cs | 20 +-- .../SqlClientEventSource.NetCoreApp.cs | 168 +++++++++++------- .../Data/SqlClient/SqlClientEventSource.cs | 36 +++- 8 files changed, 160 insertions(+), 98 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbConnectionFactory.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbConnectionFactory.cs index be5ce95bfa..846d82ac25 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbConnectionFactory.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbConnectionFactory.cs @@ -283,7 +283,7 @@ internal DbConnectionPoolGroup GetConnectionPoolGroup(DbConnectionPoolKey key, D // lock prevents race condition with PruneConnectionPoolGroups newConnectionPoolGroups.Add(key, newConnectionPoolGroup); - SqlClientEventSource.Log.ActiveConnectionPoolGroupRequest(); + SqlClientEventSource.Log.EnterActiveConnectionPoolGroup(); connectionPoolGroup = newConnectionPoolGroup; _connectionPoolGroups = newConnectionPoolGroups; } @@ -327,7 +327,7 @@ private void PruneConnectionPoolGroups(object state) { _poolsToRelease.Remove(pool); SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, ReleasePool={1}", ObjectID, pool.ObjectID); - SqlClientEventSource.Log.InactiveConnectionPoolRequest(false); + SqlClientEventSource.Log.ExitInactiveConnectionPool(); } } } @@ -352,7 +352,7 @@ private void PruneConnectionPoolGroups(object state) { _poolGroupsToRelease.Remove(poolGroup); SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, ReleasePoolGroup={1}", ObjectID, poolGroup.ObjectID); - SqlClientEventSource.Log.InactiveConnectionPoolGroupRequest(false); + SqlClientEventSource.Log.ExitInactiveConnectionPoolGroup(); } } } @@ -378,7 +378,7 @@ private void PruneConnectionPoolGroups(object state) // otherwise process entry which may move it from active to idle if (entry.Value.Prune()) { // may add entries to _poolsToRelease - SqlClientEventSource.Log.ActiveConnectionPoolGroupRequest(false); + SqlClientEventSource.Log.ExitActiveConnectionPoolGroup(); QueuePoolGroupForRelease(entry.Value); } else @@ -411,7 +411,7 @@ internal void QueuePoolForRelease(DbConnectionPool pool, bool clearing) } _poolsToRelease.Add(pool); } - SqlClientEventSource.Log.InactiveConnectionPoolRequest(); + SqlClientEventSource.Log.EnterInactiveConnectionPool(); } internal void QueuePoolGroupForRelease(DbConnectionPoolGroup poolGroup) @@ -423,7 +423,7 @@ internal void QueuePoolGroupForRelease(DbConnectionPoolGroup poolGroup) { _poolGroupsToRelease.Add(poolGroup); } - SqlClientEventSource.Log.InactiveConnectionPoolGroupRequest(); + SqlClientEventSource.Log.EnterInactiveConnectionPoolGroup(); } virtual protected DbConnectionInternal CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection, DbConnectionOptions userOptions) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs index ba0d037127..b24ed6810f 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs @@ -231,7 +231,7 @@ internal void DeactivateConnection() int activateCount = Interlocked.Decrement(ref _activateCount); #endif // DEBUG - SqlClientEventSource.Log.ActiveConnectionRequest(false); + SqlClientEventSource.Log.ExitActiveConnection(); if (!_connectionIsDoomed && Pool.UseLoadBalancing) { diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbConnectionPoolGroup.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbConnectionPoolGroup.cs index 1edae1e106..cccb707a85 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbConnectionPoolGroup.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbConnectionPoolGroup.cs @@ -129,7 +129,7 @@ internal int Clear() if (pool != null) { DbConnectionFactory connectionFactory = pool.ConnectionFactory; - SqlClientEventSource.Log.ActiveConnectionPoolRequest(false); + SqlClientEventSource.Log.ExitActiveConnectionPool(); connectionFactory.QueuePoolForRelease(pool, true); } } @@ -188,7 +188,7 @@ internal DbConnectionPool GetConnectionPool(DbConnectionFactory connectionFactor newPool.Startup(); // must start pool before usage bool addResult = _poolCollection.TryAdd(currentIdentity, newPool); Debug.Assert(addResult, "No other pool with current identity should exist at this point"); - SqlClientEventSource.Log.ActiveConnectionPoolRequest(); + SqlClientEventSource.Log.EnterActiveConnectionPool(); pool = newPool; } else @@ -266,7 +266,7 @@ internal bool Prune() DbConnectionFactory connectionFactory = pool.ConnectionFactory; connectionFactory.QueuePoolForRelease(pool, false); - SqlClientEventSource.Log.ActiveConnectionPoolRequest(false); + SqlClientEventSource.Log.ExitActiveConnectionPool(); } else { diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/ProviderBase/DbConnectionFactory.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/ProviderBase/DbConnectionFactory.cs index 7e5a66e9e9..1a2e809147 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/ProviderBase/DbConnectionFactory.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/ProviderBase/DbConnectionFactory.cs @@ -108,7 +108,7 @@ internal bool TryGetConnection(DbConnection owningConnection, TaskCompletionSour } connection = CreateNonPooledConnection(owningConnection, poolGroup, userOptions); - SqlClientEventSource.Log.NonPooledConnectionRequest(); + SqlClientEventSource.Log.EnterNonPooledConnection(); } else { @@ -212,7 +212,7 @@ private static void TryGetConnectionCompletedContinuation(Task {0}, Non-Pooled Connection has Delegated Transaction, waiting to Dispose.", ObjectID); - SqlClientEventSource.Log.StasisConnectionRequest(); + SqlClientEventSource.Log.EnterStasisConnection(); } private void TerminateStasis(bool returningToPool) @@ -499,7 +499,7 @@ private void TerminateStasis(bool returningToPool) { SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Delegated Transaction has ended, connection is closed/leaked. Disposing.", ObjectID); } - SqlClientEventSource.Log.StasisConnectionRequest(false); + SqlClientEventSource.Log.ExitStasisConnection(); _isInStasis = false; } } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/ProviderBase/DbConnectionPool.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/ProviderBase/DbConnectionPool.cs index 1399a57eaf..6b83fdce3b 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/ProviderBase/DbConnectionPool.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/ProviderBase/DbConnectionPool.cs @@ -231,7 +231,7 @@ internal void PutTransactedObject(Transaction transaction, DbConnectionInternal } SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Transaction {1}, Connection {2}, Added.", ObjectID, transaction.GetHashCode(), transactedObject.ObjectID); } - SqlClientEventSource.Log.FreeConnectionRequest(); + SqlClientEventSource.Log.EnterFreeConnection(); } internal void TransactionEnded(Transaction transaction, DbConnectionInternal transactedObject) @@ -294,7 +294,7 @@ internal void TransactionEnded(Transaction transaction, DbConnectionInternal tra // connections, we'll put it back... if (0 <= entry) { - SqlClientEventSource.Log.FreeConnectionRequest(false); + SqlClientEventSource.Log.ExitFreeConnection(); Pool.PutObjectFromTransactedPool(transactedObject); } } @@ -602,7 +602,7 @@ private void CleanupCallback(object state) { Debug.Assert(obj != null, "null connection is not expected"); // If we obtained one from the old stack, destroy it. - SqlClientEventSource.Log.FreeConnectionRequest(false); + SqlClientEventSource.Log.ExitFreeConnection(); // Transaction roots must survive even aging out (TxEnd event will clean them up). bool shouldDestroy = true; @@ -699,13 +699,13 @@ internal void Clear() while (_stackNew.TryPop(out obj)) { Debug.Assert(obj != null, "null connection is not expected"); - SqlClientEventSource.Log.FreeConnectionRequest(false); + SqlClientEventSource.Log.ExitFreeConnection(); DestroyObject(obj); } while (_stackOld.TryPop(out obj)) { Debug.Assert(obj != null, "null connection is not expected"); - SqlClientEventSource.Log.FreeConnectionRequest(false); + SqlClientEventSource.Log.ExitFreeConnection(); DestroyObject(obj); } @@ -747,7 +747,7 @@ private DbConnectionInternal CreateObject(DbConnection owningObject, DbConnectio } _objectList.Add(newObj); _totalObjects = _objectList.Count; - SqlClientEventSource.Log.PooledConnectionRequest(); + SqlClientEventSource.Log.EnterPooledConnection(); } // If the old connection belonged to another pool, we need to remove it from that @@ -973,7 +973,7 @@ internal void DestroyObject(DbConnectionInternal obj) if (removed) { SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Connection {1}, Removed from pool.", ObjectID, obj.ObjectID); - SqlClientEventSource.Log.PooledConnectionRequest(false); + SqlClientEventSource.Log.ExitPooledConnection(); } obj.Dispose(); SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Connection {1}, Disposed.", ObjectID, obj.ObjectID); @@ -1384,7 +1384,7 @@ private DbConnectionInternal GetFromGeneralPool() if (null != obj) { SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Connection {1}, Popped from general pool.", ObjectID, obj.ObjectID); - SqlClientEventSource.Log.FreeConnectionRequest(false); + SqlClientEventSource.Log.ExitFreeConnection(); } return (obj); } @@ -1401,7 +1401,7 @@ private DbConnectionInternal GetFromTransactedPool(out Transaction transaction) if (null != obj) { SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Connection {1}, Popped from transacted pool.", ObjectID, obj.ObjectID); - SqlClientEventSource.Log.FreeConnectionRequest(false); + SqlClientEventSource.Log.ExitFreeConnection(); if (obj.IsTransactionRoot) { @@ -1556,7 +1556,7 @@ internal void PutNewObject(DbConnectionInternal obj) _stackNew.Push(obj); _waitHandles.PoolSemaphore.Release(1); - SqlClientEventSource.Log.FreeConnectionRequest(); + SqlClientEventSource.Log.EnterFreeConnection(); } internal void PutObject(DbConnectionInternal obj, object owningObject) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp.cs index 3b91e80e18..1cab291611 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp.cs @@ -188,11 +188,8 @@ protected override void EventCommandMethodCall(EventCommandEventArgs command) [NonEvent] internal override void HardConnectRequest() { - if (IsEnabled()) - { - Interlocked.Increment(ref _activeHardConnectionsCounter); - Interlocked.Increment(ref _hardConnectsCounter); - } + Interlocked.Increment(ref _activeHardConnectionsCounter); + Interlocked.Increment(ref _hardConnectsCounter); } /// @@ -201,11 +198,8 @@ internal override void HardConnectRequest() [NonEvent] internal override void HardDisconnectRequest() { - if (IsEnabled()) - { - Interlocked.Decrement(ref _activeHardConnectionsCounter); - Interlocked.Increment(ref _hardDisconnectsCounter); - } + Interlocked.Decrement(ref _activeHardConnectionsCounter); + Interlocked.Increment(ref _hardDisconnectsCounter); } /// @@ -214,11 +208,8 @@ internal override void HardDisconnectRequest() [NonEvent] internal override void SoftConnectRequest() { - if (IsEnabled()) - { - Interlocked.Increment(ref _activeSoftConnectionsCounter); - Interlocked.Increment(ref _softConnectsCounter); - } + Interlocked.Increment(ref _activeSoftConnectionsCounter); + Interlocked.Increment(ref _softConnectsCounter); } /// @@ -227,126 +218,179 @@ internal override void SoftConnectRequest() [NonEvent] internal override void SoftDisconnectRequest() { - if (IsEnabled()) - { - Interlocked.Decrement(ref _activeSoftConnectionsCounter); - Interlocked.Increment(ref _softDisconnectsCounter); - } + Interlocked.Decrement(ref _activeSoftConnectionsCounter); + Interlocked.Increment(ref _softDisconnectsCounter); } /// /// The number of connections that are not using connection pooling /// - /// [NonEvent] - internal override void NonPooledConnectionRequest(bool increment = true) + internal override void EnterNonPooledConnection() + { + Interlocked.Increment(ref _nonPooledConnectionsCounter); + } + + /// + /// The number of connections that are not using connection pooling + /// + [NonEvent] + internal override void ExitNonPooledConnection() + { + Interlocked.Decrement(ref _nonPooledConnectionsCounter); + } + + /// + /// The number of connections that are managed by the connection pooler + /// + [NonEvent] + internal override void EnterPooledConnection() { - Request(ref _nonPooledConnectionsCounter, increment); + Interlocked.Increment(ref _pooledConnectionsCounter); } /// /// The number of connections that are managed by the connection pooler /// - /// [NonEvent] - internal override void PooledConnectionRequest(bool increment = true) + internal override void ExitPooledConnection() + { + Interlocked.Decrement(ref _pooledConnectionsCounter); + } + + /// + /// The number of unique connection strings + /// + [NonEvent] + internal override void EnterActiveConnectionPoolGroup() { - Request(ref _pooledConnectionsCounter, increment); + Interlocked.Increment(ref _activeConnectionPoolGroupsCounter); } /// /// The number of unique connection strings /// - /// [NonEvent] - internal override void ActiveConnectionPoolGroupRequest(bool increment = true) + internal override void ExitActiveConnectionPoolGroup() { - Request(ref _activeConnectionPoolGroupsCounter, increment); + Interlocked.Decrement(ref _activeConnectionPoolGroupsCounter); } /// /// The number of unique connection strings waiting for pruning /// - /// [NonEvent] - internal override void InactiveConnectionPoolGroupRequest(bool increment = true) + internal override void EnterInactiveConnectionPoolGroup() { - Request(ref _inactiveConnectionPoolGroupsCounter, increment); + Interlocked.Increment(ref _inactiveConnectionPoolGroupsCounter); + } + + /// + /// The number of unique connection strings waiting for pruning + /// + [NonEvent] + internal override void ExitInactiveConnectionPoolGroup() + { + Interlocked.Decrement(ref _inactiveConnectionPoolGroupsCounter); } /// /// The number of connection pools /// - /// [NonEvent] - internal override void ActiveConnectionPoolRequest(bool increment = true) + internal override void EnterActiveConnectionPool() { - Request(ref _activeConnectionPoolsCounter, increment); + Interlocked.Increment(ref _activeConnectionPoolsCounter); } /// /// The number of connection pools /// - /// [NonEvent] - internal override void InactiveConnectionPoolRequest(bool increment = true) + internal override void ExitActiveConnectionPool() { - Request(ref _inactiveConnectionPoolsCounter, increment); + Interlocked.Decrement(ref _activeConnectionPoolsCounter); + } + + /// + /// The number of connection pools + /// + [NonEvent] + internal override void EnterInactiveConnectionPool() + { + Interlocked.Increment(ref _inactiveConnectionPoolsCounter); + } + + /// + /// The number of connection pools + /// + [NonEvent] + internal override void ExitInactiveConnectionPool() + { + Interlocked.Decrement(ref _inactiveConnectionPoolsCounter); + } + + /// + /// The number of connections currently in-use + /// + [NonEvent] + internal override void EnterActiveConnection() + { + Interlocked.Increment(ref _activeConnectionsCounter); } /// /// The number of connections currently in-use /// - /// [NonEvent] - internal override void ActiveConnectionRequest(bool increment = true) + internal override void ExitActiveConnection() { - Request(ref _activeConnectionsCounter, increment); + Interlocked.Decrement(ref _activeConnectionsCounter); } /// /// The number of connections currently available for use /// - /// [NonEvent] - internal override void FreeConnectionRequest(bool increment = true) + internal override void EnterFreeConnection() { - Request(ref _freeConnectionsCounter, increment); + Interlocked.Increment(ref _freeConnectionsCounter); + } + + /// + /// The number of connections currently available for use + /// + [NonEvent] + internal override void ExitFreeConnection() + { + Interlocked.Decrement(ref _freeConnectionsCounter); } /// /// The number of connections currently waiting to be made ready for use /// - /// [NonEvent] - internal override void StasisConnectionRequest(bool increment = true) + internal override void EnterStasisConnection() { - Request(ref _stasisConnectionsCounter, increment); + Interlocked.Increment(ref _stasisConnectionsCounter); } /// - /// The number of connections we reclaim from GC'd external connections + /// The number of connections currently waiting to be made ready for use /// [NonEvent] - internal override void ReclaimedConnectionRequest() + internal override void ExitStasisConnection() { - Request(ref _reclaimedConnectionsCounter, true); + Interlocked.Decrement(ref _stasisConnectionsCounter); } + /// + /// The number of connections we reclaim from GC'd external connections + /// [NonEvent] - private void Request(ref long counter, bool increment) + internal override void ReclaimedConnectionRequest() { - if (IsEnabled()) - { - if (increment) - { - Interlocked.Increment(ref counter); - } - else - { - Interlocked.Decrement(ref counter); - } - } + Interlocked.Increment(ref _reclaimedConnectionsCounter); } } } diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.cs index 14f6d274f2..f959db0c2f 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.cs @@ -27,23 +27,41 @@ internal virtual void SoftConnectRequest() { /*no-op*/ } internal virtual void SoftDisconnectRequest() { /*no-op*/ } - internal virtual void NonPooledConnectionRequest(bool increment = true) { /*no-op*/ } + internal virtual void EnterNonPooledConnection() { /*no-op*/ } - internal virtual void PooledConnectionRequest(bool increment = true) { /*no-op*/ } + internal virtual void ExitNonPooledConnection() { /*no-op*/ } - internal virtual void ActiveConnectionPoolGroupRequest(bool increment = true) { /*no-op*/ } + internal virtual void EnterPooledConnection() { /*no-op*/ } - internal virtual void InactiveConnectionPoolGroupRequest(bool increment = true) { /*no-op*/ } + internal virtual void ExitPooledConnection() { /*no-op*/ } - internal virtual void ActiveConnectionPoolRequest(bool increment = true) { /*no-op*/ } + internal virtual void EnterActiveConnectionPoolGroup() { /*no-op*/ } - internal virtual void InactiveConnectionPoolRequest(bool increment = true) { /*no-op*/ } + internal virtual void ExitActiveConnectionPoolGroup() { /*no-op*/ } - internal virtual void ActiveConnectionRequest(bool increment = true) { /*no-op*/ } + internal virtual void EnterInactiveConnectionPoolGroup() { /*no-op*/ } - internal virtual void FreeConnectionRequest(bool increment = true) { /*no-op*/ } + internal virtual void ExitInactiveConnectionPoolGroup() { /*no-op*/ } - internal virtual void StasisConnectionRequest(bool increment = true) { /*no-op*/ } + internal virtual void EnterActiveConnectionPool() { /*no-op*/ } + + internal virtual void ExitActiveConnectionPool() { /*no-op*/ } + + internal virtual void EnterInactiveConnectionPool() { /*no-op*/ } + + internal virtual void ExitInactiveConnectionPool() { /*no-op*/ } + + internal virtual void EnterActiveConnection() { /*no-op*/ } + + internal virtual void ExitActiveConnection() { /*no-op*/ } + + internal virtual void EnterFreeConnection() { /*no-op*/ } + + internal virtual void ExitFreeConnection() { /*no-op*/ } + + internal virtual void EnterStasisConnection() { /*no-op*/ } + + internal virtual void ExitStasisConnection() { /*no-op*/ } internal virtual void ReclaimedConnectionRequest() { /*no-op*/ } #endregion From 7a52156a96b0f7fe6551951e5ee7f5ff2452e73e Mon Sep 17 00:00:00 2001 From: Nikita Kobzev Date: Wed, 10 Feb 2021 23:18:34 +0300 Subject: [PATCH 10/12] Unit tests for Microsoft.Data.SqlClient.SqlClientEventSource (#2) * Implemented tests for Microsoft.Data.SqlClient.SqlClientEventSource * Updated the EventCounter test to reflect the recent changes in the code * Working on EventCounter tests access event counters through reflection * Updated the EventCounterTest to use reflection * Fixing dangling SqlConnection's left in tests * EventCountersTest now checks hard/soft connects/disconnects counters * Reverted the DataTestUtility changes * Reverted using statements to the old-style in tests * Reverted the ConnectionPoolTest.ReclaimEmancipatedOnOpenTest() * Reverted using statements to the old-style in tests * Reverted using statements to the old-style in tests * Rewrite the EventCounterTest assertions not to conflict with other tests * Code review cleanup --- .../Data/ProviderBase/DbConnectionFactory.cs | 10 +- .../ProviderBase/DbConnectionPoolGroup.cs | 7 +- .../DDBasics/DDAsyncTest/DDAsyncTest.cs | 19 +- .../ManualTests/DataCommon/DataTestUtility.cs | 2 +- .../SQL/AdapterTest/AdapterTest.cs | 6 +- .../ConnectionPoolTest/ConnectionPoolTest.cs | 76 ++-- .../SQL/ParameterTest/DateTimeVariantTest.cs | 164 ++++----- .../SQL/RandomStressTest/RandomStressTest.cs | 6 +- .../SQL/TransactionTest/TransactionTest.cs | 12 +- .../TracingTests/EventCounterTest.cs | 327 ++++++++++++++---- 10 files changed, 425 insertions(+), 204 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbConnectionFactory.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbConnectionFactory.cs index 846d82ac25..7f3060fa73 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbConnectionFactory.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbConnectionFactory.cs @@ -25,7 +25,7 @@ internal abstract partial class DbConnectionFactory private static int _objectTypeCount; // EventSource counter internal int ObjectID { get; } = Interlocked.Increment(ref _objectTypeCount); - // s_pendingOpenNonPooled is an array of tasks used to throttle creation of non-pooled connections to + // s_pendingOpenNonPooled is an array of tasks used to throttle creation of non-pooled connections to // a maximum of Environment.ProcessorCount at a time. private static uint s_pendingOpenNonPooledNext = 0; private static Task[] s_pendingOpenNonPooled = new Task[Environment.ProcessorCount]; @@ -307,7 +307,7 @@ private void PruneConnectionPoolGroups(object state) { // when debugging this method, expect multiple threads at the same time SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}", ObjectID); - + // First, walk the pool release list and attempt to clear each // pool, when the pool is finally empty, we dispose of it. If the // pool isn't empty, it's because there are active connections or @@ -377,8 +377,8 @@ private void PruneConnectionPoolGroups(object state) // move idle entries from last prune pass to a queue for pending release // otherwise process entry which may move it from active to idle if (entry.Value.Prune()) - { // may add entries to _poolsToRelease - SqlClientEventSource.Log.ExitActiveConnectionPoolGroup(); + { + // may add entries to _poolsToRelease QueuePoolGroupForRelease(entry.Value); } else @@ -412,6 +412,7 @@ internal void QueuePoolForRelease(DbConnectionPool pool, bool clearing) _poolsToRelease.Add(pool); } SqlClientEventSource.Log.EnterInactiveConnectionPool(); + SqlClientEventSource.Log.ExitActiveConnectionPool(); } internal void QueuePoolGroupForRelease(DbConnectionPoolGroup poolGroup) @@ -424,6 +425,7 @@ internal void QueuePoolGroupForRelease(DbConnectionPoolGroup poolGroup) _poolGroupsToRelease.Add(poolGroup); } SqlClientEventSource.Log.EnterInactiveConnectionPoolGroup(); + SqlClientEventSource.Log.ExitActiveConnectionPoolGroup(); } virtual protected DbConnectionInternal CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection, DbConnectionOptions userOptions) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbConnectionPoolGroup.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbConnectionPoolGroup.cs index cccb707a85..51109fc388 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbConnectionPoolGroup.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbConnectionPoolGroup.cs @@ -129,7 +129,6 @@ internal int Clear() if (pool != null) { DbConnectionFactory connectionFactory = pool.ConnectionFactory; - SqlClientEventSource.Log.ExitActiveConnectionPool(); connectionFactory.QueuePoolForRelease(pool, true); } } @@ -196,8 +195,8 @@ internal DbConnectionPool GetConnectionPool(DbConnectionFactory connectionFactor // else pool entry has been disabled so don't create new pools Debug.Assert(PoolGroupStateDisabled == _state, "state should be disabled"); - // don't need to call connectionFactory.QueuePoolForRelease(newPool) because - // pool callbacks were delayed and no risk of connections being created + // don't need to call connectionFactory.QueuePoolForRelease(newPool) because + // pool callbacks were delayed and no risk of connections being created newPool.Shutdown(); } } @@ -264,9 +263,7 @@ internal bool Prune() // pool into a list of pools to be released when they // are completely empty. DbConnectionFactory connectionFactory = pool.ConnectionFactory; - connectionFactory.QueuePoolForRelease(pool, false); - SqlClientEventSource.Log.ExitActiveConnectionPool(); } else { diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DDBasics/DDAsyncTest/DDAsyncTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DDBasics/DDAsyncTest/DDAsyncTest.cs index d1f7ed0a24..2bdde5eda1 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DDBasics/DDAsyncTest/DDAsyncTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DDBasics/DDAsyncTest/DDAsyncTest.cs @@ -26,7 +26,7 @@ public static void OpenConnection_WithAsyncTrue() { // Passes on NetFx var asyncConnectionString = DataTestUtility.TCPConnectionString + ";async=true"; - SqlConnection connection = new SqlConnection(asyncConnectionString); + using (SqlConnection connection = new SqlConnection(asyncConnectionString)){} } #region <> @@ -60,16 +60,17 @@ private static bool DoesProcessExecutedAsync(IReadOnlyList executedProce private static async Task ExecuteCommandWithNewConnectionAsync(string processName, string cmdText, ICollection executedProcessList) { - var conn = new SqlConnection(DataTestUtility.TCPConnectionString); - - await conn.OpenAsync(); - var cmd = new SqlCommand(cmdText, conn); - - using (SqlDataReader reader = await cmd.ExecuteReaderAsync()) + using (var conn = new SqlConnection(DataTestUtility.TCPConnectionString)) { - while (await reader.ReadAsync()) + await conn.OpenAsync(); + var cmd = new SqlCommand(cmdText, conn); + + using (SqlDataReader reader = await cmd.ExecuteReaderAsync()) { - executedProcessList.Add(processName); + while (await reader.ReadAsync()) + { + executedProcessList.Add(processName); + } } } } diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs index 81f2689bd3..69af9db7cc 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs @@ -742,7 +742,7 @@ protected override void OnEventSourceCreated(EventSource eventSource) { if (eventSource.Name.Equals("Microsoft.Data.SqlClient.EventSource")) { - // Collect all traces for better code coverage + //// Collect all traces for better code coverage EnableEvents(eventSource, EventLevel.Informational, EventKeywords.All); } } diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AdapterTest/AdapterTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AdapterTest/AdapterTest.cs index 6249c4fae3..ae52a6efab 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AdapterTest/AdapterTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/AdapterTest/AdapterTest.cs @@ -91,7 +91,8 @@ public void SimpleFillTest() public void PrepUnprepTest() { // share the connection - using (SqlCommand cmd = new SqlCommand("select * from shippers", new SqlConnection(DataTestUtility.TCPConnectionString))) + using (SqlConnection connection = new SqlConnection(DataTestUtility.TCPConnectionString)) + using (SqlCommand cmd = new SqlCommand("select * from shippers", connection)) using (SqlDataAdapter sqlAdapter = new SqlDataAdapter()) { cmd.Connection.Open(); @@ -183,7 +184,8 @@ public void SqlVariantTest() ExecuteNonQueryCommand("CREATE TABLE " + tableName + " (c0_bigint bigint, c1_variant sql_variant)"); // good test for null values and unicode strings - using (SqlCommand cmd = new SqlCommand(null, new SqlConnection(DataTestUtility.TCPConnectionString))) + using (SqlConnection conn = new SqlConnection(DataTestUtility.TCPConnectionString)) + using (SqlCommand cmd = new SqlCommand(null, conn)) using (SqlDataAdapter sqlAdapter = new SqlDataAdapter()) { cmd.Connection.Open(); diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs index 2696f354aa..f86f71468f 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionPoolTest/ConnectionPoolTest.cs @@ -46,31 +46,41 @@ private static void RunDataTestForSingleConnString(string tcpConnectionString) /// private static void BasicConnectionPoolingTest(string connectionString) { - SqlConnection connection = new SqlConnection(connectionString); - connection.Open(); - InternalConnectionWrapper internalConnection = new InternalConnectionWrapper(connection); - ConnectionPoolWrapper connectionPool = new ConnectionPoolWrapper(connection); - connection.Close(); + InternalConnectionWrapper internalConnection; + ConnectionPoolWrapper connectionPool; + using (SqlConnection connection = new SqlConnection(connectionString)) + { + connection.Open(); + internalConnection = new InternalConnectionWrapper(connection); + connectionPool = new ConnectionPoolWrapper(connection); + connection.Close(); + } - SqlConnection connection2 = new SqlConnection(connectionString); - connection2.Open(); - Assert.True(internalConnection.IsInternalConnectionOf(connection2), "New connection does not use same internal connection"); - Assert.True(connectionPool.ContainsConnection(connection2), "New connection is in a different pool"); - connection2.Close(); + using (SqlConnection connection2 = new SqlConnection(connectionString)) + { + connection2.Open(); + Assert.True(internalConnection.IsInternalConnectionOf(connection2), "New connection does not use same internal connection"); + Assert.True(connectionPool.ContainsConnection(connection2), "New connection is in a different pool"); + connection2.Close(); + } - SqlConnection connection3 = new SqlConnection(connectionString + ";App=SqlConnectionPoolUnitTest;"); - connection3.Open(); - Assert.False(internalConnection.IsInternalConnectionOf(connection3), "Connection with different connection string uses same internal connection"); - Assert.False(connectionPool.ContainsConnection(connection3), "Connection with different connection string uses same connection pool"); - connection3.Close(); + using (SqlConnection connection3 = new SqlConnection(connectionString + ";App=SqlConnectionPoolUnitTest;")) + { + connection3.Open(); + Assert.False(internalConnection.IsInternalConnectionOf(connection3), "Connection with different connection string uses same internal connection"); + Assert.False(connectionPool.ContainsConnection(connection3), "Connection with different connection string uses same connection pool"); + connection3.Close(); + } connectionPool.Cleanup(); - SqlConnection connection4 = new SqlConnection(connectionString); - connection4.Open(); - Assert.True(internalConnection.IsInternalConnectionOf(connection4), "New connection does not use same internal connection"); - Assert.True(connectionPool.ContainsConnection(connection4), "New connection is in a different pool"); - connection4.Close(); + using (SqlConnection connection4 = new SqlConnection(connectionString)) + { + connection4.Open(); + Assert.True(internalConnection.IsInternalConnectionOf(connection4), "New connection does not use same internal connection"); + Assert.True(connectionPool.ContainsConnection(connection4), "New connection is in a different pool"); + connection4.Close(); + } } [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.IsAADPasswordConnStrSetup), nameof(DataTestUtility.IsAADAuthorityURLSetup))] @@ -154,18 +164,20 @@ private static void ClearAllPoolsTest(string connectionString) SqlConnection.ClearAllPools(); Assert.True(0 == ConnectionPoolWrapper.AllConnectionPools().Length, "Pools exist after clearing all pools"); - SqlConnection connection = new SqlConnection(connectionString); - connection.Open(); - ConnectionPoolWrapper pool = new ConnectionPoolWrapper(connection); - connection.Close(); - ConnectionPoolWrapper[] allPools = ConnectionPoolWrapper.AllConnectionPools(); - DataTestUtility.AssertEqualsWithDescription(1, allPools.Length, "Incorrect number of pools exist."); - Assert.True(allPools[0].Equals(pool), "Saved pool is not in the list of all pools"); - DataTestUtility.AssertEqualsWithDescription(1, pool.ConnectionCount, "Saved pool has incorrect number of connections"); - - SqlConnection.ClearAllPools(); - Assert.True(0 == ConnectionPoolWrapper.AllConnectionPools().Length, "Pools exist after clearing all pools"); - DataTestUtility.AssertEqualsWithDescription(0, pool.ConnectionCount, "Saved pool has incorrect number of connections."); + using (SqlConnection connection = new SqlConnection(connectionString)) + { + connection.Open(); + ConnectionPoolWrapper pool = new ConnectionPoolWrapper(connection); + connection.Close(); + ConnectionPoolWrapper[] allPools = ConnectionPoolWrapper.AllConnectionPools(); + DataTestUtility.AssertEqualsWithDescription(1, allPools.Length, "Incorrect number of pools exist."); + Assert.True(allPools[0].Equals(pool), "Saved pool is not in the list of all pools"); + DataTestUtility.AssertEqualsWithDescription(1, pool.ConnectionCount, "Saved pool has incorrect number of connections"); + + SqlConnection.ClearAllPools(); + Assert.True(0 == ConnectionPoolWrapper.AllConnectionPools().Length, "Pools exist after clearing all pools"); + DataTestUtility.AssertEqualsWithDescription(0, pool.ConnectionCount, "Saved pool has incorrect number of connections."); + } } /// diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/DateTimeVariantTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/DateTimeVariantTest.cs index 81cbeae7f2..8f6965d043 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/DateTimeVariantTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/DateTimeVariantTest.cs @@ -283,33 +283,35 @@ private static void TestSqlDataReaderParameterToTVP_Type(object paramValue, stri xsql(conn, string.Format("create type dbo.{0} as table (f1 {1})", tvpTypeName, expectedBaseTypeName)); // Send TVP using SqlDataReader. - SqlConnection connInput = new SqlConnection(s_connStr); - connInput.Open(); - - using (SqlCommand cmdInput = connInput.CreateCommand()) + using (SqlConnection connInput = new SqlConnection(s_connStr)) { - cmdInput.CommandText = "select @p1 as f1"; - cmdInput.Parameters.Add("@p1", GetSqlDbType(expectedBaseTypeName)); - cmdInput.Parameters["@p1"].Value = paramValue; + connInput.Open(); - using (SqlDataReader drInput = cmdInput.ExecuteReader(CommandBehavior.CloseConnection)) + using (SqlCommand cmdInput = connInput.CreateCommand()) { - using (SqlCommand cmd = conn.CreateCommand()) + cmdInput.CommandText = "select @p1 as f1"; + cmdInput.Parameters.Add("@p1", GetSqlDbType(expectedBaseTypeName)); + cmdInput.Parameters["@p1"].Value = paramValue; + + using (SqlDataReader drInput = cmdInput.ExecuteReader(CommandBehavior.CloseConnection)) { - cmd.CommandText = "select f1 from @tvpParam"; - SqlParameter p = cmd.Parameters.AddWithValue("@tvpParam", drInput); - p.SqlDbType = SqlDbType.Structured; - p.TypeName = string.Format("dbo.{0}", tvpTypeName); - using (SqlDataReader dr = cmd.ExecuteReader()) + using (SqlCommand cmd = conn.CreateCommand()) { - dr.Read(); - VerifyReaderTypeAndValue("Test SqlDataReader Parameter To TVP [Data Type]", expectedBaseTypeName, expectedTypeName, dr[0], expectedTypeName, paramValue); - dr.Dispose(); + cmd.CommandText = "select f1 from @tvpParam"; + SqlParameter p = cmd.Parameters.AddWithValue("@tvpParam", drInput); + p.SqlDbType = SqlDbType.Structured; + p.TypeName = string.Format("dbo.{0}", tvpTypeName); + using (SqlDataReader dr = cmd.ExecuteReader()) + { + dr.Read(); + VerifyReaderTypeAndValue("Test SqlDataReader Parameter To TVP [Data Type]", expectedBaseTypeName, expectedTypeName, dr[0], expectedTypeName, paramValue); + dr.Dispose(); + } } } } + connInput.Close(); } - connInput.Close(); } } catch (Exception e) @@ -345,31 +347,33 @@ private static void TestSqlDataReaderParameterToTVP_Variant(object paramValue, s xsql(conn, string.Format("create type dbo.{0} as table (f1 sql_variant)", tvpTypeName)); // Send TVP using SqlDataReader. - SqlConnection connInput = new SqlConnection(s_connStr); - connInput.Open(); - using (SqlCommand cmdInput = connInput.CreateCommand()) + using (SqlConnection connInput = new SqlConnection(s_connStr)) { - cmdInput.CommandText = "select @p1 as f1"; - cmdInput.Parameters.Add("@p1", SqlDbType.Variant); - cmdInput.Parameters["@p1"].Value = paramValue; - using (SqlDataReader drInput = cmdInput.ExecuteReader(CommandBehavior.CloseConnection)) + connInput.Open(); + using (SqlCommand cmdInput = connInput.CreateCommand()) { - using (SqlCommand cmd = conn.CreateCommand()) + cmdInput.CommandText = "select @p1 as f1"; + cmdInput.Parameters.Add("@p1", SqlDbType.Variant); + cmdInput.Parameters["@p1"].Value = paramValue; + using (SqlDataReader drInput = cmdInput.ExecuteReader(CommandBehavior.CloseConnection)) { - cmd.CommandText = "select f1, sql_variant_property(f1,'BaseType') as BaseType from @tvpParam"; - SqlParameter p = cmd.Parameters.AddWithValue("@tvpParam", drInput); - p.SqlDbType = SqlDbType.Structured; - p.TypeName = string.Format("dbo.{0}", tvpTypeName); - using (SqlDataReader dr = cmd.ExecuteReader()) + using (SqlCommand cmd = conn.CreateCommand()) { - dr.Read(); - VerifyReaderTypeAndValue("Test SqlDataReader Parameter To TVP [Variant Type]", "SqlDbType.Variant", dr, expectedTypeName, expectedBaseTypeName, paramValue); - dr.Dispose(); + cmd.CommandText = "select f1, sql_variant_property(f1,'BaseType') as BaseType from @tvpParam"; + SqlParameter p = cmd.Parameters.AddWithValue("@tvpParam", drInput); + p.SqlDbType = SqlDbType.Structured; + p.TypeName = string.Format("dbo.{0}", tvpTypeName); + using (SqlDataReader dr = cmd.ExecuteReader()) + { + dr.Read(); + VerifyReaderTypeAndValue("Test SqlDataReader Parameter To TVP [Variant Type]", "SqlDbType.Variant", dr, expectedTypeName, expectedBaseTypeName, paramValue); + dr.Dispose(); + } } } } + connInput.Close(); } - connInput.Close(); } } catch (Exception e) @@ -727,36 +731,38 @@ private static void SqlBulkCopySqlDataReader_Type(object paramValue, string expe } xsql(conn, string.Format("insert into {0}(f1) values(CAST('{1}' AS {2}));", bulkCopySrcTableName, value, expectedBaseTypeName)); - SqlConnection connInput = new SqlConnection(s_connStr); - connInput.Open(); - using (SqlCommand cmdInput = connInput.CreateCommand()) + using (SqlConnection connInput = new SqlConnection(s_connStr)) { - cmdInput.CommandText = string.Format("select * from {0}", bulkCopySrcTableName); - using (SqlDataReader drInput = cmdInput.ExecuteReader()) + connInput.Open(); + using (SqlCommand cmdInput = connInput.CreateCommand()) { - // Perform bulk copy to target. - using (SqlBulkCopy bulkCopy = new SqlBulkCopy(conn)) + cmdInput.CommandText = string.Format("select * from {0}", bulkCopySrcTableName); + using (SqlDataReader drInput = cmdInput.ExecuteReader()) { - bulkCopy.BulkCopyTimeout = 60; - bulkCopy.BatchSize = 1; - bulkCopy.DestinationTableName = bulkCopyTableName; - bulkCopy.WriteToServer(drInput); - } + // Perform bulk copy to target. + using (SqlBulkCopy bulkCopy = new SqlBulkCopy(conn)) + { + bulkCopy.BulkCopyTimeout = 60; + bulkCopy.BatchSize = 1; + bulkCopy.DestinationTableName = bulkCopyTableName; + bulkCopy.WriteToServer(drInput); + } - // Verify target. - using (SqlCommand cmd = conn.CreateCommand()) - { - cmd.CommandText = string.Format("select f1 from {0}", bulkCopyTableName); - using (SqlDataReader drVerify = cmd.ExecuteReader()) + // Verify target. + using (SqlCommand cmd = conn.CreateCommand()) { - drVerify.Read(); - VerifyReaderTypeAndValue("SqlBulkCopy From SqlDataReader [Data Type]", expectedBaseTypeName, expectedTypeName, drVerify[0], expectedTypeName, paramValue); - drVerify.Dispose(); + cmd.CommandText = string.Format("select f1 from {0}", bulkCopyTableName); + using (SqlDataReader drVerify = cmd.ExecuteReader()) + { + drVerify.Read(); + VerifyReaderTypeAndValue("SqlBulkCopy From SqlDataReader [Data Type]", expectedBaseTypeName, expectedTypeName, drVerify[0], expectedTypeName, paramValue); + drVerify.Dispose(); + } } } } + connInput.Close(); } - connInput.Close(); } } catch (Exception e) @@ -810,38 +816,40 @@ private static void SqlBulkCopySqlDataReader_Variant(object paramValue, string e } xsql(conn, string.Format("insert into {0}(f1) values(CAST('{1}' AS {2}));", bulkCopySrcTableName, value, expectedBaseTypeName)); - SqlConnection connInput = new SqlConnection(s_connStr); - connInput.Open(); - using (SqlCommand cmdInput = connInput.CreateCommand()) + using (SqlConnection connInput = new SqlConnection(s_connStr)) { - cmdInput.CommandText = string.Format("select * from {0}", bulkCopySrcTableName); - using (SqlDataReader drInput = cmdInput.ExecuteReader()) + connInput.Open(); + using (SqlCommand cmdInput = connInput.CreateCommand()) { + cmdInput.CommandText = string.Format("select * from {0}", bulkCopySrcTableName); + using (SqlDataReader drInput = cmdInput.ExecuteReader()) { - // Perform bulk copy to target. - using (SqlBulkCopy bulkCopy = new SqlBulkCopy(conn)) { - bulkCopy.BulkCopyTimeout = 60; - bulkCopy.BatchSize = 1; - bulkCopy.DestinationTableName = bulkCopyTableName; - bulkCopy.WriteToServer(drInput); - } + // Perform bulk copy to target. + using (SqlBulkCopy bulkCopy = new SqlBulkCopy(conn)) + { + bulkCopy.BulkCopyTimeout = 60; + bulkCopy.BatchSize = 1; + bulkCopy.DestinationTableName = bulkCopyTableName; + bulkCopy.WriteToServer(drInput); + } - // Verify target. - using (SqlCommand cmd = conn.CreateCommand()) - { - cmd.CommandText = string.Format("select f1, sql_variant_property(f1,'BaseType') as BaseType from {0}", bulkCopyTableName); - using (SqlDataReader drVerify = cmd.ExecuteReader()) + // Verify target. + using (SqlCommand cmd = conn.CreateCommand()) { - drVerify.Read(); - VerifyReaderTypeAndValue("SqlBulkCopy From SqlDataReader [Variant Type]", "SqlDbType.Variant", drVerify, expectedTypeName, expectedBaseTypeName, paramValue); - drVerify.Dispose(); + cmd.CommandText = string.Format("select f1, sql_variant_property(f1,'BaseType') as BaseType from {0}", bulkCopyTableName); + using (SqlDataReader drVerify = cmd.ExecuteReader()) + { + drVerify.Read(); + VerifyReaderTypeAndValue("SqlBulkCopy From SqlDataReader [Variant Type]", "SqlDbType.Variant", drVerify, expectedTypeName, expectedBaseTypeName, paramValue); + drVerify.Dispose(); + } } } } } + connInput.Close(); } - connInput.Close(); conn.Close(); } @@ -1288,7 +1296,7 @@ private static bool IsExpectedException(Exception e, object paramValue, string e return false; } } - + private static bool IsExpectedInvalidOperationException(Exception e, string expectedBaseTypeName) { return ((e.GetType() == typeof(InvalidOperationException)) && diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/RandomStressTest/RandomStressTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/RandomStressTest/RandomStressTest.cs index 75b2a55119..154bd2aee2 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/RandomStressTest/RandomStressTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/RandomStressTest/RandomStressTest.cs @@ -64,7 +64,6 @@ public void TestMain() if (_randPool.ReproMode) { - _runningThreads = 1; TestThread(); } else @@ -75,6 +74,8 @@ public void TestMain() t.Start(); } } + + _endEvent.WaitOne(); } private void NextConnection(ref SqlConnection con, Randomizer rand) @@ -82,6 +83,7 @@ private void NextConnection(ref SqlConnection con, Randomizer rand) if (con != null) { con.Close(); + con.Dispose(); } string connString = _connectionStrings[rand.Next(_connectionStrings.Length)]; @@ -92,6 +94,7 @@ private void NextConnection(ref SqlConnection con, Randomizer rand) private void TestThread() { + Interlocked.Increment(ref _runningThreads); try { using (var rootScope = _randPool.RootScope()) @@ -132,6 +135,7 @@ private void TestThread() if (con != null) { con.Close(); + con.Dispose(); } } } diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/TransactionTest/TransactionTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/TransactionTest/TransactionTest.cs index b223a709e9..b32dd75f46 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/TransactionTest/TransactionTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/TransactionTest/TransactionTest.cs @@ -246,12 +246,14 @@ private void ExceptionTest() DataTestUtility.AssertThrowsWrapper(() => { - SqlConnection con1 = new SqlConnection(_connectionString); - con1.Open(); + using (SqlConnection con1 = new SqlConnection(_connectionString)) + { + con1.Open(); - SqlCommand command = new SqlCommand("sql", con1); - command.Transaction = tx; - command.ExecuteNonQuery(); + SqlCommand command = new SqlCommand("sql", con1); + command.Transaction = tx; + command.ExecuteNonQuery(); + } }, transactionConflictErrorMessage); DataTestUtility.AssertThrowsWrapper(() => diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/EventCounterTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/EventCounterTest.cs index ef2e1d7af3..7df619a4fe 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/EventCounterTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/EventCounterTest.cs @@ -2,11 +2,9 @@ // 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.Collections.Generic; -using System.Diagnostics.Tracing; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; +using System.Diagnostics; +using System.Reflection; +using System.Transactions; using Xunit; namespace Microsoft.Data.SqlClient.ManualTesting.Tests @@ -16,91 +14,286 @@ namespace Microsoft.Data.SqlClient.ManualTesting.Tests /// public class EventCounterTest { + public EventCounterTest() + { + ClearConnectionPools(); + } + + [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + public void EventCounter_HardConnectionsCounters_Functional() + { + //create a non-pooled connection + var stringBuilder = new SqlConnectionStringBuilder(DataTestUtility.TCPConnectionString) {Pooling = false}; + + var ahc = SqlClientEventSourceProps.ActiveHardConnections; + var npc = SqlClientEventSourceProps.NonPooledConnections; + + using (var conn = new SqlConnection(stringBuilder.ToString())) + { + //initially we have no open physical connections + Assert.Equal(SqlClientEventSourceProps.ActiveHardConnections, + SqlClientEventSourceProps.HardConnects - SqlClientEventSourceProps.HardDisconnects); + + conn.Open(); + + //when the connection gets opened, the real physical connection appears + Assert.Equal(ahc + 1, SqlClientEventSourceProps.ActiveHardConnections); + Assert.Equal(npc + 1, SqlClientEventSourceProps.NonPooledConnections); + Assert.Equal(SqlClientEventSourceProps.ActiveHardConnections, + SqlClientEventSourceProps.HardConnects - SqlClientEventSourceProps.HardDisconnects); + + conn.Close(); + + //when the connection gets closed, the real physical connection is also closed + Assert.Equal(ahc, SqlClientEventSourceProps.ActiveHardConnections); + Assert.Equal(npc, SqlClientEventSourceProps.NonPooledConnections); + Assert.Equal(SqlClientEventSourceProps.ActiveHardConnections, + SqlClientEventSourceProps.HardConnects - SqlClientEventSourceProps.HardDisconnects); + } + } + [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] - public void EventCounterTestAll() + public void EventCounter_SoftConnectionsCounters_Functional() { - var stringBuilder = new SqlConnectionStringBuilder(DataTestUtility.TCPConnectionString) + //create a pooled connection + var stringBuilder = new SqlConnectionStringBuilder(DataTestUtility.TCPConnectionString) {Pooling = true}; + + var ahc = SqlClientEventSourceProps.ActiveHardConnections; + var asc = SqlClientEventSourceProps.ActiveSoftConnections; + var pc = SqlClientEventSourceProps.PooledConnections; + var npc = SqlClientEventSourceProps.NonPooledConnections; + var acp = SqlClientEventSourceProps.ActiveConnectionPools; + var ac = SqlClientEventSourceProps.ActiveConnections; + var fc = SqlClientEventSourceProps.FreeConnections; + + using (var conn = new SqlConnection(stringBuilder.ToString())) { - Pooling = true, - MaxPoolSize = 20 - }; + //initially we have no open physical connections + Assert.Equal(SqlClientEventSourceProps.ActiveHardConnections, + SqlClientEventSourceProps.HardConnects - SqlClientEventSourceProps.HardDisconnects); + Assert.Equal(SqlClientEventSourceProps.ActiveSoftConnections, + SqlClientEventSourceProps.SoftConnects - SqlClientEventSourceProps.SoftDisconnects); + + conn.Open(); + + //when the connection gets opened, the real physical connection appears + //and the appropriate pooling infrastructure gets deployed + Assert.Equal(ahc + 1, SqlClientEventSourceProps.ActiveHardConnections); + Assert.Equal(asc + 1, SqlClientEventSourceProps.ActiveSoftConnections); + Assert.Equal(pc + 1, SqlClientEventSourceProps.PooledConnections); + Assert.Equal(npc, SqlClientEventSourceProps.NonPooledConnections); + Assert.Equal(acp + 1, SqlClientEventSourceProps.ActiveConnectionPools); + Assert.Equal(ac + 1, SqlClientEventSourceProps.ActiveConnections); + Assert.Equal(fc, SqlClientEventSourceProps.FreeConnections); + Assert.Equal(SqlClientEventSourceProps.ActiveHardConnections, + SqlClientEventSourceProps.HardConnects - SqlClientEventSourceProps.HardDisconnects); + Assert.Equal(SqlClientEventSourceProps.ActiveSoftConnections, + SqlClientEventSourceProps.SoftConnects - SqlClientEventSourceProps.SoftDisconnects); + + conn.Close(); + + //when the connection gets closed, the real physical connection gets returned to the pool + Assert.Equal(ahc + 1, SqlClientEventSourceProps.ActiveHardConnections); + Assert.Equal(asc, SqlClientEventSourceProps.ActiveSoftConnections); + Assert.Equal(pc + 1, SqlClientEventSourceProps.PooledConnections); + Assert.Equal(npc, SqlClientEventSourceProps.NonPooledConnections); + Assert.Equal(acp + 1, SqlClientEventSourceProps.ActiveConnectionPools); + Assert.Equal(ac, SqlClientEventSourceProps.ActiveConnections); + Assert.Equal(fc + 1, SqlClientEventSourceProps.FreeConnections); + Assert.Equal(SqlClientEventSourceProps.ActiveHardConnections, + SqlClientEventSourceProps.HardConnects - SqlClientEventSourceProps.HardDisconnects); + Assert.Equal(SqlClientEventSourceProps.ActiveSoftConnections, + SqlClientEventSourceProps.SoftConnects - SqlClientEventSourceProps.SoftDisconnects); + } - using (var TraceListener = new TraceEventCounterListener()) + using (var conn2 = new SqlConnection(stringBuilder.ToString())) { - OpenConnections(stringBuilder.ConnectionString); - stringBuilder.Pooling = false; - OpenConnections(stringBuilder.ConnectionString); + conn2.Open(); - Thread.Sleep(3000); // wait to complete sampling! - Assert.All(TraceListener.EventCounters, item => Assert.True(item.Value > 0)); + //the next open connection will reuse the underlying physical connection + Assert.Equal(ahc + 1, SqlClientEventSourceProps.ActiveHardConnections); + Assert.Equal(asc + 1, SqlClientEventSourceProps.ActiveSoftConnections); + Assert.Equal(pc + 1, SqlClientEventSourceProps.PooledConnections); + Assert.Equal(npc, SqlClientEventSourceProps.NonPooledConnections); + Assert.Equal(acp + 1, SqlClientEventSourceProps.ActiveConnectionPools); + Assert.Equal(ac + 1, SqlClientEventSourceProps.ActiveConnections); + Assert.Equal(fc, SqlClientEventSourceProps.FreeConnections); + Assert.Equal(SqlClientEventSourceProps.ActiveHardConnections, + SqlClientEventSourceProps.HardConnects - SqlClientEventSourceProps.HardDisconnects); + Assert.Equal(SqlClientEventSourceProps.ActiveSoftConnections, + SqlClientEventSourceProps.SoftConnects - SqlClientEventSourceProps.SoftDisconnects); } } - private void OpenConnections(string cnnString) + [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + public void EventCounter_StasisCounters_Functional() { - List tasks = new List(); + var stringBuilder = new SqlConnectionStringBuilder(DataTestUtility.TCPConnectionString) {Pooling = false}; - Enumerable.Range(1, 100).ToList().ForEach(i => + using (var conn = new SqlConnection(stringBuilder.ToString())) + using (new TransactionScope()) { - SqlConnection cnn = new SqlConnection(cnnString); - cnn.Open(); - int x = i; - tasks.Add(Task.Run(() => { Thread.Sleep(x); cnn.Close(); })); - }); - Task.WhenAll(tasks).Wait(); + conn.Open(); + conn.EnlistTransaction(System.Transactions.Transaction.Current); + conn.Close(); + + //when the connection gets closed, but the ambient transaction is still in prigress + //the physical connection gets in stasis, until the transaction ends + Assert.Equal(1, SqlClientEventSourceProps.StasisConnections); + } + + //when the transaction finally ends, the physical connection is returned from stasis + Assert.Equal(0, SqlClientEventSourceProps.StasisConnections); } - } - public class TraceEventCounterListener : EventListener - { - private const string Name = "Name"; + private void ClearConnectionPools() + { + //ClearAllPoos kills all the existing pooled connection thus deactivating all the active pools + var liveConnectionPools = SqlClientEventSourceProps.ActiveConnectionPools + + SqlClientEventSourceProps.InactiveConnectionPools; + SqlConnection.ClearAllPools(); + Assert.InRange(SqlClientEventSourceProps.InactiveConnectionPools, 0, liveConnectionPools); + Assert.Equal(0, SqlClientEventSourceProps.ActiveConnectionPools); + + //the 1st PruneConnectionPoolGroups call cleans the dangling inactive connection pools + PruneConnectionPoolGroups(); + Assert.Equal(0, SqlClientEventSourceProps.InactiveConnectionPools); - public Dictionary EventCounters { get; private set; } + //the 2nd call deactivates the dangling connection pool groups + var liveConnectionPoolGroups = SqlClientEventSourceProps.ActiveConnectionPoolGroups + + SqlClientEventSourceProps.InactiveConnectionPoolGroups; + PruneConnectionPoolGroups(); + Assert.InRange(SqlClientEventSourceProps.InactiveConnectionPoolGroups, 0, liveConnectionPoolGroups); + Assert.Equal(0, SqlClientEventSourceProps.ActiveConnectionPoolGroups); + + //the 3rd call cleans the dangling connection pool groups + PruneConnectionPoolGroups(); + Assert.Equal(0, SqlClientEventSourceProps.InactiveConnectionPoolGroups); + } - public TraceEventCounterListener() + private static void PruneConnectionPoolGroups() { - EventCounters = new Dictionary - { - { "active-hard-connections", 0 }, - { "hard-connects", 0 }, - { "hard-disconnects", 0 }, - { "active-soft-connects", 0 }, - { "soft-connects", 0 }, - { "soft-disconnects", 0 }, - { "number-of-non-pooled-connections", 0 }, - { "number-of-pooled-connections", 0 }, - { "number-of-active-connection-pool-groups", 0 }, - { "number-of-inactive-connection-pool-groups", 0 }, - { "number-of-active-connection-pools", 0 }, - { "number-of-inactive-connection-pools", 0 }, - { "number-of-active-connections", 0 }, - { "number-of-free-connections", 0 }, - { "number-of-stasis-connections", 0 }, - { "number-of-reclaimed-connections", 0 } - }; + FieldInfo connectionFactoryField = GetConnectionFactoryField(); + MethodInfo pruneConnectionPoolGroupsMethod = + connectionFactoryField.FieldType.GetMethod("PruneConnectionPoolGroups", + BindingFlags.NonPublic | BindingFlags.Instance); + Debug.Assert(pruneConnectionPoolGroupsMethod != null); + pruneConnectionPoolGroupsMethod.Invoke(connectionFactoryField.GetValue(null), new[] {(object)null}); } - protected override void OnEventSourceCreated(EventSource eventSource) + private static FieldInfo GetConnectionFactoryField() { - if (eventSource.Name.Equals("Microsoft.Data.SqlClient.EventSource")) - { - var options = new Dictionary(); - // define time interval 1 second - // without defining this parameter event counters will not enabled - options.Add("EventCounterIntervalSec", "1"); - // enable for the None keyword - EnableEvents(eventSource, EventLevel.Informational, EventKeywords.None, options); - } + FieldInfo connectionFactoryField = + typeof(SqlConnection).GetField("s_connectionFactory", BindingFlags.Static | BindingFlags.NonPublic); + Debug.Assert(connectionFactoryField != null); + return connectionFactoryField; } + } - protected override void OnEventWritten(EventWrittenEventArgs eventData) + internal static class SqlClientEventSourceProps + { + private static readonly object _log; + private static readonly FieldInfo _activeHardConnectionsCounter; + private static readonly FieldInfo _hardConnectsCounter; + private static readonly FieldInfo _hardDisconnectsCounter; + private static readonly FieldInfo _activeSoftConnectionsCounter; + private static readonly FieldInfo _softConnectsCounter; + private static readonly FieldInfo _softDisconnectsCounter; + private static readonly FieldInfo _nonPooledConnectionsCounter; + private static readonly FieldInfo _pooledConnectionsCounter; + private static readonly FieldInfo _activeConnectionPoolGroupsCounter; + private static readonly FieldInfo _inactiveConnectionPoolGroupsCounter; + private static readonly FieldInfo _activeConnectionPoolsCounter; + private static readonly FieldInfo _inactiveConnectionPoolsCounter; + private static readonly FieldInfo _activeConnectionsCounter; + private static readonly FieldInfo _freeConnectionsCounter; + private static readonly FieldInfo _stasisConnectionsCounter; + + static SqlClientEventSourceProps() { - object counter = null; - eventData.Payload.FirstOrDefault(p => p is IDictionary x && x.TryGetValue(Name, out counter)); - if (counter is string cntName && EventCounters.ContainsKey(cntName)) - { - EventCounters[cntName] += 1; - } + var sqlClientEventSourceType = + Assembly.GetAssembly(typeof(SqlConnection))!.GetType("Microsoft.Data.SqlClient.SqlClientEventSource"); + Debug.Assert(sqlClientEventSourceType != null); + var logField = sqlClientEventSourceType.GetField("Log", BindingFlags.Static | BindingFlags.NonPublic); + Debug.Assert(logField != null); + _log = logField.GetValue(null); + + var _bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic; + _activeHardConnectionsCounter = + sqlClientEventSourceType.GetField(nameof(_activeHardConnectionsCounter), _bindingFlags); + Debug.Assert(_activeHardConnectionsCounter != null); + _hardConnectsCounter = + sqlClientEventSourceType.GetField(nameof(_hardConnectsCounter), _bindingFlags); + Debug.Assert(_hardConnectsCounter != null); + _hardDisconnectsCounter = + sqlClientEventSourceType.GetField(nameof(_hardDisconnectsCounter), _bindingFlags); + Debug.Assert(_hardDisconnectsCounter != null); + _activeSoftConnectionsCounter = + sqlClientEventSourceType.GetField(nameof(_activeSoftConnectionsCounter), _bindingFlags); + Debug.Assert(_activeSoftConnectionsCounter != null); + _softConnectsCounter = + sqlClientEventSourceType.GetField(nameof(_softConnectsCounter), _bindingFlags); + Debug.Assert(_softConnectsCounter != null); + _softDisconnectsCounter = + sqlClientEventSourceType.GetField(nameof(_softDisconnectsCounter), _bindingFlags); + Debug.Assert(_softDisconnectsCounter != null); + _nonPooledConnectionsCounter = + sqlClientEventSourceType.GetField(nameof(_nonPooledConnectionsCounter), _bindingFlags); + Debug.Assert(_nonPooledConnectionsCounter != null); + _pooledConnectionsCounter = + sqlClientEventSourceType.GetField(nameof(_pooledConnectionsCounter), _bindingFlags); + Debug.Assert(_pooledConnectionsCounter != null); + _activeConnectionPoolGroupsCounter = + sqlClientEventSourceType.GetField(nameof(_activeConnectionPoolGroupsCounter), _bindingFlags); + Debug.Assert(_activeConnectionPoolGroupsCounter != null); + _inactiveConnectionPoolGroupsCounter = + sqlClientEventSourceType.GetField(nameof(_inactiveConnectionPoolGroupsCounter), _bindingFlags); + Debug.Assert(_inactiveConnectionPoolGroupsCounter != null); + _activeConnectionPoolsCounter = + sqlClientEventSourceType.GetField(nameof(_activeConnectionPoolsCounter), _bindingFlags); + Debug.Assert(_activeConnectionPoolsCounter != null); + _inactiveConnectionPoolsCounter = + sqlClientEventSourceType.GetField(nameof(_inactiveConnectionPoolsCounter), _bindingFlags); + Debug.Assert(_inactiveConnectionPoolsCounter != null); + _activeConnectionsCounter = + sqlClientEventSourceType.GetField(nameof(_activeConnectionsCounter), _bindingFlags); + Debug.Assert(_activeConnectionsCounter != null); + _freeConnectionsCounter = + sqlClientEventSourceType.GetField(nameof(_freeConnectionsCounter), _bindingFlags); + Debug.Assert(_freeConnectionsCounter != null); + _stasisConnectionsCounter = + sqlClientEventSourceType.GetField(nameof(_stasisConnectionsCounter), _bindingFlags); + Debug.Assert(_stasisConnectionsCounter != null); } + + public static long ActiveHardConnections => (long)_activeHardConnectionsCounter.GetValue(_log)!; + + public static long HardConnects => (long)_hardConnectsCounter.GetValue(_log)!; + + public static long HardDisconnects => (long)_hardDisconnectsCounter.GetValue(_log)!; + + public static long ActiveSoftConnections => (long)_activeSoftConnectionsCounter.GetValue(_log)!; + + public static long SoftConnects => (long)_softConnectsCounter.GetValue(_log)!; + + public static long SoftDisconnects => (long)_softDisconnectsCounter.GetValue(_log)!; + + public static long NonPooledConnections => (long)_nonPooledConnectionsCounter.GetValue(_log)!; + + public static long PooledConnections => (long)_pooledConnectionsCounter.GetValue(_log)!; + + public static long ActiveConnectionPoolGroups => (long)_activeConnectionPoolGroupsCounter.GetValue(_log)!; + + public static long InactiveConnectionPoolGroups => (long)_inactiveConnectionPoolGroupsCounter.GetValue(_log)!; + + public static long ActiveConnectionPools => (long)_activeConnectionPoolsCounter.GetValue(_log)!; + + public static long InactiveConnectionPools => (long)_inactiveConnectionPoolsCounter.GetValue(_log)!; + + public static long ActiveConnections => (long)_activeConnectionsCounter.GetValue(_log)!; + + public static long FreeConnections => (long)_freeConnectionsCounter.GetValue(_log)!; + + public static long StasisConnections => (long)_stasisConnectionsCounter.GetValue(_log)!; } } From 190e304dcb33c71244e31cd85665d96b830cff7e Mon Sep 17 00:00:00 2001 From: Karina Zhou Date: Thu, 11 Mar 2021 15:26:45 -0800 Subject: [PATCH 11/12] Add more tests (#5) Added EventCounter_ReclaimedConnectionsCounter_Functional & EventCounter_ConnectionPoolGroupsCounter_Functional tests. --- .../TracingTests/EventCounterTest.cs | 71 ++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/EventCounterTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/EventCounterTest.cs index 7df619a4fe..3635bacf7d 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/EventCounterTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/EventCounterTest.cs @@ -1,7 +1,7 @@ // 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; using System.Diagnostics; using System.Reflection; using System.Transactions; @@ -146,6 +146,69 @@ public void EventCounter_StasisCounters_Functional() Assert.Equal(0, SqlClientEventSourceProps.StasisConnections); } + [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + public void EventCounter_ReclaimedConnectionsCounter_Functional() + { + SqlConnection.ClearAllPools(); + var stringBuilder = new SqlConnectionStringBuilder(DataTestUtility.TCPConnectionString) { Pooling = true, MaxPoolSize = 1}; + + long rc = SqlClientEventSourceProps.ReclaimedConnections; + + InternalConnectionWrapper internalConnection = CreateEmancipatedConnection(stringBuilder.ToString()); + + GC.Collect(); + GC.WaitForPendingFinalizers(); + + using (SqlConnection conn = new SqlConnection(stringBuilder.ToString())) + { + conn.Open(); + + // when calling open, the connection is reclaimed. + Assert.Equal(rc + 1, SqlClientEventSourceProps.ReclaimedConnections); + } + } + + [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + public void EventCounter_ConnectionPoolGroupsCounter_Functional() + { + SqlConnection.ClearAllPools(); + + var stringBuilder = new SqlConnectionStringBuilder(DataTestUtility.TCPConnectionString) { Pooling = true}; + + long acpg = SqlClientEventSourceProps.ActiveConnectionPoolGroups; + long iacpg = SqlClientEventSourceProps.InactiveConnectionPoolGroups; + + using (SqlConnection conn = new SqlConnection(stringBuilder.ToString())) { + conn.Open(); + + // when calling open, we have 1 more active connection pool group + Assert.Equal(acpg + 1, SqlClientEventSourceProps.ActiveConnectionPoolGroups); + + conn.Close(); + } + + SqlConnection.ClearAllPools(); + + // poolGroup state is changed from Active to Idle + PruneConnectionPoolGroups(); + + // poolGroup state is changed from Idle to Disabled + PruneConnectionPoolGroups(); + Assert.Equal(acpg, SqlClientEventSourceProps.ActiveConnectionPoolGroups); + Assert.Equal(iacpg + 1, SqlClientEventSourceProps.InactiveConnectionPoolGroups); + + // Remove poolGroup from poolGroupsToRelease list + PruneConnectionPoolGroups(); + Assert.Equal(iacpg, SqlClientEventSourceProps.ActiveConnectionPoolGroups); + } + + private static InternalConnectionWrapper CreateEmancipatedConnection(string connectionString) + { + SqlConnection connection = new SqlConnection(connectionString); + connection.Open(); + return new InternalConnectionWrapper(connection); + } + private void ClearConnectionPools() { //ClearAllPoos kills all the existing pooled connection thus deactivating all the active pools @@ -208,6 +271,7 @@ internal static class SqlClientEventSourceProps private static readonly FieldInfo _activeConnectionsCounter; private static readonly FieldInfo _freeConnectionsCounter; private static readonly FieldInfo _stasisConnectionsCounter; + private static readonly FieldInfo _reclaimedConnectionsCounter; static SqlClientEventSourceProps() { @@ -264,6 +328,9 @@ static SqlClientEventSourceProps() _stasisConnectionsCounter = sqlClientEventSourceType.GetField(nameof(_stasisConnectionsCounter), _bindingFlags); Debug.Assert(_stasisConnectionsCounter != null); + _reclaimedConnectionsCounter = + sqlClientEventSourceType.GetField(nameof(_reclaimedConnectionsCounter), _bindingFlags); + Debug.Assert(_reclaimedConnectionsCounter != null); } public static long ActiveHardConnections => (long)_activeHardConnectionsCounter.GetValue(_log)!; @@ -295,5 +362,7 @@ static SqlClientEventSourceProps() public static long FreeConnections => (long)_freeConnectionsCounter.GetValue(_log)!; public static long StasisConnections => (long)_stasisConnectionsCounter.GetValue(_log)!; + + public static long ReclaimedConnections => (long)_reclaimedConnectionsCounter.GetValue(_log)!; } } From a915aeba608d20bd87911e9cb7acb1a46283cdd6 Mon Sep 17 00:00:00 2001 From: Davoud Eshtehari Date: Fri, 12 Mar 2021 17:26:52 -0800 Subject: [PATCH 12/12] Address comments --- .../Microsoft.Data.SqlClient.ManualTesting.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj index 138b53c88f..9ad8c827e0 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj @@ -246,7 +246,7 @@ - +