blob: 1b8b285737821281a251a553c6887eb25121e353 [file] [log] [blame]
Stephane Barbarie260a5632019-02-26 16:12:49 -05001// 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 Baker8461e152019-10-01 14:44:30 -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 }
Stephane Barbarie260a5632019-02-26 16:12:49 -050033 return &rrBalanced{
Scott Baker8461e152019-10-01 14:44:30 -070034 p: RoundrobinBalanced,
35 lg: cfg.Logger,
Stephane Barbarie260a5632019-02-26 16:12:49 -050036 scs: scs,
Scott Baker8461e152019-10-01 14:44:30 -070037 scToAddr: cfg.SubConnToResolverAddress,
Stephane Barbarie260a5632019-02-26 16:12:49 -050038 }
39}
40
41type rrBalanced struct {
Scott Baker8461e152019-10-01 14:44:30 -070042 p Policy
43
Stephane Barbarie260a5632019-02-26 16:12:49 -050044 lg *zap.Logger
45
Scott Baker8461e152019-10-01 14:44:30 -070046 mu sync.RWMutex
47 next int
48 scs []balancer.SubConn
Stephane Barbarie260a5632019-02-26 16:12:49 -050049 scToAddr map[balancer.SubConn]resolver.Address
50}
51
Scott Baker8461e152019-10-01 14:44:30 -070052func (rb *rrBalanced) String() string { return rb.p.String() }
53
Stephane Barbarie260a5632019-02-26 16:12:49 -050054// 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 Baker8461e152019-10-01 14:44:30 -070072 zap.String("picker", rb.p.String()),
Stephane Barbarie260a5632019-02-26 16:12:49 -050073 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 Baker8461e152019-10-01 14:44:30 -070082 zap.String("picker", rb.p.String()),
Stephane Barbarie260a5632019-02-26 16:12:49 -050083 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}