From 2c4cdedcaebe9412a1f2ca05b0102ff96b21d147 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 30 Jan 2024 16:14:28 +0100 Subject: [PATCH] Don't run monitor if empty. --- dns_monitor.go | 36 +++++++++++++++++++++++++++++++++++- dns_monitor_test.go | 17 +++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/dns_monitor.go b/dns_monitor.go index be19d63..48f6231 100644 --- a/dns_monitor.go +++ b/dns_monitor.go @@ -126,7 +126,11 @@ type DnsMonitor struct { stopFunc func() mu sync.RWMutex + cond *sync.Cond hostnames map[string]*dnsMonitorEntry + + // Can be overwritten from tests. + checkHostnames func() } func NewDnsMonitor(interval time.Duration) (*DnsMonitor, error) { @@ -143,6 +147,8 @@ func NewDnsMonitor(interval time.Duration) (*DnsMonitor, error) { hostnames: make(map[string]*dnsMonitorEntry), } + monitor.cond = sync.NewCond(&monitor.mu) + monitor.checkHostnames = monitor.doCheckHostnames return monitor, nil } @@ -153,6 +159,7 @@ func (m *DnsMonitor) Start() error { func (m *DnsMonitor) Stop() { m.stopFunc() + m.cond.Signal() } 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 entry.entries[e] = true + m.cond.Signal() return e, nil } @@ -209,11 +217,37 @@ func (m *DnsMonitor) Remove(entry *DnsMonitorEntry) { entry.entry = nil 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() { ticker := time.NewTicker(m.interval) + defer ticker.Stop() + 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 { case <-m.stopCtx.Done(): return @@ -223,7 +257,7 @@ func (m *DnsMonitor) run() { } } -func (m *DnsMonitor) checkHostnames() { +func (m *DnsMonitor) doCheckHostnames() { m.mu.RLock() defer m.mu.RUnlock() diff --git a/dns_monitor_test.go b/dns_monitor_test.go index 72cd89d..0b1466d 100644 --- a/dns_monitor_test.go +++ b/dns_monitor_test.go @@ -27,6 +27,7 @@ import ( "net" "reflect" "sync" + "sync/atomic" "testing" "time" ) @@ -315,3 +316,19 @@ func TestDnsMonitorIP(t *testing.T) { rec1.ExpectNone() 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") + } +}