Skip to content

Commit eca7943

Browse files
committed
Switch from ConcurrentDictionary to ReaderWriterLockSlim.
This avoid multiple ConnectionPools being created simultaneously for the same connection string (in GetOrAdd). It also seems like a better fit for the expected access patterns of this variable.
1 parent b098883 commit eca7943

File tree

1 file changed

+37
-7
lines changed

1 file changed

+37
-7
lines changed

src/MySqlConnector/Core/ConnectionPool.cs

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using System;
2-
using System.Collections.Concurrent;
32
using System.Collections.Generic;
43
using System.Linq;
54
using System.Threading;
@@ -288,25 +287,55 @@ public static ConnectionPool GetPool(ConnectionSettings cs)
288287

289288
var key = cs.ConnectionString;
290289

291-
if (!s_pools.TryGetValue(key, out var pool))
290+
try
291+
{
292+
s_poolLock.EnterReadLock();
293+
if (s_pools.TryGetValue(key, out var pool))
294+
return pool;
295+
}
296+
finally
297+
{
298+
s_poolLock.ExitReadLock();
299+
}
300+
301+
try
302+
{
303+
s_poolLock.EnterWriteLock();
304+
if (!s_pools.TryGetValue(key, out var pool))
305+
pool = s_pools[key] = new ConnectionPool(cs);
306+
return pool;
307+
}
308+
finally
292309
{
293-
pool = s_pools.GetOrAdd(cs.ConnectionString, newKey => new ConnectionPool(cs));
310+
s_poolLock.ExitWriteLock();
294311
}
295-
return pool;
296312
}
297313

298314
public static async Task ClearPoolsAsync(IOBehavior ioBehavior, CancellationToken cancellationToken)
299315
{
300-
foreach (var pool in s_pools.Values)
316+
foreach (var pool in GetAllPools())
301317
await pool.ClearAsync(ioBehavior, cancellationToken).ConfigureAwait(false);
302318
}
303319

304320
public static async Task ReapPoolsAsync(IOBehavior ioBehavior, CancellationToken cancellationToken)
305321
{
306-
foreach (var pool in s_pools.Values)
322+
foreach (var pool in GetAllPools())
307323
await pool.ReapAsync(ioBehavior, cancellationToken).ConfigureAwait(false);
308324
}
309325

326+
private static IReadOnlyList<ConnectionPool> GetAllPools()
327+
{
328+
try
329+
{
330+
s_poolLock.EnterReadLock();
331+
return s_pools.Values.ToList();
332+
}
333+
finally
334+
{
335+
s_poolLock.ExitReadLock();
336+
}
337+
}
338+
310339
private ConnectionPool(ConnectionSettings cs)
311340
{
312341
m_connectionSettings = cs;
@@ -350,7 +379,8 @@ public IEnumerable<string> LoadBalance(IReadOnlyList<string> hosts)
350379
readonly ConnectionPool m_pool;
351380
}
352381

353-
static readonly ConcurrentDictionary<string, ConnectionPool> s_pools = new ConcurrentDictionary<string, ConnectionPool>();
382+
static readonly ReaderWriterLockSlim s_poolLock = new ReaderWriterLockSlim();
383+
static readonly Dictionary<string, ConnectionPool> s_pools = new Dictionary<string, ConnectionPool>();
354384
#if DEBUG
355385
static readonly TimeSpan ReaperInterval = TimeSpan.FromSeconds(1);
356386
#else

0 commit comments

Comments
 (0)