dont use thread static buffers they are overlapping on server due to async io

This commit is contained in:
Jan Eggers
2018-06-25 15:31:49 +02:00
parent 5923c7c408
commit b77798f885
5 changed files with 27 additions and 31 deletions
+5 -1
View File
@@ -23,6 +23,10 @@ namespace MQTTnet.Adapter
private readonly IMqttNetChildLogger _logger; private readonly IMqttNetChildLogger _logger;
private readonly IMqttChannel _channel; private readonly IMqttChannel _channel;
private readonly byte[] _fixedHeaderBuffer = new byte[2];
private readonly byte[] _singleByteBuffer = new byte[1];
private bool _isDisposed; private bool _isDisposed;
public MqttChannelAdapter(IMqttChannel channel, IMqttPacketSerializer serializer, IMqttNetChildLogger logger) public MqttChannelAdapter(IMqttChannel channel, IMqttPacketSerializer serializer, IMqttNetChildLogger logger)
@@ -163,7 +167,7 @@ namespace MQTTnet.Adapter
private async Task<ReceivedMqttPacket> ReceiveAsync(IMqttChannel channel, CancellationToken cancellationToken) private async Task<ReceivedMqttPacket> ReceiveAsync(IMqttChannel channel, CancellationToken cancellationToken)
{ {
var fixedHeader = await MqttPacketReader.ReadFixedHeaderAsync(channel, cancellationToken).ConfigureAwait(false); var fixedHeader = await MqttPacketReader.ReadFixedHeaderAsync(channel, _fixedHeaderBuffer, _singleByteBuffer, cancellationToken).ConfigureAwait(false);
try try
{ {
+8 -25
View File
@@ -9,19 +9,13 @@ namespace MQTTnet.Serializer
{ {
public static class MqttPacketReader public static class MqttPacketReader
{ {
[ThreadStatic] public static async Task<MqttFixedHeader> ReadFixedHeaderAsync(IMqttChannel channel, byte[] fixedHeaderBuffer, byte[] singleByteBuffer, CancellationToken cancellationToken)
private static byte[] _fixedHeaderBuffer;
[ThreadStatic]
private static byte[] _singleByteBuffer;
public static async Task<MqttFixedHeader> ReadFixedHeaderAsync(IMqttChannel channel, CancellationToken cancellationToken)
{ {
// The MQTT fixed header contains 1 byte of flags and at least 1 byte for the remaining data length. // The MQTT fixed header contains 1 byte of flags and at least 1 byte for the remaining data length.
// So in all cases at least 2 bytes must be read for a complete MQTT packet. // So in all cases at least 2 bytes must be read for a complete MQTT packet.
// async/await is used here because the next packet is received in a couple of minutes so the performance // async/await is used here because the next packet is received in a couple of minutes so the performance
// impact is acceptable according to a useless waiting thread. // impact is acceptable according to a useless waiting thread.
var buffer = InitializeFixedHeaderBuffer(); var buffer = fixedHeaderBuffer;
var totalBytesRead = 0; var totalBytesRead = 0;
while (totalBytesRead < buffer.Length) while (totalBytesRead < buffer.Length)
@@ -42,11 +36,11 @@ namespace MQTTnet.Serializer
return new MqttFixedHeader(buffer[0], 0); return new MqttFixedHeader(buffer[0], 0);
} }
var bodyLength = ReadBodyLength(channel, buffer[1], cancellationToken); var bodyLength = ReadBodyLength(channel, buffer[1], singleByteBuffer, cancellationToken);
return new MqttFixedHeader(buffer[0], bodyLength); return new MqttFixedHeader(buffer[0], bodyLength);
} }
private static int ReadBodyLength(IMqttChannel channel, byte initialEncodedByte, CancellationToken cancellationToken) private static int ReadBodyLength(IMqttChannel channel, byte initialEncodedByte, byte[] singleByteBuffer, CancellationToken cancellationToken)
{ {
// Alorithm taken from https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/errata01/os/mqtt-v3.1.1-errata01-os-complete.html. // Alorithm taken from https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/errata01/os/mqtt-v3.1.1-errata01-os-complete.html.
var multiplier = 128; var multiplier = 128;
@@ -61,7 +55,7 @@ namespace MQTTnet.Serializer
// is too big for reading 1 byte in a row. We expect that the remaining data was sent // is too big for reading 1 byte in a row. We expect that the remaining data was sent
// directly after the initial bytes. If the client disconnects just in this moment we // directly after the initial bytes. If the client disconnects just in this moment we
// will get an exception anyway. // will get an exception anyway.
encodedByte = ReadByte(channel, cancellationToken); encodedByte = ReadByte(channel, singleByteBuffer, cancellationToken);
value += (byte)(encodedByte & 127) * multiplier; value += (byte)(encodedByte & 127) * multiplier;
if (multiplier > 128 * 128 * 128) if (multiplier > 128 * 128 * 128)
@@ -75,27 +69,16 @@ namespace MQTTnet.Serializer
return value; return value;
} }
private static byte ReadByte(IMqttChannel channel, CancellationToken cancellationToken) private static byte ReadByte(IMqttChannel channel, byte[] singleByteBuffer, CancellationToken cancellationToken)
{ {
var buffer = InitializeSingleByteBuffer(); var readCount = channel.ReadAsync(singleByteBuffer, 0, 1, cancellationToken).GetAwaiter().GetResult();
var readCount = channel.ReadAsync(buffer, 0, 1, cancellationToken).GetAwaiter().GetResult();
if (readCount <= 0) if (readCount <= 0)
{ {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
ExceptionHelper.ThrowGracefulSocketClose(); ExceptionHelper.ThrowGracefulSocketClose();
} }
return buffer[0]; return singleByteBuffer[0];
}
private static byte[] InitializeFixedHeaderBuffer()
{
return _fixedHeaderBuffer ?? (_fixedHeaderBuffer = new byte[2]);
}
private static byte[] InitializeSingleByteBuffer()
{
return _singleByteBuffer ?? (_singleByteBuffer = new byte[1]);
} }
} }
} }
@@ -47,12 +47,14 @@ namespace MQTTnet.Benchmarks
public void Deserialize_10000_Messages() public void Deserialize_10000_Messages()
{ {
var channel = new BenchmarkMqttChannel(_serializedPacket); var channel = new BenchmarkMqttChannel(_serializedPacket);
var fixedHeader = new byte[2];
var singleByteBuffer = new byte[1];
for (var i = 0; i < 10000; i++) for (var i = 0; i < 10000; i++)
{ {
channel.Reset(); channel.Reset();
var header = MqttPacketReader.ReadFixedHeaderAsync(channel, CancellationToken.None).GetAwaiter().GetResult(); var header = MqttPacketReader.ReadFixedHeaderAsync(channel, fixedHeader, singleByteBuffer, CancellationToken.None).GetAwaiter().GetResult();
var receivedPacket = new ReceivedMqttPacket( var receivedPacket = new ReceivedMqttPacket(
header.Flags, header.Flags,
@@ -14,7 +14,9 @@ namespace MQTTnet.Core.Tests
[ExpectedException(typeof(MqttCommunicationClosedGracefullyException))] [ExpectedException(typeof(MqttCommunicationClosedGracefullyException))]
public void MqttPacketReader_EmptyStream() public void MqttPacketReader_EmptyStream()
{ {
MqttPacketReader.ReadFixedHeaderAsync(new TestMqttChannel(new MemoryStream()), CancellationToken.None).GetAwaiter().GetResult(); var fixedHeader = new byte[2];
var singleByteBuffer = new byte[1];
MqttPacketReader.ReadFixedHeaderAsync(new TestMqttChannel(new MemoryStream()), fixedHeader, singleByteBuffer, CancellationToken.None).GetAwaiter().GetResult();
} }
} }
} }
@@ -476,7 +476,9 @@ namespace MQTTnet.Core.Tests
using (var headerStream = new MemoryStream(Join(buffer1))) using (var headerStream = new MemoryStream(Join(buffer1)))
{ {
var channel = new TestMqttChannel(headerStream); var channel = new TestMqttChannel(headerStream);
var header = MqttPacketReader.ReadFixedHeaderAsync(channel, CancellationToken.None).GetAwaiter().GetResult(); var fixedHeader = new byte[2];
var singleByteBuffer = new byte[1];
var header = MqttPacketReader.ReadFixedHeaderAsync(channel, fixedHeader, singleByteBuffer, CancellationToken.None).GetAwaiter().GetResult();
using (var bodyStream = new MemoryStream(Join(buffer1), (int)headerStream.Position, header.RemainingLength)) using (var bodyStream = new MemoryStream(Join(buffer1), (int)headerStream.Position, header.RemainingLength))
{ {
@@ -498,7 +500,10 @@ namespace MQTTnet.Core.Tests
using (var headerStream = new MemoryStream(Join(buffer1))) using (var headerStream = new MemoryStream(Join(buffer1)))
{ {
var channel = new TestMqttChannel(headerStream); var channel = new TestMqttChannel(headerStream);
var header = MqttPacketReader.ReadFixedHeaderAsync(channel, CancellationToken.None).GetAwaiter().GetResult(); var fixedHeader = new byte[2];
var singleByteBuffer = new byte[1];
var header = MqttPacketReader.ReadFixedHeaderAsync(channel, fixedHeader, singleByteBuffer, CancellationToken.None).GetAwaiter().GetResult();
using (var bodyStream = new MemoryStream(Join(buffer1), (int)headerStream.Position, header.RemainingLength)) using (var bodyStream = new MemoryStream(Join(buffer1), (int)headerStream.Position, header.RemainingLength))
{ {