From: Brad Fitzpatrick Date: Thu, 29 Sep 2016 15:51:29 +0000 (-0700) Subject: net/http: use atomic.Value for Transport's alternate protocol map X-Git-Tag: go1.8beta1~1107 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=c1e06dcb611822ba3c881b170f278d18237372c9;p=gostls13.git net/http: use atomic.Value for Transport's alternate protocol map Fix an old TODO and use atomic.Value for holding the Transport's alternate protocol map. It is very frequently accessed and almost never set or updated. Change-Id: Ic5a71c504bdac76678114c6390d1fc0673e07aa9 Reviewed-on: https://go-review.googlesource.com/29967 Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- diff --git a/src/net/http/transport.go b/src/net/http/transport.go index ed2b3a26ed..5594c948cd 100644 --- a/src/net/http/transport.go +++ b/src/net/http/transport.go @@ -25,6 +25,7 @@ import ( "os" "strings" "sync" + "sync/atomic" "time" "golang_org/x/net/lex/httplex" @@ -79,8 +80,8 @@ type Transport struct { reqMu sync.Mutex reqCanceler map[*Request]func(error) - altMu sync.RWMutex - altProto map[string]RoundTripper // nil or map of URI scheme => RoundTripper + altMu sync.Mutex // guards changing altProto only + altProto atomic.Value // of nil or map[string]RoundTripper, key is URI scheme // Proxy specifies a function to return a proxy for a given // Request. If the function returns a non-nil error, the @@ -331,11 +332,9 @@ func (t *Transport) RoundTrip(req *Request) (*Response, error) { } } } - // TODO(bradfitz): switch to atomic.Value for this map instead of RWMutex - t.altMu.RLock() - altRT := t.altProto[scheme] - t.altMu.RUnlock() - if altRT != nil { + + altProto, _ := t.altProto.Load().(map[string]RoundTripper) + if altRT := altProto[scheme]; altRT != nil { if resp, err := altRT.RoundTrip(req); err != ErrSkipAltProtocol { return resp, err } @@ -460,13 +459,16 @@ var ErrSkipAltProtocol = errors.New("net/http: skip alternate protocol") func (t *Transport) RegisterProtocol(scheme string, rt RoundTripper) { t.altMu.Lock() defer t.altMu.Unlock() - if t.altProto == nil { - t.altProto = make(map[string]RoundTripper) - } - if _, exists := t.altProto[scheme]; exists { + oldMap, _ := t.altProto.Load().(map[string]RoundTripper) + if _, exists := oldMap[scheme]; exists { panic("protocol " + scheme + " already registered") } - t.altProto[scheme] = rt + newMap := make(map[string]RoundTripper) + for k, v := range oldMap { + newMap[k] = v + } + newMap[scheme] = rt + t.altProto.Store(newMap) } // CloseIdleConnections closes any connections which were previously