Skip to content

Commit 4fa6e56

Browse files
committed
use ArrayBufferWriter<T> for composing the response, to reduce allocation and calls
1 parent a4ab812 commit 4fa6e56

File tree

1 file changed

+31
-25
lines changed

1 file changed

+31
-25
lines changed

src/Smdn.Net.MuninNode/Smdn.Net.MuninNode/NodeBase.cs

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ public abstract class NodeBase : IDisposable, IAsyncDisposable {
4646

4747
public EndPoint LocalEndPoint => server?.LocalEndPoint ?? throw new InvalidOperationException("not yet bound or already disposed");
4848

49+
private readonly ArrayBufferWriter<byte> responseBuffer = new(initialCapacity: 1024); // TODO: define best initial capacity
50+
4951
protected NodeBase(
5052
IAccessRule? accessRule,
5153
ILogger? logger
@@ -229,7 +231,6 @@ public async ValueTask AcceptSingleSessionAsync(
229231
try {
230232
await SendResponseAsync(
231233
client,
232-
Encoding,
233234
$"# munin node at {HostName}",
234235
cancellationToken
235236
).ConfigureAwait(false);
@@ -550,7 +551,6 @@ CancellationToken cancellationToken
550551
else {
551552
return SendResponseAsync(
552553
client,
553-
Encoding,
554554
"# Unknown command. Try cap, list, nodes, config, fetch, version or quit",
555555
cancellationToken
556556
);
@@ -566,22 +566,19 @@ CancellationToken cancellationToken
566566
".",
567567
];
568568

569-
private static ValueTask SendResponseAsync(
569+
private ValueTask SendResponseAsync(
570570
Socket client,
571-
Encoding encoding,
572571
string responseLine,
573572
CancellationToken cancellationToken
574573
)
575574
=> SendResponseAsync(
576575
client: client,
577-
encoding: encoding,
578576
responseLines: Enumerable.Repeat(responseLine, 1),
579577
cancellationToken: cancellationToken
580578
);
581579

582-
private static async ValueTask SendResponseAsync(
580+
private async ValueTask SendResponseAsync(
583581
Socket client,
584-
Encoding encoding,
585582
IEnumerable<string> responseLines,
586583
CancellationToken cancellationToken
587584
)
@@ -591,21 +588,38 @@ CancellationToken cancellationToken
591588

592589
cancellationToken.ThrowIfCancellationRequested();
593590

594-
foreach (var responseLine in responseLines) {
595-
var resp = encoding.GetBytes(responseLine);
591+
try {
592+
foreach (var responseLine in responseLines) {
593+
#if SYSTEM_TEXT_ENCODINGEXTENSIONS
594+
_ = Encoding.GetBytes(responseLine, responseBuffer);
596595

597-
await client.SendAsync(
598-
buffer: resp,
599-
socketFlags: SocketFlags.None,
600-
cancellationToken: cancellationToken
601-
).ConfigureAwait(false);
596+
responseBuffer.Write(EndOfLine.Span);
597+
#else
598+
var totalByteCount = Encoding.GetByteCount(responseLine) + EndOfLine.Length;
599+
var buffer = responseBuffer.GetMemory(totalByteCount);
600+
var bytesWritten = Encoding.GetBytes(responseLine, buffer.Span);
601+
602+
EndOfLine.CopyTo(buffer[bytesWritten..]);
603+
604+
bytesWritten += EndOfLine.Length;
605+
606+
responseBuffer.Advance(bytesWritten);
607+
#endif
608+
}
602609

603610
await client.SendAsync(
604-
buffer: EndOfLine,
611+
buffer: responseBuffer.WrittenMemory,
605612
socketFlags: SocketFlags.None,
606613
cancellationToken: cancellationToken
607614
).ConfigureAwait(false);
608615
}
616+
finally {
617+
#if SYSTEM_BUFFERS_ARRAYBUFFERWRITER_RESETWRITTENCOUNT
618+
responseBuffer.ResetWrittenCount();
619+
#else
620+
responseBuffer.Clear();
621+
#endif
622+
}
609623
}
610624

611625
private ValueTask ProcessCommandNodesAsync(
@@ -615,11 +629,10 @@ CancellationToken cancellationToken
615629
{
616630
return SendResponseAsync(
617631
client: client,
618-
encoding: Encoding,
619-
responseLines: new[] {
632+
responseLines: [
620633
HostName,
621634
".",
622-
},
635+
],
623636
cancellationToken: cancellationToken
624637
);
625638
}
@@ -631,7 +644,6 @@ CancellationToken cancellationToken
631644
{
632645
return SendResponseAsync(
633646
client: client,
634-
encoding: Encoding,
635647
responseLine: $"munins node on {HostName} version: {NodeVersion}",
636648
cancellationToken: cancellationToken
637649
);
@@ -650,7 +662,6 @@ CancellationToken cancellationToken
650662
// XXX: ignores capability arguments
651663
return SendResponseAsync(
652664
client: client,
653-
encoding: Encoding,
654665
responseLine: "cap",
655666
cancellationToken: cancellationToken
656667
);
@@ -669,7 +680,6 @@ CancellationToken cancellationToken
669680
// XXX: ignore [node] arguments
670681
return SendResponseAsync(
671682
client: client,
672-
encoding: Encoding,
673683
responseLine: string.Join(" ", PluginProvider.Plugins.Select(static plugin => plugin.Name)),
674684
cancellationToken: cancellationToken
675685
);
@@ -690,7 +700,6 @@ CancellationToken cancellationToken
690700
if (plugin is null) {
691701
await SendResponseAsync(
692702
client,
693-
Encoding,
694703
ResponseLinesUnknownService,
695704
cancellationToken
696705
).ConfigureAwait(false);
@@ -712,7 +721,6 @@ await SendResponseAsync(
712721

713722
await SendResponseAsync(
714723
client: client,
715-
encoding: Encoding,
716724
responseLines: responseLines,
717725
cancellationToken: cancellationToken
718726
).ConfigureAwait(false);
@@ -750,7 +758,6 @@ CancellationToken cancellationToken
750758
if (plugin is null) {
751759
return SendResponseAsync(
752760
client,
753-
Encoding,
754761
ResponseLinesUnknownService,
755762
cancellationToken
756763
);
@@ -816,7 +823,6 @@ void AddFieldValueRange(string attr, PluginFieldNormalValueRange range)
816823

817824
return SendResponseAsync(
818825
client: client,
819-
encoding: Encoding,
820826
responseLines: responseLines,
821827
cancellationToken: cancellationToken
822828
);

0 commit comments

Comments
 (0)