public static Segmentrange <TStored, TSearch> Create(int segmentCount, int initialSegmentSize) { var instance = new Segmentrange <TStored, TSearch>(); instance.Initialize(segmentCount, initialSegmentSize); return(instance); }
/// <summary> /// Adjusts the segmentation to the new segment count /// </summary> /// <param name="newSegmentCount">The new number of segments to use. This must be a power of 2.</param> /// <param name="segmentSize">The number of item slots to reserve in each segment.</param> void SetSegmentation(Int32 newSegmentCount, Int32 segmentSize) { //Variables to detect a bad hash. var totalNewSegmentSize = 0; var largestSegmentSize = 0; Segment <TStored, TSearch> largestSegment = null; lock (SyncRoot) { #if DEBUG //<<<<<<<<<<<<<<<<<<<< debug <<<<<<<<<<<<<<<<<<<<<<<< //{ // int minSize = _CurrentRange.GetSegmentByIndex(0)._List.Length; // int maxSize = minSize; // for (int i = 1, end = _CurrentRange.Count; i < end; ++i) // { // int currentSize = _CurrentRange.GetSegmentByIndex(i)._List.Length; // if (currentSize < minSize) // minSize = currentSize; // if (currentSize > maxSize) // maxSize = currentSize; // } // System.Diagnostics.Debug.Assert(maxSize <= 8 * minSize, "Probably a bad hash"); //} //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> #endif unchecked { //create the new range Segmentrange <TStored, TSearch> newRange = CreateSegmentRange(newSegmentCount, segmentSize); //increase total allocated space now. We can do this safely //because at this point _AssessSegmentationPending flag will be true, //preventing an immediate reassesment. Interlocked.Add(ref _AllocatedSpace, newSegmentCount * segmentSize); //lock all new segments //we are going to release these locks while we migrate the items from the //old (current) range to the new range. for (int i = 0, end = newRange.Count; i != end; ++i) { newRange.GetSegmentByIndex(i).LockForWriting(); } //set new (completely locked) range Interlocked.Exchange(ref _NewRange, newRange); //calculate the step sizes for our switch points var currentSwitchPointStep = (UInt32)(1 << _CurrentRange.Shift); var newSwitchPointStep = (UInt32)(1 << newRange.Shift); //position in new range up from where the new segments are locked var newLockedPoint = (UInt32)0; //At this moment _SwitchPoint should be 0 var switchPoint = (UInt32)_SwitchPoint; do { Segment <TStored, TSearch> currentSegment; do { //aquire segment to migrate currentSegment = _CurrentRange.GetSegment(switchPoint); //lock segment currentSegment.LockForWriting(); if (currentSegment.IsAlive) { break; } currentSegment.ReleaseForWriting(); }while (true); //migrate all items in the segment to the new range TStored currentKey; int it = -1; while ((it = currentSegment.GetNextItem(it, out currentKey, this)) >= 0) { var currentKeyHash = this.GetItemHashCode(ref currentKey); //get the new segment. this is already locked. var newSegment = _NewRange.GetSegment(currentKeyHash); TStored dummyKey; newSegment.InsertItem(ref currentKey, out dummyKey, this); } //substract allocated space from allocated space count and trash segment. currentSegment.Bye(this); currentSegment.ReleaseForWriting(); if (switchPoint == 0 - currentSwitchPointStep) { //we are about to wrap _SwitchPoint arround. //We have migrated all items from the entire table to the //new range. //replace current with new before advancing, otherwise //we would create a completely blocked table. Interlocked.Exchange(ref _CurrentRange, newRange); } //advance _SwitchPoint switchPoint = (UInt32)Interlocked.Add(ref _SwitchPoint, (Int32)currentSwitchPointStep); //release lock of new segments upto the point where we can still add new items //during this migration. while (true) { var nextNewLockedPoint = newLockedPoint + newSwitchPointStep; if (nextNewLockedPoint > switchPoint || nextNewLockedPoint == 0) { break; } var newSegment = newRange.GetSegment(newLockedPoint); newSegment.Trim(this); var newSegmentSize = newSegment._Count; totalNewSegmentSize += newSegmentSize; if (newSegmentSize > largestSegmentSize) { largestSegmentSize = newSegmentSize; largestSegment = newSegment; } newSegment.ReleaseForWriting(); newLockedPoint = nextNewLockedPoint; } }while (switchPoint != 0); //unlock any remaining new segments while (newLockedPoint != 0) { var newSegment = newRange.GetSegment(newLockedPoint); newSegment.Trim(this); var newSegmentSize = newSegment._Count; totalNewSegmentSize += newSegmentSize; if (newSegmentSize > largestSegmentSize) { largestSegmentSize = newSegmentSize; largestSegment = newSegment; } newSegment.ReleaseForWriting(); newLockedPoint += newSwitchPointStep; } } } }
/// <summary> /// Create a segment range /// </summary> /// <param name="segmentCount">Number of segments in range.</param> /// <param name="initialSegmentSize">Number of slots allocated initialy in each segment.</param> /// <returns>The created <see cref="Segmentrange{TStored,TSearch}"/> instance.</returns> internal virtual Segmentrange <TStored, TSearch> CreateSegmentRange(int segmentCount, int initialSegmentSize) { return(Segmentrange <TStored, TSearch> .Create(segmentCount, initialSegmentSize)); }