From 3ae610474341653cdc26102bde147160b2958de4 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Tue, 8 Oct 2024 14:40:50 -0500 Subject: [PATCH 01/11] Move netfx version of DbConnectionInternal.cs --- .../src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/Microsoft.Data.SqlClient/{netfx => }/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs (100%) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs similarity index 100% rename from src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs rename to src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs From 67666c022701d72429f3e4f524cdc2c8bd34e172 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Tue, 8 Oct 2024 15:06:20 -0500 Subject: [PATCH 02/11] Merge the three files into the common one: * netcore/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs * netcore/src/Common/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs * netfx/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs --- .../Data/ProviderBase/DbConnectionInternal.cs | 136 ++++++++++++++---- 1 file changed, 105 insertions(+), 31 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs index 336cb876ab..57d28b92f4 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs @@ -2,9 +2,19 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +//netcore--- +using System; +using System.Data.Common; +using System.Diagnostics; +using System.Threading; +using System.Transactions; +using Microsoft.Data.Common; +using Microsoft.Data.SqlClient; +//---netcore + namespace Microsoft.Data.ProviderBase { - + //netfx--- using System; using System.Data; using System.Data.Common; @@ -16,6 +26,7 @@ namespace Microsoft.Data.ProviderBase using Microsoft.Data.Common; using Microsoft.Data.SqlClient; using System.Transactions; + //---netfx internal abstract class DbConnectionInternal { @@ -23,6 +34,7 @@ internal abstract class DbConnectionInternal internal readonly int _objectID = Interlocked.Increment(ref _objectTypeCount); private TransactionCompletedEventHandler _transactionCompletedEventHandler = null; + //netfx--- internal static readonly StateChangeEventArgs StateChangeClosed = new StateChangeEventArgs(ConnectionState.Open, ConnectionState.Closed); internal static readonly StateChangeEventArgs StateChangeOpen = new StateChangeEventArgs(ConnectionState.Closed, ConnectionState.Open); @@ -39,6 +51,7 @@ internal abstract class DbConnectionInternal private bool _connectionIsDoomed; // true when the connection should no longer be used. private bool _cannotBePooled; // true when the connection should no longer be pooled. + //---netfx private bool _isInStasis; private DateTime _createTime; // when the connection was created. @@ -56,7 +69,7 @@ internal abstract class DbConnectionInternal #endif //DEBUG protected DbConnectionInternal() : this(ConnectionState.Open, true, false) - { // V1.1.3300 + { //netfx // V1.1.3300 } // Constructor for internal connections @@ -219,6 +232,7 @@ internal bool IsTxRootWaitingForTxEnd } } + //netfx--- /// /// Get boolean that specifies whether an enlisted transaction can be unbound from /// the connection when that transaction completes. @@ -268,7 +282,7 @@ internal bool IsEmancipated // (DbConnectionPool.Clear and ReclaimEmancipatedObjects // do this for us) - // Remember how this works (I keep getting confused...) + // The functionality is as follows: // // _pooledCount is incremented when the connection is pushed into the pool // _pooledCount is decremented when the connection is popped from the pool @@ -276,17 +290,18 @@ internal bool IsEmancipated // // That means that: // - // _pooledCount > 1 connection is in the pool multiple times (this is a serious bug...) + // _pooledCount > 1 connection is in the pool multiple times (This should not happen) // _pooledCount == 1 connection is in the pool // _pooledCount == 0 connection is out of the pool // _pooledCount == -1 connection is not a pooled connection; we shouldn't be here for non-pooled connections. - // _pooledCount < -1 connection out of the pool multiple times (not sure how this could happen...) + // _pooledCount < -1 connection out of the pool multiple times // // Now, our job is to return TRUE when the connection is out // of the pool and it's owning object is no longer around to // return it. - return !IsTxRootWaitingForTxEnd && (_pooledCount < 1) && !_owningObject.TryGetTarget(out _); + //netfx return !IsTxRootWaitingForTxEnd && (_pooledCount < 1) && !_owningObject.TryGetTarget(out _); + //netcore return (_pooledCount < 1) && !_owningObject.TryGetTarget(out _); } } @@ -329,6 +344,7 @@ internal DbConnectionPool Pool } } + //netfx--- protected DbConnectionPoolCounters PerformanceCounters { get @@ -336,6 +352,33 @@ protected DbConnectionPoolCounters PerformanceCounters return _performanceCounters; } } + //---netfx + //netcore--- + virtual protected bool UnbindOnTransactionCompletion + { + get + { + return true; + } + } + + // Is this a connection that must be put in stasis (or is already in stasis) pending the end of it's transaction? + virtual protected internal bool IsNonPoolableTransactionRoot + { + get + { + return false; // if you want to have delegated transactions that are non-poolable, you better override this... + } + } + + virtual internal bool IsTransactionRoot + { + get + { + return false; // if you want to have delegated transactions, you better override this... + } + } + //---netcore virtual protected bool ReadyToPrepareTransaction { @@ -399,7 +442,8 @@ internal void ActivateConnection(Transaction transaction) Activate(transaction); - PerformanceCounters.NumberOfActiveConnections.Increment(); + //netfx PerformanceCounters.NumberOfActiveConnections.Increment(); + //netcore SqlClientEventSource.Log.EnterActiveConnection(); } internal void AddWeakReference(object value, int tag) @@ -419,7 +463,8 @@ internal void AddWeakReference(object value, int tag) virtual public void ChangeDatabase(string value) { - throw ADP.MethodNotImplemented("ChangeDatabase"); + //netfx throw ADP.MethodNotImplemented("ChangeDatabase"); + //netcore throw ADP.MethodNotImplemented(); } internal virtual void CloseConnection(DbConnection owningObject, DbConnectionFactory connectionFactory) @@ -476,7 +521,8 @@ internal virtual void CloseConnection(DbConnection owningObject, DbConnectionFac lock (this) { - object lockToken = ObtainAdditionalLocksForClose(); + //netfx object lockToken = ObtainAdditionalLocksForClose(); + //netcore bool lockToken = ObtainAdditionalLocksForClose(); try { PrepareForCloseConnection(); @@ -492,15 +538,16 @@ internal virtual void CloseConnection(DbConnection owningObject, DbConnectionFac if (connectionPool != null) { connectionPool.PutObject(this, owningObject); // PutObject calls Deactivate for us... - // NOTE: Before we leave the PutObject call, another - // thread may have already popped the connection from - // the pool, so don't expect to be able to verify it. + // NOTE: Before we leave the PutObject call, another + // thread may have already popped the connection from + // the pool, so don't expect to be able to verify it. } else { Deactivate(); // ensure we de-activate non-pooled connections, or the data readers and transactions may not get cleaned up... - PerformanceCounters.HardDisconnectsPerSecond.Increment(); + //netfx PerformanceCounters.HardDisconnectsPerSecond.Increment(); + //netcore SqlClientEventSource.Log.HardDisconnectRequest(); // To prevent an endless recursion, we need to clear // the owning object before we call dispose so that @@ -517,11 +564,17 @@ internal virtual void CloseConnection(DbConnection owningObject, DbConnectionFac } else { + //netfx--- PerformanceCounters.NumberOfNonPooledConnections.Decrement(); if (this.GetType() != typeof(Microsoft.Data.SqlClient.SqlInternalConnectionSmi)) { Dispose(); } + //---netfx + //netcore--- + SqlClientEventSource.Log.ExitNonPooledConnection(); + Dispose(); + //---netcore } } } @@ -546,12 +599,21 @@ virtual protected void PrepareForCloseConnection() // By default, there is no preparation required } + //netfx--- virtual protected object ObtainAdditionalLocksForClose() { return null; // no additional locks in default implementation } + //---netfx + //netcore--- + virtual protected bool ObtainAdditionalLocksForClose() + { + return false; // no additional locks in default implementation + } + //---netcore - virtual protected void ReleaseAdditionalLocksForClose(object lockToken) + //netfx virtual protected void ReleaseAdditionalLocksForClose(object lockToken) + //netcore virtual protected void ReleaseAdditionalLocksForClose(bool lockToken) { // no additional locks in default implementation } @@ -570,20 +632,25 @@ internal void DeactivateConnection() SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Deactivating", ObjectID); #if DEBUG int activateCount = Interlocked.Decrement(ref _activateCount); - Debug.Assert(0 == activateCount, "activated multiple times?"); + //netfx Debug.Assert(0 == activateCount, "activated multiple times?"); #endif // DEBUG + //netfx--- if (PerformanceCounters != null) { // Pool.Clear will DestroyObject that will clean performanceCounters before going here PerformanceCounters.NumberOfActiveConnections.Decrement(); } + //---netfx + //netcore--- + SqlClientEventSource.Log.ExitActiveConnection(); + //---netcore if (!_connectionIsDoomed && Pool.UseLoadBalancing) { // If we're not already doomed, check the connection's lifetime and // doom it if it's lifetime has elapsed. - DateTime now = DateTime.UtcNow; // WebData 111116 + DateTime now = DateTime.UtcNow; if ((now.Ticks - _createTime.Ticks) > Pool.LoadBalanceTimeout.Ticks) { DoNotPoolThisConnection(); @@ -635,7 +702,8 @@ virtual internal void DelegatedTransactionEnded() // once and for all, or the server will have fits about us // leaving connections open until the client-side GC kicks // in. - PerformanceCounters.NumberOfNonPooledConnections.Decrement(); + //netfx PerformanceCounters.NumberOfNonPooledConnections.Decrement(); + //netcore SqlClientEventSource.Log.ExitNonPooledConnection(); Dispose(); } // When _pooledCount is 0, the connection is a pooled connection @@ -647,7 +715,7 @@ virtual internal void DelegatedTransactionEnded() public virtual void Dispose() { _connectionPool = null; - _performanceCounters = null; + //netfx _performanceCounters = null; _connectionIsDoomed = true; _enlistedTransactionOriginal = null; // should not be disposed @@ -668,7 +736,7 @@ protected internal void DoNotPoolThisConnection() } /// Ensure that this connection cannot be put back into the pool. - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + //netfx [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] protected internal void DoomThisConnection() { _connectionIsDoomed = true; @@ -683,7 +751,8 @@ protected internal void UnDoomThisConnection() abstract public void EnlistTransaction(Transaction transaction); - virtual protected internal DataTable GetSchema(DbConnectionFactory factory, DbConnectionPoolGroup poolGroup, DbConnection outerConnection, string collectionName, string[] restrictions) + //netfx virtual protected internal DataTable GetSchema(DbConnectionFactory factory, DbConnectionPoolGroup poolGroup, DbConnection outerConnection, string collectionName, string[] restrictions) + //netcore protected internal virtual DataTable GetSchema(DbConnectionFactory factory, DbConnectionPoolGroup poolGroup, DbConnection outerConnection, string collectionName, string[] restrictions) { Debug.Assert(outerConnection != null, "outerConnection may not be null."); @@ -693,13 +762,14 @@ virtual protected internal DataTable GetSchema(DbConnectionFactory factory, DbCo return metaDataFactory.GetSchema(outerConnection, collectionName, restrictions); } - internal void MakeNonPooledObject(DbConnection owningObject, DbConnectionPoolCounters performanceCounters) + //netfx internal void MakeNonPooledObject(DbConnection owningObject, DbConnectionPoolCounters performanceCounters) + //netcore internal void MakeNonPooledObject(DbConnection owningObject) { // Used by DbConnectionFactory to indicate that this object IS NOT part of // a connection pool. _connectionPool = null; - _performanceCounters = performanceCounters; + //netfx _performanceCounters = performanceCounters; _owningObject.SetTarget(owningObject); _pooledCount = -1; } @@ -709,11 +779,12 @@ internal void MakePooledConnection(DbConnectionPool connectionPool) // Used by DbConnectionFactory to indicate that this object IS part of // a connection pool. - // TODO: consider using ADP.TimerCurrent() for this. - _createTime = DateTime.UtcNow; // WebData 111116 + //netfx // TODO: consider using ADP.TimerCurrent() for this. + //netfx _createTime = DateTime.UtcNow; // WebData 111116 + //netcore _createTime = DateTime.UtcNow; _connectionPool = connectionPool; - _performanceCounters = connectionPool.PerformanceCounters; + //netfx _performanceCounters = connectionPool.PerformanceCounters; } internal void NotifyWeakReference(int message) @@ -745,7 +816,8 @@ internal virtual bool TryOpenConnection(DbConnection outerConnection, DbConnecti internal virtual bool TryReplaceConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource retry, DbConnectionOptions userOptions) { - throw ADP.MethodNotImplemented("TryReplaceConnection"); + //netfx throw ADP.MethodNotImplemented("TryReplaceConnection"); + //netcore throw ADP.MethodNotImplemented(); } protected bool TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource retry, DbConnectionOptions userOptions) @@ -836,7 +908,7 @@ internal void PostPop(DbConnection newOwner) _owningObject.SetTarget(newOwner); _pooledCount--; - //DbConnection x = (newOwner as DbConnection); + //netfx //DbConnection x = (newOwner as DbConnection); SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Preparing to pop from pool, owning connection {1}, pooledCount={2}", ObjectID, 0, _pooledCount); //3 // The following tests are retail assertions of things we can't allow to happen. @@ -945,8 +1017,8 @@ void TransactionCompletedEvent(object sender, TransactionEventArgs e) } - // TODO: Review whether we need the unmanaged code permission when we have the new object model available. - [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.UnmanagedCode)] + //netfx // TODO: Review whether we need the unmanaged code permission when we have the new object model available. + //netfx [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.UnmanagedCode)] private void TransactionOutcomeEnlist(Transaction transaction) { _transactionCompletedEventHandler ??= new TransactionCompletedEventHandler(TransactionCompletedEvent); @@ -957,7 +1029,8 @@ internal void SetInStasis() { _isInStasis = true; SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Non-Pooled Connection has Delegated Transaction, waiting to Dispose.", ObjectID); - PerformanceCounters.NumberOfStasisConnections.Increment(); + //netfx PerformanceCounters.NumberOfStasisConnections.Increment(); + //netcore SqlClientEventSource.Log.EnterStasisConnection(); } private void TerminateStasis(bool returningToPool) @@ -971,7 +1044,8 @@ private void TerminateStasis(bool returningToPool) SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Delegated Transaction has ended, connection is closed/leaked. Disposing.", ObjectID); } - PerformanceCounters.NumberOfStasisConnections.Decrement(); + //netfx PerformanceCounters.NumberOfStasisConnections.Decrement(); + //netcore SqlClientEventSource.Log.ExitStasisConnection(); _isInStasis = false; } From 94b4c594d565c312b4b84b746fce2fd08d0fdcba Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Tue, 8 Oct 2024 15:08:48 -0500 Subject: [PATCH 03/11] Ensure System.Transactions is included in the common project --- .../src/Microsoft.Data.SqlClient.csproj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/src/Microsoft.Data.SqlClient.csproj index d8e41155af..d72711b7e4 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/src/Microsoft.Data.SqlClient.csproj @@ -4,5 +4,8 @@ net6.0;net8.0;net462 + + + From 5274f73d746a9326c85650f66f915b3fa2047806 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Tue, 8 Oct 2024 15:15:28 -0500 Subject: [PATCH 04/11] Bring in the DbConnectionPoolCounters from netfx project --- .../Data/ProviderBase/DbConnectionPoolCounters.netfx.cs} | 4 ++++ 1 file changed, 4 insertions(+) rename src/Microsoft.Data.SqlClient/{netfx/src/Microsoft/Data/ProviderBase/DbConnectionPoolCounters.cs => src/Microsoft/Data/ProviderBase/DbConnectionPoolCounters.netfx.cs} (99%) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/ProviderBase/DbConnectionPoolCounters.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionPoolCounters.netfx.cs similarity index 99% rename from src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/ProviderBase/DbConnectionPoolCounters.cs rename to src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionPoolCounters.netfx.cs index 72823f2c5a..e20bc410ca 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/ProviderBase/DbConnectionPoolCounters.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionPoolCounters.netfx.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#if NETFRAMEWORK + namespace Microsoft.Data.ProviderBase { @@ -353,3 +355,5 @@ private DbConnectionPoolCountersNoCounters() : base() } } } + +#endif From 95eab471578d280755c6763f0821a5303b51a52c Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Tue, 8 Oct 2024 15:42:38 -0500 Subject: [PATCH 05/11] Add stubs for types used in DbConnectionInternal --- .../ProviderBase/DbConnectionPool.stub.cs | 31 +++++++++++++++++++ .../SqlInternalConnectionSmi.stub.cs | 16 ++++++++++ 2 files changed, 47 insertions(+) create mode 100644 src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionPool.stub.cs create mode 100644 src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlInternalConnectionSmi.stub.cs diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionPool.stub.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionPool.stub.cs new file mode 100644 index 0000000000..a548d3d4d8 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionPool.stub.cs @@ -0,0 +1,31 @@ +// 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.Transactions; + +namespace Microsoft.Data.ProviderBase +{ + // DO NOT USE THIS FILE IN ANY PROJECT! + // This is a temporary stub to enable migrating DbConnectionInternal to the common project. + internal class DbConnectionPool + { + internal TimeSpan LoadBalanceTimeout => throw new NotImplementedException("STUB"); + + #if NETFRAMEWORK + internal DbConnectionPoolCounters PerformanceCounters => throw new NotImplementedException("STUB"); + #endif + + internal bool UseLoadBalancing => throw new NotImplementedException("STUB"); + + internal void PutObject(DbConnectionInternal obj, object owningObject) => + throw new NotImplementedException("STUB"); + + internal void PutObjectFromTransactedPool(DbConnectionInternal obj) => + throw new NotImplementedException("STUB"); + + internal void TransactionEnded(Transaction transaction, DbConnectionInternal transactedObject) => + throw new NotImplementedException("STUB"); + } +} diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlInternalConnectionSmi.stub.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlInternalConnectionSmi.stub.cs new file mode 100644 index 0000000000..aaafc74b5a --- /dev/null +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlInternalConnectionSmi.stub.cs @@ -0,0 +1,16 @@ +// 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. + +#if NETFRAMEWORK + +namespace Microsoft.Data.SqlClient +{ + // DO NOT USE THIS FILE IN ANY PROJECT! + // This is a temporary stub to enable migrating DbConnectionInternal to the common project. + internal class SqlInternalConnectionSmi + { + } +} + +#endif From 9be0990b8fc5c88795ede6f6269e183d8af4be39 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Tue, 8 Oct 2024 15:49:01 -0500 Subject: [PATCH 06/11] Resolve conflicts from merge file --- .../Data/ProviderBase/DbConnectionInternal.cs | 192 ++++++++---------- 1 file changed, 88 insertions(+), 104 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs index 57d28b92f4..13d191555c 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs @@ -2,39 +2,29 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -//netcore--- using System; +using System.Data; using System.Data.Common; using System.Diagnostics; using System.Threading; +using System.Threading.Tasks; using System.Transactions; using Microsoft.Data.Common; using Microsoft.Data.SqlClient; -//---netcore + +#if NETFRAMEWORK +using System.Runtime.ConstrainedExecution; +using System.Security.Permissions; +#endif namespace Microsoft.Data.ProviderBase { - //netfx--- - using System; - using System.Data; - using System.Data.Common; - using System.Diagnostics; - using System.Runtime.ConstrainedExecution; - using System.Security.Permissions; - using System.Threading; - using System.Threading.Tasks; - using Microsoft.Data.Common; - using Microsoft.Data.SqlClient; - using System.Transactions; - //---netfx - internal abstract class DbConnectionInternal { private static int _objectTypeCount; internal readonly int _objectID = Interlocked.Increment(ref _objectTypeCount); private TransactionCompletedEventHandler _transactionCompletedEventHandler = null; - //netfx--- internal static readonly StateChangeEventArgs StateChangeClosed = new StateChangeEventArgs(ConnectionState.Open, ConnectionState.Closed); internal static readonly StateChangeEventArgs StateChangeOpen = new StateChangeEventArgs(ConnectionState.Closed, ConnectionState.Open); @@ -45,13 +35,11 @@ internal abstract class DbConnectionInternal private readonly WeakReference _owningObject = new WeakReference(null, false); // [usage must be thread safe] the owning object, when not in the pool. (both Pooled and Non-Pooled connections) private DbConnectionPool _connectionPool; // the pooler that the connection came from (Pooled connections only) - private DbConnectionPoolCounters _performanceCounters; // the performance counters we're supposed to update private DbReferenceCollection _referenceCollection; // collection of objects that we need to notify in some way when we're being deactivated private int _pooledCount; // [usage must be thread safe] the number of times this object has been pushed into the pool less the number of times it's been popped (0 != inPool) private bool _connectionIsDoomed; // true when the connection should no longer be used. private bool _cannotBePooled; // true when the connection should no longer be pooled. - //---netfx private bool _isInStasis; private DateTime _createTime; // when the connection was created. @@ -64,12 +52,16 @@ internal abstract class DbConnectionInternal // Also, this reference should not be disposed, since we aren't taking ownership of it. private Transaction _enlistedTransactionOriginal; -#if DEBUG + #if NETFRAMEWORK + private DbConnectionPoolCounters _performanceCounters; // the performance counters we're supposed to update + #endif + + #if DEBUG private int _activateCount; // debug only counter to verify activate/deactivates are in sync. -#endif //DEBUG + #endif protected DbConnectionInternal() : this(ConnectionState.Open, true, false) - { //netfx // V1.1.3300 + { } // Constructor for internal connections @@ -232,7 +224,6 @@ internal bool IsTxRootWaitingForTxEnd } } - //netfx--- /// /// Get boolean that specifies whether an enlisted transaction can be unbound from /// the connection when that transaction completes. @@ -300,8 +291,11 @@ internal bool IsEmancipated // of the pool and it's owning object is no longer around to // return it. - //netfx return !IsTxRootWaitingForTxEnd && (_pooledCount < 1) && !_owningObject.TryGetTarget(out _); - //netcore return (_pooledCount < 1) && !_owningObject.TryGetTarget(out _); + #if NETFRAMEWORK + return !IsTxRootWaitingForTxEnd && (_pooledCount < 1) && !_owningObject.TryGetTarget(out _); + #else + return (_pooledCount < 1) && !_owningObject.TryGetTarget(out _); + #endif } } @@ -344,7 +338,7 @@ internal DbConnectionPool Pool } } - //netfx--- + #if NETFRAMEWORK protected DbConnectionPoolCounters PerformanceCounters { get @@ -352,33 +346,7 @@ protected DbConnectionPoolCounters PerformanceCounters return _performanceCounters; } } - //---netfx - //netcore--- - virtual protected bool UnbindOnTransactionCompletion - { - get - { - return true; - } - } - - // Is this a connection that must be put in stasis (or is already in stasis) pending the end of it's transaction? - virtual protected internal bool IsNonPoolableTransactionRoot - { - get - { - return false; // if you want to have delegated transactions that are non-poolable, you better override this... - } - } - - virtual internal bool IsTransactionRoot - { - get - { - return false; // if you want to have delegated transactions, you better override this... - } - } - //---netcore + #endif virtual protected bool ReadyToPrepareTransaction { @@ -442,8 +410,11 @@ internal void ActivateConnection(Transaction transaction) Activate(transaction); - //netfx PerformanceCounters.NumberOfActiveConnections.Increment(); - //netcore SqlClientEventSource.Log.EnterActiveConnection(); + #if NETFRAMEWORK + PerformanceCounters.NumberOfActiveConnections.Increment(); + #else + SqlClientEventSource.Log.EnterActiveConnection(); + #endif } internal void AddWeakReference(object value, int tag) @@ -463,8 +434,7 @@ internal void AddWeakReference(object value, int tag) virtual public void ChangeDatabase(string value) { - //netfx throw ADP.MethodNotImplemented("ChangeDatabase"); - //netcore throw ADP.MethodNotImplemented(); + throw ADP.MethodNotImplemented(); } internal virtual void CloseConnection(DbConnection owningObject, DbConnectionFactory connectionFactory) @@ -520,9 +490,7 @@ internal virtual void CloseConnection(DbConnection owningObject, DbConnectionFac // Lock to prevent race condition with cancellation lock (this) { - - //netfx object lockToken = ObtainAdditionalLocksForClose(); - //netcore bool lockToken = ObtainAdditionalLocksForClose(); + bool lockToken = ObtainAdditionalLocksForClose(); try { PrepareForCloseConnection(); @@ -546,8 +514,11 @@ internal virtual void CloseConnection(DbConnection owningObject, DbConnectionFac { Deactivate(); // ensure we de-activate non-pooled connections, or the data readers and transactions may not get cleaned up... - //netfx PerformanceCounters.HardDisconnectsPerSecond.Increment(); - //netcore SqlClientEventSource.Log.HardDisconnectRequest(); + #if NETFRAMEWORK + PerformanceCounters.HardDisconnectsPerSecond.Increment(); + #else + SqlClientEventSource.Log.HardDisconnectRequest(); + #endif // To prevent an endless recursion, we need to clear // the owning object before we call dispose so that @@ -564,17 +535,16 @@ internal virtual void CloseConnection(DbConnection owningObject, DbConnectionFac } else { - //netfx--- + #if NETFRAMEWORK PerformanceCounters.NumberOfNonPooledConnections.Decrement(); if (this.GetType() != typeof(Microsoft.Data.SqlClient.SqlInternalConnectionSmi)) { Dispose(); } - //---netfx - //netcore--- + #else SqlClientEventSource.Log.ExitNonPooledConnection(); Dispose(); - //---netcore + #endif } } } @@ -599,21 +569,12 @@ virtual protected void PrepareForCloseConnection() // By default, there is no preparation required } - //netfx--- - virtual protected object ObtainAdditionalLocksForClose() - { - return null; // no additional locks in default implementation - } - //---netfx - //netcore--- virtual protected bool ObtainAdditionalLocksForClose() { return false; // no additional locks in default implementation } - //---netcore - //netfx virtual protected void ReleaseAdditionalLocksForClose(object lockToken) - //netcore virtual protected void ReleaseAdditionalLocksForClose(bool lockToken) + virtual protected void ReleaseAdditionalLocksForClose(bool lockToken) { // no additional locks in default implementation } @@ -632,18 +593,19 @@ internal void DeactivateConnection() SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Deactivating", ObjectID); #if DEBUG int activateCount = Interlocked.Decrement(ref _activateCount); - //netfx Debug.Assert(0 == activateCount, "activated multiple times?"); + #if NETFRAMEWORK + Debug.Assert(0 == activateCount, "activated multiple times?"); + #endif #endif // DEBUG - //netfx--- + #if NETFRAMEWORK if (PerformanceCounters != null) { // Pool.Clear will DestroyObject that will clean performanceCounters before going here PerformanceCounters.NumberOfActiveConnections.Decrement(); } - //---netfx - //netcore--- + #else SqlClientEventSource.Log.ExitActiveConnection(); - //---netcore + #endif if (!_connectionIsDoomed && Pool.UseLoadBalancing) { @@ -702,8 +664,12 @@ virtual internal void DelegatedTransactionEnded() // once and for all, or the server will have fits about us // leaving connections open until the client-side GC kicks // in. - //netfx PerformanceCounters.NumberOfNonPooledConnections.Decrement(); - //netcore SqlClientEventSource.Log.ExitNonPooledConnection(); + #if NETFRAMEWORK + PerformanceCounters.NumberOfNonPooledConnections.Decrement(); + #else + SqlClientEventSource.Log.ExitNonPooledConnection(); + #endif + Dispose(); } // When _pooledCount is 0, the connection is a pooled connection @@ -715,10 +681,13 @@ virtual internal void DelegatedTransactionEnded() public virtual void Dispose() { _connectionPool = null; - //netfx _performanceCounters = null; _connectionIsDoomed = true; _enlistedTransactionOriginal = null; // should not be disposed + #if NETFRAMEWORK + _performanceCounters = null; + #endif + // Dispose of the _enlistedTransaction since it is a clone // of the original reference. // VSDD 780271 - _enlistedTransaction can be changed by another thread (TX end event) @@ -736,7 +705,9 @@ protected internal void DoNotPoolThisConnection() } /// Ensure that this connection cannot be put back into the pool. - //netfx [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + #if NETFRAMEWORK + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + #endif protected internal void DoomThisConnection() { _connectionIsDoomed = true; @@ -751,8 +722,7 @@ protected internal void UnDoomThisConnection() abstract public void EnlistTransaction(Transaction transaction); - //netfx virtual protected internal DataTable GetSchema(DbConnectionFactory factory, DbConnectionPoolGroup poolGroup, DbConnection outerConnection, string collectionName, string[] restrictions) - //netcore protected internal virtual DataTable GetSchema(DbConnectionFactory factory, DbConnectionPoolGroup poolGroup, DbConnection outerConnection, string collectionName, string[] restrictions) + protected internal virtual DataTable GetSchema(DbConnectionFactory factory, DbConnectionPoolGroup poolGroup, DbConnection outerConnection, string collectionName, string[] restrictions) { Debug.Assert(outerConnection != null, "outerConnection may not be null."); @@ -762,14 +732,20 @@ protected internal void UnDoomThisConnection() return metaDataFactory.GetSchema(outerConnection, collectionName, restrictions); } - //netfx internal void MakeNonPooledObject(DbConnection owningObject, DbConnectionPoolCounters performanceCounters) - //netcore internal void MakeNonPooledObject(DbConnection owningObject) + #if NETFRAMEWORK + internal void MakeNonPooledObject(DbConnection owningObject, DbConnectionPoolCounters performanceCounters) + #else + internal void MakeNonPooledObject(DbConnection owningObject) + #endif { // Used by DbConnectionFactory to indicate that this object IS NOT part of // a connection pool. + #if NETFRAMEWORK + _performanceCounters = performanceCounters; + #endif + _connectionPool = null; - //netfx _performanceCounters = performanceCounters; _owningObject.SetTarget(owningObject); _pooledCount = -1; } @@ -778,13 +754,13 @@ internal void MakePooledConnection(DbConnectionPool connectionPool) { // Used by DbConnectionFactory to indicate that this object IS part of // a connection pool. - - //netfx // TODO: consider using ADP.TimerCurrent() for this. - //netfx _createTime = DateTime.UtcNow; // WebData 111116 - //netcore _createTime = DateTime.UtcNow; + _createTime = DateTime.UtcNow; _connectionPool = connectionPool; - //netfx _performanceCounters = connectionPool.PerformanceCounters; + + #if NETFRAMEWORK + _performanceCounters = connectionPool.PerformanceCounters; + #endif } internal void NotifyWeakReference(int message) @@ -816,8 +792,7 @@ internal virtual bool TryOpenConnection(DbConnection outerConnection, DbConnecti internal virtual bool TryReplaceConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource retry, DbConnectionOptions userOptions) { - //netfx throw ADP.MethodNotImplemented("TryReplaceConnection"); - //netcore throw ADP.MethodNotImplemented(); + throw ADP.MethodNotImplemented(); } protected bool TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource retry, DbConnectionOptions userOptions) @@ -908,7 +883,6 @@ internal void PostPop(DbConnection newOwner) _owningObject.SetTarget(newOwner); _pooledCount--; - //netfx //DbConnection x = (newOwner as DbConnection); SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Preparing to pop from pool, owning connection {1}, pooledCount={2}", ObjectID, 0, _pooledCount); //3 // The following tests are retail assertions of things we can't allow to happen. @@ -1017,8 +991,10 @@ void TransactionCompletedEvent(object sender, TransactionEventArgs e) } - //netfx // TODO: Review whether we need the unmanaged code permission when we have the new object model available. - //netfx [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.UnmanagedCode)] + #if NETFRAMEWORK + // TODO: Review whether we need the unmanaged code permission when we have the new object model available. + [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.UnmanagedCode)] + #endif private void TransactionOutcomeEnlist(Transaction transaction) { _transactionCompletedEventHandler ??= new TransactionCompletedEventHandler(TransactionCompletedEvent); @@ -1029,8 +1005,12 @@ internal void SetInStasis() { _isInStasis = true; SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Non-Pooled Connection has Delegated Transaction, waiting to Dispose.", ObjectID); - //netfx PerformanceCounters.NumberOfStasisConnections.Increment(); - //netcore SqlClientEventSource.Log.EnterStasisConnection(); + + #if NETFRAMEWORK + PerformanceCounters.NumberOfStasisConnections.Increment(); + #else + SqlClientEventSource.Log.EnterStasisConnection(); + #endif } private void TerminateStasis(bool returningToPool) @@ -1044,8 +1024,12 @@ private void TerminateStasis(bool returningToPool) SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Delegated Transaction has ended, connection is closed/leaked. Disposing.", ObjectID); } - //netfx PerformanceCounters.NumberOfStasisConnections.Decrement(); - //netcore SqlClientEventSource.Log.ExitStasisConnection(); + #if NETFRAMEWORK + PerformanceCounters.NumberOfStasisConnections.Decrement(); + #else + SqlClientEventSource.Log.ExitStasisConnection(); + #endif + _isInStasis = false; } From 518328e4bc6a94775d5d127183d74908d0bcd2f7 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Tue, 8 Oct 2024 16:24:32 -0500 Subject: [PATCH 07/11] External changes following merge * Just use a bool as the lock token --- .../Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs index 96b9f9635a..d0c64d07e3 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs @@ -2333,7 +2333,7 @@ internal void FailoverPermissionDemand() // PREPARED COMMAND METHODS //////////////////////////////////////////////////////////////////////////////////////// - protected override object ObtainAdditionalLocksForClose() + protected override bool ObtainAdditionalLocksForClose() { bool obtainParserLock = !ThreadHasParserLockForClose; Debug.Assert(obtainParserLock || _parserLock.ThreadMayHaveLock(), "Thread claims to have lock, but lock is not taken"); @@ -2345,10 +2345,9 @@ protected override object ObtainAdditionalLocksForClose() return obtainParserLock; } - protected override void ReleaseAdditionalLocksForClose(object lockToken) + protected override void ReleaseAdditionalLocksForClose(bool lockToken) { - Debug.Assert(lockToken is bool, "Lock token should be boolean"); - if ((bool)lockToken) + if (lockToken) { ThreadHasParserLockForClose = false; _parserLock.Release(); From 3146c6a59ad7fbcee731ca7f7776731b8270718d Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Tue, 8 Oct 2024 16:24:50 -0500 Subject: [PATCH 08/11] Remove netcore version of the files --- .../Data/ProviderBase/DbConnectionInternal.cs | 454 ---------------- .../Data/ProviderBase/DbConnectionInternal.cs | 512 ------------------ 2 files changed, 966 deletions(-) delete mode 100644 src/Microsoft.Data.SqlClient/netcore/src/Common/Microsoft/Data/ProviderBase/DbConnectionInternal.cs delete mode 100644 src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/Microsoft/Data/ProviderBase/DbConnectionInternal.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/Microsoft/Data/ProviderBase/DbConnectionInternal.cs deleted file mode 100644 index fd5e3e2848..0000000000 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/Microsoft/Data/ProviderBase/DbConnectionInternal.cs +++ /dev/null @@ -1,454 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.Data.Common; -using Microsoft.Data.SqlClient; -using System; -using System.Data; -using System.Data.Common; -using System.Diagnostics; -using System.Threading; -using System.Threading.Tasks; -using System.Transactions; - - -namespace Microsoft.Data.ProviderBase -{ - internal abstract partial class DbConnectionInternal - { - internal static readonly StateChangeEventArgs StateChangeClosed = new StateChangeEventArgs(ConnectionState.Open, ConnectionState.Closed); - internal static readonly StateChangeEventArgs StateChangeOpen = new StateChangeEventArgs(ConnectionState.Closed, ConnectionState.Open); - - private readonly bool _allowSetConnectionString; - private readonly bool _hidePassword; - private readonly ConnectionState _state; - - private readonly WeakReference _owningObject = new WeakReference(null, false); // [usage must be thread safe] the owning object, when not in the pool. (both Pooled and Non-Pooled connections) - - private DbConnectionPool _connectionPool; // the pooler that the connection came from (Pooled connections only) - private DbReferenceCollection _referenceCollection; // collection of objects that we need to notify in some way when we're being deactivated - private int _pooledCount; // [usage must be thread safe] the number of times this object has been pushed into the pool less the number of times it's been popped (0 != inPool) - - private bool _connectionIsDoomed; // true when the connection should no longer be used. - private bool _cannotBePooled; // true when the connection should no longer be pooled. - - private DateTime _createTime; // when the connection was created. - -#if DEBUG - private int _activateCount; // debug only counter to verify activate/deactivates are in sync. -#endif //DEBUG - - protected DbConnectionInternal() : this(ConnectionState.Open, true, false) - { - } - - // Constructor for internal connections - internal DbConnectionInternal(ConnectionState state, bool hidePassword, bool allowSetConnectionString) - { - _allowSetConnectionString = allowSetConnectionString; - _hidePassword = hidePassword; - _state = state; - } - - internal bool AllowSetConnectionString - { - get - { - return _allowSetConnectionString; - } - } - - internal bool CanBePooled - { - get - { - return (!_connectionIsDoomed && !_cannotBePooled && !_owningObject.TryGetTarget(out _)); - } - } - - protected internal bool IsConnectionDoomed - { - get - { - return _connectionIsDoomed; - } - } - - internal bool IsEmancipated - { - get - { - // NOTE: There are race conditions between PrePush, PostPop and this - // property getter -- only use this while this object is locked; - // (DbConnectionPool.Clear and ReclaimEmancipatedObjects - // do this for us) - - // The functionality is as follows: - // - // _pooledCount is incremented when the connection is pushed into the pool - // _pooledCount is decremented when the connection is popped from the pool - // _pooledCount is set to -1 when the connection is not pooled (just in case...) - // - // That means that: - // - // _pooledCount > 1 connection is in the pool multiple times (This should not happen) - // _pooledCount == 1 connection is in the pool - // _pooledCount == 0 connection is out of the pool - // _pooledCount == -1 connection is not a pooled connection; we shouldn't be here for non-pooled connections. - // _pooledCount < -1 connection out of the pool multiple times - // - // Now, our job is to return TRUE when the connection is out - // of the pool and it's owning object is no longer around to - // return it. - - return (_pooledCount < 1) && !_owningObject.TryGetTarget(out _); - } - } - - internal bool IsInPool - { - get - { - Debug.Assert(_pooledCount <= 1 && _pooledCount >= -1, "Pooled count for object is invalid"); - return (_pooledCount == 1); - } - } - - - protected internal DbConnection Owner - { - // We use a weak reference to the owning object so we can identify when - // it has been garbage collected without throwing exceptions. - get - { - if (_owningObject.TryGetTarget(out DbConnection connection)) - { - return connection; - } - return null; - } - } - - internal DbConnectionPool Pool - { - get - { - return _connectionPool; - } - } - - protected internal DbReferenceCollection ReferenceCollection - { - get - { - return _referenceCollection; - } - } - - abstract public string ServerVersion - { - get; - } - - // this should be abstract but until it is added to all the providers virtual will have to do - virtual public string ServerVersionNormalized - { - get - { - throw ADP.NotSupported(); - } - } - - public bool ShouldHidePassword - { - get - { - return _hidePassword; - } - } - - public ConnectionState State - { - get - { - return _state; - } - } - - internal void AddWeakReference(object value, int tag) - { - if (_referenceCollection == null) - { - _referenceCollection = CreateReferenceCollection(); - if (_referenceCollection == null) - { - throw ADP.InternalError(ADP.InternalErrorCode.CreateReferenceCollectionReturnedNull); - } - } - _referenceCollection.Add(value, tag); - } - - abstract public DbTransaction BeginTransaction(System.Data.IsolationLevel il); - - virtual public void ChangeDatabase(string value) - { - throw ADP.MethodNotImplemented(); - } - - virtual internal void PrepareForReplaceConnection() - { - // By default, there is no preparation required - } - - virtual protected void PrepareForCloseConnection() - { - // By default, there is no preparation required - } - - virtual protected bool ObtainAdditionalLocksForClose() - { - return false; // no additional locks in default implementation - } - - virtual protected void ReleaseAdditionalLocksForClose(bool lockToken) - { - // no additional locks in default implementation - } - - virtual protected DbReferenceCollection CreateReferenceCollection() - { - throw ADP.InternalError(ADP.InternalErrorCode.AttemptingToConstructReferenceCollectionOnStaticObject); - } - - abstract protected void Deactivate(); - - internal void DeactivateConnection() - { - // Internal method called from the connection pooler so we don't expose - // the Deactivate method publicly. - SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Deactivating", ObjectID); - -#if DEBUG - int activateCount = Interlocked.Decrement(ref _activateCount); -#endif // DEBUG - - SqlClientEventSource.Log.ExitActiveConnection(); - - if (!_connectionIsDoomed && Pool.UseLoadBalancing) - { - // If we're not already doomed, check the connection's lifetime and - // doom it if it's lifetime has elapsed. - - DateTime now = DateTime.UtcNow; - if ((now.Ticks - _createTime.Ticks) > Pool.LoadBalanceTimeout.Ticks) - { - DoNotPoolThisConnection(); - } - } - Deactivate(); - } - - protected internal void DoNotPoolThisConnection() - { - _cannotBePooled = true; - SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Marking pooled object as non-poolable so it will be disposed", ObjectID); - } - - /// Ensure that this connection cannot be put back into the pool. - protected internal void DoomThisConnection() - { - _connectionIsDoomed = true; - SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Dooming", ObjectID); - } - - // Reset connection doomed status so it can be re-connected and pooled. - protected internal void UnDoomThisConnection() - { - _connectionIsDoomed = false; - } - - protected internal virtual DataTable GetSchema(DbConnectionFactory factory, DbConnectionPoolGroup poolGroup, DbConnection outerConnection, string collectionName, string[] restrictions) - { - Debug.Assert(outerConnection != null, "outerConnection may not be null."); - - DbMetaDataFactory metaDataFactory = factory.GetMetaDataFactory(poolGroup, this); - Debug.Assert(metaDataFactory != null, "metaDataFactory may not be null."); - - return metaDataFactory.GetSchema(outerConnection, collectionName, restrictions); - } - - internal void MakeNonPooledObject(DbConnection owningObject) - { - // Used by DbConnectionFactory to indicate that this object IS NOT part of - // a connection pool. - - _connectionPool = null; - _owningObject.SetTarget(owningObject); - _pooledCount = -1; - } - - internal void MakePooledConnection(DbConnectionPool connectionPool) - { - // Used by DbConnectionFactory to indicate that this object IS part of - // a connection pool. - _createTime = DateTime.UtcNow; - - _connectionPool = connectionPool; - } - - internal void NotifyWeakReference(int message) - { - DbReferenceCollection referenceCollection = ReferenceCollection; - if (referenceCollection != null) - { - referenceCollection.Notify(message); - } - } - - internal virtual void OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory) - { - if (!TryOpenConnection(outerConnection, connectionFactory, null, null)) - { - throw ADP.InternalError(ADP.InternalErrorCode.SynchronousConnectReturnedPending); - } - } - - /// The default implementation is for the open connection objects, and - /// it simply throws. Our private closed-state connection objects - /// override this and do the correct thing. - // User code should either override DbConnectionInternal.Activate when it comes out of the pool - // or override DbConnectionFactory.CreateConnection when the connection is created for non-pooled connections - internal virtual bool TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource retry, DbConnectionOptions userOptions) - { - throw ADP.ConnectionAlreadyOpen(State); - } - - internal virtual bool TryReplaceConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource retry, DbConnectionOptions userOptions) - { - throw ADP.MethodNotImplemented(); - } - - protected bool TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource retry, DbConnectionOptions userOptions) - { - // ?->Connecting: prevent set_ConnectionString during Open - if (connectionFactory.SetInnerConnectionFrom(outerConnection, DbConnectionClosedConnecting.SingletonInstance, this)) - { - DbConnectionInternal openConnection = null; - try - { - connectionFactory.PermissionDemand(outerConnection); - if (!connectionFactory.TryGetConnection(outerConnection, retry, userOptions, this, out openConnection)) - { - return false; - } - } - catch - { - // This should occur for all exceptions, even ADP.UnCatchableExceptions. - connectionFactory.SetInnerConnectionTo(outerConnection, this); - throw; - } - if (openConnection == null) - { - connectionFactory.SetInnerConnectionTo(outerConnection, this); - throw ADP.InternalConnectionError(ADP.ConnectionError.GetConnectionReturnsNull); - } - connectionFactory.SetInnerConnectionEvent(outerConnection, openConnection); - } - - return true; - } - - internal void PrePush(object expectedOwner) - { - // Called by DbConnectionPool when we're about to be put into it's pool, we - // take this opportunity to ensure ownership and pool counts are legit. - - // IMPORTANT NOTE: You must have taken a lock on the object before - // you call this method to prevent race conditions with Clear and - // ReclaimEmancipatedObjects. - - //3 // The following tests are retail assertions of things we can't allow to happen. - bool isAlive = _owningObject.TryGetTarget(out DbConnection connection); - if (expectedOwner == null) - { - if (isAlive) - { - throw ADP.InternalError(ADP.InternalErrorCode.UnpooledObjectHasOwner); // new unpooled object has an owner - } - } - else if (isAlive && connection != expectedOwner) - { - throw ADP.InternalError(ADP.InternalErrorCode.UnpooledObjectHasWrongOwner); // unpooled object has incorrect owner - } - if (0 != _pooledCount) - { - throw ADP.InternalError(ADP.InternalErrorCode.PushingObjectSecondTime); // pushing object onto stack a second time - } - - SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Preparing to push into pool, owning connection {1}, pooledCount={2}", ObjectID, 0, _pooledCount); - _pooledCount++; - _owningObject.SetTarget(null); // NOTE: doing this and checking for InternalError.PooledObjectHasOwner degrades the close by 2% - } - - internal void PostPop(DbConnection newOwner) - { - // Called by DbConnectionPool right after it pulls this from it's pool, we - // take this opportunity to ensure ownership and pool counts are legit. - - Debug.Assert(!IsEmancipated, "pooled object not in pool"); - - // When another thread is clearing this pool, it - // will doom all connections in this pool without prejudice which - // causes the following assert to fire, which really mucks up stress - // against checked bits. The assert is benign, so we're commenting - // it out. - //Debug.Assert(CanBePooled, "pooled object is not poolable"); - - // IMPORTANT NOTE: You must have taken a lock on the object before - // you call this method to prevent race conditions with Clear and - // ReclaimEmancipatedObjects. - if (_owningObject.TryGetTarget(out _)) - { - throw ADP.InternalError(ADP.InternalErrorCode.PooledObjectHasOwner); // pooled connection already has an owner! - } - _owningObject.SetTarget(newOwner); - _pooledCount--; - SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Preparing to pop from pool, owning connection {1}, pooledCount={2}", ObjectID, 0, _pooledCount); - - //3 // The following tests are retail assertions of things we can't allow to happen. - if (Pool != null) - { - if (0 != _pooledCount) - { - throw ADP.InternalError(ADP.InternalErrorCode.PooledObjectInPoolMoreThanOnce); // popping object off stack with multiple pooledCount - } - } - else if (-1 != _pooledCount) - { - throw ADP.InternalError(ADP.InternalErrorCode.NonPooledObjectUsedMoreThanOnce); // popping object off stack with multiple pooledCount - } - } - - internal void RemoveWeakReference(object value) - { - DbReferenceCollection referenceCollection = ReferenceCollection; - if (referenceCollection != null) - { - referenceCollection.Remove(value); - } - } - - /// - /// When overridden in a derived class, will check if the underlying connection is still actually alive - /// - /// If true an exception will be thrown if the connection is dead instead of returning true\false - /// (this allows the caller to have the real reason that the connection is not alive (e.g. network error, etc)) - /// True if the connection is still alive, otherwise false (If not overridden, then always true) - internal virtual bool IsConnectionAlive(bool throwOnException = false) - { - return true; - } - } -} diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs deleted file mode 100644 index 6458d11f48..0000000000 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs +++ /dev/null @@ -1,512 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Data.Common; -using System.Diagnostics; -using System.Threading; -using System.Transactions; -using Microsoft.Data.Common; -using Microsoft.Data.SqlClient; - -namespace Microsoft.Data.ProviderBase -{ - internal abstract partial class DbConnectionInternal - { - private static int _objectTypeCount; - internal readonly int _objectID = Interlocked.Increment(ref _objectTypeCount); - private TransactionCompletedEventHandler _transactionCompletedEventHandler = null; - - private bool _isInStasis; - - private Transaction _enlistedTransaction; // [usage must be thread-safe] the transaction that we're enlisted in, either manually or automatically - - // _enlistedTransaction is a clone, so that transaction information can be queried even if the original transaction object is disposed. - // However, there are times when we need to know if the original transaction object was disposed, so we keep a reference to it here. - // This field should only be assigned a value at the same time _enlistedTransaction is updated. - // Also, this reference should not be disposed, since we aren't taking ownership of it. - private Transaction _enlistedTransactionOriginal; - - protected internal Transaction EnlistedTransaction - { - get - { - return _enlistedTransaction; - } - set - { - Transaction currentEnlistedTransaction = _enlistedTransaction; - if ((currentEnlistedTransaction == null && value != null) - || (currentEnlistedTransaction != null && !currentEnlistedTransaction.Equals(value))) - { // WebData 20000024 - - // Pay attention to the order here: - // 1) defect from any notifications - // 2) replace the transaction - // 3) re-enlist in notifications for the new transaction - - // SQLBUDT #230558 we need to use a clone of the transaction - // when we store it, or we'll end up keeping it past the - // duration of the using block of the TransactionScope - Transaction valueClone = null; - Transaction previousTransactionClone = null; - try - { - if (value != null) - { - valueClone = value.Clone(); - } - - // NOTE: rather than take locks around several potential round- - // trips to the server, and/or virtual function calls, we simply - // presume that you aren't doing something illegal from multiple - // threads, and check once we get around to finalizing things - // inside a lock. - - lock (this) - { - // NOTE: There is still a race condition here, when we are - // called from EnlistTransaction (which cannot re-enlist) - // instead of EnlistDistributedTransaction (which can), - // however this should have been handled by the outer - // connection which checks to ensure that it's OK. The - // only case where we have the race condition is multiple - // concurrent enlist requests to the same connection, which - // is a bit out of line with something we should have to - // support. - - // enlisted transaction can be nullified in Dispose call without lock - previousTransactionClone = Interlocked.Exchange(ref _enlistedTransaction, valueClone); - _enlistedTransactionOriginal = value; - value = valueClone; - valueClone = null; // we've stored it, don't dispose it. - } - } - finally - { - // we really need to dispose our clones; they may have - // native resources and GC may not happen soon enough. - // VSDevDiv 479564: don't dispose if still holding reference in _enlistedTransaction - if (previousTransactionClone != null && - !object.ReferenceEquals(previousTransactionClone, _enlistedTransaction)) - { - previousTransactionClone.Dispose(); - } - if (valueClone != null && !object.ReferenceEquals(valueClone, _enlistedTransaction)) - { - valueClone.Dispose(); - } - } - - // I don't believe that we need to lock to protect the actual - // enlistment in the transaction; it would only protect us - // against multiple concurrent calls to enlist, which really - // isn't supported anyway. - - if (value != null) - { - SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Transaction {1}, Enlisting.", ObjectID, value.GetHashCode()); - TransactionOutcomeEnlist(value); - } - } - } - } - - /// - /// Get boolean value that indicates whether the enlisted transaction has been disposed. - /// - /// - /// True if there is an enlisted transaction, and it has been disposed. - /// False if there is an enlisted transaction that has not been disposed, or if the transaction reference is null. - /// - /// - /// This method must be called while holding a lock on the DbConnectionInternal instance. - /// - protected bool EnlistedTransactionDisposed - { - get - { - // Until the Transaction.Disposed property is public it is necessary to access a member - // that throws if the object is disposed to determine if in fact the transaction is disposed. - try - { - bool disposed; - - Transaction currentEnlistedTransactionOriginal = _enlistedTransactionOriginal; - if (currentEnlistedTransactionOriginal != null) - { - disposed = currentEnlistedTransactionOriginal.TransactionInformation == null; - } - else - { - // Don't expect to get here in the general case, - // Since this getter is called by CheckEnlistedTransactionBinding - // after checking for a non-null enlisted transaction (and it does so under lock). - disposed = false; - } - - return disposed; - } - catch (ObjectDisposedException) - { - return true; - } - } - } - - internal bool IsTxRootWaitingForTxEnd - { - get - { - return _isInStasis; - } - } - - internal int ObjectID - { - get - { - return _objectID; - } - } - - virtual protected bool UnbindOnTransactionCompletion - { - get - { - return true; - } - } - - // Is this a connection that must be put in stasis (or is already in stasis) pending the end of it's transaction? - virtual protected internal bool IsNonPoolableTransactionRoot - { - get - { - return false; // if you want to have delegated transactions that are non-poolable, you better override this... - } - } - - virtual internal bool IsTransactionRoot - { - get - { - return false; // if you want to have delegated transactions, you better override this... - } - } - - virtual protected bool ReadyToPrepareTransaction - { - get - { - return true; - } - } - - internal virtual bool IsAccessTokenExpired => false; - - abstract protected void Activate(Transaction transaction); - - internal void ActivateConnection(Transaction transaction) - { - // Internal method called from the connection pooler so we don't expose - // the Activate method publicly. - SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Activating", ObjectID); - -#if DEBUG - int activateCount = Interlocked.Increment(ref _activateCount); - Debug.Assert(1 == activateCount, "activated multiple times?"); -#endif // DEBUG - - Activate(transaction); - SqlClientEventSource.Log.EnterActiveConnection(); - } - - internal virtual void CloseConnection(DbConnection owningObject, DbConnectionFactory connectionFactory) - { - // The implementation here is the implementation required for the - // "open" internal connections, since our own private "closed" - // singleton internal connection objects override this method to - // prevent anything funny from happening (like disposing themselves - // or putting them into a connection pool) - // - // Derived class should override DbConnectionInternal.Deactivate and DbConnectionInternal.Dispose - // for cleaning up after DbConnection.Close - // protected override void Deactivate() { // override DbConnectionInternal.Close - // // do derived class connection deactivation for both pooled & non-pooled connections - // } - // public override void Dispose() { // override DbConnectionInternal.Close - // // do derived class cleanup - // base.Dispose(); - // } - // - // overriding DbConnection.Close is also possible, but must provider for their own synchronization - // public override void Close() { // override DbConnection.Close - // base.Close(); - // // do derived class outer connection for both pooled & non-pooled connections - // // user must do their own synchronization here - // } - // - // if the DbConnectionInternal derived class needs to close the connection it should - // delegate to the DbConnection if one exists or directly call dispose - // DbConnection owningObject = (DbConnection)Owner; - // if (owningObject != null) { - // owningObject.Close(); // force the closed state on the outer object. - // } - // else { - // Dispose(); - // } - // - //////////////////////////////////////////////////////////////// - // DON'T MESS WITH THIS CODE UNLESS YOU KNOW WHAT YOU'RE DOING! - //////////////////////////////////////////////////////////////// - Debug.Assert(owningObject != null, "null owningObject"); - Debug.Assert(connectionFactory != null, "null connectionFactory"); - SqlClientEventSource.Log.TryPoolerTraceEvent(" {0} Closing.", ObjectID); - - // if an exception occurs after the state change but before the try block - // the connection will be stuck in OpenBusy state. The commented out try-catch - // block doesn't really help because a ThreadAbort during the finally block - // would just revert the connection to a bad state. - // Open->Closed: guarantee internal connection is returned to correct pool - if (connectionFactory.SetInnerConnectionFrom(owningObject, DbConnectionOpenBusy.SingletonInstance, this)) - { - // Lock to prevent race condition with cancellation - lock (this) - { - bool lockToken = ObtainAdditionalLocksForClose(); - try - { - PrepareForCloseConnection(); - - DbConnectionPool connectionPool = Pool; - - // Detach from enlisted transactions that are no longer active on close - DetachCurrentTransactionIfEnded(); - - // The singleton closed classes won't have owners and - // connection pools, and we won't want to put them back - // into the pool. - if (connectionPool != null) - { - connectionPool.PutObject(this, owningObject); // PutObject calls Deactivate for us... - // NOTE: Before we leave the PutObject call, another - // thread may have already popped the connection from - // the pool, so don't expect to be able to verify it. - } - else - { - Deactivate(); // ensure we de-activate non-pooled connections, or the data readers and transactions may not get cleaned up... - SqlClientEventSource.Log.HardDisconnectRequest(); - - // To prevent an endless recursion, we need to clear - // the owning object before we call dispose so that - // we can't get here a second time... Ordinarily, I - // would call setting the owner to null a hack, but - // this is safe since we're about to dispose the - // object and it won't have an owner after that for - // certain. - _owningObject.SetTarget(null); - - if (IsTransactionRoot) - { - SetInStasis(); - } - else - { - SqlClientEventSource.Log.ExitNonPooledConnection(); - Dispose(); - } - } - } - finally - { - ReleaseAdditionalLocksForClose(lockToken); - // if a ThreadAbort puts us here then its possible the outer connection will not reference - // this and this will be orphaned, not reclaimed by object pool until outer connection goes out of scope. - connectionFactory.SetInnerConnectionEvent(owningObject, DbConnectionClosedPreviouslyOpened.SingletonInstance); - } - } - } - } - - virtual internal void DelegatedTransactionEnded() - { - // Called by System.Transactions when the delegated transaction has - // completed. We need to make closed connections that are in stasis - // available again, or disposed closed/leaked non-pooled connections. - - // IMPORTANT NOTE: You must have taken a lock on the object before - // you call this method to prevent race conditions with Clear and - // ReclaimEmancipatedObjects. - SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Delegated Transaction Completed.", ObjectID); - - if (1 == _pooledCount) - { - // When _pooledCount is 1, it indicates a closed, pooled, - // connection so it is ready to put back into the pool for - // general use. - - TerminateStasis(true); - - Deactivate(); // call it one more time just in case - - DbConnectionPool pool = Pool; - - if (pool == null) - { - throw ADP.InternalError(ADP.InternalErrorCode.PooledObjectWithoutPool); // pooled connection does not have a pool - } - pool.PutObjectFromTransactedPool(this); - } - else if (-1 == _pooledCount && !_owningObject.TryGetTarget(out _)) - { - // When _pooledCount is -1 and the owning object no longer exists, - // it indicates a closed (or leaked), non-pooled connection so - // it is safe to dispose. - - TerminateStasis(false); - - Deactivate(); // call it one more time just in case - - // it's a non-pooled connection, we need to dispose of it - // once and for all, or the server will have fits about us - // leaving connections open until the client-side GC kicks - // in. - SqlClientEventSource.Log.ExitNonPooledConnection(); - Dispose(); - } - // When _pooledCount is 0, the connection is a pooled connection - // that is either open (if the owning object is alive) or leaked (if - // the owning object is not alive) In either case, we can't muck - // with the connection here. - } - - public virtual void Dispose() - { - _connectionPool = null; - _connectionIsDoomed = true; - _enlistedTransactionOriginal = null; // should not be disposed - - // Dispose of the _enlistedTransaction since it is a clone - // of the original reference. - // VSDD 780271 - _enlistedTransaction can be changed by another thread (TX end event) - Transaction enlistedTransaction = Interlocked.Exchange(ref _enlistedTransaction, null); - if (enlistedTransaction != null) - { - enlistedTransaction.Dispose(); - } - } - - abstract public void EnlistTransaction(Transaction transaction); - - // Cleanup connection's transaction-specific structures (currently used by Delegated transaction). - // This is a separate method because cleanup can be triggered in multiple ways for a delegated - // transaction. - virtual protected void CleanupTransactionOnCompletion(Transaction transaction) - { - } - - internal void DetachCurrentTransactionIfEnded() - { - Transaction enlistedTransaction = EnlistedTransaction; - if (enlistedTransaction != null) - { - bool transactionIsDead; - try - { - transactionIsDead = (TransactionStatus.Active != enlistedTransaction.TransactionInformation.Status); - } - catch (TransactionException) - { - // If the transaction is being processed (i.e. is part way through a rollback\commit\etc then TransactionInformation.Status will throw an exception) - transactionIsDead = true; - } - if (transactionIsDead) - { - DetachTransaction(enlistedTransaction, true); - } - } - } - - // Detach transaction from connection. - internal void DetachTransaction(Transaction transaction, bool isExplicitlyReleasing) - { - SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Transaction Completed. (pooledCount={1})", ObjectID, _pooledCount); - - // potentially a multi-threaded event, so lock the connection to make sure we don't enlist in a new - // transaction between compare and assignment. No need to short circuit outside of lock, since failed comparisons should - // be the exception, not the rule. - // locking on anything other than the transaction object would lead to a thread deadlock with sys.Transaction.TransactionCompleted event. - lock (transaction) - { - // Detach if detach-on-end behavior, or if outer connection was closed - DbConnection owner = Owner; - if (isExplicitlyReleasing || UnbindOnTransactionCompletion || owner is null) - { - Transaction currentEnlistedTransaction = _enlistedTransaction; - if (currentEnlistedTransaction != null && transaction.Equals(currentEnlistedTransaction)) - { - // We need to remove the transaction completed event handler to cease listening for the transaction to end. - currentEnlistedTransaction.TransactionCompleted -= _transactionCompletedEventHandler; - - EnlistedTransaction = null; - - if (IsTxRootWaitingForTxEnd) - { - DelegatedTransactionEnded(); - } - } - } - } - } - - // Handle transaction detach, pool cleanup and other post-transaction cleanup tasks associated with - internal void CleanupConnectionOnTransactionCompletion(Transaction transaction) - { - DetachTransaction(transaction, false); - - DbConnectionPool pool = Pool; - if (pool != null) - { - pool.TransactionEnded(transaction, this); - } - } - - void TransactionCompletedEvent(object sender, TransactionEventArgs e) - { - Transaction transaction = e.Transaction; - SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Transaction Completed. (pooledCount = {1})", ObjectID, _pooledCount); - CleanupTransactionOnCompletion(transaction); - CleanupConnectionOnTransactionCompletion(transaction); - } - - private void TransactionOutcomeEnlist(Transaction transaction) - { - _transactionCompletedEventHandler ??= new TransactionCompletedEventHandler(TransactionCompletedEvent); - transaction.TransactionCompleted += _transactionCompletedEventHandler; - } - - internal void SetInStasis() - { - _isInStasis = true; - SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Non-Pooled Connection has Delegated Transaction, waiting to Dispose.", ObjectID); - SqlClientEventSource.Log.EnterStasisConnection(); - } - - private void TerminateStasis(bool returningToPool) - { - if (returningToPool) - { - SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Delegated Transaction has ended, connection is closed. Returning to general pool.", ObjectID); - } - else - { - SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Delegated Transaction has ended, connection is closed/leaked. Disposing.", ObjectID); - } - SqlClientEventSource.Log.ExitStasisConnection(); - _isInStasis = false; - } - } -} From 45965cb3b4fff128a68ea5943e811c80315292c6 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Tue, 8 Oct 2024 16:26:10 -0500 Subject: [PATCH 09/11] Change the project files to point to the merged file (this completes the basic merge process) --- .../netcore/src/Microsoft.Data.SqlClient.csproj | 8 ++++++-- .../netfx/src/Microsoft.Data.SqlClient.csproj | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj index f956aa8594..b2f4b12c20 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -77,6 +77,9 @@ Microsoft\Data\ProviderBase\DbConnectionPool.cs + + Microsoft\Data\ProviderBase\DbConnectionInternal.cs + Microsoft\Data\ProviderBase\DbConnectionPoolAuthenticationContext.cs @@ -614,7 +617,7 @@ Microsoft\Data\SqlDbTypeExtensions.cs - + @@ -630,7 +633,8 @@ - + + diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj index 03eb18b686..b6130f3c28 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -139,6 +139,9 @@ Microsoft\Data\ProviderBase\DbConnectionFactory.cs + + Microsoft\Data\ProviderBase\DbConnectionInternal.cs + Microsoft\Data\ProviderBase\DbConnectionPool.cs @@ -148,6 +151,9 @@ Microsoft\Data\ProviderBase\DbConnectionPoolAuthenticationContextKey.cs + + Microsoft\Data\ProviderBase\DbConnectionPoolCounters.netfx.cs + Microsoft\Data\ProviderBase\DbConnectionPoolGroup.cs @@ -699,8 +705,6 @@ - - From 7013f90b94dc1dfac037b608f8cb50e64377c913 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Thu, 10 Oct 2024 17:15:51 -0500 Subject: [PATCH 10/11] Patching up after rebase --- .../src/Microsoft.Data.SqlClient.csproj | 3 -- .../ProviderBase/DbConnectionPool.stub.cs | 31 ------------------- 2 files changed, 34 deletions(-) delete mode 100644 src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionPool.stub.cs diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj index b2f4b12c20..80d3596754 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -618,7 +618,6 @@ Microsoft\Data\SqlDbTypeExtensions.cs - @@ -633,8 +632,6 @@ - - diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionPool.stub.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionPool.stub.cs deleted file mode 100644 index a548d3d4d8..0000000000 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionPool.stub.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Transactions; - -namespace Microsoft.Data.ProviderBase -{ - // DO NOT USE THIS FILE IN ANY PROJECT! - // This is a temporary stub to enable migrating DbConnectionInternal to the common project. - internal class DbConnectionPool - { - internal TimeSpan LoadBalanceTimeout => throw new NotImplementedException("STUB"); - - #if NETFRAMEWORK - internal DbConnectionPoolCounters PerformanceCounters => throw new NotImplementedException("STUB"); - #endif - - internal bool UseLoadBalancing => throw new NotImplementedException("STUB"); - - internal void PutObject(DbConnectionInternal obj, object owningObject) => - throw new NotImplementedException("STUB"); - - internal void PutObjectFromTransactedPool(DbConnectionInternal obj) => - throw new NotImplementedException("STUB"); - - internal void TransactionEnded(Transaction transaction, DbConnectionInternal transactedObject) => - throw new NotImplementedException("STUB"); - } -} From da456c9c978e10566eb743f4f55440eccf2519d9 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Mon, 14 Oct 2024 12:29:15 -0500 Subject: [PATCH 11/11] Adopt netfx implementation for IsEmancipated --- .../src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs index 13d191555c..bf07f527a1 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionInternal.cs @@ -290,12 +290,8 @@ internal bool IsEmancipated // Now, our job is to return TRUE when the connection is out // of the pool and it's owning object is no longer around to // return it. - - #if NETFRAMEWORK + return !IsTxRootWaitingForTxEnd && (_pooledCount < 1) && !_owningObject.TryGetTarget(out _); - #else - return (_pooledCount < 1) && !_owningObject.TryGetTarget(out _); - #endif } }