Skip to content

Commit e328dbc

Browse files
Further optimize response writing
- Add a specific overload for the newly used span based write methods - Use specific stream type to avoid virtual calls
1 parent 62f97a3 commit e328dbc

6 files changed

Lines changed: 46 additions & 11 deletions

File tree

Engine/Internal/Infrastructure/Endpoints/EndPoint.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using GenHTTP.Api.Infrastructure;
66

77
using GenHTTP.Engine.Internal.Protocol;
8+
using GenHTTP.Engine.Internal.Utilities;
89
using GenHTTP.Engine.Shared.Infrastructure;
910

1011
namespace GenHTTP.Engine.Internal.Infrastructure.Endpoints;
@@ -98,7 +99,7 @@ private void Handle(Socket client)
9899

99100
protected abstract ValueTask Accept(Socket client);
100101

101-
protected ValueTask Handle(Socket client, Stream inputStream, X509Certificate? clientCertificate = null)
102+
protected ValueTask Handle(Socket client, PoolBufferedStream inputStream, X509Certificate? clientCertificate = null)
102103
{
103104
client.NoDelay = true;
104105

Engine/Internal/Protocol/ChunkedStream.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
namespace GenHTTP.Engine.Internal.Protocol;
1+
using GenHTTP.Engine.Internal.Utilities;
2+
3+
namespace GenHTTP.Engine.Internal.Protocol;
24

35
/// <summary>
46
/// Implements chunked transfer encoding by letting the client
@@ -9,7 +11,7 @@
911
/// soon as there is no known content length. To avoid this overhead,
1012
/// specify the length of your content whenever possible.
1113
/// </remarks>
12-
public sealed class ChunkedStream(Stream target) : Stream
14+
public sealed class ChunkedStream(PoolBufferedStream target) : Stream
1315
{
1416

1517
#region Get-/Setters

Engine/Internal/Protocol/ClientHandler.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using GenHTTP.Api.Protocol;
88

99
using GenHTTP.Engine.Internal.Protocol.Parser;
10+
using GenHTTP.Engine.Internal.Utilities;
1011
using GenHTTP.Engine.Shared.Infrastructure;
1112
using GenHTTP.Engine.Shared.Types;
1213

@@ -38,7 +39,7 @@ internal sealed class ClientHandler
3839

3940
internal X509Certificate? ClientCertificate { get; set; }
4041

41-
internal Stream Stream { get; }
42+
internal PoolBufferedStream Stream { get; }
4243

4344
private bool? KeepAlive { get; set; }
4445

@@ -48,7 +49,7 @@ internal sealed class ClientHandler
4849

4950
#region Initialization
5051

51-
internal ClientHandler(Socket socket, Stream stream, X509Certificate? clientCertificate, IServer server, IEndPoint endPoint, NetworkConfiguration config)
52+
internal ClientHandler(Socket socket, PoolBufferedStream stream, X509Certificate? clientCertificate, IServer server, IEndPoint endPoint, NetworkConfiguration config)
5253
{
5354
Server = server;
5455
EndPoint = endPoint;

Engine/Internal/Protocol/ResponseHandler.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using GenHTTP.Api.Infrastructure;
44
using GenHTTP.Api.Protocol;
55

6+
using GenHTTP.Engine.Internal.Utilities;
67
using GenHTTP.Engine.Shared.Infrastructure;
78

89
namespace GenHTTP.Engine.Internal.Protocol;
@@ -16,15 +17,15 @@ internal sealed class ResponseHandler
1617

1718
private Socket Socket { get; }
1819

19-
private Stream Output { get; }
20+
private PoolBufferedStream Output { get; }
2021

2122
private NetworkConfiguration Configuration { get; }
2223

2324
#endregion
2425

2526
#region Initialization
2627

27-
internal ResponseHandler(IServer server, Socket socket, Stream output, NetworkConfiguration configuration)
28+
internal ResponseHandler(IServer server, Socket socket, PoolBufferedStream output, NetworkConfiguration configuration)
2829
{
2930
Server = server;
3031
Socket = socket;

Engine/Internal/Protocol/StreamExtensions.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
using System.Runtime.CompilerServices;
22

3+
using GenHTTP.Engine.Internal.Utilities;
4+
35
namespace GenHTTP.Engine.Internal.Protocol;
46

57
internal static class StreamExtensions
68
{
79

810
[MethodImpl(MethodImplOptions.AggressiveInlining)]
9-
internal static void Write(this Stream stream, string value)
11+
internal static void Write(this PoolBufferedStream stream, string value)
1012
{
1113
Span<byte> buffer = stackalloc byte[value.Length];
1214

@@ -19,7 +21,7 @@ internal static void Write(this Stream stream, string value)
1921
}
2022

2123
[MethodImpl(MethodImplOptions.AggressiveInlining)]
22-
internal static void Write(this Stream stream, long number)
24+
internal static void Write(this PoolBufferedStream stream, long number)
2325
{
2426
Span<byte> buffer = stackalloc byte[20];
2527

@@ -34,7 +36,7 @@ internal static void Write(this Stream stream, long number)
3436
}
3537

3638
[MethodImpl(MethodImplOptions.AggressiveInlining)]
37-
internal static void Write(this Stream stream, ulong number)
39+
internal static void Write(this PoolBufferedStream stream, ulong number)
3840
{
3941
Span<byte> buffer = stackalloc byte[20];
4042

@@ -49,7 +51,7 @@ internal static void Write(this Stream stream, ulong number)
4951
}
5052

5153
[MethodImpl(MethodImplOptions.AggressiveInlining)]
52-
internal static void Write(this Stream stream, DateTime time)
54+
internal static void Write(this PoolBufferedStream stream, DateTime time)
5355
{
5456
Span<char> charBuffer = stackalloc char[29]; // RFC1123 format is 29 chars
5557

Engine/Internal/Utilities/PoolBufferedStream.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Buffers;
2+
using System.Runtime.CompilerServices;
23

34
namespace GenHTTP.Engine.Internal.Utilities;
45

@@ -118,6 +119,33 @@ public override async Task WriteAsync(byte[] buffer, int offset, int count, Canc
118119
await WriteAsync(buffer.AsMemory(offset, count - offset), cancellationToken);
119120
}
120121

122+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
123+
public override void Write(ReadOnlySpan<byte> buffer)
124+
{
125+
var toWrite = buffer.Length;
126+
127+
if (toWrite <= Buffer.Length - Current)
128+
{
129+
buffer.CopyTo(Buffer.AsSpan(Current));
130+
Current += toWrite;
131+
return;
132+
}
133+
134+
if (Current > 0)
135+
{
136+
WriteBuffer();
137+
}
138+
139+
if (toWrite > Buffer.Length)
140+
{
141+
Stream.Write(buffer);
142+
return;
143+
}
144+
145+
buffer.CopyTo(Buffer);
146+
Current = toWrite;
147+
}
148+
121149
public override async ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default)
122150
{
123151
var count = buffer.Length;

0 commit comments

Comments
 (0)