Pull request: data race

Merge in DNS/adguard-home from 2489-data-race to master

Closes #2489.

Squashed commit of the following:

commit 7745b79f0489970f3ba1bb11bb757b998fa6369c
Merge: d070cfd53 93ffed780
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Mon Dec 28 19:00:07 2020 +0300

    Merge branch 'master' into 2489-data-race

commit d070cfd53e72b609f305cd8d79d747fbf47dc5f4
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Fri Dec 25 20:31:21 2020 +0300

    util: fix ignoring write events bug

commit 725850bdbd96eaf65fb3228fcaeba51a3ec95905
Author: Eugene Burkov <e.burkov@adguard.com>
Date:   Fri Dec 25 17:38:29 2020 +0300

    util: simpl hosts upd algo
This commit is contained in:
Eugene Burkov 2020-12-28 19:07:29 +03:00
parent 93ffed7809
commit 8a1d86aa7d
1 changed files with 25 additions and 30 deletions

View File

@ -29,10 +29,12 @@ type AutoHosts struct {
// TODO(a.garipov): Make better use of newtypes. Perhaps a custom map. // TODO(a.garipov): Make better use of newtypes. Perhaps a custom map.
tableReverse map[string][]string tableReverse map[string][]string
hostsFn string // path to the main hosts-file hostsFn string // path to the main hosts-file
hostsDirs []string // paths to OS-specific directories with hosts-files hostsDirs []string // paths to OS-specific directories with hosts-files
watcher *fsnotify.Watcher // file and directory watcher object watcher *fsnotify.Watcher // file and directory watcher object
updateChan chan bool // signal for 'updateLoop' goroutine
// onlyWritesChan used to contain only writing events from watcher.
onlyWritesChan chan fsnotify.Event
onChanged onChangedT // notification to other modules onChanged onChangedT // notification to other modules
} }
@ -54,7 +56,7 @@ func (a *AutoHosts) notify() {
// hostsFn: Override default name for the hosts-file (optional) // hostsFn: Override default name for the hosts-file (optional)
func (a *AutoHosts) Init(hostsFn string) { func (a *AutoHosts) Init(hostsFn string) {
a.table = make(map[string][]net.IP) a.table = make(map[string][]net.IP)
a.updateChan = make(chan bool, 2) a.onlyWritesChan = make(chan fsnotify.Event, 2)
a.hostsFn = "/etc/hosts" a.hostsFn = "/etc/hosts"
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {
@ -82,8 +84,7 @@ func (a *AutoHosts) Init(hostsFn string) {
func (a *AutoHosts) Start() { func (a *AutoHosts) Start() {
log.Debug("Start AutoHosts module") log.Debug("Start AutoHosts module")
go a.updateLoop() a.updateHosts()
a.updateChan <- true
if a.watcher != nil { if a.watcher != nil {
go a.watcherLoop() go a.watcherLoop()
@ -104,11 +105,10 @@ func (a *AutoHosts) Start() {
// Close - close module // Close - close module
func (a *AutoHosts) Close() { func (a *AutoHosts) Close() {
a.updateChan <- false
close(a.updateChan)
if a.watcher != nil { if a.watcher != nil {
_ = a.watcher.Close() _ = a.watcher.Close()
} }
close(a.onlyWritesChan)
} }
// Process returns the list of IP addresses for the hostname or nil if nothing // Process returns the list of IP addresses for the hostname or nil if nothing
@ -273,20 +273,32 @@ func (a *AutoHosts) load(table map[string][]net.IP, tableRev map[string][]string
} }
} }
// onlyWrites is a filter for (*fsnotify.Watcher).Events.
func (a *AutoHosts) onlyWrites() {
for event := range a.watcher.Events {
if event.Op&fsnotify.Write == fsnotify.Write {
a.onlyWritesChan <- event
}
}
}
// Receive notifications from fsnotify package // Receive notifications from fsnotify package
func (a *AutoHosts) watcherLoop() { func (a *AutoHosts) watcherLoop() {
go a.onlyWrites()
for { for {
select { select {
case event, ok := <-a.watcher.Events: case event, ok := <-a.onlyWritesChan:
if !ok { if !ok {
return return
} }
// Assume that we sometimes have the same event occurred
// several times.
repeat := true repeat := true
for repeat { for repeat {
select { select {
case <-a.watcher.Events: case _, ok = <-a.onlyWritesChan:
// Skip this duplicating event repeat = ok
default: default:
repeat = false repeat = false
} }
@ -294,12 +306,7 @@ func (a *AutoHosts) watcherLoop() {
if event.Op&fsnotify.Write == fsnotify.Write { if event.Op&fsnotify.Write == fsnotify.Write {
log.Debug("AutoHosts: modified: %s", event.Name) log.Debug("AutoHosts: modified: %s", event.Name)
select { a.updateHosts()
case a.updateChan <- true:
// sent a signal to 'updateLoop' goroutine
default:
// queue is full
}
} }
case err, ok := <-a.watcher.Errors: case err, ok := <-a.watcher.Errors:
@ -311,18 +318,6 @@ func (a *AutoHosts) watcherLoop() {
} }
} }
// updateLoop reads static hosts from system files.
func (a *AutoHosts) updateLoop() {
for ok := range a.updateChan {
if !ok {
log.Debug("Finished AutoHosts update loop")
return
}
a.updateHosts()
}
}
// updateHosts - loads system hosts // updateHosts - loads system hosts
func (a *AutoHosts) updateHosts() { func (a *AutoHosts) updateHosts() {
table := make(map[string][]net.IP) table := make(map[string][]net.IP)