diff options
author | vnugent <public@vaughnnugent.com> | 2023-03-09 21:41:15 -0500 |
---|---|---|
committer | vnugent <public@vaughnnugent.com> | 2023-03-09 21:41:15 -0500 |
commit | 606e9b3331e73d68da38ec8139051ee1d0149061 (patch) | |
tree | 617e9ed2ee0a4be9c4fbf4c47116366648056f5b /lib/Net.Http/src/Helpers | |
parent | 5ddef0fcb742e77b99a0e17015d2eea0a1d4131a (diff) |
Minor HTTP buffs
Diffstat (limited to 'lib/Net.Http/src/Helpers')
-rw-r--r-- | lib/Net.Http/src/Helpers/CoreBufferHelpers.cs | 71 | ||||
-rw-r--r-- | lib/Net.Http/src/Helpers/InitDataBuffer.cs | 136 |
2 files changed, 149 insertions, 58 deletions
diff --git a/lib/Net.Http/src/Helpers/CoreBufferHelpers.cs b/lib/Net.Http/src/Helpers/CoreBufferHelpers.cs index 15c617c..719f4f8 100644 --- a/lib/Net.Http/src/Helpers/CoreBufferHelpers.cs +++ b/lib/Net.Http/src/Helpers/CoreBufferHelpers.cs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2022 Vaughn Nugent +* Copyright (c) 2023 Vaughn Nugent * * Library: VNLib * Package: VNLib.Net.Http @@ -31,10 +31,7 @@ * allocations and help provide memory optimization. */ - - using System; -using System.IO; using System.Buffers; using System.Security; using System.Threading; @@ -51,54 +48,11 @@ namespace VNLib.Net.Http.Core /// </summary> internal static class CoreBufferHelpers { - private sealed class InitDataBuffer : ISlindingWindowBuffer<byte> - { - private readonly ArrayPool<byte> pool; - private readonly int size; - - private byte[]? buffer; - - public InitDataBuffer(ArrayPool<byte> pool, int size) - { - this.buffer = pool.Rent(size, true); - this.pool = pool; - this.size = size; - WindowStartPos = 0; - WindowEndPos = 0; - } - - public int WindowStartPos { get; set; } - public int WindowEndPos { get; set; } - Memory<byte> ISlindingWindowBuffer<byte>.Buffer => buffer.AsMemory(0, size); - - public void Advance(int count) - { - WindowEndPos += count; - } - - public void AdvanceStart(int count) - { - WindowStartPos += count; - } - - public void Reset() - { - WindowStartPos = 0; - WindowEndPos = 0; - } - - //Release the buffer back to the pool - void ISlindingWindowBuffer<byte>.Close() - { - pool.Return(buffer!); - buffer = null; - } - } - /// <summary> /// An internal HTTP character binary pool for HTTP specific internal buffers /// </summary> public static ArrayPool<byte> HttpBinBufferPool { get; } = ArrayPool<byte>.Create(); + /// <summary> /// An <see cref="IUnmangedHeap"/> used for internal HTTP buffers /// </summary> @@ -117,7 +71,7 @@ namespace VNLib.Net.Http.Core public static UnsafeMemoryHandle<byte> GetBinBuffer(int size, bool zero) { //Calc buffer size to the nearest page size - size = (size / 4096 + 1) * 4096; + size = (int)MemoryUtil.NearestPage(size); //If rpmalloc lib is loaded, use it if (MemoryUtil.IsRpMallocLoaded) @@ -137,7 +91,7 @@ namespace VNLib.Net.Http.Core public static IMemoryOwner<byte> GetMemory(int size, bool zero) { //Calc buffer size to the nearest page size - size = (size / 4096 + 1) * 4096; + size = (int)MemoryUtil.NearestPage(size); //If rpmalloc lib is loaded, use it if (MemoryUtil.IsRpMallocLoaded) @@ -167,7 +121,7 @@ namespace VNLib.Net.Http.Core /// <param name="reader"></param> /// <param name="maxContentLength">Maximum content size to clamp the remaining buffer window to</param> /// <returns></returns> - public static ISlindingWindowBuffer<byte>? GetReminaingData<T>(this ref T reader, long maxContentLength) where T: struct, IVnTextReader + public static InitDataBuffer? GetReminaingData<T>(this ref T reader, long maxContentLength) where T: struct, IVnTextReader { //clamp max available to max content length int available = Math.Clamp(reader.Available, 0, (int)maxContentLength); @@ -175,13 +129,14 @@ namespace VNLib.Net.Http.Core { return null; } - //Alloc sliding window buffer - ISlindingWindowBuffer<byte> buffer = new InitDataBuffer(HttpBinBufferPool, available); - //Read remaining data - reader.ReadRemaining(buffer.RemainingBuffer.Span); - //Advance the buffer to the end of available data - buffer.Advance(available); - return buffer; + + //Creates the new initial data buffer + InitDataBuffer buf = InitDataBuffer.AllocBuffer(HttpBinBufferPool, available); + + //Read remaining data into the buffer's data segment + _ = reader.ReadRemaining(buf.DataSegment); + + return buf; } } diff --git a/lib/Net.Http/src/Helpers/InitDataBuffer.cs b/lib/Net.Http/src/Helpers/InitDataBuffer.cs new file mode 100644 index 0000000..36e1f11 --- /dev/null +++ b/lib/Net.Http/src/Helpers/InitDataBuffer.cs @@ -0,0 +1,136 @@ +/* +* Copyright (c) 2023 Vaughn Nugent +* +* Library: VNLib +* Package: VNLib.Net.Http +* File: InitDataBuffer.cs +* +* InitDataBuffer.cs is part of VNLib.Net.Http which is part of the larger +* VNLib collection of libraries and utilities. +* +* VNLib.Net.Http is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as +* published by the Free Software Foundation, either version 3 of the +* License, or (at your option) any later version. +* +* VNLib.Net.Http is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see https://www.gnu.org/licenses/. +*/ + +using System; +using System.Buffers; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +using VNLib.Utils; +using VNLib.Utils.Extensions; + +namespace VNLib.Net.Http.Core +{ + /// <summary> + /// A structure that buffers data remaining from an initial transport read. Stored + /// data will be read by copying. + /// </summary> + internal readonly struct InitDataBuffer + { + const int POSITION_SEG_SIZE = sizeof(int); + + readonly int _dataSize; + readonly byte[] _buffer; + readonly ArrayPool<byte> _pool; + + + InitDataBuffer(ArrayPool<byte> pool, byte[] buffer, int size) + { + _pool = pool; + _buffer = buffer; + _dataSize = size; + } + + /// <summary> + /// Allocates the correct size buffer for the given data size + /// </summary> + /// <param name="pool">The pool to allocate the array from</param> + /// <param name="dataSize">The size of the remaining data segment</param> + /// <returns>The newly allocated data buffer</returns> + internal static InitDataBuffer AllocBuffer(ArrayPool<byte> pool, int dataSize) + { + //Alloc buffer + byte[] buffer = pool.Rent(dataSize + POSITION_SEG_SIZE, true); + + return new(pool, buffer, dataSize); + } + + readonly Span<byte> _positionSegment + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _buffer.AsSpan(0, POSITION_SEG_SIZE); + } + + /// <summary> + /// Gets the entire internal data segment to read/write data to/from + /// </summary> + internal readonly Span<byte> DataSegment + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _buffer.AsSpan(POSITION_SEG_SIZE, _dataSize); + } + + private readonly int Position + { + //Reading/wriging the data buffe postion segment + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => MemoryMarshal.Read<int>(_positionSegment); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => MemoryMarshal.Write(_positionSegment, ref value); + } + + /// <summary> + /// Get the amount of data remaining in the data buffer + /// </summary> + internal readonly int Remaining + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _dataSize - Position; + } + + /// <summary> + /// Reads data from the internal buffer into the supplied buffer + /// </summary> + /// <param name="buffer">The buffer to write data to</param> + /// <returns>The number of bytes written to the output buffer</returns> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal readonly ERRNO Read(Span<byte> buffer) + { + //Calc how many bytes can be read into the output buffer + int bytesToRead = Math.Min(Remaining, buffer.Length); + + Span<byte> btr = DataSegment[Position..bytesToRead]; + + //Write data to output buffer + btr.CopyTo(buffer); + + //Update position pointer + Position += bytesToRead; + + //Return the number of bytes read + return bytesToRead; + } + + /// <summary> + /// Releases the internal buffer back to its pool + /// </summary> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal readonly void Release() + { + //Return buffer back to pool + _pool.Return(_buffer); + } + } +} |