Skip to content

Commit bae37e3

Browse files
committed
grpc: Add useBytesPoolForParser option
1 parent cb8827d commit bae37e3

File tree

4 files changed

+42
-4
lines changed

4 files changed

+42
-4
lines changed

dialoptions.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ type dialOptions struct {
7676
defaultServiceConfig *ServiceConfig // defaultServiceConfig is parsed from defaultServiceConfigRawJSON.
7777
defaultServiceConfigRawJSON *string
7878
resolvers []resolver.Builder
79+
useBytesPoolForParser bool
7980
}
8081

8182
// DialOption configures how we set up the connection.
@@ -635,3 +636,17 @@ func WithResolvers(rs ...resolver.Builder) DialOption {
635636
o.resolvers = append(o.resolvers, rs...)
636637
})
637638
}
639+
640+
// WithUseBytesPoolForParser returns a DialOption that specifies whether to use
641+
// a bytes pool for parsing. Setting this to true will reduce the memory allocation
642+
// in the parser.
643+
//
644+
// # Experimental
645+
//
646+
// Notice: This API is EXPERIMENTAL and may be changed or removed in a
647+
// later release.
648+
func WithUseBytesPoolForParser(useBytesPoolForParser bool) DialOption {
649+
return newFuncDialOption(func(o *dialOptions) {
650+
o.useBytesPoolForParser = useBytesPoolForParser
651+
})
652+
}

rpc_util.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,9 @@ type parser struct {
541541
// The header of a gRPC message. Find more detail at
542542
// https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md
543543
header [5]byte
544+
545+
// useBytesPool indicates whether to use bytes pool to allocate
546+
useBytesPool bool
544547
}
545548

546549
// recvMsg reads a complete gRPC message from the stream.
@@ -574,7 +577,11 @@ func (p *parser) recvMsg(maxReceiveMessageSize int) (pf payloadFormat, msg []byt
574577
if int(length) > maxReceiveMessageSize {
575578
return 0, nil, status.Errorf(codes.ResourceExhausted, "grpc: received message larger than max (%d vs. %d)", length, maxReceiveMessageSize)
576579
}
577-
msg = pool.Get(int(length))
580+
if p.useBytesPool {
581+
msg = pool.Get(int(length))
582+
} else {
583+
msg = make([]byte, int(length))
584+
}
578585
if _, err := p.r.Read(msg); err != nil {
579586
if err == io.EOF {
580587
err = io.ErrUnexpectedEOF
@@ -764,7 +771,9 @@ func recv(p *parser, c baseCodec, s *transport.Stream, dc Decompressor, m interf
764771
payInfo.uncompressedBytes = make([]byte, len(buf))
765772
copy(payInfo.uncompressedBytes, buf)
766773
}
767-
pool.Put(&buf)
774+
if p.useBytesPool {
775+
pool.Put(&buf)
776+
}
768777
return nil
769778
}
770779

server.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ type serverOptions struct {
174174
maxHeaderListSize *uint32
175175
headerTableSize *uint32
176176
numServerWorkers uint32
177+
useBytesPoolForParser bool
177178
}
178179

179180
var defaultServerOptions = serverOptions{
@@ -552,6 +553,19 @@ func NumStreamWorkers(numServerWorkers uint32) ServerOption {
552553
})
553554
}
554555

556+
// UseBytesPoolForParser returns a ServerOption that sets whether to use a bytes pool
557+
// for the parser. Setting this to true will reduce the memory allocation in the parser.
558+
//
559+
// # Experimental
560+
//
561+
// Notice: This API is EXPERIMENTAL and may be changed or removed in a
562+
// later release.
563+
func UseBytesPoolForParser(useBytesPoolForParser bool) ServerOption {
564+
return newFuncServerOption(func(o *serverOptions) {
565+
o.useBytesPoolForParser = useBytesPoolForParser
566+
})
567+
}
568+
555569
// serverWorkerResetThreshold defines how often the stack must be reset. Every
556570
// N requests, by spawning a new goroutine in its place, a worker can reset its
557571
// stack so that large stacks don't live in memory forever. 2^16 should allow

stream.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -490,7 +490,7 @@ func (a *csAttempt) newStream() error {
490490
return toRPCErr(nse.Err)
491491
}
492492
a.s = s
493-
a.p = &parser{r: s}
493+
a.p = &parser{r: s, useBytesPool: a.cs.cc.dopts.useBytesPoolForParser}
494494
return nil
495495
}
496496

@@ -1249,7 +1249,7 @@ func newNonRetryClientStream(ctx context.Context, desc *StreamDesc, method strin
12491249
return nil, err
12501250
}
12511251
as.s = s
1252-
as.p = &parser{r: s}
1252+
as.p = &parser{r: s, useBytesPool: ac.dopts.useBytesPoolForParser}
12531253
ac.incrCallsStarted()
12541254
if desc != unaryStreamDesc {
12551255
// Listen on cc and stream contexts to cleanup when the user closes the

0 commit comments

Comments
 (0)