/// <summary> /// Removes all the elements. /// </summary> public void Clear() { _entriesOld = null; _entriesNew = new FixedSizeHashBucket <TKey, TValue>(INT_DefaultCapacity, _keyComparer); Thread.VolatileWrite(ref _status, (int)BucketStatus.Free); Thread.VolatileWrite(ref _count, 0); _revision++; }
private bool ContainsKeyExtracted(TKey key, FixedSizeHashBucket <TKey, TValue> entries) { for (int attempts = 0; attempts < _maxProbing; attempts++) { if (entries.ContainsKey(key, attempts) != -1) { return(true); } } return(false); }
private bool TryGetExtracted(int index, FixedSizeHashBucket <TKey, TValue> entries, out TKey key, out TValue value) { value = default(TValue); key = default(TKey); if (entries != null) { if (entries.TryGet(index, out key, out value)) { return(true); } } return(false); }
private bool RemoveExtracted(TKey key, FixedSizeHashBucket <TKey, TValue> entries) { if (entries != null) { for (int attempts = 0; attempts < _maxProbing; attempts++) { if (entries.Remove(key, attempts) != -1) { return(true); } } } return(false); }
/// <summary> /// Initializes a new instance of the <see cref="HashBucket{TValue}" /> class. /// </summary> /// <param name="capacity">The initial capacity.</param> /// <param name="comparer">The key comparer.</param> /// <param name="maxProbing">The maximum number of steps in linear probing.</param> /// <exception cref="System.ArgumentOutOfRangeException">maxProbing;maxProbing must be greater or equal to 1 and less than capacity.</exception> public HashBucket(int capacity, IEqualityComparer <TKey> comparer, int maxProbing) { if (maxProbing < 1 || maxProbing >= capacity) { throw new ArgumentOutOfRangeException("maxProbing", "maxProbing must be greater or equal to 1 and less than capacity."); } else { _keyComparer = comparer ?? EqualityComparer <TKey> .Default; _entriesOld = null; _entriesNew = new FixedSizeHashBucket <TKey, TValue>(capacity, _keyComparer); _maxProbing = maxProbing; } }
private bool TryGetValueExtracted(TKey key, FixedSizeHashBucket <TKey, TValue> entries, out TValue value) { value = default(TValue); if (entries != null) { for (int attempts = 0; attempts < _maxProbing; attempts++) { if (entries.TryGetValue(key, attempts, out value) != -1) { return(true); } } } return(false); }
private int TryAddExtracted(TKey key, TValue value, FixedSizeHashBucket <TKey, TValue> entries, out KeyValuePair <TKey, TValue> previous) { previous = default(KeyValuePair <TKey, TValue>); if (entries != null) { for (int attempts = 0; attempts < _maxProbing; attempts++) { int index = entries.TryAdd(key, value, attempts, out previous); if (index != -1) { return(index); } } } return(-1); }
private int SetExtracted(TKey key, TValue value, FixedSizeHashBucket <TKey, TValue> entries, out bool isNew) { isNew = false; if (entries != null) { for (int attempts = 0; attempts < _maxProbing; attempts++) { int index = entries.Set(key, value, attempts, out isNew); if (index != -1) { return(index); } } } return(-1); }
private int AddExtracted(TKey key, TValue value, FixedSizeHashBucket <TKey, TValue> entries, out bool isCollision) { isCollision = true; if (entries != null) { for (int attempts = 0; attempts < _maxProbing; attempts++) { int index = entries.Add(key, value, attempts, out isCollision); if (index != -1 || !isCollision) { return(index); } } } return(-1); }
private void CooperativeGrow() { int status; do { status = Thread.VolatileRead(ref _status); int oldStatus; switch (status) { case (int)BucketStatus.GrowRequested: // This area is only accessed by one thread, if that thread is aborted, we are doomed. // This class is not abort safe // If a thread is being aborted here it's pending operation will be lost and there is risk of a livelock var priority = Thread.CurrentThread.Priority; oldStatus = Interlocked.CompareExchange(ref _status, (int)BucketStatus.Waiting, (int)BucketStatus.GrowRequested); if (oldStatus == (int)BucketStatus.GrowRequested) { try { // The progress of other threads depend of this one, we should not allow a priority inversion. Thread.CurrentThread.Priority = ThreadPriority.Highest; //_copyPosition is set to -1. _copyPosition is incremented before it is used, so the first time it is used it will be 0. Thread.VolatileWrite(ref _copyPosition, -1); //The new capacity is twice the old capacity, the capacity must be a power of two. var newCapacity = _entriesNew.Capacity * 2; _entriesOld = Interlocked.Exchange(ref _entriesNew, new FixedSizeHashBucket <TKey, TValue>(newCapacity, _keyComparer)); oldStatus = Interlocked.CompareExchange(ref _status, (int)BucketStatus.Copy, (int)BucketStatus.Waiting); } finally { Thread.CurrentThread.Priority = priority; _revision++; } } break; case (int)BucketStatus.Waiting: // This is the whole reason why this datastructure is not wait free. // Testing shows that it is uncommon that a thread enters here. // _status is 2 only for a short period. // Still, it happens, so this is needed for correctness. // Going completely wait-free adds complexity with deminished value. Thread.SpinWait(INT_SpinWaitHint); if (Thread.VolatileRead(ref _status) == 2) { Thread.Sleep(0); } break; case (int)BucketStatus.Copy: // It is time to cooperate to copy the old storage to the new one var old = _entriesOld; if (old != null) { // This class is not abort safe // If a thread is being aborted here it will causing lost items. _revision++; Interlocked.Increment(ref _copyingThreads); TKey key; TValue value; int index = Interlocked.Increment(ref _copyPosition); for (; index < old.Capacity; index = Interlocked.Increment(ref _copyPosition)) { if (old.TryGet(index, out key, out value)) { // We have read an item, so let's try to add it to the new storage bool dummy; if (SetExtracted(key, value, _entriesNew, out dummy) == -1) { GC.KeepAlive(dummy); } } } Interlocked.CompareExchange(ref _status, (int)BucketStatus.CopyCleanup, (int)BucketStatus.Copy); _revision++; Interlocked.Decrement(ref _copyingThreads); } break; case (int)BucketStatus.CopyCleanup: // Our copy is finished, we don't need the old storage anymore oldStatus = Interlocked.CompareExchange(ref _status, (int)BucketStatus.Waiting, (int)BucketStatus.CopyCleanup); if (oldStatus == (int)BucketStatus.CopyCleanup) { _revision++; Interlocked.Exchange(ref _entriesOld, null); Interlocked.CompareExchange(ref _status, (int)BucketStatus.Free, (int)BucketStatus.Waiting); } break; default: break; } }while (status != (int)BucketStatus.Free); }