/* * * Copyright 2021 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 priority import ( "google.golang.org/grpc/balancer" "google.golang.org/grpc/balancer/base" "google.golang.org/grpc/connectivity" "google.golang.org/grpc/resolver" "google.golang.org/grpc/serviceconfig" ) type childBalancer struct { name string parent *priorityBalancer bb *ignoreResolveNowBalancerBuilder ignoreReresolutionRequests bool config serviceconfig.LoadBalancingConfig rState resolver.State started bool state balancer.State } // newChildBalancer creates a child balancer place holder, but doesn't // build/start the child balancer. func newChildBalancer(name string, parent *priorityBalancer, bb balancer.Builder) *childBalancer { return &childBalancer{ name: name, parent: parent, bb: newIgnoreResolveNowBalancerBuilder(bb, false), started: false, // Start with the connecting state and picker with re-pick error, so // that when a priority switch causes this child picked before it's // balancing policy is created, a re-pick will happen. state: balancer.State{ ConnectivityState: connectivity.Connecting, Picker: base.NewErrPicker(balancer.ErrNoSubConnAvailable), }, } } // updateBuilder updates builder for the child, but doesn't build. func (cb *childBalancer) updateBuilder(bb balancer.Builder) { cb.bb = newIgnoreResolveNowBalancerBuilder(bb, cb.ignoreReresolutionRequests) } // updateConfig sets childBalancer's config and state, but doesn't send update to // the child balancer. func (cb *childBalancer) updateConfig(child *Child, rState resolver.State) { cb.ignoreReresolutionRequests = child.IgnoreReresolutionRequests cb.config = child.Config.Config cb.rState = rState } // start builds the child balancer if it's not already started. // // It doesn't do it directly. It asks the balancer group to build it. func (cb *childBalancer) start() { if cb.started { return } cb.started = true cb.parent.bg.Add(cb.name, cb.bb) } // sendUpdate sends the addresses and config to the child balancer. func (cb *childBalancer) sendUpdate() { cb.bb.updateIgnoreResolveNow(cb.ignoreReresolutionRequests) // TODO: return and aggregate the returned error in the parent. err := cb.parent.bg.UpdateClientConnState(cb.name, balancer.ClientConnState{ ResolverState: cb.rState, BalancerConfig: cb.config, }) if err != nil { cb.parent.logger.Warningf("failed to update ClientConn state for child %v: %v", cb.name, err) } } // stop stops the child balancer and resets the state. // // It doesn't do it directly. It asks the balancer group to remove it. // // Note that the underlying balancer group could keep the child in a cache. func (cb *childBalancer) stop() { if !cb.started { return } cb.parent.bg.Remove(cb.name) cb.started = false cb.state = balancer.State{ ConnectivityState: connectivity.Connecting, Picker: base.NewErrPicker(balancer.ErrNoSubConnAvailable), } }