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);
+ }
+ }
+ }
+}
+//
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 bdecce6fc1..a41eeb8b02 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];
@@ -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.TryTraceEvent(" {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.TryTraceEvent(" {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.EnterActiveConnectionPoolGroup();
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.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
@@ -324,6 +327,7 @@ private void PruneConnectionPoolGroups(object state)
{
_poolsToRelease.Remove(pool);
SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, ReleasePool={1}", ObjectID, pool.ObjectID);
+ SqlClientEventSource.Log.ExitInactiveConnectionPool();
}
}
}
@@ -348,6 +352,7 @@ private void PruneConnectionPoolGroups(object state)
{
_poolGroupsToRelease.Remove(poolGroup);
SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, ReleasePoolGroup={1}", ObjectID, poolGroup.ObjectID);
+ SqlClientEventSource.Log.ExitInactiveConnectionPoolGroup();
}
}
}
@@ -372,7 +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
+ {
+ // may add entries to _poolsToRelease
QueuePoolGroupForRelease(entry.Value);
}
else
@@ -405,6 +411,8 @@ internal void QueuePoolForRelease(DbConnectionPool pool, bool clearing)
}
_poolsToRelease.Add(pool);
}
+ SqlClientEventSource.Log.EnterInactiveConnectionPool();
+ SqlClientEventSource.Log.ExitActiveConnectionPool();
}
internal void QueuePoolGroupForRelease(DbConnectionPoolGroup poolGroup)
@@ -416,6 +424,8 @@ 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/DbConnectionInternal.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs
index 0e92ed4f00..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,6 +231,7 @@ internal void DeactivateConnection()
int activateCount = Interlocked.Decrement(ref _activateCount);
#endif // DEBUG
+ 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 5801057092..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
@@ -187,6 +187,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.EnterActiveConnectionPool();
pool = newPool;
}
else
@@ -194,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();
}
}
@@ -262,7 +263,6 @@ 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);
}
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 79d03a8863..3f956374f7 100644
--- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj
@@ -327,6 +327,10 @@
+
+
+
+
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 d620caa34a..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,6 +108,7 @@ internal bool TryGetConnection(DbConnection owningConnection, TaskCompletionSour
}
connection = CreateNonPooledConnection(owningConnection, poolGroup, userOptions);
+ SqlClientEventSource.Log.EnterNonPooledConnection();
}
else
{
@@ -209,6 +210,10 @@ private static void TryGetConnectionCompletedContinuation(Task {0}, Non-Pooled Connection has Delegated Transaction, waiting to Dispose.", ObjectID);
+ SqlClientEventSource.Log.EnterStasisConnection();
}
private void TerminateStasis(bool returningToPool)
@@ -494,6 +499,7 @@ private void TerminateStasis(bool returningToPool)
{
SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Delegated Transaction has ended, connection is closed/leaked. Disposing.", ObjectID);
}
+ 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 d0921da04c..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,6 +231,7 @@ internal void PutTransactedObject(Transaction transaction, DbConnectionInternal
}
SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Transaction {1}, Connection {2}, Added.", ObjectID, transaction.GetHashCode(), transactedObject.ObjectID);
}
+ SqlClientEventSource.Log.EnterFreeConnection();
}
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.ExitFreeConnection();
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.ExitFreeConnection();
// 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.ExitFreeConnection();
DestroyObject(obj);
}
while (_stackOld.TryPop(out obj))
{
Debug.Assert(obj != null, "null connection is not expected");
+ SqlClientEventSource.Log.ExitFreeConnection();
DestroyObject(obj);
}
@@ -742,6 +747,7 @@ private DbConnectionInternal CreateObject(DbConnection owningObject, DbConnectio
}
_objectList.Add(newObj);
_totalObjects = _objectList.Count;
+ SqlClientEventSource.Log.EnterPooledConnection();
}
// 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.TryPoolerTraceEvent(" {0}, Connection {1}, Removed from pool.", ObjectID, obj.ObjectID);
+ SqlClientEventSource.Log.ExitPooledConnection();
}
obj.Dispose();
SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Connection {1}, Disposed.", ObjectID, obj.ObjectID);
+ SqlClientEventSource.Log.HardDisconnectRequest();
}
}
@@ -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.TryPoolerTraceEvent(" {0}, Connection {1}, Popped from general pool.", ObjectID, obj.ObjectID);
+ SqlClientEventSource.Log.ExitFreeConnection();
}
return (obj);
}
@@ -1390,6 +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.ExitFreeConnection();
if (obj.IsTransactionRoot)
{
@@ -1544,12 +1556,13 @@ internal void PutNewObject(DbConnectionInternal obj)
_stackNew.Push(obj);
_waitHandles.PoolSemaphore.Release(1);
+ SqlClientEventSource.Log.EnterFreeConnection();
}
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.TryPoolerTraceEvent(" {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..1cab291611
--- /dev/null
+++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientEventSource.NetCoreApp.cs
@@ -0,0 +1,396 @@
+// 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, () => _activeConnectionPoolGroupsCounter)
+ {
+ 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 override void HardConnectRequest()
+ {
+ Interlocked.Increment(ref _activeHardConnectionsCounter);
+ Interlocked.Increment(ref _hardConnectsCounter);
+ }
+
+ ///
+ /// The number of actual disconnects that are being made to servers
+ ///
+ [NonEvent]
+ internal override void HardDisconnectRequest()
+ {
+ Interlocked.Decrement(ref _activeHardConnectionsCounter);
+ Interlocked.Increment(ref _hardDisconnectsCounter);
+ }
+
+ ///
+ /// The number of connections we get from the pool
+ ///
+ [NonEvent]
+ internal override void SoftConnectRequest()
+ {
+ Interlocked.Increment(ref _activeSoftConnectionsCounter);
+ Interlocked.Increment(ref _softConnectsCounter);
+ }
+
+ ///
+ /// The number of connections we return to the pool
+ ///
+ [NonEvent]
+ internal override void SoftDisconnectRequest()
+ {
+ Interlocked.Decrement(ref _activeSoftConnectionsCounter);
+ Interlocked.Increment(ref _softDisconnectsCounter);
+ }
+
+ ///
+ /// The number of connections that are not using connection pooling
+ ///
+ [NonEvent]
+ 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()
+ {
+ Interlocked.Increment(ref _pooledConnectionsCounter);
+ }
+
+ ///
+ /// The number of connections that are managed by the connection pooler
+ ///
+ [NonEvent]
+ internal override void ExitPooledConnection()
+ {
+ Interlocked.Decrement(ref _pooledConnectionsCounter);
+ }
+
+ ///
+ /// The number of unique connection strings
+ ///
+ [NonEvent]
+ internal override void EnterActiveConnectionPoolGroup()
+ {
+ Interlocked.Increment(ref _activeConnectionPoolGroupsCounter);
+ }
+
+ ///
+ /// The number of unique connection strings
+ ///
+ [NonEvent]
+ internal override void ExitActiveConnectionPoolGroup()
+ {
+ Interlocked.Decrement(ref _activeConnectionPoolGroupsCounter);
+ }
+
+ ///
+ /// The number of unique connection strings waiting for pruning
+ ///
+ [NonEvent]
+ internal override void EnterInactiveConnectionPoolGroup()
+ {
+ 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 EnterActiveConnectionPool()
+ {
+ Interlocked.Increment(ref _activeConnectionPoolsCounter);
+ }
+
+ ///
+ /// The number of connection pools
+ ///
+ [NonEvent]
+ internal override void ExitActiveConnectionPool()
+ {
+ 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 ExitActiveConnection()
+ {
+ Interlocked.Decrement(ref _activeConnectionsCounter);
+ }
+
+ ///
+ /// The number of connections currently available for use
+ ///
+ [NonEvent]
+ internal override void EnterFreeConnection()
+ {
+ 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 EnterStasisConnection()
+ {
+ Interlocked.Increment(ref _stasisConnectionsCounter);
+ }
+
+ ///
+ /// The number of connections currently waiting to be made ready for use
+ ///
+ [NonEvent]
+ internal override void ExitStasisConnection()
+ {
+ Interlocked.Decrement(ref _stasisConnectionsCounter);
+ }
+
+ ///
+ /// The number of connections we reclaim from GC'd external connections
+ ///
+ [NonEvent]
+ internal override void ReclaimedConnectionRequest()
+ {
+ Interlocked.Increment(ref _reclaimedConnectionsCounter);
+ }
+ }
+}
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 caa30908c6..a4b3f0bded 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 045b8c7eba..a32d202bb0 100644
--- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.cs
+++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.cs
@@ -9,8 +9,67 @@
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) { }
+
+ #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 EnterNonPooledConnection() { /*no-op*/ }
+
+ internal virtual void ExitNonPooledConnection() { /*no-op*/ }
+
+ internal virtual void EnterPooledConnection() { /*no-op*/ }
+
+ internal virtual void ExitPooledConnection() { /*no-op*/ }
+
+ internal virtual void EnterActiveConnectionPoolGroup() { /*no-op*/ }
+
+ internal virtual void ExitActiveConnectionPoolGroup() { /*no-op*/ }
+
+ internal virtual void EnterInactiveConnectionPoolGroup() { /*no-op*/ }
+
+ internal virtual void ExitInactiveConnectionPoolGroup() { /*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
+ }
+
[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/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 e6cb387284..80701905f3 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs
@@ -776,7 +776,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 e441bea00d..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
@@ -245,6 +245,10 @@
+
+
+
+
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 3bed4b5e12..8eb8ec7684 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
new file mode 100644
index 0000000000..3635bacf7d
--- /dev/null
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/EventCounterTest.cs
@@ -0,0 +1,368 @@
+// 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;
+using Xunit;
+
+namespace Microsoft.Data.SqlClient.ManualTesting.Tests
+{
+ ///
+ /// This unit test is just valid for .NetCore 3.0 and above
+ ///
+ 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 EventCounter_SoftConnectionsCounters_Functional()
+ {
+ //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()))
+ {
+ //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 conn2 = new SqlConnection(stringBuilder.ToString()))
+ {
+ conn2.Open();
+
+ //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);
+ }
+ }
+
+ [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))]
+ public void EventCounter_StasisCounters_Functional()
+ {
+ var stringBuilder = new SqlConnectionStringBuilder(DataTestUtility.TCPConnectionString) {Pooling = false};
+
+ using (var conn = new SqlConnection(stringBuilder.ToString()))
+ using (new TransactionScope())
+ {
+ 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);
+ }
+
+ [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
+ 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);
+
+ //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);
+ }
+
+ private static void PruneConnectionPoolGroups()
+ {
+ 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});
+ }
+
+ private static FieldInfo GetConnectionFactoryField()
+ {
+ FieldInfo connectionFactoryField =
+ typeof(SqlConnection).GetField("s_connectionFactory", BindingFlags.Static | BindingFlags.NonPublic);
+ Debug.Assert(connectionFactoryField != null);
+ return connectionFactoryField;
+ }
+ }
+
+ 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;
+ private static readonly FieldInfo _reclaimedConnectionsCounter;
+
+ static SqlClientEventSourceProps()
+ {
+ 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);
+ _reclaimedConnectionsCounter =
+ sqlClientEventSourceType.GetField(nameof(_reclaimedConnectionsCounter), _bindingFlags);
+ Debug.Assert(_reclaimedConnectionsCounter != 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)!;
+
+ public static long ReclaimedConnections => (long)_reclaimedConnectionsCounter.GetValue(_log)!;
+ }
+}