@@ -9,10 +9,36 @@ import (
9
9
"context"
10
10
11
11
"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"
12
17
"google.golang.org/grpc"
13
18
"storj.io/drpc"
14
19
)
15
20
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
+
16
42
// TODODRPC is a marker to identify each RPC client creation site that needs to
17
43
// be updated to support DRPC.
18
44
const TODODRPC = false
@@ -31,3 +57,62 @@ type NodeDialerNoBreaker interface {
31
57
DialNoBreaker (context.Context , roachpb.NodeID , ConnectionClass ) (_ * grpc.ClientConn , err error )
32
58
DRPCDialNoBreaker (context.Context , roachpb.NodeID , ConnectionClass ) (_ drpc.Conn , err error )
33
59
}
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