Skip to content

Commit 6e38c0c

Browse files
committed
perf(grpc): switch to gRPC CodecV2 for improved performance
This PR updates the gRPC codec from v1 to v2, enhancing performance and reducing memory allocations by utilizing a memory pool for encoded messages. Refs: - grpc/grpc-go#7356 - vitessio/vitess#16790
1 parent cfae896 commit 6e38c0c

1 file changed

Lines changed: 41 additions & 14 deletions

File tree

pkg/rpc/codec.go

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,62 @@
11
package rpc
22

33
import (
4-
gogoproto "github.com/gogo/protobuf/proto"
5-
"github.com/golang/protobuf/proto" //nolint:staticcheck
64
"google.golang.org/grpc/encoding"
5+
"google.golang.org/grpc/mem"
76
)
87

98
const name = "proto"
109

11-
type codec struct{}
10+
type gogoprotoMessage interface {
11+
MarshalToSizedBuffer([]byte) (int, error)
12+
Unmarshal([]byte) error
13+
ProtoSize() int
14+
}
15+
16+
var pool = mem.DefaultBufferPool()
17+
18+
type codec struct {
19+
fallback encoding.CodecV2
20+
}
1221

13-
var _ encoding.Codec = codec{}
22+
var _ encoding.CodecV2 = &codec{}
1423

1524
func init() {
16-
encoding.RegisterCodec(codec{})
25+
encoding.RegisterCodecV2(&codec{
26+
fallback: encoding.GetCodecV2(name),
27+
})
1728
}
1829

19-
func (codec) Marshal(v interface{}) ([]byte, error) {
20-
if m, ok := v.(gogoproto.Marshaler); ok {
21-
return m.Marshal()
30+
func (c *codec) Marshal(v any) (mem.BufferSlice, error) {
31+
if m, ok := v.(gogoprotoMessage); ok {
32+
size := m.ProtoSize()
33+
if mem.IsBelowBufferPoolingThreshold(size) {
34+
buf := make([]byte, size)
35+
if _, err := m.MarshalToSizedBuffer(buf[:size]); err != nil {
36+
return nil, err
37+
}
38+
return mem.BufferSlice{mem.SliceBuffer(buf)}, nil
39+
}
40+
41+
buf := pool.Get(size)
42+
if _, err := m.MarshalToSizedBuffer((*buf)[:size]); err != nil {
43+
pool.Put(buf)
44+
return nil, err
45+
}
46+
return mem.BufferSlice{mem.NewBuffer(buf, pool)}, nil
2247
}
23-
return proto.Marshal(v.(proto.Message))
48+
return c.fallback.Marshal(v)
2449
}
2550

26-
func (codec) Unmarshal(data []byte, v interface{}) error {
27-
if m, ok := v.(gogoproto.Unmarshaler); ok {
28-
return m.Unmarshal(data)
51+
func (c *codec) Unmarshal(data mem.BufferSlice, v any) error {
52+
if m, ok := v.(gogoprotoMessage); ok {
53+
buf := data.MaterializeToBuffer(pool)
54+
defer buf.Free()
55+
return m.Unmarshal(buf.ReadOnlyData())
2956
}
30-
return proto.Unmarshal(data, v.(proto.Message))
57+
return c.fallback.Unmarshal(data, v)
3158
}
3259

33-
func (codec) Name() string {
60+
func (*codec) Name() string {
3461
return name
3562
}

0 commit comments

Comments
 (0)