Skip to content

Commit 646c289

Browse files
Merge pull request #443 from Pliner/reduce-outbound-frame-allocations
Reduce outbound frame allocations
2 parents b4decec + 6cac825 commit 646c289

File tree

4 files changed

+72
-61
lines changed

4 files changed

+72
-61
lines changed

projects/client/RabbitMQ.Client/RabbitMQ.Client.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@
4040
<DefineConstants>$(DefineConstants);CORECLR</DefineConstants>
4141
</PropertyGroup>
4242

43+
<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard1.5'">
44+
<DefineConstants>$(DefineConstants);CORECLR15</DefineConstants>
45+
</PropertyGroup>
46+
4347
<PropertyGroup Condition=" '$(Configuration)' == 'SignedRelease' ">
4448
<DelaySign>true</DelaySign>
4549
<OutputType>Library</OutputType>

projects/client/RabbitMQ.Client/src/client/impl/ExtensionMethods.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040

4141
using System;
4242
using System.Collections.Generic;
43+
using System.IO;
4344
using System.Linq;
4445

4546
namespace RabbitMQ.Client.Impl
@@ -63,5 +64,16 @@ public static T RandomItem<T>(this IList<T> list)
6364
var hashCode = Math.Abs(Guid.NewGuid().GetHashCode());
6465
return list.ElementAt<T>(hashCode % n);
6566
}
67+
68+
internal static ArraySegment<byte> GetBufferSegment(this MemoryStream ms)
69+
{
70+
#if CORECLR15
71+
var payload = ms.ToArray();
72+
return new ArraySegment<byte>(payload, 0, payload.Length);
73+
#else
74+
var buffer = ms.GetBuffer();
75+
return new ArraySegment<byte>(buffer, 0, (int)ms.Position);
76+
#endif
77+
}
6678
}
6779
}

projects/client/RabbitMQ.Client/src/client/impl/Frame.cs

Lines changed: 50 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -56,98 +56,103 @@ namespace RabbitMQ.Client.Impl
5656
{
5757
public class HeaderOutboundFrame : OutboundFrame
5858
{
59+
private readonly ContentHeaderBase header;
60+
private readonly int bodyLength;
61+
5962
public HeaderOutboundFrame(int channel, ContentHeaderBase header, int bodyLength) : base(FrameType.FrameHeader, channel)
6063
{
61-
NetworkBinaryWriter writer = base.GetWriter();
64+
this.header = header;
65+
this.bodyLength = bodyLength;
66+
}
67+
68+
public override void WritePayload(NetworkBinaryWriter writer)
69+
{
70+
var ms = new MemoryStream();
71+
var nw = new NetworkBinaryWriter(ms);
72+
73+
nw.Write(header.ProtocolClassId);
74+
header.WriteTo(nw, (ulong)bodyLength);
6275

63-
writer.Write(header.ProtocolClassId);
64-
header.WriteTo(writer, (ulong)bodyLength);
76+
var bufferSegment = ms.GetBufferSegment();
77+
writer.Write((uint)bufferSegment.Count);
78+
writer.Write(bufferSegment.Array, bufferSegment.Offset, bufferSegment.Count);
6579
}
6680
}
6781

6882
public class BodySegmentOutboundFrame : OutboundFrame
6983
{
84+
private readonly byte[] body;
85+
private readonly int offset;
86+
private readonly int count;
87+
7088
public BodySegmentOutboundFrame(int channel, byte[] body, int offset, int count) : base(FrameType.FrameBody, channel)
7189
{
72-
NetworkBinaryWriter writer = base.GetWriter();
90+
this.body = body;
91+
this.offset = offset;
92+
this.count = count;
93+
}
7394

95+
public override void WritePayload(NetworkBinaryWriter writer)
96+
{
97+
writer.Write((uint)count);
7498
writer.Write(body, offset, count);
7599
}
76100
}
77101

78102
public class MethodOutboundFrame : OutboundFrame
79103
{
104+
private readonly MethodBase method;
105+
80106
public MethodOutboundFrame(int channel, MethodBase method) : base(FrameType.FrameMethod, channel)
81107
{
82-
NetworkBinaryWriter writer = base.GetWriter();
108+
this.method = method;
109+
}
83110

84-
writer.Write(method.ProtocolClassId);
85-
writer.Write(method.ProtocolMethodId);
111+
public override void WritePayload(NetworkBinaryWriter writer)
112+
{
113+
var ms = new MemoryStream();
114+
var nw = new NetworkBinaryWriter(ms);
86115

87-
var argWriter = new MethodArgumentWriter(writer);
116+
nw.Write(method.ProtocolClassId);
117+
nw.Write(method.ProtocolMethodId);
88118

119+
var argWriter = new MethodArgumentWriter(nw);
89120
method.WriteArgumentsTo(argWriter);
90-
91121
argWriter.Flush();
122+
123+
var bufferSegment = ms.GetBufferSegment();
124+
writer.Write((uint)bufferSegment.Count);
125+
writer.Write(bufferSegment.Array, bufferSegment.Offset, bufferSegment.Count);
92126
}
93127
}
94128

95129
public class EmptyOutboundFrame : OutboundFrame
96130
{
97-
private static readonly byte[] m_emptyByteArray = new byte[0];
98-
99131
public EmptyOutboundFrame() : base(FrameType.FrameHeartbeat, 0)
100132
{
101-
base.GetWriter().Write(m_emptyByteArray);
102133
}
103134

104-
public override string ToString()
135+
public override void WritePayload(NetworkBinaryWriter writer)
105136
{
106-
return base.ToString() + string.Format("(type={0}, channel={1}, {2} bytes of payload)",
107-
Type,
108-
Channel,
109-
Payload == null
110-
? "(null)"
111-
: Payload.Length.ToString());
137+
writer.Write((uint)0);
112138
}
113139
}
114140

115-
public class OutboundFrame : Frame
141+
public abstract class OutboundFrame : Frame
116142
{
117-
private readonly MemoryStream m_accumulator;
118-
private readonly NetworkBinaryWriter writer;
119-
120143
public OutboundFrame(FrameType type, int channel) : base(type, channel)
121144
{
122-
m_accumulator = new MemoryStream();
123-
writer = new NetworkBinaryWriter(m_accumulator);
124-
}
125-
126-
public NetworkBinaryWriter GetWriter()
127-
{
128-
return writer;
129-
}
130-
131-
public override string ToString()
132-
{
133-
return base.ToString() + string.Format("(type={0}, channel={1}, {2} bytes of payload)",
134-
Type,
135-
Channel,
136-
Payload == null
137-
? "(null)"
138-
: Payload.Length.ToString());
139145
}
140146

141147
public void WriteTo(NetworkBinaryWriter writer)
142148
{
143-
var payload = m_accumulator.ToArray();
144-
145149
writer.Write((byte)Type);
146150
writer.Write((ushort)Channel);
147-
writer.Write((uint)payload.Length);
148-
writer.Write(payload);
151+
WritePayload(writer);
149152
writer.Write((byte)Constants.FrameEnd);
150153
}
154+
155+
public abstract void WritePayload(NetworkBinaryWriter writer);
151156
}
152157

153158
public class InboundFrame : Frame
@@ -252,16 +257,6 @@ public NetworkBinaryReader GetReader()
252257
{
253258
return new NetworkBinaryReader(new MemoryStream(base.Payload));
254259
}
255-
256-
public override string ToString()
257-
{
258-
return base.ToString() + string.Format("(type={0}, channel={1}, {2} bytes of payload)",
259-
base.Type,
260-
base.Channel,
261-
base.Payload == null
262-
? "(null)"
263-
: base.Payload.Length.ToString());
264-
}
265260
}
266261

267262
public class Frame
@@ -288,7 +283,7 @@ public Frame(FrameType type, int channel, byte[] payload)
288283

289284
public override string ToString()
290285
{
291-
return base.ToString() + string.Format("(type={0}, channel={1}, {2} bytes of payload)",
286+
return string.Format("(type={0}, channel={1}, {2} bytes of payload)",
292287
Type,
293288
Channel,
294289
Payload == null

projects/client/RabbitMQ.Client/src/client/impl/SocketFrameHandler.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ public void SendHeader()
222222
nbw.Write((byte)Endpoint.Protocol.MajorVersion);
223223
nbw.Write((byte)Endpoint.Protocol.MinorVersion);
224224
}
225-
Write(ms.ToArray());
225+
Write(ms.GetBufferSegment());
226226
}
227227

228228
public void WriteFrame(OutboundFrame frame)
@@ -231,7 +231,7 @@ public void WriteFrame(OutboundFrame frame)
231231
var nbw = new NetworkBinaryWriter(ms);
232232
frame.WriteTo(nbw);
233233
m_socket.Client.Poll(m_writeableStateTimeout, SelectMode.SelectWrite);
234-
Write(ms.ToArray());
234+
Write(ms.GetBufferSegment());
235235
}
236236

237237
public void WriteFrameSet(IList<OutboundFrame> frames)
@@ -240,21 +240,21 @@ public void WriteFrameSet(IList<OutboundFrame> frames)
240240
var nbw = new NetworkBinaryWriter(ms);
241241
foreach (var f in frames) f.WriteTo(nbw);
242242
m_socket.Client.Poll(m_writeableStateTimeout, SelectMode.SelectWrite);
243-
Write(ms.ToArray());
243+
Write(ms.GetBufferSegment());
244244
}
245245

246-
private void Write(byte [] buffer)
246+
private void Write(ArraySegment<byte> bufferSegment)
247247
{
248248
if(_ssl)
249249
{
250250
lock (_sslStreamLock)
251251
{
252-
m_writer.Write(buffer);
252+
m_writer.Write(bufferSegment.Array, bufferSegment.Offset, bufferSegment.Count);
253253
}
254254
}
255255
else
256256
{
257-
m_writer.Write(buffer);
257+
m_writer.Write(bufferSegment.Array, bufferSegment.Offset, bufferSegment.Count);
258258
}
259259
}
260260

0 commit comments

Comments
 (0)