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(); }
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()); }