Skip to content

Commit 56b3ebf

Browse files
authored
Merge pull request #1613 from bollhals/fix/InboundFrame
change InboundFrame to a class
2 parents 3188515 + 004ce32 commit 56b3ebf

File tree

10 files changed

+120
-129
lines changed

10 files changed

+120
-129
lines changed

projects/RabbitMQ.Client/client/api/ReadonlyBasicProperties.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@ public PublicationAddress? ReplyToAddress
8484

8585
public ReadOnlyBasicProperties(ReadOnlySpan<byte> span)
8686
{
87+
if (span.IsEmpty)
88+
{
89+
return;
90+
}
91+
8792
int offset = 2;
8893
ref readonly byte bits = ref span[0];
8994
if (bits.IsBitSet(BasicProperties.ContentTypeBit)) { offset += WireFormatting.ReadShortstr(span.Slice(offset), out _contentType); }

projects/RabbitMQ.Client/client/impl/CommandAssembler.cs

Lines changed: 33 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,9 @@ internal sealed class CommandAssembler
4545
private const int MaxArrayOfBytesSize = 2_147_483_591;
4646

4747
private ProtocolCommandId _commandId;
48-
private ReadOnlyMemory<byte> _methodMemory;
49-
private byte[]? _rentedMethodArray;
50-
private ReadOnlyMemory<byte> _headerMemory;
51-
private byte[]? _rentedHeaderArray;
52-
private ReadOnlyMemory<byte> _bodyMemory;
53-
private byte[]? _rentedBodyArray;
48+
private RentedMemory _methodMemory;
49+
private RentedMemory _headerMemory;
50+
private RentedMemory _bodyMemory;
5451
private int _remainingBodyByteCount;
5552
private int _offset;
5653
private AssemblyState _state;
@@ -66,61 +63,49 @@ public CommandAssembler(uint maxBodyLength)
6663
private void Reset()
6764
{
6865
_commandId = default;
69-
_methodMemory = ReadOnlyMemory<byte>.Empty;
70-
_rentedMethodArray = null;
71-
_headerMemory = ReadOnlyMemory<byte>.Empty;
72-
_rentedHeaderArray = null;
73-
_bodyMemory = ReadOnlyMemory<byte>.Empty;
74-
_rentedBodyArray = null;
66+
_methodMemory = default;
67+
_headerMemory = default;
68+
_bodyMemory = default;
7569
_remainingBodyByteCount = 0;
7670
_offset = 0;
7771
_state = AssemblyState.ExpectingMethod;
7872
}
7973

80-
public bool HandleFrame(in InboundFrame frame, out IncomingCommand command)
74+
public void HandleFrame(InboundFrame frame, out IncomingCommand command)
8175
{
82-
bool shallReturn = true;
8376
switch (_state)
8477
{
8578
case AssemblyState.ExpectingMethod:
86-
ParseMethodFrame(in frame);
87-
shallReturn = false;
79+
ParseMethodFrame(frame);
8880
break;
8981
case AssemblyState.ExpectingContentHeader:
90-
shallReturn = ParseHeaderFrame(in frame);
82+
ParseHeaderFrame(frame);
9183
break;
9284
case AssemblyState.ExpectingContentBody:
93-
shallReturn = ParseBodyFrame(in frame);
85+
ParseBodyFrame(frame);
9486
break;
9587
}
9688

9789
if (_state != AssemblyState.Complete)
9890
{
9991
command = IncomingCommand.Empty;
100-
return shallReturn;
92+
return;
10193
}
10294

10395
RabbitMqClientEventSource.Log.CommandReceived();
104-
105-
var method = new RentedMemory(_methodMemory, _rentedMethodArray);
106-
var header = new RentedMemory(_headerMemory, _rentedHeaderArray);
107-
var body = new RentedMemory(_bodyMemory, _rentedBodyArray);
108-
109-
command = new IncomingCommand(_commandId, method, header, body);
96+
command = new IncomingCommand(_commandId, _methodMemory, _headerMemory, _bodyMemory);
11097
Reset();
111-
return shallReturn;
11298
}
11399

114-
private void ParseMethodFrame(in InboundFrame frame)
100+
private void ParseMethodFrame(InboundFrame frame)
115101
{
116102
if (frame.Type != FrameType.FrameMethod)
117103
{
118104
throw new UnexpectedFrameException(frame.Type);
119105
}
120106

121-
_rentedMethodArray = frame.TakeoverPayload();
122107
_commandId = (ProtocolCommandId)NetworkOrderDeserializer.ReadUInt32(frame.Payload.Span);
123-
_methodMemory = frame.Payload.Slice(4);
108+
_methodMemory = frame.TakeoverPayload(Framing.Method.ArgumentsOffset);
124109

125110
switch (_commandId)
126111
{
@@ -136,7 +121,7 @@ private void ParseMethodFrame(in InboundFrame frame)
136121
}
137122
}
138123

139-
private bool ParseHeaderFrame(in InboundFrame frame)
124+
private void ParseHeaderFrame(InboundFrame frame)
140125
{
141126
if (frame.Type != FrameType.FrameHeader)
142127
{
@@ -150,7 +135,7 @@ private bool ParseHeaderFrame(in InboundFrame frame)
150135
throw new UnknownClassOrMethodException(classId, 0);
151136
}
152137

153-
ulong totalBodyBytes = NetworkOrderDeserializer.ReadUInt64(span.Slice(4));
138+
ulong totalBodyBytes = NetworkOrderDeserializer.ReadUInt64(span.Slice(Framing.Header.BodyLengthOffset));
154139
if (totalBodyBytes > MaxArrayOfBytesSize)
155140
{
156141
throw new UnexpectedFrameException(frame.Type);
@@ -162,16 +147,21 @@ private bool ParseHeaderFrame(in InboundFrame frame)
162147
throw new MalformedFrameException(message: msg, canShutdownCleanly: false);
163148
}
164149

165-
_rentedHeaderArray = totalBodyBytes != 0 ? frame.TakeoverPayload() : Array.Empty<byte>();
166-
167-
_headerMemory = frame.Payload.Slice(12);
150+
// There are always at least 2 bytes, even for empty ones
151+
if (frame.Payload.Length <= Framing.Header.HeaderArgumentOffset + 2)
152+
{
153+
frame.TryReturnPayload();
154+
}
155+
else
156+
{
157+
_headerMemory = frame.TakeoverPayload(Framing.Header.HeaderArgumentOffset);
158+
}
168159

169160
_remainingBodyByteCount = (int)totalBodyBytes;
170161
UpdateContentBodyState();
171-
return _rentedHeaderArray.Length == 0;
172162
}
173163

174-
private bool ParseBodyFrame(in InboundFrame frame)
164+
private void ParseBodyFrame(InboundFrame frame)
175165
{
176166
if (frame.Type != FrameType.FrameBody)
177167
{
@@ -184,27 +174,26 @@ private bool ParseBodyFrame(in InboundFrame frame)
184174
throw new MalformedFrameException($"Overlong content body received - {_remainingBodyByteCount} bytes remaining, {payloadLength} bytes received");
185175
}
186176

187-
if (_rentedBodyArray is null)
177+
if (_bodyMemory.RentedArray is null)
188178
{
189179
// check for single frame payload for an early exit
190180
if (payloadLength == _remainingBodyByteCount)
191181
{
192-
_rentedBodyArray = frame.TakeoverPayload();
193-
_bodyMemory = frame.Payload;
182+
_bodyMemory = frame.TakeoverPayload(0);
194183
_state = AssemblyState.Complete;
195-
return false;
184+
return;
196185
}
197186

198187
// Is returned by IncomingCommand.ReturnPayload in Session.HandleFrame
199-
_rentedBodyArray = ArrayPool<byte>.Shared.Rent(_remainingBodyByteCount);
200-
_bodyMemory = new ReadOnlyMemory<byte>(_rentedBodyArray, 0, _remainingBodyByteCount);
188+
var rentedBodyArray = ArrayPool<byte>.Shared.Rent(_remainingBodyByteCount);
189+
_bodyMemory = new RentedMemory(new ReadOnlyMemory<byte>(rentedBodyArray, 0, _remainingBodyByteCount), rentedBodyArray);
201190
}
202191

203-
frame.Payload.Span.CopyTo(_rentedBodyArray.AsSpan(_offset));
192+
frame.Payload.Span.CopyTo(_bodyMemory.RentedArray.AsSpan(_offset));
193+
frame.TryReturnPayload();
204194
_remainingBodyByteCount -= payloadLength;
205195
_offset += payloadLength;
206196
UpdateContentBodyState();
207-
return true;
208197
}
209198

210199
private void UpdateContentBodyState()

projects/RabbitMQ.Client/client/impl/Connection.Receive.cs

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -123,29 +123,30 @@ await FinishCloseAsync(cts.Token)
123123

124124
private async Task ReceiveLoopAsync(CancellationToken mainLoopCancellationToken)
125125
{
126+
InboundFrame frame = new InboundFrame();
127+
126128
while (false == _closed)
127129
{
128130
mainLoopCancellationToken.ThrowIfCancellationRequested();
129131

130-
while (_frameHandler.TryReadFrame(out InboundFrame frame))
132+
while (_frameHandler.TryReadFrame(frame))
131133
{
132134
NotifyHeartbeatListener();
133135
await ProcessFrameAsync(frame, mainLoopCancellationToken)
134136
.ConfigureAwait(false);
135137
}
136138

137139
// Done reading frames synchronously, go async
138-
InboundFrame asyncFrame = await _frameHandler.ReadFrameAsync(mainLoopCancellationToken)
140+
await _frameHandler.ReadFrameAsync(frame, mainLoopCancellationToken)
139141
.ConfigureAwait(false);
140142
NotifyHeartbeatListener();
141-
await ProcessFrameAsync(asyncFrame, mainLoopCancellationToken)
142-
.ConfigureAwait(false);
143+
await ProcessFrameAsync(frame, mainLoopCancellationToken)
144+
.ConfigureAwait(false);
143145
}
144146
}
145147

146148
private async Task ProcessFrameAsync(InboundFrame frame, CancellationToken cancellationToken)
147149
{
148-
bool shallReturnPayload = true;
149150
if (frame.Channel == 0)
150151
{
151152
if (frame.Type == FrameType.FrameHeartbeat)
@@ -164,7 +165,7 @@ private async Task ProcessFrameAsync(InboundFrame frame, CancellationToken cance
164165
// quiescing situation, even though technically we
165166
// should be ignoring everything except
166167
// connection.close-ok.
167-
shallReturnPayload = await _session0.HandleFrameAsync(frame, cancellationToken)
168+
await _session0.HandleFrameAsync(frame, cancellationToken)
168169
.ConfigureAwait(false);
169170
}
170171
}
@@ -182,15 +183,12 @@ private async Task ProcessFrameAsync(InboundFrame frame, CancellationToken cance
182183
// Session itself may be quiescing this particular
183184
// channel, but that's none of our concern.)
184185
ISession session = _sessionManager.Lookup(frame.Channel);
185-
shallReturnPayload = await session.HandleFrameAsync(frame, cancellationToken)
186+
await session.HandleFrameAsync(frame, cancellationToken)
186187
.ConfigureAwait(false);
187188
}
188189
}
189190

190-
if (shallReturnPayload)
191-
{
192-
frame.ReturnPayload();
193-
}
191+
frame.TryReturnPayload();
194192
}
195193

196194
///<remarks>

0 commit comments

Comments
 (0)