Skip to content

Commit a26ff2a

Browse files
authored
ringhash: Sort endpoints to prevent unnecessary connection attempts (#8086)
1 parent fabe274 commit a26ff2a

File tree

1 file changed

+18
-2
lines changed

1 file changed

+18
-2
lines changed

xds/internal/balancer/ringhash/ringhash.go

+18-2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"encoding/json"
2424
"errors"
2525
"fmt"
26+
"sort"
2627
"sync"
2728

2829
"google.golang.org/grpc/balancer"
@@ -240,9 +241,24 @@ func (b *ringhashBalancer) updatePickerLocked() {
240241
// 2. There are four endpoints in the following states: TF, TF,
241242
// CONNECTING, and IDLE. If the CONNECTING endpoint is removed, the
242243
// new states become: TF, TF, IDLE.
244+
245+
// After calling `ExitIdle` on a child balancer, the child will send a
246+
// picker update asynchronously. A race condition may occur if another
247+
// picker update from endpointsharding arrives before the child's
248+
// picker update. The received picker may trigger a re-execution of the
249+
// loop below to find an idle child. Since map iteration order is
250+
// non-deterministic, the list of `endpointState`s must be sorted to
251+
// ensure `ExitIdle` is called on the same child, preventing unnecessary
252+
// connections.
253+
var endpointStates = make([]*endpointState, b.endpointStates.Len())
254+
for i, val := range b.endpointStates.Values() {
255+
endpointStates[i] = val.(*endpointState)
256+
}
257+
sort.Slice(endpointStates, func(i, j int) bool {
258+
return endpointStates[i].firstAddr < endpointStates[j].firstAddr
259+
})
243260
var idleBalancer balancer.ExitIdler
244-
for _, val := range b.endpointStates.Values() {
245-
es := val.(*endpointState)
261+
for _, es := range endpointStates {
246262
connState := es.state.ConnectivityState
247263
if connState == connectivity.Connecting {
248264
idleBalancer = nil

0 commit comments

Comments
 (0)