1
1
using System ;
2
+ using System . Collections . Concurrent ;
2
3
using System . Collections . Generic ;
3
4
using System . Linq ;
4
5
using System . Threading ;
@@ -340,54 +341,39 @@ private async Task CreateMinimumPooledSessions(IOBehavior ioBehavior, Cancellati
340
341
public static ConnectionPool GetPool ( string connectionString )
341
342
{
342
343
// check if pool has already been created for this exact connection string
343
- try
344
- {
345
- s_poolLock . EnterReadLock ( ) ;
346
- if ( s_pools . TryGetValue ( connectionString , out var pool ) )
347
- return pool ;
348
- }
349
- finally
350
- {
351
- s_poolLock . ExitReadLock ( ) ;
352
- }
344
+ if ( s_pools . TryGetValue ( connectionString , out var pool ) )
345
+ return pool ;
353
346
354
- // parse connection string and check for 'Pooling' setting
347
+ // parse connection string and check for 'Pooling' setting; return 'null' if pooling is disabled
355
348
var connectionStringBuilder = new MySqlConnectionStringBuilder ( connectionString ) ;
356
349
if ( ! connectionStringBuilder . Pooling )
350
+ {
351
+ s_pools . GetOrAdd ( connectionString , default ( ConnectionPool ) ) ;
357
352
return null ;
353
+ }
358
354
359
355
// check for pool using normalized form of connection string
360
356
var normalizedConnectionString = connectionStringBuilder . ConnectionString ;
361
- try
357
+ if ( normalizedConnectionString != connectionString && s_pools . TryGetValue ( normalizedConnectionString , out pool ) )
362
358
{
363
- s_poolLock . EnterReadLock ( ) ;
364
- if ( s_pools . TryGetValue ( normalizedConnectionString , out var pool ) )
365
- return pool ;
366
- // TODO: Add an entry using 'connectionString'?
367
- }
368
- finally
369
- {
370
- s_poolLock . ExitReadLock ( ) ;
359
+ // try to set the pool for the connection string to the canonical pool; if someone else
360
+ // beats us to it, just use the existing value
361
+ pool = s_pools . GetOrAdd ( connectionString , pool ) ;
362
+ return pool ;
371
363
}
372
364
365
+ // create a new pool and attempt to insert it; if someone else beats us to it, just use their value
373
366
var connectionSettings = new ConnectionSettings ( connectionStringBuilder ) ;
367
+ var newPool = new ConnectionPool ( connectionSettings ) ;
368
+ pool = s_pools . GetOrAdd ( normalizedConnectionString , newPool ) ;
374
369
375
- try
376
- {
377
- s_poolLock . EnterWriteLock ( ) ;
378
- if ( ! s_pools . TryGetValue ( normalizedConnectionString , out var pool ) )
379
- {
380
- pool = new ConnectionPool ( connectionSettings ) ;
381
- s_pools [ normalizedConnectionString ] = pool ;
382
- if ( normalizedConnectionString != connectionString )
383
- s_pools [ connectionString ] = pool ;
384
- }
385
- return pool ;
386
- }
387
- finally
388
- {
389
- s_poolLock . ExitWriteLock ( ) ;
390
- }
370
+ // if we won the race to create the new pool, also store it under the original connection string
371
+ if ( pool == newPool && connectionString != normalizedConnectionString )
372
+ s_pools . GetOrAdd ( connectionString , pool ) ;
373
+ else if ( pool != newPool && Log . IsInfoEnabled ( ) )
374
+ Log . Info ( "{0} was created but will not be used (due to race)" , newPool . m_logArguments [ 0 ] ) ;
375
+
376
+ return pool ;
391
377
}
392
378
393
379
public static async Task ClearPoolsAsync ( IOBehavior ioBehavior , CancellationToken cancellationToken )
@@ -404,15 +390,14 @@ public static async Task ReapPoolsAsync(IOBehavior ioBehavior, CancellationToken
404
390
405
391
private static IReadOnlyList < ConnectionPool > GetAllPools ( )
406
392
{
407
- try
408
- {
409
- s_poolLock . EnterReadLock ( ) ;
410
- return s_pools . Values . ToList ( ) ;
411
- }
412
- finally
393
+ var pools = new List < ConnectionPool > ( s_pools . Count ) ;
394
+ var uniquePools = new HashSet < ConnectionPool > ( ) ;
395
+ foreach ( var pool in s_pools . Values )
413
396
{
414
- s_poolLock . ExitReadLock ( ) ;
397
+ if ( pool != null && uniquePools . Add ( pool ) )
398
+ pools . Add ( pool ) ;
415
399
}
400
+ return pools ;
416
401
}
417
402
418
403
private ConnectionPool ( ConnectionSettings cs )
@@ -464,8 +449,7 @@ public IEnumerable<string> LoadBalance(IReadOnlyList<string> hosts)
464
449
}
465
450
466
451
static readonly IMySqlConnectorLogger Log = MySqlConnectorLogManager . CreateLogger ( nameof ( ConnectionPool ) ) ;
467
- static readonly ReaderWriterLockSlim s_poolLock = new ReaderWriterLockSlim ( ) ;
468
- static readonly Dictionary < string , ConnectionPool > s_pools = new Dictionary < string , ConnectionPool > ( ) ;
452
+ static readonly ConcurrentDictionary < string , ConnectionPool > s_pools = new ConcurrentDictionary < string , ConnectionPool > ( ) ;
469
453
#if DEBUG
470
454
static readonly TimeSpan ReaperInterval = TimeSpan . FromSeconds ( 1 ) ;
471
455
#else
0 commit comments