Example #1
0
 protected DictionaryImpl(int capacity, DictionaryImpl <TKey, TKeyStore, TValue> other)
 {
     capacity     = AlignToPowerOfTwo(capacity);
     _entries     = new Entry[capacity];
     _size        = other._size;
     _topDict     = other._topDict;
     _keyComparer = other._keyComparer;
 }
Example #2
0
            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();
            }
Example #3
0
        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
            };
        }
Example #4
0
        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);
        }
Example #5
0
 public SnapshotIDict(DictionaryImpl <TKey, TKeyStore, TValue> dict) : base(dict)
 {
 }