protected DictionaryImpl(int capacity, DictionaryImpl <TKey, TKeyStore, TValue> other) { capacity = AlignToPowerOfTwo(capacity); this._entries = new Entry[capacity]; this._size = other._size; this._topDict = other._topDict; this._keyComparer = other._keyComparer; }
public Snapshot(DictionaryImpl <TKey, TKeyStore, TValue> dict) { _table = dict; // linearization point. // if table is quiescent and has no copy in progress, // we can simply iterate over its table. while (true) { if (_table._newTable == null) { break; } // there is a copy in progress, finish it and try again _table.HelpCopyImpl(copy_all: true); _table = (DictionaryImpl <TKey, TKeyStore, TValue>)(_table._topDict._table); } // Warm-up the iterator MoveNext(); }
private ConcurrentDictionary( int capacity, IEqualityComparer <TKey> comparer = null) { if (capacity < 0) { throw new ArgumentOutOfRangeException(nameof(capacity)); } if (default(TKey) == null) { if (typeof(TKey) == typeof(ValueType) || !(default(TKey) is ValueType)) { _table = DictionaryImpl <TKey, TValue> .CreateRefUnsafe(this, capacity); _table._keyComparer = comparer ?? EqualityComparer <TKey> .Default; return; } } else { if (typeof(TKey) == typeof(uint) || typeof(TKey) == typeof(ulong)) { throw new NotSupportedException("Unsupported until we have confirmation of how to by-pass the code-gen issue with the casting of Boxed<TKey>. Use int or long instead."); } if (typeof(TKey) == typeof(int)) { if (comparer == null) { _table = (DictionaryImpl <TKey, TValue>)(object) new DictionaryImplIntNoComparer <TValue>(capacity, (ConcurrentDictionary <int, TValue>)(object) this); } else { _table = (DictionaryImpl <TKey, TValue>)(object) new DictionaryImplInt <TValue>(capacity, (ConcurrentDictionary <int, TValue>)(object) this); _table._keyComparer = comparer; } return; } if (typeof(TKey) == typeof(long)) { if (comparer == null) { _table = (DictionaryImpl <TKey, TValue>)(object) new DictionaryImplLongNoComparer <TValue>(capacity, (ConcurrentDictionary <long, TValue>)(object) this); } else { _table = (DictionaryImpl <TKey, TValue>)(object) new DictionaryImplLong <TValue>(capacity, (ConcurrentDictionary <long, TValue>)(object) this); _table._keyComparer = comparer; } return; } } _table = new DictionaryImplBoxed <TKey, TValue>(capacity, this) { _keyComparer = comparer ?? EqualityComparer <TKey> .Default }; }
private static bool CopySlot(ref Entry oldEntry, DictionaryImpl <TKey, TKeyStore, TValue> newTable) { Debug.Assert(newTable != null); // Blindly set the hash from 0 to TOMBPRIMEHASH, to eagerly stop // fresh put's from claiming new slots in the old table when the old // table is mid-resize. var hash = oldEntry.hash; if (hash == 0) { hash = Interlocked.CompareExchange(ref oldEntry.hash, TOMBPRIMEHASH, 0); if (hash == 0) { // slot was not claimed, copy is done here return(true); } } if (hash == TOMBPRIMEHASH) { // slot was trivially copied, but not by us return(false); } // Prevent new values from appearing in the old table. // Box what we see in the old table, to prevent further updates. // NOTE: Read of the value below must happen before reading of the key, // however this read does not need to be volatile since we will have // some fences in between reads. object oldval = oldEntry.value; // already boxed? Prime box = oldval as Prime; if (box != null) { // volatile read here since we need to make sure // that the key read below happens after we have read oldval above Volatile.Read(ref box.originalValue); } else { do { box = EntryValueNullOrDead(oldval) ? TOMBPRIME : new Prime(oldval); // CAS down a box'd version of oldval // also works as a complete fence between reading the value and the key object prev = Interlocked.CompareExchange(ref oldEntry.value, box, oldval); if (prev == oldval) { // If we made the Value slot hold a TOMBPRIME, then we both // prevented further updates here but also the (absent) // oldval is vacuously available in the new table. We // return with true here: any thread looking for a value for // this key can correctly go straight to the new table and // skip looking in the old table. if (box == TOMBPRIME) { return(true); } // Break loop; oldval is now boxed by us // it still needs to be copied into the new table. break; } oldval = prev; box = oldval as Prime; }while (box == null); } if (box == TOMBPRIME) { // Copy already complete here, but not by us. return(false); } // Copy the value into the new table, but only if we overwrite a null. // If another value is already in the new table, then somebody else // wrote something there and that write is happens-after any value that // appears in the old table. If putIfMatch does not find a null in the // new table - somebody else should have recorded the null-not_null // transition in this copy. object originalValue = box.originalValue; Debug.Assert(originalValue != TOMBSTONE); // since we have a real value, there must be a nontrivial key in the table // regular read is ok because value is always CASed down after the key // and we ensured that we read the key after the value with fences above var key = oldEntry.key; bool copiedIntoNew = newTable.PutSlotCopy(key, originalValue, hash); // Finally, now that any old value is exposed in the new table, we can // forever hide the old-table value by gently inserting TOMBPRIME value. // This will stop other threads from uselessly attempting to copy this slot // (i.e., it's a speed optimization not a correctness issue). // Check if we are not too late though, to not pay for MESI RFO and // GC fence needlessly. if (oldEntry.value != TOMBPRIME) { oldEntry.value = TOMBPRIME; } // if we failed to copy, it means something has already appeared in // the new table and old value should have been copied before that (not by us). return(copiedIntoNew); }
public SnapshotIDict(DictionaryImpl <TKey, TKeyStore, TValue> dict) : base(dict) { }