Feature: reuse dns resolver cache when hot reload

This commit is contained in:
Dreamacro 2020-08-31 00:32:18 +08:00
parent b8ed738238
commit a32ee13fc9
4 changed files with 48 additions and 0 deletions

View file

@ -146,6 +146,23 @@ func (c *LruCache) SetWithExpire(key interface{}, value interface{}, expires tim
c.maybeDeleteOldest() c.maybeDeleteOldest()
} }
// CloneTo clone and overwrite elements to another LruCache
func (c *LruCache) CloneTo(n *LruCache) {
c.mu.Lock()
defer c.mu.Unlock()
n.mu.Lock()
defer n.mu.Unlock()
n.lru = list.New()
n.cache = make(map[interface{}]*list.Element)
for e := c.lru.Front(); e != nil; e = e.Next() {
elm := e.Value.(*entry)
n.cache[elm.key] = n.lru.PushBack(elm)
}
}
func (c *LruCache) get(key interface{}) *entry { func (c *LruCache) get(key interface{}) *entry {
c.mu.Lock() c.mu.Lock()
defer c.mu.Unlock() defer c.mu.Unlock()

View file

@ -164,3 +164,21 @@ func TestStale(t *testing.T) {
assert.Equal(t, tenSecBefore, expires) assert.Equal(t, tenSecBefore, expires)
assert.Equal(t, true, exist) assert.Equal(t, true, exist)
} }
func TestCloneTo(t *testing.T) {
o := NewLRUCache(WithSize(10))
o.Set("1", 1)
o.Set("2", 2)
n := NewLRUCache(WithSize(2))
n.Set("3", 3)
n.Set("4", 4)
o.CloneTo(n)
assert.False(t, n.Exist("3"))
assert.True(t, n.Exist("1"))
n.Set("5", 5)
assert.False(t, n.Exist("1"))
}

View file

@ -186,6 +186,11 @@ func (r *Resolver) IsFakeIP(ip net.IP) bool {
return false return false
} }
// PatchCache overwrite lruCache to the new resolver
func (r *Resolver) PatchCache(n *Resolver) {
r.lruCache.CloneTo(n.lruCache)
}
func (r *Resolver) batchExchange(clients []dnsClient, m *D.Msg) (msg *D.Msg, err error) { func (r *Resolver) batchExchange(clients []dnsClient, m *D.Msg) (msg *D.Msg, err error) {
fast, ctx := picker.WithTimeout(context.Background(), time.Second*5) fast, ctx := picker.WithTimeout(context.Background(), time.Second*5)
for _, client := range clients { for _, client := range clients {

View file

@ -120,6 +120,14 @@ func updateDNS(c *config.DNS) {
}, },
Default: c.DefaultNameserver, Default: c.DefaultNameserver,
}) })
// reuse cache of old resolver
if resolver.DefaultResolver != nil {
if o, ok := resolver.DefaultResolver.(*dns.Resolver); ok {
o.PatchCache(r)
}
}
resolver.DefaultResolver = r resolver.DefaultResolver = r
tunnel.SetResolver(r) tunnel.SetResolver(r)
if err := dns.ReCreateServer(c.Listen, r); err != nil { if err := dns.ReCreateServer(c.Listen, r); err != nil {