blob: 29f7a4ddd68f50fb5794081d081629d4e83bcd77 [file] [log] [blame]
Matteo Scandoloa6a3aee2019-11-26 13:30:14 -07001/*
2 *
3 * Copyright 2017 gRPC authors.
4 *
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
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
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.
16 *
17 */
18
19// Package roundrobin defines a roundrobin balancer. Roundrobin balancer is
20// installed as one of the default balancers in gRPC, users don't need to
21// explicitly install this balancer.
22package roundrobin
23
24import (
David K. Bainbridgec415efe2021-08-19 13:05:21 +000025 "context"
Matteo Scandoloa6a3aee2019-11-26 13:30:14 -070026 "sync"
27
28 "google.golang.org/grpc/balancer"
29 "google.golang.org/grpc/balancer/base"
30 "google.golang.org/grpc/grpclog"
31 "google.golang.org/grpc/internal/grpcrand"
David K. Bainbridgec415efe2021-08-19 13:05:21 +000032 "google.golang.org/grpc/resolver"
Matteo Scandoloa6a3aee2019-11-26 13:30:14 -070033)
34
35// Name is the name of round_robin balancer.
36const Name = "round_robin"
37
38// newBuilder creates a new roundrobin balancer builder.
39func newBuilder() balancer.Builder {
David K. Bainbridgec415efe2021-08-19 13:05:21 +000040 return base.NewBalancerBuilderWithConfig(Name, &rrPickerBuilder{}, base.Config{HealthCheck: true})
Matteo Scandoloa6a3aee2019-11-26 13:30:14 -070041}
42
43func init() {
44 balancer.Register(newBuilder())
45}
46
47type rrPickerBuilder struct{}
48
David K. Bainbridgec415efe2021-08-19 13:05:21 +000049func (*rrPickerBuilder) Build(readySCs map[resolver.Address]balancer.SubConn) balancer.Picker {
50 grpclog.Infof("roundrobinPicker: newPicker called with readySCs: %v", readySCs)
51 if len(readySCs) == 0 {
52 return base.NewErrPicker(balancer.ErrNoSubConnAvailable)
Matteo Scandoloa6a3aee2019-11-26 13:30:14 -070053 }
54 var scs []balancer.SubConn
David K. Bainbridgec415efe2021-08-19 13:05:21 +000055 for _, sc := range readySCs {
Matteo Scandoloa6a3aee2019-11-26 13:30:14 -070056 scs = append(scs, sc)
57 }
58 return &rrPicker{
59 subConns: scs,
60 // Start at a random index, as the same RR balancer rebuilds a new
61 // picker when SubConn states change, and we don't want to apply excess
62 // load to the first server in the list.
63 next: grpcrand.Intn(len(scs)),
64 }
65}
66
67type rrPicker struct {
68 // subConns is the snapshot of the roundrobin balancer when this picker was
69 // created. The slice is immutable. Each Get() will do a round robin
70 // selection from it and return the selected SubConn.
71 subConns []balancer.SubConn
72
73 mu sync.Mutex
74 next int
75}
76
David K. Bainbridgec415efe2021-08-19 13:05:21 +000077func (p *rrPicker) Pick(ctx context.Context, opts balancer.PickOptions) (balancer.SubConn, func(balancer.DoneInfo), error) {
Matteo Scandoloa6a3aee2019-11-26 13:30:14 -070078 p.mu.Lock()
79 sc := p.subConns[p.next]
80 p.next = (p.next + 1) % len(p.subConns)
81 p.mu.Unlock()
David K. Bainbridgec415efe2021-08-19 13:05:21 +000082 return sc, nil, nil
Matteo Scandoloa6a3aee2019-11-26 13:30:14 -070083}