]> Cypherpunks repositories - gostls13.git/commitdiff
net/http: use atomic.Value for Transport's alternate protocol map
authorBrad Fitzpatrick <bradfitz@golang.org>
Thu, 29 Sep 2016 15:51:29 +0000 (08:51 -0700)
committerBrad Fitzpatrick <bradfitz@golang.org>
Thu, 29 Sep 2016 20:43:04 +0000 (20:43 +0000)
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 <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
src/net/http/transport.go

index ed2b3a26edaca7bd9087aba1de217ad38929b316..5594c948cd8854139231e8a442f0757b6a11540b 100644 (file)
@@ -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