podman

Форк
0
249 строк · 7.2 Кб
1
/*
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 grpc
20

21
import (
22
	"encoding/json"
23
	"errors"
24
	"fmt"
25

26
	"google.golang.org/grpc/balancer"
27
	"google.golang.org/grpc/connectivity"
28
	internalgrpclog "google.golang.org/grpc/internal/grpclog"
29
	"google.golang.org/grpc/internal/grpcrand"
30
	"google.golang.org/grpc/internal/pretty"
31
	"google.golang.org/grpc/resolver"
32
	"google.golang.org/grpc/serviceconfig"
33
)
34

35
const (
36
	// PickFirstBalancerName is the name of the pick_first balancer.
37
	PickFirstBalancerName = "pick_first"
38
	logPrefix             = "[pick-first-lb %p] "
39
)
40

41
func newPickfirstBuilder() balancer.Builder {
42
	return &pickfirstBuilder{}
43
}
44

45
type pickfirstBuilder struct{}
46

47
func (*pickfirstBuilder) Build(cc balancer.ClientConn, opt balancer.BuildOptions) balancer.Balancer {
48
	b := &pickfirstBalancer{cc: cc}
49
	b.logger = internalgrpclog.NewPrefixLogger(logger, fmt.Sprintf(logPrefix, b))
50
	return b
51
}
52

53
func (*pickfirstBuilder) Name() string {
54
	return PickFirstBalancerName
55
}
56

57
type pfConfig struct {
58
	serviceconfig.LoadBalancingConfig `json:"-"`
59

60
	// If set to true, instructs the LB policy to shuffle the order of the list
61
	// of addresses received from the name resolver before attempting to
62
	// connect to them.
63
	ShuffleAddressList bool `json:"shuffleAddressList"`
64
}
65

66
func (*pickfirstBuilder) ParseConfig(js json.RawMessage) (serviceconfig.LoadBalancingConfig, error) {
67
	var cfg pfConfig
68
	if err := json.Unmarshal(js, &cfg); err != nil {
69
		return nil, fmt.Errorf("pickfirst: unable to unmarshal LB policy config: %s, error: %v", string(js), err)
70
	}
71
	return cfg, nil
72
}
73

74
type pickfirstBalancer struct {
75
	logger  *internalgrpclog.PrefixLogger
76
	state   connectivity.State
77
	cc      balancer.ClientConn
78
	subConn balancer.SubConn
79
}
80

81
func (b *pickfirstBalancer) ResolverError(err error) {
82
	if b.logger.V(2) {
83
		b.logger.Infof("Received error from the name resolver: %v", err)
84
	}
85
	if b.subConn == nil {
86
		b.state = connectivity.TransientFailure
87
	}
88

89
	if b.state != connectivity.TransientFailure {
90
		// The picker will not change since the balancer does not currently
91
		// report an error.
92
		return
93
	}
94
	b.cc.UpdateState(balancer.State{
95
		ConnectivityState: connectivity.TransientFailure,
96
		Picker:            &picker{err: fmt.Errorf("name resolver error: %v", err)},
97
	})
98
}
99

100
func (b *pickfirstBalancer) UpdateClientConnState(state balancer.ClientConnState) error {
101
	addrs := state.ResolverState.Addresses
102
	if len(addrs) == 0 {
103
		// The resolver reported an empty address list. Treat it like an error by
104
		// calling b.ResolverError.
105
		if b.subConn != nil {
106
			// Shut down the old subConn. All addresses were removed, so it is
107
			// no longer valid.
108
			b.subConn.Shutdown()
109
			b.subConn = nil
110
		}
111
		b.ResolverError(errors.New("produced zero addresses"))
112
		return balancer.ErrBadResolverState
113
	}
114

115
	// We don't have to guard this block with the env var because ParseConfig
116
	// already does so.
117
	cfg, ok := state.BalancerConfig.(pfConfig)
118
	if state.BalancerConfig != nil && !ok {
119
		return fmt.Errorf("pickfirst: received illegal BalancerConfig (type %T): %v", state.BalancerConfig, state.BalancerConfig)
120
	}
121
	if cfg.ShuffleAddressList {
122
		addrs = append([]resolver.Address{}, addrs...)
123
		grpcrand.Shuffle(len(addrs), func(i, j int) { addrs[i], addrs[j] = addrs[j], addrs[i] })
124
	}
125

126
	if b.logger.V(2) {
127
		b.logger.Infof("Received new config %s, resolver state %s", pretty.ToJSON(cfg), pretty.ToJSON(state.ResolverState))
128
	}
129

130
	if b.subConn != nil {
131
		b.cc.UpdateAddresses(b.subConn, addrs)
132
		return nil
133
	}
134

135
	var subConn balancer.SubConn
136
	subConn, err := b.cc.NewSubConn(addrs, balancer.NewSubConnOptions{
137
		StateListener: func(state balancer.SubConnState) {
138
			b.updateSubConnState(subConn, state)
139
		},
140
	})
141
	if err != nil {
142
		if b.logger.V(2) {
143
			b.logger.Infof("Failed to create new SubConn: %v", err)
144
		}
145
		b.state = connectivity.TransientFailure
146
		b.cc.UpdateState(balancer.State{
147
			ConnectivityState: connectivity.TransientFailure,
148
			Picker:            &picker{err: fmt.Errorf("error creating connection: %v", err)},
149
		})
150
		return balancer.ErrBadResolverState
151
	}
152
	b.subConn = subConn
153
	b.state = connectivity.Idle
154
	b.cc.UpdateState(balancer.State{
155
		ConnectivityState: connectivity.Connecting,
156
		Picker:            &picker{err: balancer.ErrNoSubConnAvailable},
157
	})
158
	b.subConn.Connect()
159
	return nil
160
}
161

162
// UpdateSubConnState is unused as a StateListener is always registered when
163
// creating SubConns.
164
func (b *pickfirstBalancer) UpdateSubConnState(subConn balancer.SubConn, state balancer.SubConnState) {
165
	b.logger.Errorf("UpdateSubConnState(%v, %+v) called unexpectedly", subConn, state)
166
}
167

168
func (b *pickfirstBalancer) updateSubConnState(subConn balancer.SubConn, state balancer.SubConnState) {
169
	if b.logger.V(2) {
170
		b.logger.Infof("Received SubConn state update: %p, %+v", subConn, state)
171
	}
172
	if b.subConn != subConn {
173
		if b.logger.V(2) {
174
			b.logger.Infof("Ignored state change because subConn is not recognized")
175
		}
176
		return
177
	}
178
	if state.ConnectivityState == connectivity.Shutdown {
179
		b.subConn = nil
180
		return
181
	}
182

183
	switch state.ConnectivityState {
184
	case connectivity.Ready:
185
		b.cc.UpdateState(balancer.State{
186
			ConnectivityState: state.ConnectivityState,
187
			Picker:            &picker{result: balancer.PickResult{SubConn: subConn}},
188
		})
189
	case connectivity.Connecting:
190
		if b.state == connectivity.TransientFailure {
191
			// We stay in TransientFailure until we are Ready. See A62.
192
			return
193
		}
194
		b.cc.UpdateState(balancer.State{
195
			ConnectivityState: state.ConnectivityState,
196
			Picker:            &picker{err: balancer.ErrNoSubConnAvailable},
197
		})
198
	case connectivity.Idle:
199
		if b.state == connectivity.TransientFailure {
200
			// We stay in TransientFailure until we are Ready. Also kick the
201
			// subConn out of Idle into Connecting. See A62.
202
			b.subConn.Connect()
203
			return
204
		}
205
		b.cc.UpdateState(balancer.State{
206
			ConnectivityState: state.ConnectivityState,
207
			Picker:            &idlePicker{subConn: subConn},
208
		})
209
	case connectivity.TransientFailure:
210
		b.cc.UpdateState(balancer.State{
211
			ConnectivityState: state.ConnectivityState,
212
			Picker:            &picker{err: state.ConnectionError},
213
		})
214
	}
215
	b.state = state.ConnectivityState
216
}
217

218
func (b *pickfirstBalancer) Close() {
219
}
220

221
func (b *pickfirstBalancer) ExitIdle() {
222
	if b.subConn != nil && b.state == connectivity.Idle {
223
		b.subConn.Connect()
224
	}
225
}
226

227
type picker struct {
228
	result balancer.PickResult
229
	err    error
230
}
231

232
func (p *picker) Pick(balancer.PickInfo) (balancer.PickResult, error) {
233
	return p.result, p.err
234
}
235

236
// idlePicker is used when the SubConn is IDLE and kicks the SubConn into
237
// CONNECTING when Pick is called.
238
type idlePicker struct {
239
	subConn balancer.SubConn
240
}
241

242
func (i *idlePicker) Pick(balancer.PickInfo) (balancer.PickResult, error) {
243
	i.subConn.Connect()
244
	return balancer.PickResult{}, balancer.ErrNoSubConnAvailable
245
}
246

247
func init() {
248
	balancer.Register(newPickfirstBuilder())
249
}
250

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.