Esempio n. 1
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();
        }
Esempio n. 2
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());
        }