Skip to content

Commit 59b936e

Browse files
committed
Don't add prefix padding in VectorArrayBuffer.
1 parent 97187c7 commit 59b936e

File tree

3 files changed

+25
-15
lines changed

3 files changed

+25
-15
lines changed

NetworkToolkit/Http/Primitives/Http1Connection.Parsers.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ namespace NetworkToolkitInternal.Http.Primitives
1515
public partial class Http1Connection
1616
{
1717
/// <summary>
18-
/// The amount of padding, in terms of valid address space before and after the buffer header parsing is done from.
18+
/// The amount of padding, in terms of valid address space after the buffer header parsing is done from.
1919
/// </summary>
2020
public static int HeaderBufferPadding => Vector256<byte>.Count - 1;
2121

@@ -102,7 +102,8 @@ internal unsafe bool ReadHeadersPortable(Span<byte> buffer, IHttpHeadersSink hea
102102
}
103103

104104
/// <remarks>
105-
/// This method REQUIRES (32-1) bytes of valid address space in front of and after <paramref name="buffer"/>.
105+
/// This method REQUIRES (32-1) bytes of valid address space after <paramref name="buffer"/>.
106+
/// It also assumes that it can always step backwards to a 32-byte aligned address.
106107
/// It is built to be used with VectorArrayBuffer, which does this.
107108
/// </remarks>
108109
internal unsafe bool ReadHeadersAvx2(Span<byte> buffer, IHttpHeadersSink headersSink, object? state, out int bytesConsumed)
@@ -115,7 +116,6 @@ internal unsafe bool ReadHeadersAvx2(Span<byte> buffer, IHttpHeadersSink headers
115116
fixed (byte* vectorBegin = buffer)
116117
{
117118
// align to a 32 byte address for optimal loads.
118-
// This is why padding is required.
119119
byte* vectorEnd = vectorBegin + buffer.Length;
120120
byte* vectorIter = (byte*)((nint)vectorBegin & ~(32 - 1));
121121

NetworkToolkit/VectorArrayBuffer.cs

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// See the LICENSE file in the project root for more information.
44

55
#nullable enable
6+
using NetworkToolkit.Http.Primitives;
67
using System;
78
using System.Buffers;
89
using System.Diagnostics;
@@ -27,10 +28,13 @@ namespace NetworkToolkit
2728
[StructLayout(LayoutKind.Auto)]
2829
internal struct VectorArrayBuffer : IDisposable
2930
{
30-
// Pad the front and back of the array with enough bytes to ensure we
31+
// It is assumed that (due to how virtual memory works) we do
32+
// not need to add padding to the front of the buffer.
33+
private const int PrefixPaddingLength = 0;
34+
// Pad the back of the array with enough bytes to ensure we
3135
// can always safely read an Vector256 at any index within returned spans.
32-
private static int PerSidePaddingLength => Vector256<byte>.Count - 1;
33-
private static int TotalPaddingLength => PerSidePaddingLength * 2;
36+
private static int SuffixPaddingLength => Http1Connection.HeaderBufferPadding;
37+
private static int TotalPaddingLength => PrefixPaddingLength + SuffixPaddingLength;
3438

3539
private byte[] _bytes;
3640
private int _activeStart;
@@ -61,12 +65,12 @@ public void Dispose()
6165
}
6266

6367
public int ActiveLength => _availableStart - _activeStart;
64-
public Span<byte> ActiveSpan => new Span<byte>(_bytes, _activeStart + PerSidePaddingLength, ActiveLength);
65-
public Memory<byte> ActiveMemory => new Memory<byte>(_bytes, _activeStart + PerSidePaddingLength, ActiveLength);
68+
public Span<byte> ActiveSpan => new Span<byte>(_bytes, _activeStart + PrefixPaddingLength, ActiveLength);
69+
public Memory<byte> ActiveMemory => new Memory<byte>(_bytes, _activeStart + PrefixPaddingLength, ActiveLength);
6670

6771
public int AvailableLength => Capacity - _availableStart;
68-
public Span<byte> AvailableSpan => new Span<byte>(_bytes, _availableStart + PerSidePaddingLength, AvailableLength);
69-
public Memory<byte> AvailableMemory => new Memory<byte>(_bytes, _availableStart + PerSidePaddingLength, AvailableLength);
72+
public Span<byte> AvailableSpan => new Span<byte>(_bytes, _availableStart + PrefixPaddingLength, AvailableLength);
73+
public Memory<byte> AvailableMemory => new Memory<byte>(_bytes, _availableStart + PrefixPaddingLength, AvailableLength);
7074

7175
public int Capacity => _bytes.Length - TotalPaddingLength;
7276

@@ -76,8 +80,14 @@ private static byte[] Rent(int byteCount)
7680
array.AsSpan().Clear();
7781

7882
// zero out the prefix and suffix padding, so they won't match any compares later on.
79-
array.AsSpan(0, PerSidePaddingLength).Clear();
80-
array.AsSpan(array.Length - PerSidePaddingLength, PerSidePaddingLength).Clear();
83+
if(PrefixPaddingLength != 0)
84+
{
85+
#pragma warning disable CS0162 // Unreachable code detected
86+
array.AsSpan(0, PrefixPaddingLength).Clear();
87+
#pragma warning restore CS0162 // Unreachable code detected
88+
}
89+
90+
array.AsSpan(array.Length - SuffixPaddingLength, SuffixPaddingLength).Clear();
8191

8292
return array;
8393
}
@@ -115,7 +125,7 @@ private void EnsureAvailableSpaceSlow(int byteCount)
115125
if (byteCount <= totalFree)
116126
{
117127
// We can free up enough space by just shifting the bytes down, so do so.
118-
Buffer.BlockCopy(_bytes, _activeStart + PerSidePaddingLength, _bytes, PerSidePaddingLength, ActiveLength);
128+
Buffer.BlockCopy(_bytes, _activeStart + PrefixPaddingLength, _bytes, PrefixPaddingLength, ActiveLength);
119129
_availableStart = ActiveLength;
120130
_activeStart = 0;
121131
Debug.Assert(byteCount <= AvailableLength);
@@ -136,7 +146,7 @@ private void EnsureAvailableSpaceSlow(int byteCount)
136146

137147
if (ActiveLength != 0)
138148
{
139-
Buffer.BlockCopy(oldBytes, _activeStart + PerSidePaddingLength, newBytes, PerSidePaddingLength, ActiveLength);
149+
Buffer.BlockCopy(oldBytes, _activeStart + PrefixPaddingLength, newBytes, PrefixPaddingLength, ActiveLength);
140150
}
141151

142152
_availableStart = ActiveLength;

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ Avoid a connection pool to have exact control over connections.
3939
```c#
4040
await using ConnectionFactory connectionFactory = new SocketConnectionFactory();
4141
await using Connection connection = await connectionFactory.ConnectAsync(new DnsEndPoint("microsoft.com", 80));
42-
await using HttpConnection httpConnection = new Http1Connection(connection);
42+
await using HttpConnection httpConnection = new Http1Connection(connection.Stream);
4343
await using ValueHttpRequest request = (await httpConnection.CreateNewRequestAsync(HttpPrimitiveVersion.Version11, HttpVersionPolicy.RequestVersionExact)).Value;
4444

4545
request.ConfigureRequest(contentLength: 0, hasTrailingHeaders: false);

0 commit comments

Comments
 (0)