blob: d4d645501c14c600bb52b86708e0538a8f01418b [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 (
Matteo Scandoloa6a3aee2019-11-26 13:30:14 -070025 "sync"
26
27 "google.golang.org/grpc/balancer"
28 "google.golang.org/grpc/balancer/base"
29 "google.golang.org/grpc/grpclog"
30 "google.golang.org/grpc/internal/grpcrand"
Matteo Scandoloa6a3aee2019-11-26 13:30:14 -070031)
32
33// Name is the name of round_robin balancer.
34const Name = "round_robin"
35
36// newBuilder creates a new roundrobin balancer builder.
37func newBuilder() balancer.Builder {
Arjun E K57a7fcb2020-01-30 06:44:45 +000038 return base.NewBalancerBuilderV2(Name, &rrPickerBuilder{}, base.Config{HealthCheck: true})
Matteo Scandoloa6a3aee2019-11-26 13:30:14 -070039}
40
41func init() {
42 balancer.Register(newBuilder())
43}
44
45type rrPickerBuilder struct{}
46
Arjun E K57a7fcb2020-01-30 06:44:45 +000047func (*rrPickerBuilder) Build(info base.PickerBuildInfo) balancer.V2Picker {
48 grpclog.Infof("roundrobinPicker: newPicker called with info: %v", info)
49 if len(info.ReadySCs) == 0 {
50 return base.NewErrPickerV2(balancer.ErrNoSubConnAvailable)
Matteo Scandoloa6a3aee2019-11-26 13:30:14 -070051 }
52 var scs []balancer.SubConn
Arjun E K57a7fcb2020-01-30 06:44:45 +000053 for sc := range info.ReadySCs {
Matteo Scandoloa6a3aee2019-11-26 13:30:14 -070054 scs = append(scs, sc)
55 }
56 return &rrPicker{
57 subConns: scs,
58 // Start at a random index, as the same RR balancer rebuilds a new
59 // picker when SubConn states change, and we don't want to apply excess
60 // load to the first server in the list.
61 next: grpcrand.Intn(len(scs)),
62 }
63}
64
65type rrPicker struct {
66 // subConns is the snapshot of the roundrobin balancer when this picker was
67 // created. The slice is immutable. Each Get() will do a round robin
68 // selection from it and return the selected SubConn.
69 subConns []balancer.SubConn
70
71 mu sync.Mutex
72 next int
73}
74
Arjun E K57a7fcb2020-01-30 06:44:45 +000075func (p *rrPicker) Pick(balancer.PickInfo) (balancer.PickResult, error) {
Matteo Scandoloa6a3aee2019-11-26 13:30:14 -070076 p.mu.Lock()
77 sc := p.subConns[p.next]
78 p.next = (p.next + 1) % len(p.subConns)
79 p.mu.Unlock()
Arjun E K57a7fcb2020-01-30 06:44:45 +000080 return balancer.PickResult{SubConn: sc}, nil
Matteo Scandoloa6a3aee2019-11-26 13:30:14 -070081}