Skip to content

Commit

Permalink
Add ConcurrentDictionary.IsEmpty fast path (dotnet/corefx#30098)
Browse files Browse the repository at this point in the history
If an unprotected iteration of the buckets shows the collection is not
empty, we can return false without ever acquiring a lock.

If we do not observe an entry, we must fall back to acquiring a lock
and re-scanning.

Fixes dotnet/corefx#29994.

Commit migrated from dotnet/corefx@bf2fdb6
  • Loading branch information
drewnoakes authored and stephentoub committed Jun 3, 2018
1 parent 099776a commit cf7e566
Showing 1 changed file with 26 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1207,27 +1207,45 @@ public bool IsEmpty
{
get
{
// Check if any buckets are non-empty, without acquiring any locks.
// This fast path should generally suffice as collections are usually not empty.
if (!AreAllBucketsEmpty())
{
return false;
}

// We didn't see any buckets containing items, however we can't be sure
// the collection was actually empty at any point in time as items may have been
// added and removed while iterating over the buckets such that we never saw an
// empty bucket, but there was always an item present in at least one bucket.
int acquiredLocks = 0;
try
{
// Acquire all locks
AcquireAllLocks(ref acquiredLocks);

for (int i = 0; i < _tables._countPerLock.Length; i++)
{
if (_tables._countPerLock[i] != 0)
{
return false;
}
}
return AreAllBucketsEmpty();
}
finally
{
// Release locks that have been acquired earlier
ReleaseLocks(0, acquiredLocks);
}

return true;
bool AreAllBucketsEmpty()
{
int[] countPerLock = _tables._countPerLock;

for (int i = 0; i < countPerLock.Length; i++)
{
if (countPerLock[i] != 0)
{
return false;
}
}

return true;
}
}
}

Expand Down

0 comments on commit cf7e566

Please sign in to comment.