Skip to content

Commit 2e3e0f6

Browse files
committed
Add option to reuse buffers for interleaved frames
1 parent 208d828 commit 2e3e0f6

File tree

4 files changed

+62
-4
lines changed

4 files changed

+62
-4
lines changed

client.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,8 @@ type Client struct {
251251
BytesReceived *uint64
252252
// pointer to a variable that stores sent bytes.
253253
BytesSent *uint64
254+
// enable reuse of buffers for incoming packets.
255+
BufferReuseEnable bool
254256

255257
//
256258
// system functions (all optional)
@@ -883,7 +885,11 @@ func (c *Client) connOpen() error {
883885

884886
c.nconn = nconn
885887
bc := bytecounter.New(c.nconn, c.BytesReceived, c.BytesSent)
886-
c.conn = conn.NewConn(bc)
888+
if c.BufferReuseEnable {
889+
c.conn = conn.NewConn(bc, conn.ConnOptionFrameBufferReuseEnable(true))
890+
} else {
891+
c.conn = conn.NewConn(bc)
892+
}
887893
c.reader = &clientReader{
888894
c: c,
889895
}

pkg/base/interleaved_frame.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,13 @@ func (f *InterleavedFrame) Unmarshal(br *bufio.Reader) error {
3737
payloadLen := int(uint16(header[2])<<8 | uint16(header[3]))
3838

3939
f.Channel = int(header[1])
40-
f.Payload = make([]byte, payloadLen)
41-
40+
if cap(f.Payload) < payloadLen {
41+
// if there's not enough space, extend the buffer
42+
f.Payload = append(f.Payload[:cap(f.Payload)], make([]byte, payloadLen-cap(f.Payload))...)
43+
} else {
44+
// otherwise, set the len of the buffer to the payloadLen
45+
f.Payload = f.Payload[:payloadLen]
46+
}
4247
_, err = io.ReadFull(br, f.Payload)
4348
return err
4449
}

pkg/conn/conn.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,28 @@ type Conn struct {
1919

2020
// reuse interleaved frames. they should never be passed to secondary routines
2121
fr base.InterleavedFrame
22+
23+
frameBufferReuseEnable bool
2224
}
2325

2426
// NewConn allocates a Conn.
25-
func NewConn(rw io.ReadWriter) *Conn {
27+
func NewConn(rw io.ReadWriter, opts ...ConnOption) *Conn {
2628
return &Conn{
2729
w: rw,
2830
br: bufio.NewReaderSize(rw, readBufferSize),
2931
}
3032
}
3133

34+
// ConnOption is an option for Conn.
35+
type ConnOption func(c *Conn)
36+
37+
// ConnOptionFrameBufferReuseEnable enables buffer reuse.
38+
func ConnOptionFrameBufferReuseEnable(v bool) ConnOption {
39+
return func(c *Conn) {
40+
c.frameBufferReuseEnable = v
41+
}
42+
}
43+
3244
// Read reads a Request, a Response or an Interleaved frame.
3345
func (c *Conn) Read() (interface{}, error) {
3446
byts, err := c.br.Peek(2)
@@ -63,6 +75,9 @@ func (c *Conn) ReadResponse() (*base.Response, error) {
6375

6476
// ReadInterleavedFrame reads a InterleavedFrame.
6577
func (c *Conn) ReadInterleavedFrame() (*base.InterleavedFrame, error) {
78+
if !c.frameBufferReuseEnable {
79+
c.fr.Payload = nil // reset the payload, causing a new buffer to be allocated
80+
}
6681
err := c.fr.Unmarshal(c.br)
6782
return &c.fr, err
6883
}

pkg/conn/conn_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,38 @@ func TestRead(t *testing.T) {
7676
}
7777
}
7878

79+
func TestReadInterleavedFrameWithBufferReuse(t *testing.T) {
80+
buf := bytes.NewBuffer([]byte{0x24, 0x6, 0x0, 0x4, 0x1, 0x2, 0x3, 0x4, 0x24, 0x6, 0x0, 0x3, 0x2, 0x3, 0x4, 0x24, 0x6, 0x0, 0x5, 0x3, 0x4, 0x5, 0x6, 0x7})
81+
conn := NewConn(buf)
82+
// read first packet
83+
dec1, err1 := conn.Read()
84+
require.NoError(t, err1)
85+
require.Equal(t, &base.InterleavedFrame{
86+
Channel: 6,
87+
Payload: []byte{0x01, 0x02, 0x03, 0x04},
88+
}, dec1)
89+
p1 := &dec1.(*base.InterleavedFrame).Payload
90+
// read second packet
91+
dec2, err2 := conn.Read()
92+
require.NoError(t, err2)
93+
require.Equal(t, &base.InterleavedFrame{
94+
Channel: 6,
95+
Payload: []byte{0x02, 0x03, 0x04},
96+
}, dec2)
97+
p2 := &dec2.(*base.InterleavedFrame).Payload
98+
// read third packet
99+
dec3, err3 := conn.Read()
100+
require.NoError(t, err3)
101+
require.Equal(t, &base.InterleavedFrame{
102+
Channel: 6,
103+
Payload: []byte{0x03, 0x04, 0x05, 0x06, 0x07},
104+
}, dec3)
105+
p3 := &dec3.(*base.InterleavedFrame).Payload
106+
// assert that the buffer was reused
107+
require.Equal(t, p1, p2)
108+
require.Equal(t, p2, p3)
109+
}
110+
79111
func TestReadError(t *testing.T) {
80112
var buf bytes.Buffer
81113
conn := NewConn(&buf)

0 commit comments

Comments
 (0)