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)!; } }