Skip to content

Commit 2027c5d

Browse files
committed
Move CompletedTask and merge FindConnectionOptions
(and cleanup CreateMetaDataFactory)
1 parent 3d12896 commit 2027c5d

File tree

2 files changed

+47
-61
lines changed

2 files changed

+47
-61
lines changed

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

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -18,35 +18,6 @@ namespace Microsoft.Data.ProviderBase
1818
{
1919
internal abstract class DbConnectionFactory
2020
{
21-
protected virtual DbMetaDataFactory CreateMetaDataFactory(DbConnectionInternal internalConnection, out bool cacheMetaDataFactory)
22-
{
23-
// providers that support GetSchema must override this with a method that creates a meta data
24-
// factory appropriate for them.
25-
cacheMetaDataFactory = false;
26-
throw ADP.NotSupported();
27-
}
28-
29-
protected DbConnectionOptions FindConnectionOptions(DbConnectionPoolKey key)
30-
{
31-
Debug.Assert(key != null, "key cannot be null");
32-
if (!string.IsNullOrEmpty(key.ConnectionString))
33-
{
34-
DbConnectionPoolGroup connectionPoolGroup;
35-
Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup> connectionPoolGroups = _connectionPoolGroups;
36-
if (connectionPoolGroups.TryGetValue(key, out connectionPoolGroup))
37-
{
38-
return connectionPoolGroup.ConnectionOptions;
39-
}
40-
}
41-
return null;
42-
}
43-
44-
protected static Task<DbConnectionInternal> GetCompletedTask()
45-
{
46-
Debug.Assert(Monitor.IsEntered(s_pendingOpenNonPooled), $"Expected {nameof(s_pendingOpenNonPooled)} lock to be held.");
47-
return s_completedTask ?? (s_completedTask = Task.FromResult<DbConnectionInternal>(null));
48-
}
49-
5021
abstract protected DbConnectionOptions CreateConnectionOptions(string connectionString, DbConnectionOptions previous);
5122

5223
abstract protected DbConnectionPoolGroupOptions CreateConnectionPoolGroupOptions(DbConnectionOptions options);
@@ -66,10 +37,5 @@ protected static Task<DbConnectionInternal> GetCompletedTask()
6637
abstract internal bool SetInnerConnectionFrom(DbConnection owningObject, DbConnectionInternal to, DbConnectionInternal from);
6738

6839
abstract internal void SetInnerConnectionTo(DbConnection owningObject, DbConnectionInternal to);
69-
70-
virtual internal void Unload()
71-
{
72-
_pruningTimer.Dispose();
73-
}
7440
}
7541
}

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

Lines changed: 47 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,15 @@ internal sealed class SqlConnectionFactory : DbConnectionFactory
2828

2929
private static readonly TimeSpan PruningDueTime = TimeSpan.FromMinutes(4);
3030
private static readonly TimeSpan PruningPeriod = TimeSpan.FromSeconds(30);
31+
private static readonly Task<DbConnectionInternal> CompletedTask =
32+
Task.FromResult<DbConnectionInternal>(null);
3133

3234
// s_pendingOpenNonPooled is an array of tasks used to throttle creation of non-pooled
3335
// connections to a maximum of Environment.ProcessorCount at a time.
34-
private static Task<DbConnectionInternal> s_completedTask;
35-
private static int s_objectTypeCount;
36-
private static Task<DbConnectionInternal>[] s_pendingOpenNonPooled =
36+
private static readonly Task<DbConnectionInternal>[] s_pendingOpenNonPooled =
3737
new Task<DbConnectionInternal>[Environment.ProcessorCount];
38+
39+
private static int s_objectTypeCount;
3840
private static uint s_pendingOpenNonPooledNext = 0;
3941

4042
private readonly List<DbConnectionPoolGroup> _poolGroupsToRelease;
@@ -79,7 +81,7 @@ private SqlConnectionFactory()
7981
internal void ClearAllPools()
8082
{
8183
using TryEventScope scope = TryEventScope.Create(nameof(SqlConnectionFactory));
82-
foreach ((DbConnectionPoolKey _, DbConnectionPoolGroup group) in _connectionPoolGroups)
84+
foreach (DbConnectionPoolGroup group in _connectionPoolGroups.Values)
8385
{
8486
group?.Clear();
8587
}
@@ -368,7 +370,7 @@ internal bool TryGetConnection(
368370
Task task = s_pendingOpenNonPooled[idx];
369371
if (task is null)
370372
{
371-
s_pendingOpenNonPooled[idx] = GetCompletedTask();
373+
s_pendingOpenNonPooled[idx] = CompletedTask;
372374
break;
373375
}
374376

@@ -390,7 +392,14 @@ internal bool TryGetConnection(
390392

391393
// now that we have an antecedent task, schedule our work when it is completed.
392394
// If it is a new slot or a completed task, this continuation will start right away.
393-
newTask = CreateReplaceConnectionContinuation(s_pendingOpenNonPooled[idx], owningConnection, retry, userOptions, oldConnection, poolGroup, cancellationTokenSource);
395+
newTask = CreateReplaceConnectionContinuation(
396+
s_pendingOpenNonPooled[idx],
397+
owningConnection,
398+
retry,
399+
userOptions,
400+
oldConnection,
401+
poolGroup,
402+
cancellationTokenSource);
394403

395404
// Place this new task in the slot so any future work will be queued behind it
396405
s_pendingOpenNonPooled[idx] = newTask;
@@ -523,16 +532,27 @@ internal DbConnectionPoolGroupProviderInfo CreateConnectionPoolGroupProviderInfo
523532

524533
internal SqlConnectionString FindSqlConnectionOptions(SqlConnectionPoolKey key)
525534
{
526-
SqlConnectionString connectionOptions = (SqlConnectionString)FindConnectionOptions(key);
527-
if (connectionOptions == null)
535+
Debug.Assert(key is not null, "Key cannot be null");
536+
537+
DbConnectionOptions connectionOptions = null;
538+
539+
if (!string.IsNullOrEmpty(key.ConnectionString) &&
540+
_connectionPoolGroups.TryGetValue(key, out DbConnectionPoolGroup poolGroup))
541+
{
542+
connectionOptions = poolGroup.ConnectionOptions;
543+
}
544+
545+
if (connectionOptions is null)
528546
{
529547
connectionOptions = new SqlConnectionString(key.ConnectionString);
530548
}
549+
531550
if (connectionOptions.IsEmpty)
532551
{
533552
throw ADP.NoConnectionString();
534553
}
535-
return connectionOptions;
554+
555+
return (SqlConnectionString)connectionOptions;
536556
}
537557

538558
// @TODO: All these methods seem redundant ... shouldn't we always have a SqlConnection?
@@ -612,20 +632,6 @@ internal override void SetInnerConnectionTo(DbConnection owningObject, DbConnect
612632
}
613633
}
614634

615-
protected override DbMetaDataFactory CreateMetaDataFactory(DbConnectionInternal internalConnection, out bool cacheMetaDataFactory)
616-
{
617-
Debug.Assert(internalConnection != null, "internalConnection may not be null.");
618-
619-
Stream xmlStream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("Microsoft.Data.SqlClient.SqlMetaData.xml");
620-
cacheMetaDataFactory = true;
621-
622-
Debug.Assert(xmlStream != null, nameof(xmlStream) + " may not be null.");
623-
624-
return new SqlMetaDataFactory(xmlStream,
625-
internalConnection.ServerVersion,
626-
internalConnection.ServerVersion);
627-
}
628-
629635
#region Private Methods
630636

631637
// @TODO: I think this could be broken down into methods more specific to use cases above
@@ -662,8 +668,7 @@ private static SqlInternalConnectionTds CreateConnection(
662668
bool redirectedUserInstance = false;
663669
DbConnectionPoolIdentity identity = null;
664670

665-
// Pass DbConnectionPoolIdentity to SqlInternalConnectionTds if using integrated security
666-
// or active directory integrated security.
671+
// Pass DbConnectionPoolIdentity to SqlInternalConnectionTds if using integrated security.
667672
// Used by notifications.
668673
if (opt.IntegratedSecurity || opt.Authentication == SqlAuthenticationMethod.ActiveDirectoryIntegrated)
669674
{
@@ -752,6 +757,21 @@ private static SqlInternalConnectionTds CreateConnection(
752757
key.AccessTokenCallback);
753758
}
754759

760+
private static DbMetaDataFactory CreateMetaDataFactory(
761+
DbConnectionInternal internalConnection,
762+
out bool cacheMetaDataFactory)
763+
{
764+
Debug.Assert(internalConnection is not null, "internalConnection may not be null.");
765+
766+
Stream xmlStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Microsoft.Data.SqlClient.SqlMetaData.xml");
767+
Debug.Assert(xmlStream is not null, $"{nameof(xmlStream)} may not be null.");
768+
769+
cacheMetaDataFactory = true;
770+
return new SqlMetaDataFactory(xmlStream,
771+
internalConnection.ServerVersion,
772+
internalConnection.ServerVersion);
773+
}
774+
755775
private Task<DbConnectionInternal> CreateReplaceConnectionContinuation(
756776
Task<DbConnectionInternal> task,
757777
DbConnection owningConnection,
@@ -884,7 +904,7 @@ private void PruneConnectionPoolGroups(object state)
884904
}
885905

886906
// 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.
907+
// one. This will cause any empty pools to be put into the release list.
888908
lock (this)
889909
{
890910
Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup> connectionPoolGroups = _connectionPoolGroups;
@@ -952,7 +972,7 @@ private void Unload(object sender, EventArgs e)
952972
{
953973
try
954974
{
955-
Unload();
975+
_pruningTimer.Dispose();
956976
}
957977
finally
958978
{

0 commit comments

Comments
 (0)