diff options
| author | Brad Fitzpatrick <bradfitz@golang.org> | 2015-11-30 12:07:50 -0800 |
|---|---|---|
| committer | Brad Fitzpatrick <bradfitz@golang.org> | 2015-11-30 20:48:24 +0000 |
| commit | ccdcd6e903dd01d7d1cb8385edd0275740bab694 (patch) | |
| tree | 3aa49d69c7aef7b36a4524dacdb24559bb9969a7 /src/net/http/h2_bundle.go | |
| parent | afc2c45f05ad1091f1176f37ba90fb813b2776be (diff) | |
| download | go-ccdcd6e903dd01d7d1cb8385edd0275740bab694.tar.xz | |
net/http: update h2_bundle.go
Updates to x/net rev 195180cf
(golang.org/cl/17134, http2: merge duplicate Transport dials)
Change-Id: I50b9c73b30c6a21e725aad80126b713d8b0fa362
Reviewed-on: https://go-review.googlesource.com/17261
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Diffstat (limited to 'src/net/http/h2_bundle.go')
| -rw-r--r-- | src/net/http/h2_bundle.go | 64 |
1 files changed, 54 insertions, 10 deletions
diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go index d9046c4c18..41b4bc14dd 100644 --- a/src/net/http/h2_bundle.go +++ b/src/net/http/h2_bundle.go @@ -45,11 +45,12 @@ type http2ClientConnPool interface { type http2clientConnPool struct { t *http2Transport - mu sync.Mutex // TODO: switch to RWMutex + mu sync.Mutex // TODO: maybe switch to RWMutex // TODO: add support for sharing conns based on cert names // (e.g. share conn for googleapis.com and appspot.com) - conns map[string][]*http2ClientConn // key is host:port - keys map[*http2ClientConn][]string + conns map[string][]*http2ClientConn // key is host:port + dialing map[string]*http2dialCall // currently in-flight dials + keys map[*http2ClientConn][]string } func (p *http2clientConnPool) GetClientConn(req *Request, addr string) (*http2ClientConn, error) { @@ -64,22 +65,65 @@ func (p *http2clientConnPool) getClientConn(req *Request, addr string, dialOnMis return cc, nil } } - p.mu.Unlock() if !dialOnMiss { + p.mu.Unlock() return nil, http2ErrNoCachedConn } + call := p.getStartDialLocked(addr) + p.mu.Unlock() + <-call.done + return call.res, call.err +} - cc, err := p.t.dialClientConn(addr) - if err != nil { - return nil, err +// dialCall is an in-flight Transport dial call to a host. +type http2dialCall struct { + p *http2clientConnPool + done chan struct{} // closed when done + res *http2ClientConn // valid after done is closed + err error // valid after done is closed +} + +// requires p.mu is held. +func (p *http2clientConnPool) getStartDialLocked(addr string) *http2dialCall { + if call, ok := p.dialing[addr]; ok { + + return call } - p.addConn(addr, cc) - return cc, nil + call := &http2dialCall{p: p, done: make(chan struct{})} + if p.dialing == nil { + p.dialing = make(map[string]*http2dialCall) + } + p.dialing[addr] = call + go call.dial(addr) + return call +} + +// run in its own goroutine. +func (c *http2dialCall) dial(addr string) { + c.res, c.err = c.p.t.dialClientConn(addr) + close(c.done) + + c.p.mu.Lock() + delete(c.p.dialing, addr) + if c.err == nil { + c.p.addConnLocked(addr, c.res) + } + c.p.mu.Unlock() } func (p *http2clientConnPool) addConn(key string, cc *http2ClientConn) { p.mu.Lock() - defer p.mu.Unlock() + p.addConnLocked(key, cc) + p.mu.Unlock() +} + +// p.mu must be held +func (p *http2clientConnPool) addConnLocked(key string, cc *http2ClientConn) { + for _, v := range p.conns[key] { + if v == cc { + return + } + } if p.conns == nil { p.conns = make(map[string][]*http2ClientConn) } |
