private void RecoverSpace(RecoveryFinishedCondition finishCondition) { bool finished = false; while (!finished) { if (_cleanupQueue.Count == 0) { _cleanupQueue = new Queue <TKey>(_keyCounts.ToArray().Select(k => k.Key)); } TKey key = _cleanupQueue.Dequeue(); uint count; if (_keyCounts.TryGetValue(key, out count)) { if (count <= 1) { _keyCounts.TryRemove(key, out count); Interlocked.Add(ref _sumOfAmountsOverAllKeys, -count); Interlocked.Add(ref _numberOfElements, -1); } else { _keyCounts.AddOrUpdate(key, k => 0, (k, priorValue) => priorValue - 1); Interlocked.Add(ref _sumOfAmountsOverAllKeys, -1); } } finished = finishCondition(); } lock (_recoveryTaskLock) { _recoveryTask = null; } }
/// <summary> /// Recover space when the MaxCapacity limit is reached /// </summary> private void RecoverSpace(RecoveryFinishedCondition finishCondition) { // We're finished when the capacity has been reduced to CapacityToTargetWhenRecoveringSpace bool finished = false; while (!finished) { // If there queue of keys to cleanup is empty, refill it with all of the key's keys if (_cleanupQueue.Count == 0) { _cleanupQueue = new Queue <TKey>(_keyCounts.ToArray().Select(k => k.Key)); } // Dequeue one key from the clean-up queue (we only run one recovery-task at a time, // so we don't need task/thread safety here. TKey key = _cleanupQueue.Dequeue(); // Reduce the count for the current key on the queue and, if the count reaches 0, // remove that key uint count; if (_keyCounts.TryGetValue(key, out count)) { if (count <= 1) { _keyCounts.TryRemove(key, out count); Interlocked.Add(ref _sumOfAmountsOverAllKeys, -count); Interlocked.Add(ref _numberOfElements, -1); } else { _keyCounts.AddOrUpdate(key, k => 0, (k, priorValue) => priorValue - 1); Interlocked.Add(ref _sumOfAmountsOverAllKeys, -1); } } // We're finished when the capacity has reached the target capacity finished = finishCondition(); } // Now that the task is done, clear the task object so that a new task can be started // if necessary. lock (_recoveryTaskLock) { _recoveryTask = null; } }