Skip to content

Commit 3d12896

Browse files
committed
Move GetMetaDataFactory and PruneConnectionPoolGroups
# Conflicts: # src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionFactory.cs
1 parent 111e42b commit 3d12896

File tree

3 files changed

+114
-116
lines changed

3 files changed

+114
-116
lines changed

src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnection.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2197,7 +2197,7 @@ public static void ChangePassword(string connectionString, string newPassword)
21972197

21982198
SqlConnectionPoolKey key = new SqlConnectionPoolKey(connectionString, credential: null, accessToken: null, accessTokenCallback: null);
21992199

2200-
SqlConnectionString connectionOptions = SqlConnectionFactory.FindSqlConnectionOptions(key);
2200+
SqlConnectionString connectionOptions = SqlConnectionFactory.Instance.FindSqlConnectionOptions(key);
22012201
if (connectionOptions.IntegratedSecurity || connectionOptions.Authentication == SqlAuthenticationMethod.ActiveDirectoryIntegrated)
22022202
{
22032203
throw SQL.ChangePasswordConflictsWithSSPI();
@@ -2249,7 +2249,7 @@ public static void ChangePassword(string connectionString, SqlCredential credent
22492249

22502250
SqlConnectionPoolKey key = new SqlConnectionPoolKey(connectionString, credential, accessToken: null, accessTokenCallback: null);
22512251

2252-
SqlConnectionString connectionOptions = SqlConnectionFactory.FindSqlConnectionOptions(key);
2252+
SqlConnectionString connectionOptions = SqlConnectionFactory.Instance.FindSqlConnectionOptions(key);
22532253

22542254
// Check for connection string values incompatible with SqlCredential
22552255
if (!string.IsNullOrEmpty(connectionOptions.UserID) || !string.IsNullOrEmpty(connectionOptions.Password))

src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionFactory.cs

Lines changed: 0 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -47,118 +47,6 @@ protected static Task<DbConnectionInternal> GetCompletedTask()
4747
return s_completedTask ?? (s_completedTask = Task.FromResult<DbConnectionInternal>(null));
4848
}
4949

50-
internal DbMetaDataFactory GetMetaDataFactory(DbConnectionPoolGroup connectionPoolGroup, DbConnectionInternal internalConnection)
51-
{
52-
Debug.Assert(connectionPoolGroup != null, "connectionPoolGroup may not be null.");
53-
54-
// get the matadatafactory from the pool entry. If it does not already have one
55-
// create one and save it on the pool entry
56-
DbMetaDataFactory metaDataFactory = connectionPoolGroup.MetaDataFactory;
57-
58-
// consider serializing this so we don't construct multiple metadata factories
59-
// if two threads happen to hit this at the same time. One will be GC'd
60-
if (metaDataFactory == null)
61-
{
62-
bool allowCache = false;
63-
metaDataFactory = CreateMetaDataFactory(internalConnection, out allowCache);
64-
if (allowCache)
65-
{
66-
connectionPoolGroup.MetaDataFactory = metaDataFactory;
67-
}
68-
}
69-
return metaDataFactory;
70-
}
71-
72-
protected void PruneConnectionPoolGroups(object state)
73-
{
74-
// when debugging this method, expect multiple threads at the same time
75-
SqlClientEventSource.Log.TryAdvancedTraceEvent("<prov.DbConnectionFactory.PruneConnectionPoolGroups|RES|INFO|CPOOL> {0}", ObjectID);
76-
77-
// First, walk the pool release list and attempt to clear each
78-
// pool, when the pool is finally empty, we dispose of it. If the
79-
// pool isn't empty, it's because there are active connections or
80-
// distributed transactions that need it.
81-
lock (_poolsToRelease)
82-
{
83-
if (0 != _poolsToRelease.Count)
84-
{
85-
IDbConnectionPool[] poolsToRelease = _poolsToRelease.ToArray();
86-
foreach (IDbConnectionPool pool in poolsToRelease)
87-
{
88-
if (pool != null)
89-
{
90-
pool.Clear();
91-
92-
if (0 == pool.Count)
93-
{
94-
_poolsToRelease.Remove(pool);
95-
SqlClientEventSource.Log.TryAdvancedTraceEvent("<prov.DbConnectionFactory.PruneConnectionPoolGroups|RES|INFO|CPOOL> {0}, ReleasePool={1}", ObjectID, pool.Id);
96-
97-
SqlClientEventSource.Metrics.ExitInactiveConnectionPool();
98-
}
99-
}
100-
}
101-
}
102-
}
103-
104-
// Next, walk the pool entry release list and dispose of each
105-
// pool entry when it is finally empty. If the pool entry isn't
106-
// empty, it's because there are active pools that need it.
107-
lock (_poolGroupsToRelease)
108-
{
109-
if (0 != _poolGroupsToRelease.Count)
110-
{
111-
DbConnectionPoolGroup[] poolGroupsToRelease = _poolGroupsToRelease.ToArray();
112-
foreach (DbConnectionPoolGroup poolGroup in poolGroupsToRelease)
113-
{
114-
if (poolGroup != null)
115-
{
116-
int poolsLeft = poolGroup.Clear(); // may add entries to _poolsToRelease
117-
118-
if (0 == poolsLeft)
119-
{
120-
_poolGroupsToRelease.Remove(poolGroup);
121-
SqlClientEventSource.Log.TryAdvancedTraceEvent("<prov.DbConnectionFactory.PruneConnectionPoolGroups|RES|INFO|CPOOL> {0}, ReleasePoolGroup={1}", ObjectID, poolGroup.ObjectID);
122-
123-
SqlClientEventSource.Metrics.ExitInactiveConnectionPoolGroup();
124-
}
125-
}
126-
}
127-
}
128-
}
129-
130-
// Finally, we walk through the collection of connection pool entries
131-
// and prune each one. This will cause any empty pools to be put
132-
// into the release list.
133-
lock (this)
134-
{
135-
Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup> connectionPoolGroups = _connectionPoolGroups;
136-
Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup> newConnectionPoolGroups = new Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup>(connectionPoolGroups.Count);
137-
138-
foreach (KeyValuePair<DbConnectionPoolKey, DbConnectionPoolGroup> entry in connectionPoolGroups)
139-
{
140-
if (entry.Value != null)
141-
{
142-
Debug.Assert(!entry.Value.IsDisabled, "Disabled pool entry discovered");
143-
144-
// entries start active and go idle during prune if all pools are gone
145-
// move idle entries from last prune pass to a queue for pending release
146-
// otherwise process entry which may move it from active to idle
147-
if (entry.Value.Prune())
148-
{
149-
// may add entries to _poolsToRelease
150-
QueuePoolGroupForRelease(entry.Value);
151-
}
152-
else
153-
{
154-
newConnectionPoolGroups.Add(entry.Key, entry.Value);
155-
}
156-
}
157-
}
158-
_connectionPoolGroups = newConnectionPoolGroups;
159-
}
160-
}
161-
16250
abstract protected DbConnectionOptions CreateConnectionOptions(string connectionString, DbConnectionOptions previous);
16351

16452
abstract protected DbConnectionPoolGroupOptions CreateConnectionPoolGroupOptions(DbConnectionOptions options);

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnectionFactory.cs

Lines changed: 112 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,30 @@ internal DbConnectionPoolGroup GetConnectionPoolGroup(
257257

258258
return connectionPoolGroup;
259259
}
260+
261+
internal DbMetaDataFactory GetMetaDataFactory(
262+
DbConnectionPoolGroup poolGroup,
263+
DbConnectionInternal internalConnection)
264+
{
265+
Debug.Assert(poolGroup is not null, "connectionPoolGroup may not be null.");
266+
267+
// Get the matadatafactory from the pool entry. If it does not already have one
268+
// create one and save it on the pool entry
269+
DbMetaDataFactory metaDataFactory = poolGroup.MetaDataFactory;
270+
271+
// CONSIDER: serializing this so we don't construct multiple metadata factories
272+
// if two threads happen to hit this at the same time. One will be GC'd
273+
if (metaDataFactory is null)
274+
{
275+
metaDataFactory = CreateMetaDataFactory(internalConnection, out bool allowCache);
276+
if (allowCache)
277+
{
278+
poolGroup.MetaDataFactory = metaDataFactory;
279+
}
280+
}
281+
282+
return metaDataFactory;
283+
}
260284

261285
internal void QueuePoolForRelease(IDbConnectionPool pool, bool clearing)
262286
{
@@ -801,8 +825,94 @@ private IDbConnectionPool GetConnectionPool(
801825
IDbConnectionPool connectionPool = connectionPoolGroup.GetConnectionPool(this);
802826
return connectionPool;
803827
}
804-
805-
828+
829+
private void PruneConnectionPoolGroups(object state)
830+
{
831+
// When debugging this method, expect multiple threads at the same time
832+
SqlClientEventSource.Log.TryAdvancedTraceEvent("<prov.SqlConnectionFactory.PruneConnectionPoolGroups|RES|INFO|CPOOL> {0}", ObjectId);
833+
834+
// First, walk the pool release list and attempt to clear each pool, when the pool is
835+
// finally empty, we dispose of it. If the pool isn't empty, it's because there are
836+
// active connections or distributed transactions that need it.
837+
lock (_poolsToRelease)
838+
{
839+
if (_poolsToRelease.Count != 0)
840+
{
841+
IDbConnectionPool[] poolsToRelease = _poolsToRelease.ToArray();
842+
foreach (IDbConnectionPool pool in poolsToRelease)
843+
{
844+
if (pool is not null)
845+
{
846+
pool.Clear();
847+
848+
if (pool.Count == 0)
849+
{
850+
_poolsToRelease.Remove(pool);
851+
852+
SqlClientEventSource.Log.TryAdvancedTraceEvent("<prov.SqlConnectionFactory.PruneConnectionPoolGroups|RES|INFO|CPOOL> {0}, ReleasePool={1}", ObjectId, pool.Id);
853+
SqlClientEventSource.Metrics.ExitInactiveConnectionPool();
854+
}
855+
}
856+
}
857+
}
858+
}
859+
860+
// Next, walk the pool entry release list and dispose of each pool entry when it is
861+
// finally empty. If the pool entry isn't empty, it's because there are active pools
862+
// that need it.
863+
lock (_poolGroupsToRelease)
864+
{
865+
if (_poolGroupsToRelease.Count != 0)
866+
{
867+
DbConnectionPoolGroup[] poolGroupsToRelease = _poolGroupsToRelease.ToArray();
868+
foreach (DbConnectionPoolGroup poolGroup in poolGroupsToRelease)
869+
{
870+
if (poolGroup != null)
871+
{
872+
int poolsLeft = poolGroup.Clear(); // may add entries to _poolsToRelease
873+
874+
if (poolsLeft == 0)
875+
{
876+
_poolGroupsToRelease.Remove(poolGroup);
877+
SqlClientEventSource.Log.TryAdvancedTraceEvent("<prov.SqlConnectionFactory.PruneConnectionPoolGroups|RES|INFO|CPOOL> {0}, ReleasePoolGroup={1}", ObjectId, poolGroup.ObjectID);
878+
879+
SqlClientEventSource.Metrics.ExitInactiveConnectionPoolGroup();
880+
}
881+
}
882+
}
883+
}
884+
}
885+
886+
// Finally, we walk through the collection of connection pool entries and prune each
887+
// one. This will cause any empty pools to be put into the release list.
888+
lock (this)
889+
{
890+
Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup> connectionPoolGroups = _connectionPoolGroups;
891+
Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup> newConnectionPoolGroups = new Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup>(connectionPoolGroups.Count);
892+
893+
foreach (KeyValuePair<DbConnectionPoolKey, DbConnectionPoolGroup> entry in connectionPoolGroups)
894+
{
895+
if (entry.Value != null)
896+
{
897+
Debug.Assert(!entry.Value.IsDisabled, "Disabled pool entry discovered");
898+
899+
// entries start active and go idle during prune if all pools are gone
900+
// move idle entries from last prune pass to a queue for pending release
901+
// otherwise process entry which may move it from active to idle
902+
if (entry.Value.Prune())
903+
{
904+
// may add entries to _poolsToRelease
905+
QueuePoolGroupForRelease(entry.Value);
906+
}
907+
else
908+
{
909+
newConnectionPoolGroups.Add(entry.Key, entry.Value);
910+
}
911+
}
912+
}
913+
_connectionPoolGroups = newConnectionPoolGroups;
914+
}
915+
}
806916

807917
private void TryGetConnectionCompletedContinuation(Task<DbConnectionInternal> task, object state)
808918
{

0 commit comments

Comments
 (0)