@@ -9,10 +9,36 @@ import (
99 "context"
1010
1111 "github.com/cockroachdb/cockroach/pkg/roachpb"
12+ "github.com/cockroachdb/cockroach/pkg/settings"
13+ "github.com/cockroachdb/cockroach/pkg/settings/cluster"
14+ "github.com/cockroachdb/cockroach/pkg/util/buildutil"
15+ "github.com/cockroachdb/cockroach/pkg/util/envutil"
16+ "github.com/cockroachdb/errors"
1217 "google.golang.org/grpc"
1318 "storj.io/drpc"
1419)
1520
21+ var envExperimentalDRPCEnabled = envutil .EnvOrDefaultBool ("COCKROACH_EXPERIMENTAL_DRPC_ENABLED" , false )
22+
23+ // ExperimentalDRPCEnabled determines whether a drpc server accepting BatchRequest
24+ // is enabled. This server is experimental and completely unsuitable to production
25+ // usage (for example, does not implement authorization checks).
26+ var ExperimentalDRPCEnabled = settings .RegisterBoolSetting (
27+ settings .ApplicationLevel ,
28+ "rpc.experimental_drpc.enabled" ,
29+ "if true, use drpc to execute Batch RPCs (instead of gRPC)" ,
30+ envExperimentalDRPCEnabled ,
31+ settings .WithValidateBool (func (values * settings.Values , b bool ) error {
32+ // drpc support is highly experimental and should not be enabled in production.
33+ // Since authorization is not implemented, we only even host the server if the
34+ // env var is set or it's a CRDB test build. Consequently, these are prereqs
35+ // for setting the cluster setting.
36+ if b && ! (envExperimentalDRPCEnabled || buildutil .CrdbTestBuild ) {
37+ return errors .New ("experimental drpc is not allowed in this environment" )
38+ }
39+ return nil
40+ }))
41+
1642// TODODRPC is a marker to identify each RPC client creation site that needs to
1743// be updated to support DRPC.
1844const TODODRPC = false
@@ -31,3 +57,62 @@ type NodeDialerNoBreaker interface {
3157 DialNoBreaker (context.Context , roachpb.NodeID , ConnectionClass ) (_ * grpc.ClientConn , err error )
3258 DRPCDialNoBreaker (context.Context , roachpb.NodeID , ConnectionClass ) (_ drpc.Conn , err error )
3359}
60+
61+ // DialRPCClient establishes a connection to a node identified by its ID and
62+ // returns a client for the requested service type. When DRPC is enabled, it
63+ // creates a DRPC client; otherwise, it falls back to a gRPC client.
64+ func DialRPCClient [C any ](
65+ nd NodeDialer ,
66+ ctx context.Context ,
67+ nodeID roachpb.NodeID ,
68+ class ConnectionClass ,
69+ grpcClientFn func (* grpc.ClientConn ) C ,
70+ drpcClientFn func (drpc.Conn ) C ,
71+ st * cluster.Settings ,
72+ ) (C , error ) {
73+ useDRPC := ExperimentalDRPCEnabled .Get (& st .SV )
74+
75+ var nilC C
76+ if ! TODODRPC && ! useDRPC {
77+ conn , err := nd .Dial (ctx , nodeID , class )
78+ if err != nil {
79+ return nilC , err
80+ }
81+ return grpcClientFn (conn ), nil
82+ }
83+
84+ conn , err := nd .DRPCDial (ctx , nodeID , class )
85+ if err != nil {
86+ return nilC , err
87+ }
88+ return drpcClientFn (conn ), nil
89+ }
90+
91+ // DialRPCClientNoBreaker is like DialRPCClient, but will not check the
92+ // circuit breaker before trying to connect.
93+ func DialRPCClientNoBreaker [C any ](
94+ nd NodeDialerNoBreaker ,
95+ ctx context.Context ,
96+ nodeID roachpb.NodeID ,
97+ class ConnectionClass ,
98+ grpcClientFn func (* grpc.ClientConn ) C ,
99+ drpcClientFn func (drpc.Conn ) C ,
100+ st * cluster.Settings ,
101+ ) (C , error ) {
102+ useDRPC := ExperimentalDRPCEnabled .Get (& st .SV )
103+
104+ var nilC C
105+ if ! TODODRPC && ! useDRPC {
106+ conn , err := nd .DialNoBreaker (ctx , nodeID , class )
107+ if err != nil {
108+ return nilC , err
109+ }
110+ return grpcClientFn (conn ), nil
111+ }
112+
113+ conn , err := nd .DRPCDialNoBreaker (ctx , nodeID , class )
114+ if err != nil {
115+ return nilC , err
116+ }
117+ return drpcClientFn (conn ), nil
118+ }
0 commit comments