Skip to content

Commit 9688d93

Browse files
committed
envconfig knob
1 parent e13e8c5 commit 9688d93

File tree

5 files changed

+95
-5
lines changed

5 files changed

+95
-5
lines changed

internal/envconfig/envconfig.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ var (
3636
// "GRPC_RING_HASH_CAP". This does not override the default bounds
3737
// checking which NACKs configs specifying ring sizes > 8*1024*1024 (~8M).
3838
RingHashCap = uint64FromEnv("GRPC_RING_HASH_CAP", 4096, 1, 8*1024*1024)
39+
// PickFirstLBConfig is set if we should support configuration of the
40+
// pick_first LB policy, which can be enabled by setting the environment
41+
// variable "GRPC_EXPERIMENTAL_PICKFIRST_LB_CONFIG" to "true".
42+
PickFirstLBConfig = boolFromEnv("GRPC_EXPERIMENTAL_PICKFIRST_LB_CONFIG", false)
3943
)
4044

4145
func boolFromEnv(envVar string, def bool) bool {

pickfirst.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525

2626
"google.golang.org/grpc/balancer"
2727
"google.golang.org/grpc/connectivity"
28+
"google.golang.org/grpc/internal/envconfig"
2829
"google.golang.org/grpc/internal/grpcrand"
2930
"google.golang.org/grpc/serviceconfig"
3031
)
@@ -112,7 +113,7 @@ func (b *pickfirstBalancer) UpdateClientConnState(state balancer.ClientConnState
112113
b.cfg = cfg
113114
}
114115

115-
if b.cfg != nil && b.cfg.ShuffleAddressList {
116+
if envconfig.PickFirstLBConfig && b.cfg != nil && b.cfg.ShuffleAddressList {
116117
grpcrand.Shuffle(len(addrs), func(i, j int) { addrs[i], addrs[j] = addrs[j], addrs[i] })
117118
}
118119
if b.subConn != nil {

test/pickfirst_test.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"google.golang.org/grpc/connectivity"
3131
"google.golang.org/grpc/credentials/insecure"
3232
"google.golang.org/grpc/internal/channelz"
33+
"google.golang.org/grpc/internal/envconfig"
3334
"google.golang.org/grpc/internal/grpcrand"
3435
"google.golang.org/grpc/internal/stubserver"
3536
"google.golang.org/grpc/internal/testutils"
@@ -382,6 +383,8 @@ func (s) TestPickFirst_StickyTransientFailure(t *testing.T) {
382383
}
383384

384385
func (s) TestPickFirst_ShuffleAddressList(t *testing.T) {
386+
defer func(old bool) { envconfig.PickFirstLBConfig = old }(envconfig.PickFirstLBConfig)
387+
envconfig.PickFirstLBConfig = true
385388
const serviceConfig = `{"loadBalancingConfig": [{"pick_first":{ "shuffleAddressList": true }}]}`
386389

387390
// Install a shuffler that always reverses two entries.
@@ -431,3 +434,58 @@ func (s) TestPickFirst_ShuffleAddressList(t *testing.T) {
431434
t.Fatal(err)
432435
}
433436
}
437+
438+
func (s) TestPickFirst_ShuffleAddressListDisabled(t *testing.T) {
439+
defer func(old bool) { envconfig.PickFirstLBConfig = old }(envconfig.PickFirstLBConfig)
440+
envconfig.PickFirstLBConfig = false
441+
const serviceConfig = `{"loadBalancingConfig": [{"pick_first":{ "shuffleAddressList": true }}]}`
442+
443+
// Install a shuffler that always reverses two entries.
444+
origShuf := grpcrand.Shuffle
445+
defer func() { grpcrand.Shuffle = origShuf }()
446+
grpcrand.Shuffle = func(n int, f func(int, int)) {
447+
if n != 2 {
448+
t.Errorf("Shuffle called with n=%v; want 2", n)
449+
}
450+
f(0, 1) // reverse the two addresses
451+
}
452+
453+
// Set up our backends.
454+
cc, r, backends := setupPickFirst(t, 2)
455+
addrs := stubBackendsToResolverAddrs(backends)
456+
457+
ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
458+
defer cancel()
459+
460+
// Push an update with both addresses and shuffling disabled. We should
461+
// connect to backend 0.
462+
r.UpdateState(resolver.State{Addresses: []resolver.Address{addrs[0], addrs[1]}})
463+
if err := pickfirst.CheckRPCsToBackend(ctx, cc, addrs[0]); err != nil {
464+
t.Fatal(err)
465+
}
466+
467+
// Send a config with shuffling enabled. This will reverse the addresses,
468+
// but the channel should still be connected to backend 0.
469+
shufState := resolver.State{
470+
ServiceConfig: parseServiceConfig(t, r, serviceConfig),
471+
Addresses: []resolver.Address{addrs[0], addrs[1]},
472+
}
473+
r.UpdateState(shufState)
474+
if err := pickfirst.CheckRPCsToBackend(ctx, cc, addrs[0]); err != nil {
475+
t.Fatal(err)
476+
}
477+
478+
// Send a resolver update with no addresses. This should push the channel
479+
// into TransientFailure.
480+
r.UpdateState(resolver.State{})
481+
awaitState(ctx, t, cc, connectivity.TransientFailure)
482+
483+
// Send the same config as last time with shuffling enabled. Since we are
484+
// not connected to backend 0, we should connect to backend 1 if shuffling
485+
// is supported. However with it disabled at the start of the test, we
486+
// will connect to backend 0 instead.
487+
r.UpdateState(shufState)
488+
if err := pickfirst.CheckRPCsToBackend(ctx, cc, addrs[0]); err != nil {
489+
t.Fatal(err)
490+
}
491+
}

xds/internal/xdsclient/xdslbregistry/converter/converter.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ type pfConfig struct {
9797
}
9898

9999
func convertPickFirstProtoToServiceConfig(rawProto []byte, _ int) (json.RawMessage, error) {
100+
if !envconfig.PickFirstLBConfig {
101+
return nil, nil
102+
}
100103
pfProto := &v3pickfirstpb.PickFirst{}
101104
if err := proto.Unmarshal(rawProto, pfProto); err != nil {
102105
return nil, fmt.Errorf("failed to unmarshal resource: %v", err)

xds/internal/xdsclient/xdslbregistry/xdslbregistry_test.go

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ func (s) TestConvertToServiceConfigSuccess(t *testing.T) {
8686
policy *v3clusterpb.LoadBalancingPolicy
8787
wantConfig string // JSON config
8888
rhDisabled bool
89+
pfDisabled bool
8990
}{
9091
{
9192
name: "ring_hash",
@@ -177,6 +178,27 @@ func (s) TestConvertToServiceConfigSuccess(t *testing.T) {
177178
wantConfig: `[{"round_robin": {}}]`,
178179
rhDisabled: true,
179180
},
181+
{
182+
name: "pick_first_disabled_pf_rr_use_first_supported",
183+
policy: &v3clusterpb.LoadBalancingPolicy{
184+
Policies: []*v3clusterpb.LoadBalancingPolicy_Policy{
185+
{
186+
TypedExtensionConfig: &v3corepb.TypedExtensionConfig{
187+
TypedConfig: testutils.MarshalAny(&v3pickfirstpb.PickFirst{
188+
ShuffleAddressList: true,
189+
}),
190+
},
191+
},
192+
{
193+
TypedExtensionConfig: &v3corepb.TypedExtensionConfig{
194+
TypedConfig: testutils.MarshalAny(&v3roundrobinpb.RoundRobin{}),
195+
},
196+
},
197+
},
198+
},
199+
wantConfig: `[{"round_robin": {}}]`,
200+
pfDisabled: true,
201+
},
180202
{
181203
name: "custom_lb_type_v3_struct",
182204
policy: &v3clusterpb.LoadBalancingPolicy{
@@ -267,12 +289,14 @@ func (s) TestConvertToServiceConfigSuccess(t *testing.T) {
267289

268290
for _, test := range tests {
269291
t.Run(test.name, func(t *testing.T) {
292+
defer timer.Stop()
270293
if test.rhDisabled {
271-
oldRingHashSupport := envconfig.XDSRingHash
294+
defer func(old bool) { envconfig.XDSRingHash = old }(envconfig.XDSRingHash)
272295
envconfig.XDSRingHash = false
273-
defer func() {
274-
envconfig.XDSRingHash = oldRingHashSupport
275-
}()
296+
}
297+
if !test.pfDisabled {
298+
defer func(old bool) { envconfig.PickFirstLBConfig = old }(envconfig.PickFirstLBConfig)
299+
envconfig.PickFirstLBConfig = true
276300
}
277301
rawJSON, err := xdslbregistry.ConvertToServiceConfig(test.policy, 0)
278302
if err != nil {

0 commit comments

Comments
 (0)