@@ -28,13 +28,15 @@ internal sealed class SqlConnectionFactory : DbConnectionFactory
28
28
29
29
private static readonly TimeSpan PruningDueTime = TimeSpan . FromMinutes ( 4 ) ;
30
30
private static readonly TimeSpan PruningPeriod = TimeSpan . FromSeconds ( 30 ) ;
31
+ private static readonly Task < DbConnectionInternal > CompletedTask =
32
+ Task . FromResult < DbConnectionInternal > ( null ) ;
31
33
32
34
// s_pendingOpenNonPooled is an array of tasks used to throttle creation of non-pooled
33
35
// 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 =
37
37
new Task < DbConnectionInternal > [ Environment . ProcessorCount ] ;
38
+
39
+ private static int s_objectTypeCount ;
38
40
private static uint s_pendingOpenNonPooledNext = 0 ;
39
41
40
42
private readonly List < DbConnectionPoolGroup > _poolGroupsToRelease ;
@@ -79,7 +81,7 @@ private SqlConnectionFactory()
79
81
internal void ClearAllPools ( )
80
82
{
81
83
using TryEventScope scope = TryEventScope . Create ( nameof ( SqlConnectionFactory ) ) ;
82
- foreach ( ( DbConnectionPoolKey _ , DbConnectionPoolGroup group ) in _connectionPoolGroups )
84
+ foreach ( DbConnectionPoolGroup group in _connectionPoolGroups . Values )
83
85
{
84
86
group ? . Clear ( ) ;
85
87
}
@@ -368,7 +370,7 @@ internal bool TryGetConnection(
368
370
Task task = s_pendingOpenNonPooled [ idx ] ;
369
371
if ( task is null )
370
372
{
371
- s_pendingOpenNonPooled [ idx ] = GetCompletedTask ( ) ;
373
+ s_pendingOpenNonPooled [ idx ] = CompletedTask ;
372
374
break ;
373
375
}
374
376
@@ -390,7 +392,14 @@ internal bool TryGetConnection(
390
392
391
393
// now that we have an antecedent task, schedule our work when it is completed.
392
394
// 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 ) ;
394
403
395
404
// Place this new task in the slot so any future work will be queued behind it
396
405
s_pendingOpenNonPooled [ idx ] = newTask ;
@@ -523,16 +532,27 @@ internal DbConnectionPoolGroupProviderInfo CreateConnectionPoolGroupProviderInfo
523
532
524
533
internal SqlConnectionString FindSqlConnectionOptions ( SqlConnectionPoolKey key )
525
534
{
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 )
528
546
{
529
547
connectionOptions = new SqlConnectionString ( key . ConnectionString ) ;
530
548
}
549
+
531
550
if ( connectionOptions . IsEmpty )
532
551
{
533
552
throw ADP . NoConnectionString ( ) ;
534
553
}
535
- return connectionOptions ;
554
+
555
+ return ( SqlConnectionString ) connectionOptions ;
536
556
}
537
557
538
558
// @TODO: All these methods seem redundant ... shouldn't we always have a SqlConnection?
@@ -612,20 +632,6 @@ internal override void SetInnerConnectionTo(DbConnection owningObject, DbConnect
612
632
}
613
633
}
614
634
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
-
629
635
#region Private Methods
630
636
631
637
// @TODO: I think this could be broken down into methods more specific to use cases above
@@ -662,8 +668,7 @@ private static SqlInternalConnectionTds CreateConnection(
662
668
bool redirectedUserInstance = false ;
663
669
DbConnectionPoolIdentity identity = null ;
664
670
665
- // Pass DbConnectionPoolIdentity to SqlInternalConnectionTds if using integrated security
666
- // or active directory integrated security.
671
+ // Pass DbConnectionPoolIdentity to SqlInternalConnectionTds if using integrated security.
667
672
// Used by notifications.
668
673
if ( opt . IntegratedSecurity || opt . Authentication == SqlAuthenticationMethod . ActiveDirectoryIntegrated )
669
674
{
@@ -752,6 +757,21 @@ private static SqlInternalConnectionTds CreateConnection(
752
757
key . AccessTokenCallback ) ;
753
758
}
754
759
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
+
755
775
private Task < DbConnectionInternal > CreateReplaceConnectionContinuation (
756
776
Task < DbConnectionInternal > task ,
757
777
DbConnection owningConnection ,
@@ -884,7 +904,7 @@ private void PruneConnectionPoolGroups(object state)
884
904
}
885
905
886
906
// 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.
888
908
lock ( this )
889
909
{
890
910
Dictionary < DbConnectionPoolKey , DbConnectionPoolGroup > connectionPoolGroups = _connectionPoolGroups ;
@@ -952,7 +972,7 @@ private void Unload(object sender, EventArgs e)
952
972
{
953
973
try
954
974
{
955
- Unload ( ) ;
975
+ _pruningTimer . Dispose ( ) ;
956
976
}
957
977
finally
958
978
{
0 commit comments