From 9e3dd9be0f0ec7aaef1a719f09f96425e66369df Mon Sep 17 00:00:00 2001 From: vnugent Date: Thu, 2 Nov 2023 01:49:02 -0400 Subject: may have gottem carried away --- .../src/Core/Buffering/SplitHttpBufferElement.cs | 4 +- lib/Net.Http/src/Core/TransportReader.cs | 76 ++++++++++++++++++---- 2 files changed, 65 insertions(+), 15 deletions(-) (limited to 'lib/Net.Http') diff --git a/lib/Net.Http/src/Core/Buffering/SplitHttpBufferElement.cs b/lib/Net.Http/src/Core/Buffering/SplitHttpBufferElement.cs index e65ffd8..103d723 100644 --- a/lib/Net.Http/src/Core/Buffering/SplitHttpBufferElement.cs +++ b/lib/Net.Http/src/Core/Buffering/SplitHttpBufferElement.cs @@ -26,6 +26,8 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using VNLib.Utils.Memory; + namespace VNLib.Net.Http.Core.Buffering { internal abstract class SplitHttpBufferElement : HttpBufferElement, ISplitHttpBuffer @@ -65,6 +67,6 @@ namespace VNLib.Net.Http.Core.Buffering /// /// The desired size of the binary buffer /// The total size of the binary buffer required to store the binary and character buffer - public static int GetfullSize(int binSize) => binSize + (binSize * sizeof(char)); + public static int GetfullSize(int binSize) => binSize + MemoryUtil.ByteCount(binSize); } } diff --git a/lib/Net.Http/src/Core/TransportReader.cs b/lib/Net.Http/src/Core/TransportReader.cs index 58c23df..8d605d1 100644 --- a/lib/Net.Http/src/Core/TransportReader.cs +++ b/lib/Net.Http/src/Core/TransportReader.cs @@ -25,6 +25,9 @@ using System; using System.IO; using System.Text; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; using VNLib.Utils; using VNLib.Utils.IO; @@ -36,8 +39,17 @@ namespace VNLib.Net.Http.Core /// /// Structure implementation of /// - internal struct TransportReader : IVnTextReader + internal readonly struct TransportReader : IVnTextReader { + /* + * To make this structure read-only we can store the + * mutable values in a private segment of the internal + * buffer. 8 bytes are reserved at the beining and an + * additional word is added for padding incase small/wild + * under/over run occurs. + */ + const int PrivateBufferOffset = 4 * sizeof(int); + /// public readonly Encoding Encoding { get; } @@ -47,10 +59,25 @@ namespace VNLib.Net.Http.Core /// public readonly Stream BaseStream { get; } + /* + * Store the window start/end in the begging of the + * data buffer. Then use a constant offset to get the + * start of the buffer + */ + private readonly int BufWindowStart + { + get => MemoryMarshal.Read(Buffer.GetBinSpan()); + set => MemoryMarshal.Write(Buffer.GetBinSpan(), ref value); + } + + private readonly int BufWindowEnd + { + get => MemoryMarshal.Read(Buffer.GetBinSpan()[sizeof(int)..]); + set => MemoryMarshal.Write(Buffer.GetBinSpan()[sizeof(int)..], ref value); + } + private readonly IHttpHeaderParseBuffer Buffer; - - private int BufWindowStart; - private int BufWindowEnd; + private readonly int MAxBufferSize; /// /// Initializes a new for reading text lines from the transport stream @@ -61,29 +88,50 @@ namespace VNLib.Net.Http.Core /// The line delimiter to search for public TransportReader(Stream transport, IHttpHeaderParseBuffer buffer, Encoding encoding, ReadOnlyMemory lineTermination) { - BufWindowEnd = 0; - BufWindowStart = 0; Encoding = encoding; BaseStream = transport; LineTermination = lineTermination; Buffer = buffer; + MAxBufferSize = buffer.BinSize - PrivateBufferOffset; + + //Initialize the buffer window + SafeZeroPrivateSegments(Buffer); + + Debug.Assert(BufWindowEnd == 0 && BufWindowStart == 0); } + + /// + /// Clears the initial window start/end values with the + /// extra padding + /// + /// The buffer segment to initialize + private static void SafeZeroPrivateSegments(IHttpHeaderParseBuffer buffer) + { + ref byte start = ref MemoryMarshal.GetReference(buffer.GetBinSpan()); + Unsafe.InitBlock(ref start, 0, PrivateBufferOffset); + } + + /// + /// Gets the data segment of the buffer after the private segment + /// + /// + private readonly Span GetDataSegment() => Buffer.GetBinSpan()[PrivateBufferOffset..]; /// public readonly int Available => BufWindowEnd - BufWindowStart; /// - public readonly Span BufferedDataWindow => Buffer.GetBinSpan()[BufWindowStart..BufWindowEnd]; + public readonly Span BufferedDataWindow => GetDataSegment()[BufWindowStart..BufWindowEnd]; /// - public void Advance(int count) => BufWindowStart += count; + public readonly void Advance(int count) => BufWindowStart += count; /// - public void FillBuffer() + public readonly void FillBuffer() { //Get a buffer from the end of the current window to the end of the buffer - Span bufferWindow = Buffer.GetBinSpan()[BufWindowEnd..]; + Span bufferWindow = GetDataSegment()[BufWindowEnd..]; //Read from stream int read = BaseStream.Read(bufferWindow); @@ -93,15 +141,15 @@ namespace VNLib.Net.Http.Core } /// - public ERRNO CompactBufferWindow() + public readonly ERRNO CompactBufferWindow() { //No data to compact if window is not shifted away from start if (BufWindowStart > 0) { //Get span over engire buffer - Span buffer = Buffer.GetBinSpan(); + Span buffer = GetDataSegment(); - //Get data within window + //Get used data segment within window Span usedData = buffer[BufWindowStart..BufWindowEnd]; //Copy remaining to the begining of the buffer @@ -115,7 +163,7 @@ namespace VNLib.Net.Http.Core } //Return the number of bytes of available space from the end of the current window - return Buffer.BinSize - BufWindowEnd; + return MAxBufferSize - BufWindowEnd; } } } -- cgit