summaryrefslogtreecommitdiff
path: root/vendor/google.golang.org/grpc/internal/balancer
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/google.golang.org/grpc/internal/balancer')
-rw-r--r--vendor/google.golang.org/grpc/internal/balancer/gracefulswitch/config.go83
-rw-r--r--vendor/google.golang.org/grpc/internal/balancer/gracefulswitch/gracefulswitch.go45
2 files changed, 123 insertions, 5 deletions
diff --git a/vendor/google.golang.org/grpc/internal/balancer/gracefulswitch/config.go b/vendor/google.golang.org/grpc/internal/balancer/gracefulswitch/config.go
new file mode 100644
index 000000000..6bf7f8739
--- /dev/null
+++ b/vendor/google.golang.org/grpc/internal/balancer/gracefulswitch/config.go
@@ -0,0 +1,83 @@
+/*
+ *
+ * Copyright 2024 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 gracefulswitch
+
+import (
+ "encoding/json"
+ "fmt"
+
+ "google.golang.org/grpc/balancer"
+ "google.golang.org/grpc/serviceconfig"
+)
+
+type lbConfig struct {
+ serviceconfig.LoadBalancingConfig
+
+ childBuilder balancer.Builder
+ childConfig serviceconfig.LoadBalancingConfig
+}
+
+func ChildName(l serviceconfig.LoadBalancingConfig) string {
+ return l.(*lbConfig).childBuilder.Name()
+}
+
+// ParseConfig parses a child config list and returns a LB config for the
+// gracefulswitch Balancer.
+//
+// cfg is expected to be a json.RawMessage containing a JSON array of LB policy
+// names + configs as the format of the "loadBalancingConfig" field in
+// ServiceConfig. It returns a type that should be passed to
+// UpdateClientConnState in the BalancerConfig field.
+func ParseConfig(cfg json.RawMessage) (serviceconfig.LoadBalancingConfig, error) {
+ var lbCfg []map[string]json.RawMessage
+ if err := json.Unmarshal(cfg, &lbCfg); err != nil {
+ return nil, err
+ }
+ for i, e := range lbCfg {
+ if len(e) != 1 {
+ return nil, fmt.Errorf("expected a JSON struct with one entry; received entry %v at index %d", e, i)
+ }
+
+ var name string
+ var jsonCfg json.RawMessage
+ for name, jsonCfg = range e {
+ }
+
+ builder := balancer.Get(name)
+ if builder == nil {
+ // Skip unregistered balancer names.
+ continue
+ }
+
+ parser, ok := builder.(balancer.ConfigParser)
+ if !ok {
+ // This is a valid child with no config.
+ return &lbConfig{childBuilder: builder}, nil
+ }
+
+ cfg, err := parser.ParseConfig(jsonCfg)
+ if err != nil {
+ return nil, fmt.Errorf("error parsing config for policy %q: %v", name, err)
+ }
+
+ return &lbConfig{childBuilder: builder, childConfig: cfg}, nil
+ }
+
+ return nil, fmt.Errorf("no supported policies found in config: %v", string(cfg))
+}
diff --git a/vendor/google.golang.org/grpc/internal/balancer/gracefulswitch/gracefulswitch.go b/vendor/google.golang.org/grpc/internal/balancer/gracefulswitch/gracefulswitch.go
index 3c594e6e4..45d5e50ea 100644
--- a/vendor/google.golang.org/grpc/internal/balancer/gracefulswitch/gracefulswitch.go
+++ b/vendor/google.golang.org/grpc/internal/balancer/gracefulswitch/gracefulswitch.go
@@ -94,14 +94,23 @@ func (gsb *Balancer) balancerCurrentOrPending(bw *balancerWrapper) bool {
// process is not complete when this method returns. This method must be called
// synchronously alongside the rest of the balancer.Balancer methods this
// Graceful Switch Balancer implements.
+//
+// Deprecated: use ParseConfig and pass a parsed config to UpdateClientConnState
+// to cause the Balancer to automatically change to the new child when necessary.
func (gsb *Balancer) SwitchTo(builder balancer.Builder) error {
+ _, err := gsb.switchTo(builder)
+ return err
+}
+
+func (gsb *Balancer) switchTo(builder balancer.Builder) (*balancerWrapper, error) {
gsb.mu.Lock()
if gsb.closed {
gsb.mu.Unlock()
- return errBalancerClosed
+ return nil, errBalancerClosed
}
bw := &balancerWrapper{
- gsb: gsb,
+ builder: builder,
+ gsb: gsb,
lastState: balancer.State{
ConnectivityState: connectivity.Connecting,
Picker: base.NewErrPicker(balancer.ErrNoSubConnAvailable),
@@ -129,7 +138,7 @@ func (gsb *Balancer) SwitchTo(builder balancer.Builder) error {
gsb.balancerCurrent = nil
}
gsb.mu.Unlock()
- return balancer.ErrBadResolverState
+ return nil, balancer.ErrBadResolverState
}
// This write doesn't need to take gsb.mu because this field never gets read
@@ -138,7 +147,7 @@ func (gsb *Balancer) SwitchTo(builder balancer.Builder) error {
// bw.Balancer field will never be forwarded to until this SwitchTo()
// function returns.
bw.Balancer = newBalancer
- return nil
+ return bw, nil
}
// Returns nil if the graceful switch balancer is closed.
@@ -152,12 +161,33 @@ func (gsb *Balancer) latestBalancer() *balancerWrapper {
}
// UpdateClientConnState forwards the update to the latest balancer created.
+//
+// If the state's BalancerConfig is the config returned by a call to
+// gracefulswitch.ParseConfig, then this function will automatically SwitchTo
+// the balancer indicated by the config before forwarding its config to it, if
+// necessary.
func (gsb *Balancer) UpdateClientConnState(state balancer.ClientConnState) error {
// The resolver data is only relevant to the most recent LB Policy.
balToUpdate := gsb.latestBalancer()
+
+ gsbCfg, ok := state.BalancerConfig.(*lbConfig)
+ if ok {
+ // Switch to the child in the config unless it is already active.
+ if balToUpdate == nil || gsbCfg.childBuilder.Name() != balToUpdate.builder.Name() {
+ var err error
+ balToUpdate, err = gsb.switchTo(gsbCfg.childBuilder)
+ if err != nil {
+ return fmt.Errorf("could not switch to new child balancer: %w", err)
+ }
+ }
+ // Unwrap the child balancer's config.
+ state.BalancerConfig = gsbCfg.childConfig
+ }
+
if balToUpdate == nil {
return errBalancerClosed
}
+
// Perform this call without gsb.mu to prevent deadlocks if the child calls
// back into the channel. The latest balancer can never be closed during a
// call from the channel, even without gsb.mu held.
@@ -169,6 +199,10 @@ func (gsb *Balancer) ResolverError(err error) {
// The resolver data is only relevant to the most recent LB Policy.
balToUpdate := gsb.latestBalancer()
if balToUpdate == nil {
+ gsb.cc.UpdateState(balancer.State{
+ ConnectivityState: connectivity.TransientFailure,
+ Picker: base.NewErrPicker(err),
+ })
return
}
// Perform this call without gsb.mu to prevent deadlocks if the child calls
@@ -261,7 +295,8 @@ func (gsb *Balancer) Close() {
// graceful switch logic.
type balancerWrapper struct {
balancer.Balancer
- gsb *Balancer
+ gsb *Balancer
+ builder balancer.Builder
lastState balancer.State
subconns map[balancer.SubConn]bool // subconns created by this balancer