aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/google.golang.org/grpc/pickfirst.go
blob: d1e38aad778b44df4e452455d5b5f66d32aa729e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
/*
 *
 * Copyright 2017 gRPC authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package grpc

import (
    "context"

    "google.golang.org/grpc/balancer"
    "google.golang.org/grpc/connectivity"
    "google.golang.org/grpc/grpclog"
    "google.golang.org/grpc/resolver"
)

// PickFirstBalancerName is the name of the pick_first balancer.
const PickFirstBalancerName = "pick_first"

func newPickfirstBuilder() balancer.Builder {
    return &pickfirstBuilder{}
}

type pickfirstBuilder struct{}

func (*pickfirstBuilder) Build(cc balancer.ClientConn, opt balancer.BuildOptions) balancer.Balancer {
    return &pickfirstBalancer{cc: cc}
}

func (*pickfirstBuilder) Name() string {
    return PickFirstBalancerName
}

type pickfirstBalancer struct {
    cc balancer.ClientConn
    sc balancer.SubConn
}

func (b *pickfirstBalancer) HandleResolvedAddrs(addrs []resolver.Address, err error) {
    if err != nil {
        grpclog.Infof("pickfirstBalancer: HandleResolvedAddrs called with error %v", err)
        return
    }
    if b.sc == nil {
        b.sc, err = b.cc.NewSubConn(addrs, balancer.NewSubConnOptions{})
        if err != nil {
            //TODO(yuxuanli): why not change the cc state to Idle?
            grpclog.Errorf("pickfirstBalancer: failed to NewSubConn: %v", err)
            return
        }
        b.cc.UpdateBalancerState(connectivity.Idle, &picker{sc: b.sc})
        b.sc.Connect()
    } else {
        b.sc.UpdateAddresses(addrs)
        b.sc.Connect()
    }
}

func (b *pickfirstBalancer) HandleSubConnStateChange(sc balancer.SubConn, s connectivity.State) {
    grpclog.Infof("pickfirstBalancer: HandleSubConnStateChange: %p, %v", sc, s)
    if b.sc != sc {
        grpclog.Infof("pickfirstBalancer: ignored state change because sc is not recognized")
        return
    }
    if s == connectivity.Shutdown {
        b.sc = nil
        return
    }

    switch s {
    case connectivity.Ready, connectivity.Idle:
        b.cc.UpdateBalancerState(s, &picker{sc: sc})
    case connectivity.Connecting:
        b.cc.UpdateBalancerState(s, &picker{err: balancer.ErrNoSubConnAvailable})
    case connectivity.TransientFailure:
        b.cc.UpdateBalancerState(s, &picker{err: balancer.ErrTransientFailure})
    }
}

func (b *pickfirstBalancer) Close() {
}

type picker struct {
    err error
    sc  balancer.SubConn
}

func (p *picker) Pick(ctx context.Context, opts balancer.PickOptions) (balancer.SubConn, func(balancer.DoneInfo), error) {
    if p.err != nil {
        return nil, nil, p.err
    }
    return p.sc, nil, nil
}

func init() {
    balancer.Register(newPickfirstBuilder())
}