@@ -14,6 +14,8 @@ internal sealed class ConnectionPool
14
14
{
15
15
public int Id { get ; }
16
16
17
+ public ConnectionSettings ConnectionSettings { get ; }
18
+
17
19
public async Task < ServerSession > GetSessionAsync ( MySqlConnection connection , IOBehavior ioBehavior , CancellationToken cancellationToken )
18
20
{
19
21
cancellationToken . ThrowIfCancellationRequested ( ) ;
@@ -27,7 +29,7 @@ public async Task<ServerSession> GetSessionAsync(MySqlConnection connection, IOB
27
29
RecoverLeakedSessions ( ) ;
28
30
}
29
31
30
- if ( m_connectionSettings . MinimumPoolSize > 0 )
32
+ if ( ConnectionSettings . MinimumPoolSize > 0 )
31
33
await CreateMinimumPooledSessions ( ioBehavior , cancellationToken ) . ConfigureAwait ( false ) ;
32
34
33
35
// wait for an open slot (until the cancellationToken is cancelled, which is typically due to timeout)
@@ -61,9 +63,9 @@ public async Task<ServerSession> GetSessionAsync(MySqlConnection connection, IOB
61
63
}
62
64
else
63
65
{
64
- if ( m_connectionSettings . ConnectionReset )
66
+ if ( ConnectionSettings . ConnectionReset )
65
67
{
66
- reuseSession = await session . TryResetConnectionAsync ( m_connectionSettings , ioBehavior , cancellationToken ) . ConfigureAwait ( false ) ;
68
+ reuseSession = await session . TryResetConnectionAsync ( ConnectionSettings , ioBehavior , cancellationToken ) . ConfigureAwait ( false ) ;
67
69
}
68
70
else
69
71
{
@@ -98,7 +100,7 @@ public async Task<ServerSession> GetSessionAsync(MySqlConnection connection, IOB
98
100
session = new ServerSession ( this , m_generation , Interlocked . Increment ( ref m_lastSessionId ) ) ;
99
101
if ( Log . IsInfoEnabled ( ) )
100
102
Log . Info ( "{0} no pooled session available; created new Session{1}" , m_logArguments [ 0 ] , session . Id ) ;
101
- await session . ConnectAsync ( m_connectionSettings , m_loadBalancer , ioBehavior , cancellationToken ) . ConfigureAwait ( false ) ;
103
+ await session . ConnectAsync ( ConnectionSettings , m_loadBalancer , ioBehavior , cancellationToken ) . ConfigureAwait ( false ) ;
102
104
AdjustHostConnectionCount ( session , 1 ) ;
103
105
session . OwningConnection = new WeakReference < MySqlConnection > ( connection ) ;
104
106
int leasedSessionsCountNew ;
@@ -126,8 +128,8 @@ private bool SessionIsHealthy(ServerSession session)
126
128
return false ;
127
129
if ( session . DatabaseOverride != null )
128
130
return false ;
129
- if ( m_connectionSettings . ConnectionLifeTime > 0
130
- && ( DateTime . UtcNow - session . CreatedUtc ) . TotalSeconds >= m_connectionSettings . ConnectionLifeTime )
131
+ if ( ConnectionSettings . ConnectionLifeTime > 0
132
+ && ( DateTime . UtcNow - session . CreatedUtc ) . TotalSeconds >= ConnectionSettings . ConnectionLifeTime )
131
133
return false ;
132
134
133
135
return true ;
@@ -175,9 +177,9 @@ public async Task ReapAsync(IOBehavior ioBehavior, CancellationToken cancellatio
175
177
{
176
178
Log . Debug ( "{0} reaping connection pool" , m_logArguments ) ;
177
179
RecoverLeakedSessions ( ) ;
178
- if ( m_connectionSettings . ConnectionIdleTimeout == 0 )
180
+ if ( ConnectionSettings . ConnectionIdleTimeout == 0 )
179
181
return ;
180
- await CleanPoolAsync ( ioBehavior , session => ( DateTime . UtcNow - session . LastReturnedUtc ) . TotalSeconds >= m_connectionSettings . ConnectionIdleTimeout , true , cancellationToken ) . ConfigureAwait ( false ) ;
182
+ await CleanPoolAsync ( ioBehavior , session => ( DateTime . UtcNow - session . LastReturnedUtc ) . TotalSeconds >= ConnectionSettings . ConnectionIdleTimeout , true , cancellationToken ) . ConfigureAwait ( false ) ;
181
183
}
182
184
183
185
/// <summary>
@@ -196,7 +198,7 @@ public Dictionary<string, CachedProcedure> GetProcedureCache()
196
198
}
197
199
return procedureCache ;
198
200
}
199
-
201
+
200
202
/// <summary>
201
203
/// Examines all the <see cref="ServerSession"/> objects in <see cref="m_leasedSessions"/> to determine if any
202
204
/// have an owning <see cref="MySqlConnection"/> that has been garbage-collected. If so, assumes that the connection
@@ -238,7 +240,7 @@ private async Task CleanPoolAsync(IOBehavior ioBehavior, Func<ServerSession, boo
238
240
// if respectMinPoolSize is true, return if (leased sessions + waiting sessions <= minPoolSize)
239
241
if ( respectMinPoolSize )
240
242
lock ( m_sessions )
241
- if ( m_connectionSettings . MaximumPoolSize - m_sessionSemaphore . CurrentCount + m_sessions . Count <= m_connectionSettings . MinimumPoolSize )
243
+ if ( ConnectionSettings . MaximumPoolSize - m_sessionSemaphore . CurrentCount + m_sessions . Count <= ConnectionSettings . MinimumPoolSize )
242
244
return ;
243
245
244
246
// try to get an open slot; if this fails, connection pool is full and sessions will be disposed when returned to pool
@@ -301,7 +303,7 @@ private async Task CreateMinimumPooledSessions(IOBehavior ioBehavior, Cancellati
301
303
lock ( m_sessions )
302
304
{
303
305
// check if the desired minimum number of sessions have been created
304
- if ( m_connectionSettings . MaximumPoolSize - m_sessionSemaphore . CurrentCount + m_sessions . Count >= m_connectionSettings . MinimumPoolSize )
306
+ if ( ConnectionSettings . MaximumPoolSize - m_sessionSemaphore . CurrentCount + m_sessions . Count >= ConnectionSettings . MinimumPoolSize )
305
307
return ;
306
308
}
307
309
@@ -322,7 +324,7 @@ private async Task CreateMinimumPooledSessions(IOBehavior ioBehavior, Cancellati
322
324
{
323
325
var session = new ServerSession ( this , m_generation , Interlocked . Increment ( ref m_lastSessionId ) ) ;
324
326
Log . Info ( "{0} created Session{1} to reach minimum pool size" , m_logArguments [ 0 ] , session . Id ) ;
325
- await session . ConnectAsync ( m_connectionSettings , m_loadBalancer , ioBehavior , cancellationToken ) . ConfigureAwait ( false ) ;
327
+ await session . ConnectAsync ( ConnectionSettings , m_loadBalancer , ioBehavior , cancellationToken ) . ConfigureAwait ( false ) ;
326
328
AdjustHostConnectionCount ( session , 1 ) ;
327
329
lock ( m_sessions )
328
330
m_sessions . AddFirst ( session ) ;
@@ -335,29 +337,51 @@ private async Task CreateMinimumPooledSessions(IOBehavior ioBehavior, Cancellati
335
337
}
336
338
}
337
339
338
- public static ConnectionPool GetPool ( ConnectionSettings cs )
340
+ public static ConnectionPool GetPool ( string connectionString )
339
341
{
340
- if ( ! cs . Pooling )
341
- return null ;
342
+ // 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
+ }
342
353
343
- var key = cs . ConnectionString ;
354
+ // parse connection string and check for 'Pooling' setting
355
+ var connectionStringBuilder = new MySqlConnectionStringBuilder ( connectionString ) ;
356
+ if ( ! connectionStringBuilder . Pooling )
357
+ return null ;
344
358
359
+ // check for pool using normalized form of connection string
360
+ var normalizedConnectionString = connectionStringBuilder . ConnectionString ;
345
361
try
346
362
{
347
363
s_poolLock . EnterReadLock ( ) ;
348
- if ( s_pools . TryGetValue ( key , out var pool ) )
364
+ if ( s_pools . TryGetValue ( normalizedConnectionString , out var pool ) )
349
365
return pool ;
366
+ // TODO: Add an entry using 'connectionString'?
350
367
}
351
368
finally
352
369
{
353
370
s_poolLock . ExitReadLock ( ) ;
354
371
}
355
372
373
+ var connectionSettings = new ConnectionSettings ( connectionStringBuilder ) ;
374
+
356
375
try
357
376
{
358
377
s_poolLock . EnterWriteLock ( ) ;
359
- if ( ! s_pools . TryGetValue ( key , out var pool ) )
360
- pool = s_pools [ key ] = new ConnectionPool ( cs ) ;
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
+ }
361
385
return pool ;
362
386
}
363
387
finally
@@ -393,7 +417,7 @@ private static IReadOnlyList<ConnectionPool> GetAllPools()
393
417
394
418
private ConnectionPool ( ConnectionSettings cs )
395
419
{
396
- m_connectionSettings = cs ;
420
+ ConnectionSettings = cs ;
397
421
m_generation = 0 ;
398
422
m_cleanSemaphore = new SemaphoreSlim ( 1 ) ;
399
423
m_sessionSemaphore = new SemaphoreSlim ( cs . MaximumPoolSize ) ;
@@ -414,10 +438,7 @@ private ConnectionPool(ConnectionSettings cs)
414
438
Id = Interlocked . Increment ( ref s_poolId ) ;
415
439
m_logArguments = new object [ ] { "Pool{0}" . FormatInvariant ( Id ) } ;
416
440
if ( Log . IsInfoEnabled ( ) )
417
- {
418
- var csb = new MySqlConnectionStringBuilder ( cs . ConnectionString ) ;
419
- Log . Info ( "{0} creating new connection pool for {1}" , m_logArguments [ 0 ] , csb . GetConnectionString ( includePassword : false ) ) ;
420
- }
441
+ Log . Info ( "{0} creating new connection pool for {1}" , m_logArguments [ 0 ] , cs . ConnectionStringBuilder . GetConnectionString ( includePassword : false ) ) ;
421
442
}
422
443
423
444
private void AdjustHostConnectionCount ( ServerSession session , int delta )
@@ -472,7 +493,6 @@ public IEnumerable<string> LoadBalance(IReadOnlyList<string> hosts)
472
493
readonly SemaphoreSlim m_cleanSemaphore ;
473
494
readonly SemaphoreSlim m_sessionSemaphore ;
474
495
readonly LinkedList < ServerSession > m_sessions ;
475
- readonly ConnectionSettings m_connectionSettings ;
476
496
readonly Dictionary < string , ServerSession > m_leasedSessions ;
477
497
readonly ILoadBalancer m_loadBalancer ;
478
498
readonly Dictionary < string , int > m_hostSessions ;
0 commit comments