Example #1
0
        public GrowArrayProcess <TKey, TValue> CreateGrowArrayProcess(ConcurrentArray <TKey, TValue> oldArray, int newArraySize, ExchangeArray <TKey, TValue> setNewArray)
        {
            var growArrayProcess = _decoratedFactory.CreateGrowArrayProcess(oldArray, newArraySize, setNewArray);

            growArrayProcess.Logger = _logger;
            return(growArrayProcess);
        }
 public static ConcurrentArray <int, object> FillArray(this ConcurrentArray <int, object> targetArray)
 {
     for (var i = 0; i < targetArray.Capacity; i++)
     {
         targetArray.TryAdd(new Entry <int, object>(i.GetHashCode(), i, null));
     }
     return(targetArray);
 }
Example #3
0
        private void SetNewArray(ConcurrentArray <TKey, TValue> oldArray, ConcurrentArray <TKey, TValue> newArray)
        {
            // ReSharper disable once UnusedVariable
            var previousValue = Interlocked.CompareExchange(ref _currentArray, newArray, oldArray);

#if CONCURRENT_LOGGING
            Log(previousValue == oldArray ? $"Exchanged array {oldArray.Id} with new array {newArray.Id}" : $"Array {newArray.Id} could not be set");
#endif
        }
Example #4
0
        /// <summary>
        ///     Initializes a new instance of <see cref="LockFreeArrayBasedDictionary{TKey,TValue}" />.
        /// </summary>
        /// <param name="options">The options that specify the service objects used by this dictionary.</param>
        /// <exception cref="ArgumentNullException">Thrown when <paramref name="options" /> is null.</exception>
        public LockFreeArrayBasedDictionary(Options options)
        {
            options.MustNotBeNull(nameof(options));

            _keyComparer               = options.KeyComparer;
            _valueComparer             = options.ValueComparer;
            _growArrayStrategy         = options.GrowArrayStrategy;
            _growArrayProcessFactory   = options.GrowArrayProcessFactory;
            _backgroundCopyTaskFactory = options.BackgroundCopyTaskFactory;
            _currentArray              = CreateInitialArray();
            _setNewArray               = SetNewArray;
        }
Example #5
0
        private EstablishGrowArrayProcessResult TryEstablishNewGrowArrayProcess(ConcurrentArray <TKey, TValue> oldArray, int newArraySize)
        {
            var growArrayProcess = _growArrayProcessFactory.CreateGrowArrayProcess(oldArray, newArraySize, _setNewArray);
            var existingProcess  = oldArray.EstablishGrowArrayProcess(growArrayProcess);

            if (existingProcess == null)
            {
                growArrayProcess.CreateNewArray();
#if CONCURRENT_LOGGING
                Log($"Established grow array process for new array {growArrayProcess.NewArray.Id}");
#endif
                return(new EstablishGrowArrayProcessResult(true, growArrayProcess));
            }

#if CONCURRENT_LOGGING
            Log("Other thread established grow array process.");
#endif
            return(new EstablishGrowArrayProcessResult(false, existingProcess));
        }
Example #6
0
        private void EscalateCopying(ConcurrentArray <TKey, TValue> array, ConcurrentArray <TKey, TValue> .AddInfo addInfo)
        {
            // This method is called when the old array is full
            // It will help copying all remaining items from the old to the new array
            var growArrayProcess = array.ReadGrowArrayProcessVolatile();

            if (growArrayProcess == null)
            {
                // If the grow array process is not created yet (although the old array is already full), then create it now
                var newSize = _growArrayStrategy.GetNextCapacity(array.Count, array.Capacity, addInfo.ReprobingCount);
                if (newSize == null)
                {
                    throw new InvalidOperationException($"The {nameof(IGrowArrayStrategy)} \"{_growArrayStrategy}\" does not provide a new size although the internal array of the dictionary is full.");
                }

                growArrayProcess = TryEstablishNewGrowArrayProcess(array, newSize.Value).GrowArrayProcess;
            }

            // Copy all remaining element from the old to the new array
            growArrayProcess.CopyToTheBitterEnd();
        }
 public void ExchangeArray(ConcurrentArray <TKey, TValue> oldArray, ConcurrentArray <TKey, TValue> newArray)
 {
     ++_exchangeArrayCallCount;
 }
Example #8
0
 public static HelpCopyingInfo CreateNewArrayOutdatedInfo(ConcurrentArray <TKey, TValue> newestArray)
 {
     return(new HelpCopyingInfo(HelpCopyingResult.NewArrayOutdated, newestArray));
 }
Example #9
0
 private HelpCopyingInfo(HelpCopyingResult operationResult, ConcurrentArray <TKey, TValue> newArray)
 {
     OperationResult = operationResult;
     NewArray        = newArray;
 }
Example #10
0
 public Enumerator(ConcurrentArray <TKey, TValue> array)
 {
     _array        = array;
     _currentIndex = -1;
 }
Example #11
0
        private HelpCopyingInfo HelpCopying(ConcurrentArray <TKey, TValue> array, ConcurrentArray <TKey, TValue> .AddInfo addInfo)
        {
            // Try to get an existing grow-array-process
            var growArrayProcess = array.ReadGrowArrayProcessVolatile();

            // If there is none, then try to create it
            if (growArrayProcess == null)
            {
                var newSize = _growArrayStrategy.GetNextCapacity(array.Count, array.Capacity, addInfo.ReprobingCount);
                // If no new size was proposed by the grow-array-strategy, then we do not need to create a grow-array-process
                if (newSize == null)
                {
                    return(HelpCopyingInfo.CreateNoCopyingNeededInfo());
                }

                // Try to establish a new grow-array-process. This is a race condition because
                // other threads might be doing the same, thus we might get a process object
                // that was created by another thread.
                var establishResult = TryEstablishNewGrowArrayProcess(array, newSize.Value);
                growArrayProcess = establishResult.GrowArrayProcess;

                // If we indeed established the process object, then the initial creation of the new target array
                // must be performed.
                if (establishResult.WasGrowArrayProcessInitializedByThisThread)
                {
                    growArrayProcess.HelpCopying();
                    if (growArrayProcess.IsCopyingFinished == false)
                    {
                        _backgroundCopyTaskFactory.StartBackgroundCopyTask(growArrayProcess.CopyToTheBitterEnd);
#if CONCURRENT_LOGGING
                        Log($"Created background copy task for array {growArrayProcess.NewArray}.");
#endif
                    }

                    return(HelpCopyingInfo.CreateGrowArrayProcessInitializedInfo());
                }
            }

TryHelpExistingCopyProcess:
            // Try to copy the entry to the new array (that was previously added to the old array).
            // This might be necessary if the concurrent copy algorithm is already past this entry.
            var copyInfo = growArrayProcess.CopyEntryThatWasJustAdded(addInfo.TargetEntry);
            // When the new array is already full, then return the value indicating that the entry
            // should be added to the newest array again.
            if (copyInfo.OperationResult == AddResult.ArrayFull)
            {
                return(HelpCopyingInfo.CreateNewArrayFullInfo(growArrayProcess.NewArray));
            }

            // If the copying did succeed but the grow array process already finished copying, then
            // check if the new array is not outdated yet.
            if (copyInfo.OperationResult == AddResult.AddSuccessful && growArrayProcess.IsCopyingFinished)
            {
                var newestArray = Volatile.Read(ref _currentArray);
                // If the newest array  is the one that was established by the grow array process, then check
                // if this new array already has another grow array process associated with it, and help
                // copying there.
                if (newestArray == growArrayProcess.NewArray)
                {
                    var newGrowArrayProcess = newestArray.ReadGrowArrayProcessVolatile();
                    if (newGrowArrayProcess != null)
                    {
#if CONCURRENT_LOGGING
                        Log($"New grow array process found for array {newGrowArrayProcess.SpinGetNewArray().Id}, help copying there.");
#endif
                        growArrayProcess = newGrowArrayProcess;
                        goto TryHelpExistingCopyProcess;
                    }
                }
                // If the newest array is neither the new array of the current grow array process nor the inital
                // array that we started with, then we probably were preempted for some time, and several new
                // arrays were established since then.
                if (newestArray != array)
                {
                    return(HelpCopyingInfo.CreateNewArrayOutdatedInfo(newestArray));
                }
            }

            // Try to help copying the rest of the items over to the new array
            growArrayProcess.HelpCopying();
            return(HelpCopyingInfo.CreateHelpedCopyingInfo());
        }