Skip to content
Permalink
Browse files

Obtain copy of _nextSlot for local use to avoid race condition

  • Loading branch information...
thetranman authored and YohDeadfall committed Jun 6, 2019
1 parent 929fb41 commit 28a187fe7b2b14f504d7673c42bd8602253a3e46
Showing with 23 additions and 15 deletions.
  1. +23 −15 src/Npgsql/PoolManager.cs
@@ -18,39 +18,42 @@ static class PoolManager
internal const int InitialPoolsSize = 10;

static readonly object _lock = new object();
static (string Key, ConnectorPool Pool)[] _pools = new (string, ConnectorPool)[InitialPoolsSize];
static int _nextSlot;
static volatile (string Key, ConnectorPool Pool)[] _pools = new (string, ConnectorPool)[InitialPoolsSize];
static volatile int _nextSlot;

internal static bool TryGetValue(string key, [NotNullWhenTrue] out ConnectorPool? pool)
{
// Note that pools never get removed. _pools is strictly append-only.
var nextSlot = _nextSlot;
var pools = _pools;
var sw = new SpinWait();

// First scan the pools and do reference equality on the connection strings
for (var i = 0; i < _nextSlot; i++)
for (var i = 0; i < nextSlot; i++)
{
if (ReferenceEquals(pools[i].Key, key))
var cp = pools[i];
if (ReferenceEquals(cp.Key, key))
{
// It's possible that this pool entry is currently being written: the connection string
// component has already been writte, but the pool component is just about to be. So we
// loop on the pool until it's non-null
while (Volatile.Read(ref pools[i].Pool) == null)
while (Volatile.Read(ref cp.Pool) == null)
sw.SpinOnce();
pool = pools[i].Pool;
pool = cp.Pool;
return true;
}
}

// Next try value comparison on the strings
for (var i = 0; i < _nextSlot; i++)
for (var i = 0; i < nextSlot; i++)
{
if (pools[i].Key == key)
var cp = pools[i];
if (cp.Key == key)
{
// See comment above
while (Volatile.Read(ref pools[i].Pool) == null)
while (Volatile.Read(ref cp.Pool) == null)
sw.SpinOnce();
pool = pools[i].Pool;
pool = cp.Pool;
return true;
}
}
@@ -71,7 +74,7 @@ internal static ConnectorPool GetOrAdd(string key, ConnectorPool pool)
{
var newPools = new (string, ConnectorPool)[_pools.Length * 2];
Array.Copy(_pools, newPools, _pools.Length);
Interlocked.Exchange(ref _pools, newPools);
_pools = newPools;
}

_pools[_nextSlot].Key = key;
@@ -91,11 +94,16 @@ internal static void Clear(string connString)

internal static void ClearAll()
{
for (var i = 0; i < _nextSlot; i++)
lock (_lock)
{
if (_pools[i].Key == null)
return;
_pools[i].Pool?.Clear();
var pools = _pools;
for (var i = 0; i < _nextSlot; i++)
{
var cp = pools[i];
if (cp.Key == null)
return;
cp.Pool?.Clear();
}
}
}

0 comments on commit 28a187f

Please sign in to comment.
You can’t perform that action at this time.