MCPcopy
hub / github.com/grpc/grpc-go / Pick

Method Pick

balancer/ringhash/picker.go:55–120  ·  view source on GitHub ↗
(info balancer.PickInfo)

Source from the content-addressed store, hash-verified

53}
54
55func (p *picker) Pick(info balancer.PickInfo) (balancer.PickResult, error) {
56 usingRandomHash := false
57 var requestHash uint64
58 if p.requestHashHeader == "" {
59 var ok bool
60 if requestHash, ok = iringhash.XDSRequestHash(info.Ctx); !ok {
61 return balancer.PickResult{}, fmt.Errorf("ringhash: expected xDS config selector to set the request hash")
62 }
63 } else {
64 md, ok := metadata.FromOutgoingContext(info.Ctx)
65 if !ok || len(md.Get(p.requestHashHeader)) == 0 {
66 requestHash = p.randUint64()
67 usingRandomHash = true
68 } else {
69 values := strings.Join(md.Get(p.requestHashHeader), ",")
70 requestHash = xxhash.Sum64String(values)
71 }
72 }
73
74 e := p.ring.pick(requestHash)
75 ringSize := len(p.ring.items)
76 if !usingRandomHash {
77 // Per gRFC A61, because of sticky-TF with PickFirst's auto reconnect on TF,
78 // we ignore all TF subchannels and find the first ring entry in READY,
79 // CONNECTING or IDLE. If that entry is in IDLE, we need to initiate a
80 // connection. The idlePicker returned by the LazyLB or the new Pickfirst
81 // should do this automatically.
82 for i := 0; i < ringSize; i++ {
83 index := (e.idx + i) % ringSize
84 es := p.endpointState(p.ring.items[index])
85 switch es.state.ConnectivityState {
86 case connectivity.Ready, connectivity.Connecting, connectivity.Idle:
87 return es.state.Picker.Pick(info)
88 case connectivity.TransientFailure:
89 default:
90 panic(fmt.Sprintf("Found child balancer in unknown state: %v", es.state.ConnectivityState))
91 }
92 }
93 } else {
94 // If the picker has generated a random hash, it will walk the ring from
95 // this hash, and pick the first READY endpoint. If no endpoint is
96 // currently in CONNECTING state, it will trigger a connection attempt
97 // on at most one endpoint that is in IDLE state along the way. - A76
98 requestedConnection := p.hasEndpointInConnectingState
99 for i := 0; i < ringSize; i++ {
100 index := (e.idx + i) % ringSize
101 es := p.endpointState(p.ring.items[index])
102 if es.state.ConnectivityState == connectivity.Ready {
103 return es.state.Picker.Pick(info)
104 }
105 if !requestedConnection && es.state.ConnectivityState == connectivity.Idle {
106 requestedConnection = true
107 // If the SubChannel is in idle state, initiate a connection but
108 // continue to check other pickers to see if there is one in
109 // ready state.
110 es.balancer.ExitIdle()
111 }
112 }

Callers 4

TestPickerRandomHashMethod · 0.95

Calls 8

endpointStateMethod · 0.95
FromOutgoingContextFunction · 0.92
JoinMethod · 0.80
ErrorfMethod · 0.65
GetMethod · 0.65
PickMethod · 0.65
ExitIdleMethod · 0.65
pickMethod · 0.45

Tested by 4

TestPickerRandomHashMethod · 0.76