1
0
mirror of https://github.com/golang/go synced 2024-09-29 12:14:28 -06:00

net: change resolverConfig.dnsConfig to an atomic.Pointer

We were using a RWMutex RLock around a single memory load,
which is not a good use of a RWMutex--it introduces extra work
for the RLock but contention around a single memory load is unlikely.
And, the tryUpdate method was not acquiring the mutex anyhow.

The new atomic.Pointer type is type-safe and easy to use correctly
for a simple use-case like this.

Change-Id: Ib3859c03414c44d2e897f6d15c92c8e4b5c81a11
Reviewed-on: https://go-review.googlesource.com/c/go/+/451416
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Damien Neil <dneil@google.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Run-TryBot: Ian Lance Taylor <iant@google.com>
This commit is contained in:
Ian Lance Taylor 2022-11-16 14:19:47 -08:00 committed by Gopher Robot
parent a2d8157a7e
commit b7662047ae
2 changed files with 10 additions and 22 deletions

View File

@ -22,6 +22,7 @@ import (
"os"
"runtime"
"sync"
"sync/atomic"
"time"
"golang.org/x/net/dns/dnsmessage"
@ -342,25 +343,21 @@ type resolverConfig struct {
ch chan struct{} // guards lastChecked and modTime
lastChecked time.Time // last time resolv.conf was checked
mu sync.RWMutex // protects dnsConfig
dnsConfig *dnsConfig // parsed resolv.conf structure used in lookups
dnsConfig atomic.Pointer[dnsConfig] // parsed resolv.conf structure used in lookups
}
var resolvConf resolverConfig
func getSystemDNSConfig() *dnsConfig {
resolvConf.tryUpdate("/etc/resolv.conf")
resolvConf.mu.RLock()
resolv := resolvConf.dnsConfig
resolvConf.mu.RUnlock()
return resolv
return resolvConf.dnsConfig.Load()
}
// init initializes conf and is only called via conf.initOnce.
func (conf *resolverConfig) init() {
// Set dnsConfig and lastChecked so we don't parse
// resolv.conf twice the first time.
conf.dnsConfig = dnsReadConfig("/etc/resolv.conf")
conf.dnsConfig.Store(dnsReadConfig("/etc/resolv.conf"))
conf.lastChecked = time.Now()
// Prepare ch so that only one update of resolverConfig may
@ -374,7 +371,7 @@ func (conf *resolverConfig) init() {
func (conf *resolverConfig) tryUpdate(name string) {
conf.initOnce.Do(conf.init)
if conf.dnsConfig.noReload {
if conf.dnsConfig.Load().noReload {
return
}
@ -402,15 +399,13 @@ func (conf *resolverConfig) tryUpdate(name string) {
if fi, err := os.Stat(name); err == nil {
mtime = fi.ModTime()
}
if mtime.Equal(conf.dnsConfig.mtime) {
if mtime.Equal(conf.dnsConfig.Load().mtime) {
return
}
}
dnsConf := dnsReadConfig(name)
conf.mu.Lock()
conf.dnsConfig = dnsConf
conf.mu.Unlock()
conf.dnsConfig.Store(dnsConf)
}
func (conf *resolverConfig) tryAcquireSema() bool {

View File

@ -280,9 +280,7 @@ func (conf *resolvConfTest) forceUpdate(name string, lastChecked time.Time) erro
}
func (conf *resolvConfTest) forceUpdateConf(c *dnsConfig, lastChecked time.Time) bool {
conf.mu.Lock()
conf.dnsConfig = c
conf.mu.Unlock()
conf.dnsConfig.Store(c)
for i := 0; i < 5; i++ {
if conf.tryAcquireSema() {
conf.lastChecked = lastChecked
@ -294,10 +292,7 @@ func (conf *resolvConfTest) forceUpdateConf(c *dnsConfig, lastChecked time.Time)
}
func (conf *resolvConfTest) servers() []string {
conf.mu.RLock()
servers := conf.dnsConfig.servers
conf.mu.RUnlock()
return servers
return conf.dnsConfig.Load().servers
}
func (conf *resolvConfTest) teardown() error {
@ -1445,9 +1440,7 @@ func TestDNSGoroutineRace(t *testing.T) {
func lookupWithFake(fake fakeDNSServer, name string, typ dnsmessage.Type) error {
r := Resolver{PreferGo: true, Dial: fake.DialContext}
resolvConf.mu.RLock()
conf := resolvConf.dnsConfig
resolvConf.mu.RUnlock()
conf := resolvConf.dnsConfig.Load()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()