An Exception at MySqlPoolManager.GetPoolAsync
When i use this package,it occasionally threw the following exception during startup:
An item with the same key has already been added. Key: database=;server=;user id=;password=;characterset=;pooling=True;allowzerodatetime=True at System.Collections.Generic.Dictionary`2.TryInsert(TKey key, TValue value, InsertionBehavior behavior) at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value) at MySql.Data.MySqlClient.MySqlPoolManager.GetPoolAsync(MySqlConnectionStringBuilder settings, Boolean execAsync, CancellationToken cancellationToken) at MySql.Data.MySqlClient.MySqlConnection.OpenAsync(Boolean execAsync, CancellationToken cancellationToken) at MySql.Data.MySqlClient.MySqlConnection.Open() at
I think this exception is caused by multi-threading,and you can reporduce it with the following code:
```C#
var connStr = "Initial Catalog=***;Data Source='***';User Id='***';Password='***';charset='utf8mb4';pooling=true;Allow Zero Datetime=True;";
Parallel.For(0, 10, (i) =>
{
try
{
using (var conn = new MySqlConnection(connStr))
{
conn.Open();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
});
```
After reading the source code,I believe that this bug is casused by MySqlPoolManager incorrectly using SemaphoreSlim:
```C#
public static async Task<MySqlPool> GetPoolAsync(MySqlConnectionStringBuilder settings, bool execAsync, CancellationToken cancellationToken)
{
string text = GetKey(settings);
SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1);
semaphoreSlim.Wait(CancellationToken.None);
Pools.TryGetValue(text, out var value);
if (value == null)
{
value = await MySqlPool.CreateMySqlPoolAsync(settings, execAsync, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
Pools.Add(text, value);
}
else
{
value.Settings = settings;
}
semaphoreSlim.Release();
return value;
}
```
I think the correct way to do it shoule be like this:
```
static SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1);
public static async Task<MySqlPool> GetPoolAsync(MySqlConnectionStringBuilder settings, bool execAsync, CancellationToken cancellationToken)
{
string text = GetKey(settings);
semaphoreSlim.Wait(CancellationToken.None);
Pools.TryGetValue(text, out var value);
if (value == null)
{
value = await MySqlPool.CreateMySqlPoolAsync(settings, execAsync, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
Pools.Add(text, value);
}
else
{
value.Settings = settings;
}
semaphoreSlim.Release();
return value;
}
```