3 * Copyright 2017 gRPC authors.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
24 "golang.org/x/net/context"
25 "google.golang.org/grpc/balancer"
26 "google.golang.org/grpc/codes"
27 "google.golang.org/grpc/grpclog"
28 "google.golang.org/grpc/status"
29 "google.golang.org/grpc/transport"
32 // pickerWrapper is a wrapper of balancer.Picker. It blocks on certain pick
33 // actions and unblock when there's a picker update.
34 type pickerWrapper struct {
37 blockingCh chan struct{}
38 picker balancer.Picker
41 func newPickerWrapper() *pickerWrapper {
42 bp := &pickerWrapper{blockingCh: make(chan struct{})}
46 // updatePicker is called by UpdateBalancerState. It unblocks all blocked pick.
47 func (bp *pickerWrapper) updatePicker(p balancer.Picker) {
54 // bp.blockingCh should never be nil.
56 bp.blockingCh = make(chan struct{})
60 // pick returns the transport that will be used for the RPC.
61 // It may block in the following cases:
62 // - there's no picker
63 // - the current picker returns ErrNoSubConnAvailable
64 // - the current picker returns other errors and failfast is false.
65 // - the subConn returned by the current picker is not READY
66 // When one of these situations happens, pick blocks until the picker gets updated.
67 func (bp *pickerWrapper) pick(ctx context.Context, failfast bool, opts balancer.PickOptions) (transport.ClientTransport, func(balancer.DoneInfo), error) {
77 return nil, nil, ErrClientConnClosing
83 if ch == bp.blockingCh {
84 // This could happen when either:
85 // - bp.picker is nil (the previous if condition), or
86 // - has called pick on the current picker.
90 return nil, nil, ctx.Err()
100 subConn, put, err := p.Pick(ctx, opts)
104 case balancer.ErrNoSubConnAvailable:
106 case balancer.ErrTransientFailure:
110 return nil, nil, status.Errorf(codes.Unavailable, "%v", err)
112 // err is some other error.
113 return nil, nil, toRPCErr(err)
117 acw, ok := subConn.(*acBalancerWrapper)
119 grpclog.Infof("subconn returned from pick is not *acBalancerWrapper")
122 if t, ok := acw.getAddrConn().getReadyTransport(); ok {
125 grpclog.Infof("blockingPicker: the picked transport is not ready, loop back to repick")
126 // If ok == false, ac.state is not READY.
127 // A valid picker always returns READY subConn. This means the state of ac
128 // just changed, and picker will be updated shortly.
129 // continue back to the beginning of the for loop to repick.
133 func (bp *pickerWrapper) close() {