private void AllocateNextSegment(int required, bool allowGrowth) { //TODO: protect from documents larger than 1GB // grow by doubling segment size until we get to 1 MB, then just use 1 MB segments // otherwise a document with 17 MB will waste 15 MB and require very big allocations var nextSegmentSize = Math.Max(Bits.NextPowerOf2(required), _current.Allocation.SizeInBytes * 2); const int oneMb = 1024 * 1024; if (nextSegmentSize > oneMb && required <= oneMb) { nextSegmentSize = oneMb; } if (allowGrowth && // we successfully grew the allocation, nothing to do _context.GrowAllocation(_current.Allocation, nextSegmentSize)) { return; } var allocatedMemoryData = _context.GetMemory(nextSegmentSize); _current = new Segment { Address = (byte *)allocatedMemoryData.Address, Allocation = allocatedMemoryData, Used = 0, Previous = _current, PreviousAllocated = _current }; }
private void AllocateNextSegment(int required, bool allowGrowth) { Debug.Assert(required > 0); if (required > ArenaMemoryAllocator.MaxArenaSize) { ThrowOnAllocationSizeExceeded(required, ArenaMemoryAllocator.MaxArenaSize); } // Grow by doubling segment size until we get to 1 MB, then just use 1 MB segments // otherwise a document with 17 MB will waste 15 MB and require very big allocations var requiredPowerOfTwo = Bits.PowerOf2(required); var segmentSize = Math.Max(requiredPowerOfTwo, _head.Allocation.SizeInBytes * 2); const int oneMb = 1024 * 1024; if (segmentSize > oneMb && required <= oneMb) { segmentSize = oneMb; } // We can sometimes ask the context to grow the allocation size; // it may do so at its own discretion; if this happens, then we // are good to go. if (allowGrowth && _context.GrowAllocation(_head.Allocation, segmentSize)) { return; } // Can't change _head because there may be copies of the current // instance of UnmanagedWriteBuffer going around. Thus, we simply // mutate it to ensure all copies have the same allocations. var allocation = _context.GetMemory(segmentSize); if (allocation.SizeInBytes < required) { ThrowOnAllocationSizeMismatch(allocation.SizeInBytes, required); } // Copy the head Segment previousHead = _head.ShallowCopy(); // Reset the head (this change happens in all instances at the // same time, albeit not atomically). _head.Previous = previousHead; _head.DeallocationPendingPrevious = previousHead; _head.Allocation = allocation; _head.Address = allocation.Address; _head.Used = 0; _head.AccumulatedSizeInBytes = previousHead.AccumulatedSizeInBytes; }