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); }
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 }
/// <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; }
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)); }
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; }
public static HelpCopyingInfo CreateNewArrayOutdatedInfo(ConcurrentArray <TKey, TValue> newestArray) { return(new HelpCopyingInfo(HelpCopyingResult.NewArrayOutdated, newestArray)); }
private HelpCopyingInfo(HelpCopyingResult operationResult, ConcurrentArray <TKey, TValue> newArray) { OperationResult = operationResult; NewArray = newArray; }
public Enumerator(ConcurrentArray <TKey, TValue> array) { _array = array; _currentIndex = -1; }
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()); }