blob: 1b8b285737821281a251a553c6887eb25121e353 [file] [log] [blame]
Scott Baker2d897982019-09-24 11:50:08 -07001// Copyright 2018 The etcd Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package picker
16
17import (
18 "context"
19 "sync"
20
21 "go.uber.org/zap"
22 "go.uber.org/zap/zapcore"
23 "google.golang.org/grpc/balancer"
24 "google.golang.org/grpc/resolver"
25)
26
Scott Baker8487c5d2019-10-18 12:49:46 -070027// newRoundrobinBalanced returns a new roundrobin balanced picker.
28func newRoundrobinBalanced(cfg Config) Picker {
29 scs := make([]balancer.SubConn, 0, len(cfg.SubConnToResolverAddress))
30 for sc := range cfg.SubConnToResolverAddress {
31 scs = append(scs, sc)
32 }
Scott Baker2d897982019-09-24 11:50:08 -070033 return &rrBalanced{
Scott Baker8487c5d2019-10-18 12:49:46 -070034 p: RoundrobinBalanced,
35 lg: cfg.Logger,
Scott Baker2d897982019-09-24 11:50:08 -070036 scs: scs,
Scott Baker8487c5d2019-10-18 12:49:46 -070037 scToAddr: cfg.SubConnToResolverAddress,
Scott Baker2d897982019-09-24 11:50:08 -070038 }
39}
40
41type rrBalanced struct {
Scott Baker8487c5d2019-10-18 12:49:46 -070042 p Policy
43
Scott Baker2d897982019-09-24 11:50:08 -070044 lg *zap.Logger
45
Scott Baker8487c5d2019-10-18 12:49:46 -070046 mu sync.RWMutex
47 next int
48 scs []balancer.SubConn
Scott Baker2d897982019-09-24 11:50:08 -070049 scToAddr map[balancer.SubConn]resolver.Address
50}
51
Scott Baker8487c5d2019-10-18 12:49:46 -070052func (rb *rrBalanced) String() string { return rb.p.String() }
53
Scott Baker2d897982019-09-24 11:50:08 -070054// Pick is called for every client request.
55func (rb *rrBalanced) Pick(ctx context.Context, opts balancer.PickOptions) (balancer.SubConn, func(balancer.DoneInfo), error) {
56 rb.mu.RLock()
57 n := len(rb.scs)
58 rb.mu.RUnlock()
59 if n == 0 {
60 return nil, nil, balancer.ErrNoSubConnAvailable
61 }
62
63 rb.mu.Lock()
64 cur := rb.next
65 sc := rb.scs[cur]
66 picked := rb.scToAddr[sc].Addr
67 rb.next = (rb.next + 1) % len(rb.scs)
68 rb.mu.Unlock()
69
70 rb.lg.Debug(
71 "picked",
Scott Baker8487c5d2019-10-18 12:49:46 -070072 zap.String("picker", rb.p.String()),
Scott Baker2d897982019-09-24 11:50:08 -070073 zap.String("address", picked),
74 zap.Int("subconn-index", cur),
75 zap.Int("subconn-size", n),
76 )
77
78 doneFunc := func(info balancer.DoneInfo) {
79 // TODO: error handling?
80 fss := []zapcore.Field{
81 zap.Error(info.Err),
Scott Baker8487c5d2019-10-18 12:49:46 -070082 zap.String("picker", rb.p.String()),
Scott Baker2d897982019-09-24 11:50:08 -070083 zap.String("address", picked),
84 zap.Bool("success", info.Err == nil),
85 zap.Bool("bytes-sent", info.BytesSent),
86 zap.Bool("bytes-received", info.BytesReceived),
87 }
88 if info.Err == nil {
89 rb.lg.Debug("balancer done", fss...)
90 } else {
91 rb.lg.Warn("balancer failed", fss...)
92 }
93 }
94 return sc, doneFunc, nil
95}