Code refactoring for bpa operator
[icn.git] / cmd / bpa-operator / vendor / golang.org / x / net / http2 / client_conn_pool.go
1 // Copyright 2015 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 // Transport code's client connection pooling.
6
7 package http2
8
9 import (
10         "crypto/tls"
11         "net/http"
12         "sync"
13 )
14
15 // ClientConnPool manages a pool of HTTP/2 client connections.
16 type ClientConnPool interface {
17         GetClientConn(req *http.Request, addr string) (*ClientConn, error)
18         MarkDead(*ClientConn)
19 }
20
21 // clientConnPoolIdleCloser is the interface implemented by ClientConnPool
22 // implementations which can close their idle connections.
23 type clientConnPoolIdleCloser interface {
24         ClientConnPool
25         closeIdleConnections()
26 }
27
28 var (
29         _ clientConnPoolIdleCloser = (*clientConnPool)(nil)
30         _ clientConnPoolIdleCloser = noDialClientConnPool{}
31 )
32
33 // TODO: use singleflight for dialing and addConnCalls?
34 type clientConnPool struct {
35         t *Transport
36
37         mu sync.Mutex // TODO: maybe switch to RWMutex
38         // TODO: add support for sharing conns based on cert names
39         // (e.g. share conn for googleapis.com and appspot.com)
40         conns        map[string][]*ClientConn // key is host:port
41         dialing      map[string]*dialCall     // currently in-flight dials
42         keys         map[*ClientConn][]string
43         addConnCalls map[string]*addConnCall // in-flight addConnIfNeede calls
44 }
45
46 func (p *clientConnPool) GetClientConn(req *http.Request, addr string) (*ClientConn, error) {
47         return p.getClientConn(req, addr, dialOnMiss)
48 }
49
50 const (
51         dialOnMiss   = true
52         noDialOnMiss = false
53 )
54
55 // shouldTraceGetConn reports whether getClientConn should call any
56 // ClientTrace.GetConn hook associated with the http.Request.
57 //
58 // This complexity is needed to avoid double calls of the GetConn hook
59 // during the back-and-forth between net/http and x/net/http2 (when the
60 // net/http.Transport is upgraded to also speak http2), as well as support
61 // the case where x/net/http2 is being used directly.
62 func (p *clientConnPool) shouldTraceGetConn(st clientConnIdleState) bool {
63         // If our Transport wasn't made via ConfigureTransport, always
64         // trace the GetConn hook if provided, because that means the
65         // http2 package is being used directly and it's the one
66         // dialing, as opposed to net/http.
67         if _, ok := p.t.ConnPool.(noDialClientConnPool); !ok {
68                 return true
69         }
70         // Otherwise, only use the GetConn hook if this connection has
71         // been used previously for other requests. For fresh
72         // connections, the net/http package does the dialing.
73         return !st.freshConn
74 }
75
76 func (p *clientConnPool) getClientConn(req *http.Request, addr string, dialOnMiss bool) (*ClientConn, error) {
77         if isConnectionCloseRequest(req) && dialOnMiss {
78                 // It gets its own connection.
79                 traceGetConn(req, addr)
80                 const singleUse = true
81                 cc, err := p.t.dialClientConn(addr, singleUse)
82                 if err != nil {
83                         return nil, err
84                 }
85                 return cc, nil
86         }
87         p.mu.Lock()
88         for _, cc := range p.conns[addr] {
89                 if st := cc.idleState(); st.canTakeNewRequest {
90                         if p.shouldTraceGetConn(st) {
91                                 traceGetConn(req, addr)
92                         }
93                         p.mu.Unlock()
94                         return cc, nil
95                 }
96         }
97         if !dialOnMiss {
98                 p.mu.Unlock()
99                 return nil, ErrNoCachedConn
100         }
101         traceGetConn(req, addr)
102         call := p.getStartDialLocked(addr)
103         p.mu.Unlock()
104         <-call.done
105         return call.res, call.err
106 }
107
108 // dialCall is an in-flight Transport dial call to a host.
109 type dialCall struct {
110         p    *clientConnPool
111         done chan struct{} // closed when done
112         res  *ClientConn   // valid after done is closed
113         err  error         // valid after done is closed
114 }
115
116 // requires p.mu is held.
117 func (p *clientConnPool) getStartDialLocked(addr string) *dialCall {
118         if call, ok := p.dialing[addr]; ok {
119                 // A dial is already in-flight. Don't start another.
120                 return call
121         }
122         call := &dialCall{p: p, done: make(chan struct{})}
123         if p.dialing == nil {
124                 p.dialing = make(map[string]*dialCall)
125         }
126         p.dialing[addr] = call
127         go call.dial(addr)
128         return call
129 }
130
131 // run in its own goroutine.
132 func (c *dialCall) dial(addr string) {
133         const singleUse = false // shared conn
134         c.res, c.err = c.p.t.dialClientConn(addr, singleUse)
135         close(c.done)
136
137         c.p.mu.Lock()
138         delete(c.p.dialing, addr)
139         if c.err == nil {
140                 c.p.addConnLocked(addr, c.res)
141         }
142         c.p.mu.Unlock()
143 }
144
145 // addConnIfNeeded makes a NewClientConn out of c if a connection for key doesn't
146 // already exist. It coalesces concurrent calls with the same key.
147 // This is used by the http1 Transport code when it creates a new connection. Because
148 // the http1 Transport doesn't de-dup TCP dials to outbound hosts (because it doesn't know
149 // the protocol), it can get into a situation where it has multiple TLS connections.
150 // This code decides which ones live or die.
151 // The return value used is whether c was used.
152 // c is never closed.
153 func (p *clientConnPool) addConnIfNeeded(key string, t *Transport, c *tls.Conn) (used bool, err error) {
154         p.mu.Lock()
155         for _, cc := range p.conns[key] {
156                 if cc.CanTakeNewRequest() {
157                         p.mu.Unlock()
158                         return false, nil
159                 }
160         }
161         call, dup := p.addConnCalls[key]
162         if !dup {
163                 if p.addConnCalls == nil {
164                         p.addConnCalls = make(map[string]*addConnCall)
165                 }
166                 call = &addConnCall{
167                         p:    p,
168                         done: make(chan struct{}),
169                 }
170                 p.addConnCalls[key] = call
171                 go call.run(t, key, c)
172         }
173         p.mu.Unlock()
174
175         <-call.done
176         if call.err != nil {
177                 return false, call.err
178         }
179         return !dup, nil
180 }
181
182 type addConnCall struct {
183         p    *clientConnPool
184         done chan struct{} // closed when done
185         err  error
186 }
187
188 func (c *addConnCall) run(t *Transport, key string, tc *tls.Conn) {
189         cc, err := t.NewClientConn(tc)
190
191         p := c.p
192         p.mu.Lock()
193         if err != nil {
194                 c.err = err
195         } else {
196                 p.addConnLocked(key, cc)
197         }
198         delete(p.addConnCalls, key)
199         p.mu.Unlock()
200         close(c.done)
201 }
202
203 func (p *clientConnPool) addConn(key string, cc *ClientConn) {
204         p.mu.Lock()
205         p.addConnLocked(key, cc)
206         p.mu.Unlock()
207 }
208
209 // p.mu must be held
210 func (p *clientConnPool) addConnLocked(key string, cc *ClientConn) {
211         for _, v := range p.conns[key] {
212                 if v == cc {
213                         return
214                 }
215         }
216         if p.conns == nil {
217                 p.conns = make(map[string][]*ClientConn)
218         }
219         if p.keys == nil {
220                 p.keys = make(map[*ClientConn][]string)
221         }
222         p.conns[key] = append(p.conns[key], cc)
223         p.keys[cc] = append(p.keys[cc], key)
224 }
225
226 func (p *clientConnPool) MarkDead(cc *ClientConn) {
227         p.mu.Lock()
228         defer p.mu.Unlock()
229         for _, key := range p.keys[cc] {
230                 vv, ok := p.conns[key]
231                 if !ok {
232                         continue
233                 }
234                 newList := filterOutClientConn(vv, cc)
235                 if len(newList) > 0 {
236                         p.conns[key] = newList
237                 } else {
238                         delete(p.conns, key)
239                 }
240         }
241         delete(p.keys, cc)
242 }
243
244 func (p *clientConnPool) closeIdleConnections() {
245         p.mu.Lock()
246         defer p.mu.Unlock()
247         // TODO: don't close a cc if it was just added to the pool
248         // milliseconds ago and has never been used. There's currently
249         // a small race window with the HTTP/1 Transport's integration
250         // where it can add an idle conn just before using it, and
251         // somebody else can concurrently call CloseIdleConns and
252         // break some caller's RoundTrip.
253         for _, vv := range p.conns {
254                 for _, cc := range vv {
255                         cc.closeIfIdle()
256                 }
257         }
258 }
259
260 func filterOutClientConn(in []*ClientConn, exclude *ClientConn) []*ClientConn {
261         out := in[:0]
262         for _, v := range in {
263                 if v != exclude {
264                         out = append(out, v)
265                 }
266         }
267         // If we filtered it out, zero out the last item to prevent
268         // the GC from seeing it.
269         if len(in) != len(out) {
270                 in[len(in)-1] = nil
271         }
272         return out
273 }
274
275 // noDialClientConnPool is an implementation of http2.ClientConnPool
276 // which never dials. We let the HTTP/1.1 client dial and use its TLS
277 // connection instead.
278 type noDialClientConnPool struct{ *clientConnPool }
279
280 func (p noDialClientConnPool) GetClientConn(req *http.Request, addr string) (*ClientConn, error) {
281         return p.getClientConn(req, addr, noDialOnMiss)
282 }