From ddb026e8a889e96b9bdb10da05de36f13fd2c913 Mon Sep 17 00:00:00 2001 From: Easwar Swaminathan Date: Thu, 12 Oct 2023 18:29:29 -0700 Subject: [PATCH] experimental: add package and move recv buffer pool APIs into it (#6692) --- benchmark/benchmain/main.go | 5 +- dialoptions.go | 11 ++-- experimental/experimental.go | 65 +++++++++++++++++++ .../shared_buffer_pool_test.go | 23 +++++-- internal/experimental.go | 28 ++++++++ server.go | 11 ++-- 6 files changed, 128 insertions(+), 15 deletions(-) create mode 100644 experimental/experimental.go rename test/recv_buffer_pool_test.go => experimental/shared_buffer_pool_test.go (80%) create mode 100644 internal/experimental.go diff --git a/benchmark/benchmain/main.go b/benchmark/benchmain/main.go index ec26909ba79d..37ba489f3386 100644 --- a/benchmark/benchmain/main.go +++ b/benchmark/benchmain/main.go @@ -66,6 +66,7 @@ import ( "google.golang.org/grpc/benchmark/latency" "google.golang.org/grpc/benchmark/stats" "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/experimental" "google.golang.org/grpc/grpclog" "google.golang.org/grpc/internal/channelz" "google.golang.org/grpc/keepalive" @@ -348,8 +349,8 @@ func makeClients(bf stats.Features) ([]testgrpc.BenchmarkServiceClient, func()) case recvBufferPoolNil: // Do nothing. case recvBufferPoolSimple: - opts = append(opts, grpc.WithRecvBufferPool(grpc.NewSharedBufferPool())) - sopts = append(sopts, grpc.RecvBufferPool(grpc.NewSharedBufferPool())) + opts = append(opts, experimental.WithRecvBufferPool(grpc.NewSharedBufferPool())) + sopts = append(sopts, experimental.RecvBufferPool(grpc.NewSharedBufferPool())) default: logger.Fatalf("Unknown shared recv buffer pool type: %v", bf.RecvBufferPool) } diff --git a/dialoptions.go b/dialoptions.go index cfc9fd85e8dd..91f6c17aae71 100644 --- a/dialoptions.go +++ b/dialoptions.go @@ -46,6 +46,7 @@ func init() { internal.WithBinaryLogger = withBinaryLogger internal.JoinDialOptions = newJoinDialOption internal.DisableGlobalDialOptions = newDisableGlobalDialOptions + internal.WithRecvBufferPool = withRecvBufferPool } // dialOptions configure a Dial call. dialOptions are set by the DialOption @@ -705,11 +706,13 @@ func WithIdleTimeout(d time.Duration) DialOption { // options are used: WithStatsHandler, EnableTracing, or binary logging. In such // cases, the shared buffer pool will be ignored. // -// # Experimental -// -// Notice: This API is EXPERIMENTAL and may be changed or removed in a -// later release. +// Deprecated: use experimental.WithRecvBufferPool instead. Will be deleted in +// v1.60.0 or later. func WithRecvBufferPool(bufferPool SharedBufferPool) DialOption { + return withRecvBufferPool(bufferPool) +} + +func withRecvBufferPool(bufferPool SharedBufferPool) DialOption { return newFuncDialOption(func(o *dialOptions) { o.recvBufferPool = bufferPool }) diff --git a/experimental/experimental.go b/experimental/experimental.go new file mode 100644 index 000000000000..de7f13a2210e --- /dev/null +++ b/experimental/experimental.go @@ -0,0 +1,65 @@ +/* + * + * Copyright 2023 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Package experimental is a collection of experimental features that might +// have some rough edges to them. Housing experimental features in this package +// results in a user accessing these APIs as `experimental.Foo`, thereby making +// it explicit that the feature is experimental and using them in production +// code is at their own risk. +// +// All APIs in this package are experimental. +package experimental + +import ( + "google.golang.org/grpc" + "google.golang.org/grpc/internal" +) + +// WithRecvBufferPool returns a grpc.DialOption that configures the use of +// bufferPool for parsing incoming messages on a grpc.ClientConn. Depending on +// the application's workload, this could result in reduced memory allocation. +// +// If you are unsure about how to implement a memory pool but want to utilize +// one, begin with grpc.NewSharedBufferPool. +// +// Note: The shared buffer pool feature will not be active if any of the +// following options are used: WithStatsHandler, EnableTracing, or binary +// logging. In such cases, the shared buffer pool will be ignored. +// +// Note: It is not recommended to use the shared buffer pool when compression is +// enabled. +func WithRecvBufferPool(bufferPool grpc.SharedBufferPool) grpc.DialOption { + return internal.WithRecvBufferPool.(func(grpc.SharedBufferPool) grpc.DialOption)(bufferPool) +} + +// RecvBufferPool returns a grpc.ServerOption that configures the server to use +// the provided shared buffer pool for parsing incoming messages. Depending on +// the application's workload, this could result in reduced memory allocation. +// +// If you are unsure about how to implement a memory pool but want to utilize +// one, begin with grpc.NewSharedBufferPool. +// +// Note: The shared buffer pool feature will not be active if any of the +// following options are used: StatsHandler, EnableTracing, or binary logging. +// In such cases, the shared buffer pool will be ignored. +// +// Note: It is not recommended to use the shared buffer pool when compression is +// enabled. +func RecvBufferPool(bufferPool grpc.SharedBufferPool) grpc.ServerOption { + return internal.RecvBufferPool.(func(grpc.SharedBufferPool) grpc.ServerOption)(bufferPool) +} diff --git a/test/recv_buffer_pool_test.go b/experimental/shared_buffer_pool_test.go similarity index 80% rename from test/recv_buffer_pool_test.go rename to experimental/shared_buffer_pool_test.go index 9e7b4aaaea6b..c13b2dc02213 100644 --- a/test/recv_buffer_pool_test.go +++ b/experimental/shared_buffer_pool_test.go @@ -16,20 +16,34 @@ * */ -package test +package experimental_test import ( "bytes" "context" "io" "testing" + "time" "google.golang.org/grpc" + "google.golang.org/grpc/experimental" + "google.golang.org/grpc/internal/grpctest" "google.golang.org/grpc/internal/stubserver" + testgrpc "google.golang.org/grpc/interop/grpc_testing" testpb "google.golang.org/grpc/interop/grpc_testing" ) +type s struct { + grpctest.Tester +} + +func Test(t *testing.T) { + grpctest.RunSubTests(t, s{}) +} + +const defaultTestTimeout = 10 * time.Second + func (s) TestRecvBufferPool(t *testing.T) { ss := &stubserver.StubServer{ FullDuplexCallF: func(stream testgrpc.TestService_FullDuplexCallServer) error { @@ -48,10 +62,9 @@ func (s) TestRecvBufferPool(t *testing.T) { return nil }, } - if err := ss.Start( - []grpc.ServerOption{grpc.RecvBufferPool(grpc.NewSharedBufferPool())}, - grpc.WithRecvBufferPool(grpc.NewSharedBufferPool()), - ); err != nil { + sopts := []grpc.ServerOption{experimental.RecvBufferPool(grpc.NewSharedBufferPool())} + dopts := []grpc.DialOption{experimental.WithRecvBufferPool(grpc.NewSharedBufferPool())} + if err := ss.Start(sopts, dopts...); err != nil { t.Fatalf("Error starting endpoint server: %v", err) } defer ss.Stop() diff --git a/internal/experimental.go b/internal/experimental.go new file mode 100644 index 000000000000..7f7044e1731c --- /dev/null +++ b/internal/experimental.go @@ -0,0 +1,28 @@ +/* + * Copyright 2023 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package internal + +var ( + // WithRecvBufferPool is implemented by the grpc package and returns a dial + // option to configure a shared buffer pool for a grpc.ClientConn. + WithRecvBufferPool any // func (grpc.SharedBufferPool) grpc.DialOption + + // RecvBufferPool is implemented by the grpc package and returns a server + // option to configure a shared buffer pool for a grpc.Server. + RecvBufferPool any // func (grpc.SharedBufferPool) grpc.ServerOption +) diff --git a/server.go b/server.go index 9780a767d142..24699c0b6047 100644 --- a/server.go +++ b/server.go @@ -81,6 +81,7 @@ func init() { } internal.BinaryLogger = binaryLogger internal.JoinServerOptions = newJoinServerOption + internal.RecvBufferPool = recvBufferPool } var statusOK = status.New(codes.OK, "") @@ -578,11 +579,13 @@ func NumStreamWorkers(numServerWorkers uint32) ServerOption { // options are used: StatsHandler, EnableTracing, or binary logging. In such // cases, the shared buffer pool will be ignored. // -// # Experimental -// -// Notice: This API is EXPERIMENTAL and may be changed or removed in a -// later release. +// Deprecated: use experimental.WithRecvBufferPool instead. Will be deleted in +// v1.60.0 or later. func RecvBufferPool(bufferPool SharedBufferPool) ServerOption { + return recvBufferPool(bufferPool) +} + +func recvBufferPool(bufferPool SharedBufferPool) ServerOption { return newFuncServerOption(func(o *serverOptions) { o.recvBufferPool = bufferPool })