Skip to content

Commit cd563b8

Browse files
Muir Mandersdfawley
authored andcommitted
protoCodec: avoid buffer allocations if proto.Marshaler/Unmarshaler (grpc#1689)
* protoCodec: return early if proto.Marshaler If the object to marshal implements proto.Marshaler, delegate to that immediately instead of pre-allocating a buffer. (*proto.Buffer).Marshal has the same logic, so the []byte buffer we pre-allocate in codec.go would never be used. This is mainly for users of gogoproto. If you turn on the "marshaler" and "sizer" gogoproto options, the generated Marshal() method already pre-allocates a buffer of the appropriate size for marshaling the entire object. * protoCodec: return early if proto.Unmarshaler If the object to unmarshal implements proto.Unmarshaler, delegate to that immediately. This perhaps saves a bit of work preparing the cached the proto.Buffer object which would not end up being used for the proto.Unmarshaler case. Note that I moved the obj.Reset() call above the delegation to obj.Unmarshal(). This maintains the grpc behavior of proto.Unmarshalers always being Reset() before being delegated to, which is consistent to how proto.Unmarshal() behaves (proto.Buffer does not call Reset() in Unmarshal).
1 parent 61c6740 commit cd563b8

File tree

1 file changed

+14
-2
lines changed

1 file changed

+14
-2
lines changed

codec.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ func (p protoCodec) marshal(v interface{}, cb *cachedProtoBuffer) ([]byte, error
6969
}
7070

7171
func (p protoCodec) Marshal(v interface{}) ([]byte, error) {
72+
if pm, ok := v.(proto.Marshaler); ok {
73+
// object can marshal itself, no need for buffer
74+
return pm.Marshal()
75+
}
76+
7277
cb := protoBufferPool.Get().(*cachedProtoBuffer)
7378
out, err := p.marshal(v, cb)
7479

@@ -79,10 +84,17 @@ func (p protoCodec) Marshal(v interface{}) ([]byte, error) {
7984
}
8085

8186
func (p protoCodec) Unmarshal(data []byte, v interface{}) error {
87+
protoMsg := v.(proto.Message)
88+
protoMsg.Reset()
89+
90+
if pu, ok := protoMsg.(proto.Unmarshaler); ok {
91+
// object can unmarshal itself, no need for buffer
92+
return pu.Unmarshal(data)
93+
}
94+
8295
cb := protoBufferPool.Get().(*cachedProtoBuffer)
8396
cb.SetBuf(data)
84-
v.(proto.Message).Reset()
85-
err := cb.Unmarshal(v.(proto.Message))
97+
err := cb.Unmarshal(protoMsg)
8698
cb.SetBuf(nil)
8799
protoBufferPool.Put(cb)
88100
return err

0 commit comments

Comments
 (0)