@@ -47,7 +47,7 @@ type bb struct{}
4747func (bb ) Build (cc balancer.ClientConn , bOpts balancer.BuildOptions ) balancer.Balancer {
4848 b := & ringhashBalancer {
4949 cc : cc ,
50- subConns : make ( map [ resolver.Address ] * subConn ),
50+ subConns : resolver .NewAddressMap ( ),
5151 scStates : make (map [balancer.SubConn ]* subConn ),
5252 csEvltr : & connectivityStateEvaluator {},
5353 }
@@ -65,8 +65,9 @@ func (bb) ParseConfig(c json.RawMessage) (serviceconfig.LoadBalancingConfig, err
6565}
6666
6767type subConn struct {
68- addr string
69- sc balancer.SubConn
68+ addr string
69+ weight uint32
70+ sc balancer.SubConn
7071
7172 mu sync.RWMutex
7273 // This is the actual state of this SubConn (as updated by the ClientConn).
@@ -178,9 +179,8 @@ type ringhashBalancer struct {
178179 cc balancer.ClientConn
179180 logger * grpclog.PrefixLogger
180181
181- config * LBConfig
182-
183- subConns map [resolver.Address ]* subConn // `attributes` is stripped from the keys of this map (the addresses)
182+ config * LBConfig
183+ subConns * resolver.AddressMap // Map from resolver.Address to `*subConn`.
184184 scStates map [balancer.SubConn ]* subConn
185185
186186 // ring is always in sync with subConns. When subConns change, a new ring is
@@ -208,55 +208,47 @@ type ringhashBalancer struct {
208208// SubConn states are Idle.
209209func (b * ringhashBalancer ) updateAddresses (addrs []resolver.Address ) bool {
210210 var addrsUpdated bool
211- // addrsSet is the set converted from addrs, it's used for quick lookup of
212- // an address.
213- //
214- // Addresses in this map all have attributes stripped, but metadata set to
215- // the weight. So that weight change can be detected.
216- //
217- // TODO: this won't be necessary if there are ways to compare address
218- // attributes.
219- addrsSet := make (map [resolver.Address ]struct {})
220- for _ , a := range addrs {
221- aNoAttrs := a
222- // Strip attributes but set Metadata to the weight.
223- aNoAttrs .Attributes = nil
224- w := weightedroundrobin .GetAddrInfo (a ).Weight
225- if w == 0 {
226- // If weight is not set, use 1.
227- w = 1
228- }
229- aNoAttrs .Metadata = w
230- addrsSet [aNoAttrs ] = struct {}{}
231- if scInfo , ok := b .subConns [aNoAttrs ]; ! ok {
232- // When creating SubConn, the original address with attributes is
233- // passed through. So that connection configurations in attributes
234- // (like creds) will be used.
235- sc , err := b .cc .NewSubConn ([]resolver.Address {a }, balancer.NewSubConnOptions {HealthCheckEnabled : true })
211+ // addrsSet is the set converted from addrs, used for quick lookup.
212+ addrsSet := resolver .NewAddressMap ()
213+ for _ , addr := range addrs {
214+ addrsSet .Set (addr , true )
215+ newWeight := getWeightAttribute (addr )
216+ if val , ok := b .subConns .Get (addr ); ! ok {
217+ sc , err := b .cc .NewSubConn ([]resolver.Address {addr }, balancer.NewSubConnOptions {HealthCheckEnabled : true })
236218 if err != nil {
237219 logger .Warningf ("base.baseBalancer: failed to create new SubConn: %v" , err )
238220 continue
239221 }
240- scs := & subConn {addr : a .Addr , sc : sc }
222+ scs := & subConn {addr : addr .Addr , weight : newWeight , sc : sc }
241223 scs .setState (connectivity .Idle )
242224 b .state = b .csEvltr .recordTransition (connectivity .Shutdown , connectivity .Idle )
243- b .subConns [ aNoAttrs ] = scs
225+ b .subConns . Set ( addr , scs )
244226 b .scStates [sc ] = scs
245227 addrsUpdated = true
246228 } else {
247- // Always update the subconn's address in case the attributes
248- // changed. The SubConn does a reflect.DeepEqual of the new and old
249- // addresses. So this is a noop if the current address is the same
250- // as the old one (including attributes).
251- b .subConns [aNoAttrs ] = scInfo
252- b .cc .UpdateAddresses (scInfo .sc , []resolver.Address {a })
229+ // We have seen this address before and created a subConn for it. If the
230+ // weight associated with the address has changed, update the subConns map
231+ // with the new weight. This will be used when a new ring is created.
232+ //
233+ // There is no need to call UpdateAddresses on the subConn at this point
234+ // since *only* the weight attribute has changed, and that does not affect
235+ // subConn uniqueness.
236+ scInfo := val .(* subConn )
237+ if oldWeight := scInfo .weight ; oldWeight != newWeight {
238+ scInfo .weight = newWeight
239+ b .subConns .Set (addr , scInfo )
240+ // Return true to force recreation of the ring.
241+ addrsUpdated = true
242+ }
253243 }
254244 }
255- for a , scInfo := range b .subConns {
256- // a was removed by resolver.
257- if _ , ok := addrsSet [a ]; ! ok {
245+ for _ , addr := range b .subConns .Keys () {
246+ // addr was removed by resolver.
247+ if _ , ok := addrsSet .Get (addr ); ! ok {
248+ v , _ := b .subConns .Get (addr )
249+ scInfo := v .(* subConn )
258250 b .cc .RemoveSubConn (scInfo .sc )
259- delete ( b .subConns , a )
251+ b .subConns . Delete ( addr )
260252 addrsUpdated = true
261253 // Keep the state of this sc in b.scStates until sc's state becomes Shutdown.
262254 // The entry will be deleted in UpdateSubConnState.
@@ -304,7 +296,7 @@ func (b *ringhashBalancer) UpdateClientConnState(s balancer.ClientConnState) err
304296
305297func (b * ringhashBalancer ) ResolverError (err error ) {
306298 b .resolverErr = err
307- if len ( b .subConns ) == 0 {
299+ if b .subConns . Len ( ) == 0 {
308300 b .state = connectivity .TransientFailure
309301 }
310302
@@ -392,7 +384,8 @@ func (b *ringhashBalancer) UpdateSubConnState(sc balancer.SubConn, state balance
392384 // attempting to connect, we need to trigger one. But since the deleted
393385 // SubConn will eventually send a shutdown update, this code will run
394386 // and trigger the next SubConn to connect.
395- for _ , sc := range b .subConns {
387+ for _ , v := range b .subConns .Values () {
388+ sc := v .(* subConn )
396389 if sc .isAttemptingToConnect () {
397390 return
398391 }
@@ -485,3 +478,18 @@ func (cse *connectivityStateEvaluator) recordTransition(oldState, newState conne
485478 }
486479 return connectivity .TransientFailure
487480}
481+
482+ // getWeightAttribute is a convenience function which returns the value of the
483+ // weight attribute stored in the BalancerAttributes field of addr, using the
484+ // weightedroundrobin package.
485+ //
486+ // When used in the xDS context, the weight attribute is guaranteed to be
487+ // non-zero. But, when used in a non-xDS context, the weight attribute could be
488+ // unset. A Default of 1 is used in the latter case.
489+ func getWeightAttribute (addr resolver.Address ) uint32 {
490+ w := weightedroundrobin .GetAddrInfo (addr ).Weight
491+ if w == 0 {
492+ return 1
493+ }
494+ return w
495+ }
0 commit comments