diff options
author | appilon <apilon@hashicorp.com> | 2019-02-27 16:43:31 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-02-27 16:43:31 -0500 |
commit | 844b5a68d8af4791755b8f0ad293cc99f5959183 (patch) | |
tree | 255c250a5c9d4801c74092d33b7337d8c14438ff /vendor/google.golang.org/grpc/balancer.go | |
parent | 303b299eeb6b06e939e35905e4b34cb410dd9dc3 (diff) | |
parent | 15c0b25d011f37e7c20aeca9eaf461f78285b8d9 (diff) | |
download | terraform-provider-statuscake-844b5a68d8af4791755b8f0ad293cc99f5959183.tar.gz terraform-provider-statuscake-844b5a68d8af4791755b8f0ad293cc99f5959183.tar.zst terraform-provider-statuscake-844b5a68d8af4791755b8f0ad293cc99f5959183.zip |
Merge pull request #27 from terraform-providers/go-modules-2019-02-22
[MODULES] Switch to Go Modules
Diffstat (limited to 'vendor/google.golang.org/grpc/balancer.go')
-rw-r--r-- | vendor/google.golang.org/grpc/balancer.go | 397 |
1 files changed, 397 insertions, 0 deletions
diff --git a/vendor/google.golang.org/grpc/balancer.go b/vendor/google.golang.org/grpc/balancer.go new file mode 100644 index 0000000..cde472c --- /dev/null +++ b/vendor/google.golang.org/grpc/balancer.go | |||
@@ -0,0 +1,397 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 2016 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 | "fmt" | ||
23 | "net" | ||
24 | "sync" | ||
25 | |||
26 | "golang.org/x/net/context" | ||
27 | "google.golang.org/grpc/codes" | ||
28 | "google.golang.org/grpc/credentials" | ||
29 | "google.golang.org/grpc/grpclog" | ||
30 | "google.golang.org/grpc/naming" | ||
31 | ) | ||
32 | |||
33 | // Address represents a server the client connects to. | ||
34 | // This is the EXPERIMENTAL API and may be changed or extended in the future. | ||
35 | type Address struct { | ||
36 | // Addr is the server address on which a connection will be established. | ||
37 | Addr string | ||
38 | // Metadata is the information associated with Addr, which may be used | ||
39 | // to make load balancing decision. | ||
40 | Metadata interface{} | ||
41 | } | ||
42 | |||
43 | // BalancerConfig specifies the configurations for Balancer. | ||
44 | type BalancerConfig struct { | ||
45 | // DialCreds is the transport credential the Balancer implementation can | ||
46 | // use to dial to a remote load balancer server. The Balancer implementations | ||
47 | // can ignore this if it does not need to talk to another party securely. | ||
48 | DialCreds credentials.TransportCredentials | ||
49 | // Dialer is the custom dialer the Balancer implementation can use to dial | ||
50 | // to a remote load balancer server. The Balancer implementations | ||
51 | // can ignore this if it doesn't need to talk to remote balancer. | ||
52 | Dialer func(context.Context, string) (net.Conn, error) | ||
53 | } | ||
54 | |||
55 | // BalancerGetOptions configures a Get call. | ||
56 | // This is the EXPERIMENTAL API and may be changed or extended in the future. | ||
57 | type BalancerGetOptions struct { | ||
58 | // BlockingWait specifies whether Get should block when there is no | ||
59 | // connected address. | ||
60 | BlockingWait bool | ||
61 | } | ||
62 | |||
63 | // Balancer chooses network addresses for RPCs. | ||
64 | // This is the EXPERIMENTAL API and may be changed or extended in the future. | ||
65 | type Balancer interface { | ||
66 | // Start does the initialization work to bootstrap a Balancer. For example, | ||
67 | // this function may start the name resolution and watch the updates. It will | ||
68 | // be called when dialing. | ||
69 | Start(target string, config BalancerConfig) error | ||
70 | // Up informs the Balancer that gRPC has a connection to the server at | ||
71 | // addr. It returns down which is called once the connection to addr gets | ||
72 | // lost or closed. | ||
73 | // TODO: It is not clear how to construct and take advantage of the meaningful error | ||
74 | // parameter for down. Need realistic demands to guide. | ||
75 | Up(addr Address) (down func(error)) | ||
76 | // Get gets the address of a server for the RPC corresponding to ctx. | ||
77 | // i) If it returns a connected address, gRPC internals issues the RPC on the | ||
78 | // connection to this address; | ||
79 | // ii) If it returns an address on which the connection is under construction | ||
80 | // (initiated by Notify(...)) but not connected, gRPC internals | ||
81 | // * fails RPC if the RPC is fail-fast and connection is in the TransientFailure or | ||
82 | // Shutdown state; | ||
83 | // or | ||
84 | // * issues RPC on the connection otherwise. | ||
85 | // iii) If it returns an address on which the connection does not exist, gRPC | ||
86 | // internals treats it as an error and will fail the corresponding RPC. | ||
87 | // | ||
88 | // Therefore, the following is the recommended rule when writing a custom Balancer. | ||
89 | // If opts.BlockingWait is true, it should return a connected address or | ||
90 | // block if there is no connected address. It should respect the timeout or | ||
91 | // cancellation of ctx when blocking. If opts.BlockingWait is false (for fail-fast | ||
92 | // RPCs), it should return an address it has notified via Notify(...) immediately | ||
93 | // instead of blocking. | ||
94 | // | ||
95 | // The function returns put which is called once the rpc has completed or failed. | ||
96 | // put can collect and report RPC stats to a remote load balancer. | ||
97 | // | ||
98 | // This function should only return the errors Balancer cannot recover by itself. | ||
99 | // gRPC internals will fail the RPC if an error is returned. | ||
100 | Get(ctx context.Context, opts BalancerGetOptions) (addr Address, put func(), err error) | ||
101 | // Notify returns a channel that is used by gRPC internals to watch the addresses | ||
102 | // gRPC needs to connect. The addresses might be from a name resolver or remote | ||
103 | // load balancer. gRPC internals will compare it with the existing connected | ||
104 | // addresses. If the address Balancer notified is not in the existing connected | ||
105 | // addresses, gRPC starts to connect the address. If an address in the existing | ||
106 | // connected addresses is not in the notification list, the corresponding connection | ||
107 | // is shutdown gracefully. Otherwise, there are no operations to take. Note that | ||
108 | // the Address slice must be the full list of the Addresses which should be connected. | ||
109 | // It is NOT delta. | ||
110 | Notify() <-chan []Address | ||
111 | // Close shuts down the balancer. | ||
112 | Close() error | ||
113 | } | ||
114 | |||
115 | // downErr implements net.Error. It is constructed by gRPC internals and passed to the down | ||
116 | // call of Balancer. | ||
117 | type downErr struct { | ||
118 | timeout bool | ||
119 | temporary bool | ||
120 | desc string | ||
121 | } | ||
122 | |||
123 | func (e downErr) Error() string { return e.desc } | ||
124 | func (e downErr) Timeout() bool { return e.timeout } | ||
125 | func (e downErr) Temporary() bool { return e.temporary } | ||
126 | |||
127 | func downErrorf(timeout, temporary bool, format string, a ...interface{}) downErr { | ||
128 | return downErr{ | ||
129 | timeout: timeout, | ||
130 | temporary: temporary, | ||
131 | desc: fmt.Sprintf(format, a...), | ||
132 | } | ||
133 | } | ||
134 | |||
135 | // RoundRobin returns a Balancer that selects addresses round-robin. It uses r to watch | ||
136 | // the name resolution updates and updates the addresses available correspondingly. | ||
137 | func RoundRobin(r naming.Resolver) Balancer { | ||
138 | return &roundRobin{r: r} | ||
139 | } | ||
140 | |||
141 | type addrInfo struct { | ||
142 | addr Address | ||
143 | connected bool | ||
144 | } | ||
145 | |||
146 | type roundRobin struct { | ||
147 | r naming.Resolver | ||
148 | w naming.Watcher | ||
149 | addrs []*addrInfo // all the addresses the client should potentially connect | ||
150 | mu sync.Mutex | ||
151 | addrCh chan []Address // the channel to notify gRPC internals the list of addresses the client should connect to. | ||
152 | next int // index of the next address to return for Get() | ||
153 | waitCh chan struct{} // the channel to block when there is no connected address available | ||
154 | done bool // The Balancer is closed. | ||
155 | } | ||
156 | |||
157 | func (rr *roundRobin) watchAddrUpdates() error { | ||
158 | updates, err := rr.w.Next() | ||
159 | if err != nil { | ||
160 | grpclog.Warningf("grpc: the naming watcher stops working due to %v.", err) | ||
161 | return err | ||
162 | } | ||
163 | rr.mu.Lock() | ||
164 | defer rr.mu.Unlock() | ||
165 | for _, update := range updates { | ||
166 | addr := Address{ | ||
167 | Addr: update.Addr, | ||
168 | Metadata: update.Metadata, | ||
169 | } | ||
170 | switch update.Op { | ||
171 | case naming.Add: | ||
172 | var exist bool | ||
173 | for _, v := range rr.addrs { | ||
174 | if addr == v.addr { | ||
175 | exist = true | ||
176 | grpclog.Infoln("grpc: The name resolver wanted to add an existing address: ", addr) | ||
177 | break | ||
178 | } | ||
179 | } | ||
180 | if exist { | ||
181 | continue | ||
182 | } | ||
183 | rr.addrs = append(rr.addrs, &addrInfo{addr: addr}) | ||
184 | case naming.Delete: | ||
185 | for i, v := range rr.addrs { | ||
186 | if addr == v.addr { | ||
187 | copy(rr.addrs[i:], rr.addrs[i+1:]) | ||
188 | rr.addrs = rr.addrs[:len(rr.addrs)-1] | ||
189 | break | ||
190 | } | ||
191 | } | ||
192 | default: | ||
193 | grpclog.Errorln("Unknown update.Op ", update.Op) | ||
194 | } | ||
195 | } | ||
196 | // Make a copy of rr.addrs and write it onto rr.addrCh so that gRPC internals gets notified. | ||
197 | open := make([]Address, len(rr.addrs)) | ||
198 | for i, v := range rr.addrs { | ||
199 | open[i] = v.addr | ||
200 | } | ||
201 | if rr.done { | ||
202 | return ErrClientConnClosing | ||
203 | } | ||
204 | select { | ||
205 | case <-rr.addrCh: | ||
206 | default: | ||
207 | } | ||
208 | rr.addrCh <- open | ||
209 | return nil | ||
210 | } | ||
211 | |||
212 | func (rr *roundRobin) Start(target string, config BalancerConfig) error { | ||
213 | rr.mu.Lock() | ||
214 | defer rr.mu.Unlock() | ||
215 | if rr.done { | ||
216 | return ErrClientConnClosing | ||
217 | } | ||
218 | if rr.r == nil { | ||
219 | // If there is no name resolver installed, it is not needed to | ||
220 | // do name resolution. In this case, target is added into rr.addrs | ||
221 | // as the only address available and rr.addrCh stays nil. | ||
222 | rr.addrs = append(rr.addrs, &addrInfo{addr: Address{Addr: target}}) | ||
223 | return nil | ||
224 | } | ||
225 | w, err := rr.r.Resolve(target) | ||
226 | if err != nil { | ||
227 | return err | ||
228 | } | ||
229 | rr.w = w | ||
230 | rr.addrCh = make(chan []Address, 1) | ||
231 | go func() { | ||
232 | for { | ||
233 | if err := rr.watchAddrUpdates(); err != nil { | ||
234 | return | ||
235 | } | ||
236 | } | ||
237 | }() | ||
238 | return nil | ||
239 | } | ||
240 | |||
241 | // Up sets the connected state of addr and sends notification if there are pending | ||
242 | // Get() calls. | ||
243 | func (rr *roundRobin) Up(addr Address) func(error) { | ||
244 | rr.mu.Lock() | ||
245 | defer rr.mu.Unlock() | ||
246 | var cnt int | ||
247 | for _, a := range rr.addrs { | ||
248 | if a.addr == addr { | ||
249 | if a.connected { | ||
250 | return nil | ||
251 | } | ||
252 | a.connected = true | ||
253 | } | ||
254 | if a.connected { | ||
255 | cnt++ | ||
256 | } | ||
257 | } | ||
258 | // addr is only one which is connected. Notify the Get() callers who are blocking. | ||
259 | if cnt == 1 && rr.waitCh != nil { | ||
260 | close(rr.waitCh) | ||
261 | rr.waitCh = nil | ||
262 | } | ||
263 | return func(err error) { | ||
264 | rr.down(addr, err) | ||
265 | } | ||
266 | } | ||
267 | |||
268 | // down unsets the connected state of addr. | ||
269 | func (rr *roundRobin) down(addr Address, err error) { | ||
270 | rr.mu.Lock() | ||
271 | defer rr.mu.Unlock() | ||
272 | for _, a := range rr.addrs { | ||
273 | if addr == a.addr { | ||
274 | a.connected = false | ||
275 | break | ||
276 | } | ||
277 | } | ||
278 | } | ||
279 | |||
280 | // Get returns the next addr in the rotation. | ||
281 | func (rr *roundRobin) Get(ctx context.Context, opts BalancerGetOptions) (addr Address, put func(), err error) { | ||
282 | var ch chan struct{} | ||
283 | rr.mu.Lock() | ||
284 | if rr.done { | ||
285 | rr.mu.Unlock() | ||
286 | err = ErrClientConnClosing | ||
287 | return | ||
288 | } | ||
289 | |||
290 | if len(rr.addrs) > 0 { | ||
291 | if rr.next >= len(rr.addrs) { | ||
292 | rr.next = 0 | ||
293 | } | ||
294 | next := rr.next | ||
295 | for { | ||
296 | a := rr.addrs[next] | ||
297 | next = (next + 1) % len(rr.addrs) | ||
298 | if a.connected { | ||
299 | addr = a.addr | ||
300 | rr.next = next | ||
301 | rr.mu.Unlock() | ||
302 | return | ||
303 | } | ||
304 | if next == rr.next { | ||
305 | // Has iterated all the possible address but none is connected. | ||
306 | break | ||
307 | } | ||
308 | } | ||
309 | } | ||
310 | if !opts.BlockingWait { | ||
311 | if len(rr.addrs) == 0 { | ||
312 | rr.mu.Unlock() | ||
313 | err = Errorf(codes.Unavailable, "there is no address available") | ||
314 | return | ||
315 | } | ||
316 | // Returns the next addr on rr.addrs for failfast RPCs. | ||
317 | addr = rr.addrs[rr.next].addr | ||
318 | rr.next++ | ||
319 | rr.mu.Unlock() | ||
320 | return | ||
321 | } | ||
322 | // Wait on rr.waitCh for non-failfast RPCs. | ||
323 | if rr.waitCh == nil { | ||
324 | ch = make(chan struct{}) | ||
325 | rr.waitCh = ch | ||
326 | } else { | ||
327 | ch = rr.waitCh | ||
328 | } | ||
329 | rr.mu.Unlock() | ||
330 | for { | ||
331 | select { | ||
332 | case <-ctx.Done(): | ||
333 | err = ctx.Err() | ||
334 | return | ||
335 | case <-ch: | ||
336 | rr.mu.Lock() | ||
337 | if rr.done { | ||
338 | rr.mu.Unlock() | ||
339 | err = ErrClientConnClosing | ||
340 | return | ||
341 | } | ||
342 | |||
343 | if len(rr.addrs) > 0 { | ||
344 | if rr.next >= len(rr.addrs) { | ||
345 | rr.next = 0 | ||
346 | } | ||
347 | next := rr.next | ||
348 | for { | ||
349 | a := rr.addrs[next] | ||
350 | next = (next + 1) % len(rr.addrs) | ||
351 | if a.connected { | ||
352 | addr = a.addr | ||
353 | rr.next = next | ||
354 | rr.mu.Unlock() | ||
355 | return | ||
356 | } | ||
357 | if next == rr.next { | ||
358 | // Has iterated all the possible address but none is connected. | ||
359 | break | ||
360 | } | ||
361 | } | ||
362 | } | ||
363 | // The newly added addr got removed by Down() again. | ||
364 | if rr.waitCh == nil { | ||
365 | ch = make(chan struct{}) | ||
366 | rr.waitCh = ch | ||
367 | } else { | ||
368 | ch = rr.waitCh | ||
369 | } | ||
370 | rr.mu.Unlock() | ||
371 | } | ||
372 | } | ||
373 | } | ||
374 | |||
375 | func (rr *roundRobin) Notify() <-chan []Address { | ||
376 | return rr.addrCh | ||
377 | } | ||
378 | |||
379 | func (rr *roundRobin) Close() error { | ||
380 | rr.mu.Lock() | ||
381 | defer rr.mu.Unlock() | ||
382 | if rr.done { | ||
383 | return errBalancerClosed | ||
384 | } | ||
385 | rr.done = true | ||
386 | if rr.w != nil { | ||
387 | rr.w.Close() | ||
388 | } | ||
389 | if rr.waitCh != nil { | ||
390 | close(rr.waitCh) | ||
391 | rr.waitCh = nil | ||
392 | } | ||
393 | if rr.addrCh != nil { | ||
394 | close(rr.addrCh) | ||
395 | } | ||
396 | return nil | ||
397 | } | ||