From c1e06dcb611822ba3c881b170f278d18237372c9 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Thu, 29 Sep 2016 08:51:29 -0700 Subject: [PATCH] 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 --- src/net/http/transport.go | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) 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 -- 2.48.1