Don't run monitor if empty.

This commit is contained in:
Joachim Bauch 2024-01-30 16:14:28 +01:00
parent b1c78f6e9d
commit 2c4cdedcae
No known key found for this signature in database
GPG key ID: 77C1D22D53E15F02
2 changed files with 52 additions and 1 deletions

View file

@ -126,7 +126,11 @@ type DnsMonitor struct {
stopFunc func() stopFunc func()
mu sync.RWMutex mu sync.RWMutex
cond *sync.Cond
hostnames map[string]*dnsMonitorEntry hostnames map[string]*dnsMonitorEntry
// Can be overwritten from tests.
checkHostnames func()
} }
func NewDnsMonitor(interval time.Duration) (*DnsMonitor, error) { func NewDnsMonitor(interval time.Duration) (*DnsMonitor, error) {
@ -143,6 +147,8 @@ func NewDnsMonitor(interval time.Duration) (*DnsMonitor, error) {
hostnames: make(map[string]*dnsMonitorEntry), hostnames: make(map[string]*dnsMonitorEntry),
} }
monitor.cond = sync.NewCond(&monitor.mu)
monitor.checkHostnames = monitor.doCheckHostnames
return monitor, nil return monitor, nil
} }
@ -153,6 +159,7 @@ func (m *DnsMonitor) Start() error {
func (m *DnsMonitor) Stop() { func (m *DnsMonitor) Stop() {
m.stopFunc() m.stopFunc()
m.cond.Signal()
} }
func (m *DnsMonitor) Add(target string, callback DnsMonitorCallback) (*DnsMonitorEntry, error) { func (m *DnsMonitor) Add(target string, callback DnsMonitorCallback) (*DnsMonitorEntry, error) {
@ -191,6 +198,7 @@ func (m *DnsMonitor) Add(target string, callback DnsMonitorCallback) (*DnsMonito
} }
e.entry = entry e.entry = entry
entry.entries[e] = true entry.entries[e] = true
m.cond.Signal()
return e, nil return e, nil
} }
@ -209,11 +217,37 @@ func (m *DnsMonitor) Remove(entry *DnsMonitorEntry) {
entry.entry = nil entry.entry = nil
delete(e.entries, entry) delete(e.entries, entry)
if len(e.entries) == 0 {
delete(m.hostnames, e.hostname)
}
}
func (m *DnsMonitor) waitForEntries() (waited bool) {
m.mu.Lock()
defer m.mu.Unlock()
for len(m.hostnames) == 0 && m.stopCtx.Err() == nil {
m.cond.Wait()
waited = true
}
return
} }
func (m *DnsMonitor) run() { func (m *DnsMonitor) run() {
ticker := time.NewTicker(m.interval) ticker := time.NewTicker(m.interval)
defer ticker.Stop()
for { for {
if m.waitForEntries() {
ticker.Reset(m.interval)
if m.stopCtx.Err() == nil {
// Initial check when a new entry was added. More checks will be
// triggered by the Ticker.
m.checkHostnames()
continue
}
}
select { select {
case <-m.stopCtx.Done(): case <-m.stopCtx.Done():
return return
@ -223,7 +257,7 @@ func (m *DnsMonitor) run() {
} }
} }
func (m *DnsMonitor) checkHostnames() { func (m *DnsMonitor) doCheckHostnames() {
m.mu.RLock() m.mu.RLock()
defer m.mu.RUnlock() defer m.mu.RUnlock()

View file

@ -27,6 +27,7 @@ import (
"net" "net"
"reflect" "reflect"
"sync" "sync"
"sync/atomic"
"testing" "testing"
"time" "time"
) )
@ -315,3 +316,19 @@ func TestDnsMonitorIP(t *testing.T) {
rec1.ExpectNone() rec1.ExpectNone()
time.Sleep(5 * interval) time.Sleep(5 * interval)
} }
func TestDnsMonitorNoLookupIfEmpty(t *testing.T) {
interval := time.Millisecond
monitor := newDnsMonitorForTest(t, interval)
var checked atomic.Bool
monitor.checkHostnames = func() {
checked.Store(true)
monitor.doCheckHostnames()
}
time.Sleep(10 * interval)
if checked.Load() {
t.Error("should not have checked hostnames")
}
}