Skip to content

Commit 966afd6

Browse files
committed
wip: replace spans per memory spans
1 parent 5134e81 commit 966afd6

File tree

11 files changed

+90
-144
lines changed

11 files changed

+90
-144
lines changed

cadente/Sisk.Cadente.CoreEngine/Sisk.Cadente.CoreEngine.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
<PropertyGroup>
4848
<AssemblyVersion>1.6.0</AssemblyVersion>
4949
<FileVersion>1.6.0</FileVersion>
50-
<Version>1.6.0-beta4</Version>
50+
<Version>1.6.0-beta5</Version>
5151
</PropertyGroup>
5252

5353
<!-- licensing, readme, signing -->

cadente/Sisk.Cadente/HttpConnection.cs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,20 @@ sealed class HttpConnection : IDisposable {
2828
#endif
2929

3030
// buffer dedicated to headers.
31-
public const int RESERVED_BUFFER_SIZE = 8192;
31+
public const int RESERVED_BUFFER_SIZE = 8 * 1024;
3232

3333
internal readonly Stream networkStream;
34-
internal IMemoryOwner<byte> sharedPool;
34+
internal IMemoryOwner<byte> requestPool, responsePool;
3535

3636
public HttpConnection ( HttpHostClient client, Stream connectionStream, HttpHost host, IPEndPoint endpoint ) {
3737
_client = client;
3838
_host = host;
3939
_endpoint = endpoint;
4040

4141
networkStream = connectionStream;
42-
sharedPool = MemoryPool<byte>.Shared.Rent ( RESERVED_BUFFER_SIZE );
42+
43+
requestPool = MemoryPool<byte>.Shared.Rent ( RESERVED_BUFFER_SIZE );
44+
responsePool = MemoryPool<byte>.Shared.Rent ( RESERVED_BUFFER_SIZE );
4345
}
4446

4547
[MethodImpl ( MethodImplOptions.AggressiveOptimization )]
@@ -48,7 +50,7 @@ public async Task<HttpConnectionState> HandleConnectionEventsAsync () {
4850

4951
while (!disposedValue) {
5052

51-
HttpRequestBase? nextRequest = await HttpRequestReader.TryReadHttpRequestAsync ( sharedPool.Memory, networkStream ).ConfigureAwait ( false );
53+
HttpRequestBase? nextRequest = await HttpRequestReader.TryReadHttpRequestAsync ( requestPool.Memory, networkStream ).ConfigureAwait ( false );
5254

5355
if (nextRequest is null) {
5456
return HttpConnectionState.ConnectionClosed;
@@ -65,8 +67,7 @@ public async Task<HttpConnectionState> HandleConnectionEventsAsync () {
6567
if (!managedSession.ResponseHeadersAlreadySent) {
6668
managedSession.Response.Headers.Set ( new HttpHeader ( HttpHeaderName.ContentLength, "0" ) );
6769

68-
if (!await managedSession.WriteHttpResponseHeadersAsync ())
69-
return HttpConnectionState.ResponseWriteException;
70+
await managedSession.WriteHttpResponseHeadersAsync ();
7071
}
7172

7273
await networkStream.FlushAsync ().ConfigureAwait ( false );
@@ -83,7 +84,8 @@ private void Dispose ( bool disposing ) {
8384
if (!disposedValue) {
8485
if (disposing) {
8586
networkStream.Dispose ();
86-
sharedPool.Dispose ();
87+
requestPool.Dispose ();
88+
responsePool.Dispose ();
8789
}
8890

8991
disposedValue = true;

cadente/Sisk.Cadente/HttpHeaderList.cs

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,10 @@
77
// File name: HttpHeaderList.cs
88
// Repository: https://github.com/sisk-http/core
99

10-
using System;
1110
using System.Collections;
12-
using System.Collections.Generic;
1311
using System.Diagnostics.CodeAnalysis;
14-
using System.Linq;
15-
using System.Reflection.PortableExecutable;
12+
using System.Runtime.InteropServices;
1613
using System.Text;
17-
using System.Threading.Tasks;
18-
using static System.Runtime.InteropServices.JavaScript.JSType;
1914

2015
namespace Sisk.Cadente;
2116

@@ -24,7 +19,8 @@ namespace Sisk.Cadente;
2419
/// </summary>
2520
public sealed class HttpHeaderList : IList<HttpHeader> {
2621

27-
private static HttpHeaderListNameComparer _nameComparer = new ();
22+
private static readonly HttpHeaderListNameComparer _nameComparer = new ();
23+
2824
internal List<HttpHeader> _headers;
2925
internal bool isReadOnly = false;
3026

@@ -82,7 +78,7 @@ public void Add ( HttpHeader item ) {
8278
/// </summary>
8379
public void Set ( HttpHeader header ) {
8480
Remove ( header );
85-
Add ( header );
81+
((ICollection<HttpHeader>) _headers).Add ( header );
8682
}
8783

8884
/// <summary>
@@ -93,7 +89,14 @@ public void Set ( HttpHeader header ) {
9389
/// An array of header values that match the specified name. If no headers match, an empty array is returned.
9490
/// </returns>
9591
public string [] Get ( string name ) {
96-
return _headers.Where ( h => h.Name.Equals ( name, StringComparison.OrdinalIgnoreCase ) ).Select ( h => h.Value ).ToArray ();
92+
var result = new List<string> ();
93+
var span = CollectionsMarshal.AsSpan ( _headers );
94+
for (int i = 0; i < span.Length; i++) {
95+
ref readonly var header = ref span [ i ];
96+
if (Ascii.EqualsIgnoreCase ( name, header.NameBytes.Span ))
97+
result.Add ( header.Value );
98+
}
99+
return result.ToArray ();
97100
}
98101

99102
/// <inheritdoc/>
@@ -105,7 +108,13 @@ public void Clear () {
105108

106109
/// <inheritdoc/>
107110
public bool Contains ( HttpHeader item ) {
108-
return ((ICollection<HttpHeader>) _headers).Contains ( item, _nameComparer );
111+
ReadOnlySpan<HttpHeader> span = CollectionsMarshal.AsSpan ( _headers );
112+
for (int i = 0; i < span.Length; i++) {
113+
ref readonly var header = ref span [ i ];
114+
if (_nameComparer.Equals ( header, item ))
115+
return true;
116+
}
117+
return false;
109118
}
110119

111120
/// <summary>
@@ -116,7 +125,13 @@ public bool Contains ( HttpHeader item ) {
116125
/// <see langword="true"/> if a header with the specified name is found; otherwise, <see langword="false"/>.
117126
/// </returns>
118127
public bool Contains ( string name ) {
119-
return Contains ( new HttpHeader ( name, string.Empty ) );
128+
ReadOnlySpan<HttpHeader> span = CollectionsMarshal.AsSpan ( _headers );
129+
for (int i = 0; i < span.Length; i++) {
130+
ref readonly var header = ref span [ i ];
131+
if (Ascii.EqualsIgnoreCase ( name, header.NameBytes.Span ))
132+
return true;
133+
}
134+
return false;
120135
}
121136

122137
/// <inheritdoc/>
@@ -157,6 +172,7 @@ public bool Remove ( HttpHeader item ) {
157172

158173
if (_nameComparer.Equals ( h, item )) {
159174
_headers.RemoveAt ( i );
175+
removed++;
160176
}
161177
}
162178

cadente/Sisk.Cadente/HttpHostContext.cs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
// Repository: https://github.com/sisk-http/core
99

1010
using System.Runtime.CompilerServices;
11-
using System.Text;
1211
using Sisk.Cadente.HttpSerializer;
1312
using Sisk.Cadente.Streams;
1413
using Sisk.Core.Http;
@@ -27,13 +26,13 @@ public sealed class HttpHostContext {
2726
internal bool ResponseHeadersAlreadySent = false;
2827

2928
[MethodImpl ( MethodImplOptions.AggressiveInlining )]
30-
internal async ValueTask<bool> WriteHttpResponseHeadersAsync () {
29+
internal Task WriteHttpResponseHeadersAsync () {
3130
if (ResponseHeadersAlreadySent) {
32-
return true;
31+
return Task.FromResult ( true );
3332
}
3433

3534
ResponseHeadersAlreadySent = true;
36-
return await HttpResponseSerializer.WriteHttpResponseHeaders ( _connection.sharedPool.Memory, _connection.networkStream, Response );
35+
return HttpResponseSerializer.WriteHttpResponseHeaders ( _connection.responsePool.Memory, _connection.networkStream, Response );
3736
}
3837

3938
/// <summary>
@@ -125,7 +124,7 @@ public Stream GetRequestStream () {
125124
internal HttpRequest ( HttpRequestBase request, HttpRequestStream requestStream ) {
126125
_baseRequest = request;
127126
_requestStream = requestStream;
128-
Headers = new HttpHeaderList ( _baseRequest.HeadersAR, readOnly: true );
127+
Headers = new HttpHeaderList ( _baseRequest.Headers.ToArray (), readOnly: true );
129128
}
130129
}
131130

@@ -174,9 +173,7 @@ public async Task<Stream> GetResponseStreamAsync ( bool chunked = false ) {
174173
}
175174
}
176175

177-
if (!await _session.WriteHttpResponseHeadersAsync ()) {
178-
throw new InvalidOperationException ( "Unable to obtain an output stream for the response." );
179-
}
176+
await _session.WriteHttpResponseHeadersAsync ();
180177

181178
headersSent = true;
182179
return chunked switch {

cadente/Sisk.Cadente/HttpSerializer/HttpRequestBase.cs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
// File name: HttpRequestBase.cs
88
// Repository: https://github.com/sisk-http/core
99

10-
using System.Buffers;
1110
using System.Text;
1211

1312
namespace Sisk.Cadente.HttpSerializer;
@@ -16,7 +15,6 @@ sealed class HttpRequestBase {
1615

1716
private string? _method;
1817
private string? _path;
19-
private HttpHeader []? _headers;
2018

2119
public bool IsExpecting100;
2220
public bool IsChunked;
@@ -25,10 +23,8 @@ sealed class HttpRequestBase {
2523
public bool CanKeepAlive;
2624

2725
public required ReadOnlyMemory<byte> BufferedContent;
28-
2926
public required ReadOnlyMemory<byte> MethodRef;
3027
public required ReadOnlyMemory<byte> PathRef;
31-
3228
public required ReadOnlyMemory<HttpHeader> Headers;
3329

3430
public string Method {
@@ -44,11 +40,4 @@ public string Path {
4440
return _path;
4541
}
4642
}
47-
48-
public HttpHeader [] HeadersAR {
49-
get {
50-
_headers ??= Headers.ToArray ();
51-
return _headers;
52-
}
53-
}
5443
}

0 commit comments

Comments
 (0)