From b541f6e3717629fbc3f0d0f463835a97b30e578a Mon Sep 17 00:00:00 2001 From: Dhananjay Balan Date: Fri, 12 Feb 2016 18:59:25 +0530 Subject: [PATCH 1/4] Add memcache config entries --- godns.conf | 5 ++++- settings.go | 5 +++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/godns.conf b/godns.conf index c66a1fb..692a888 100644 --- a/godns.conf +++ b/godns.conf @@ -24,6 +24,9 @@ port = 6379 db = 0 password ="" +[memcache] +servers = ["127.0.0.1:11211"] + [log] stdout = true file = "./godns.log" @@ -32,7 +35,7 @@ level = "INFO" #DEBUG | INFO |NOTICE | WARN | ERROR [cache] -# backend option [memory|redis] +# backend option [memory|memcache|redis] # redis backend not implemented yet backend = "memory" expire = 600 # 10 minutes diff --git a/settings.go b/settings.go index a9f3282..330d874 100644 --- a/settings.go +++ b/settings.go @@ -27,6 +27,7 @@ type Settings struct { Server DNSServerSettings `toml:"server"` ResolvConfig ResolvSettings `toml:"resolv"` Redis RedisSettings `toml:"redis"` + Memcache MemcacheSettings `toml:"memcache"` Log LogSettings `toml:"log"` Cache CacheSettings `toml:"cache"` Hosts HostsSettings `toml:"hosts"` @@ -50,6 +51,10 @@ type RedisSettings struct { Password string } +type MemcacheSettings struct { + Servers []string +} + func (s RedisSettings) Addr() string { return s.Host + ":" + strconv.Itoa(s.Port) } From 8c4b338257a616e079d48241284b012a7938b660 Mon Sep 17 00:00:00 2001 From: Dhananjay Balan Date: Fri, 12 Feb 2016 21:38:48 +0530 Subject: [PATCH 2/4] Add intial memcache support. FIXME: serialization needs work. --- cache.go | 87 +++++++++++++++++++++++++++++++++++++++++++++++++----- godns.conf | 4 +-- handler.go | 7 +++++ 3 files changed, 88 insertions(+), 10 deletions(-) diff --git a/cache.go b/cache.go index 126491e..6d80acd 100644 --- a/cache.go +++ b/cache.go @@ -7,6 +7,7 @@ import ( "sync" "time" + "github.com/bradfitz/gomemcache/memcache" "github.com/hoisie/redis" "github.com/miekg/dns" ) @@ -50,8 +51,13 @@ type Cache interface { Get(key string) (Msg *dns.Msg, err error) Set(key string, Msg *dns.Msg) error Exists(key string) bool - Remove(key string) - Length() int + Remove(key string) error + Full() bool +} + +type Serializer interface { + Loads([]byte) (*dns.Msg, error) + Dumps(*dns.Msg) ([]byte, error) } type MemoryCache struct { @@ -91,10 +97,11 @@ func (c *MemoryCache) Set(key string, msg *dns.Msg) error { return nil } -func (c *MemoryCache) Remove(key string) { +func (c *MemoryCache) Remove(key string) error { c.mu.Lock() delete(c.Backend, key) c.mu.Unlock() + return nil } func (c *MemoryCache) Exists(key string) bool { @@ -118,6 +125,68 @@ func (c *MemoryCache) Full() bool { return c.Length() >= c.Maxcount } +/* +Memcached backend +*/ + +func NewMemcachedCache(servers []string, expire int32) *MemcachedCache { + c := memcache.New(servers...) + return &MemcachedCache{ + backend: c, + serializer: &JsonSerializer{}, + expire: expire, + } +} + +type MemcachedCache struct { + backend *memcache.Client + serializer Serializer + expire int32 +} + +func (m *MemcachedCache) Set(key string, msg *dns.Msg) error { + var val []byte + var err error + + // handle cases for negacache where it sets nil values + if msg == nil { + val = []byte("nil") + } else { + val, err = m.serializer.Dumps(msg) + } + if err != nil { + return err + } + return m.backend.Set(&memcache.Item{Key: key, Value: val, Expiration: m.expire}) +} + +func (m *MemcachedCache) Get(key string) (msg *dns.Msg, err error) { + item, err := m.backend.Get(key) + if err != nil { + err = KeyNotFound{key} + return + } + msg, err = m.serializer.Loads(item.Value) + return +} + +func (m *MemcachedCache) Exists(key string) bool { + _, err := m.backend.Get(key) + if err != nil { + return true + } + return false +} + +func (m *MemcachedCache) Remove(key string) error { + return m.backend.Delete(key) +} + +func (m *MemcachedCache) Full() bool { + // memcache is never full (LRU) + return false +} + /* TODO: Redis cache Backend */ @@ -149,16 +218,18 @@ func KeyGen(q Question) string { return key } +/* we need to define marsheling to encode and decode + */ type JsonSerializer struct { } func (*JsonSerializer) Dumps(mesg *dns.Msg) (encoded []byte, err error) { - encoded, err = json.Marshal(mesg) + encoded, err = json.Marshal(*mesg) return } -func (*JsonSerializer) Loads(data []byte, mesg **dns.Msg) error { - err := json.Unmarshal(data, mesg) - return err - +func (*JsonSerializer) Loads(data []byte) (*dns.Msg, error) { + var mesg dns.Msg + err := json.Unmarshal(data, &mesg) + return &mesg, err } diff --git a/godns.conf b/godns.conf index 692a888..e6633e8 100644 --- a/godns.conf +++ b/godns.conf @@ -30,7 +30,7 @@ servers = ["127.0.0.1:11211"] [log] stdout = true file = "./godns.log" -level = "INFO" #DEBUG | INFO |NOTICE | WARN | ERROR +level = "DEBUG" #DEBUG | INFO |NOTICE | WARN | ERROR @@ -38,7 +38,7 @@ level = "INFO" #DEBUG | INFO |NOTICE | WARN | ERROR # backend option [memory|memcache|redis] # redis backend not implemented yet backend = "memory" -expire = 600 # 10 minutes +expire = 6000 # 10 minutes maxcount = 0 #If set zero. The Sum of cache itmes will be unlimit. [hosts] diff --git a/handler.go b/handler.go index a1acc8e..b8a26f4 100644 --- a/handler.go +++ b/handler.go @@ -61,6 +61,13 @@ func NewHandler() *GODNSHandler { Expire: time.Duration(cacheConfig.Expire) * time.Second / 2, Maxcount: cacheConfig.Maxcount, } + case "memcache": + cache = NewMemcachedCache( + settings.Memcache.Servers, + int32(cacheConfig.Expire)) + negCache = NewMemcachedCache( + settings.Memcache.Servers, + int32(cacheConfig.Expire/2)) case "redis": // cache = &MemoryCache{ // Backend: make(map[string]*dns.Msg), From 790acb55da17c6044de7f8b9bfe7a79452e15b60 Mon Sep 17 00:00:00 2001 From: Dhananjay Balan Date: Sat, 13 Feb 2016 15:25:19 +0530 Subject: [PATCH 3/4] Use pack and unpack from dns library. --- cache.go | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/cache.go b/cache.go index 6d80acd..3281418 100644 --- a/cache.go +++ b/cache.go @@ -36,10 +36,11 @@ func (e CacheIsFull) Error() string { } type SerializerError struct { + err error } func (e SerializerError) Error() string { - return "Serializer error" + return fmt.Sprintf("Serializer error: got %v", e.err) } type Mesg struct { @@ -55,11 +56,6 @@ type Cache interface { Full() bool } -type Serializer interface { - Loads([]byte) (*dns.Msg, error) - Dumps(*dns.Msg) ([]byte, error) -} - type MemoryCache struct { Backend map[string]Mesg Expire time.Duration @@ -132,16 +128,14 @@ Memcached backend func NewMemcachedCache(servers []string, expire int32) *MemcachedCache { c := memcache.New(servers...) return &MemcachedCache{ - backend: c, - serializer: &JsonSerializer{}, - expire: expire, + backend: c, + expire: expire, } } type MemcachedCache struct { - backend *memcache.Client - serializer Serializer - expire int32 + backend *memcache.Client + expire int32 } func (m *MemcachedCache) Set(key string, msg *dns.Msg) error { @@ -152,22 +146,26 @@ func (m *MemcachedCache) Set(key string, msg *dns.Msg) error { if msg == nil { val = []byte("nil") } else { - val, err = m.serializer.Dumps(msg) + val, err = msg.Pack() } if err != nil { - return err + err = SerializerError{err} } return m.backend.Set(&memcache.Item{Key: key, Value: val, Expiration: m.expire}) } -func (m *MemcachedCache) Get(key string) (msg *dns.Msg, err error) { +func (m *MemcachedCache) Get(key string) (*dns.Msg, error) { + var msg dns.Msg item, err := m.backend.Get(key) if err != nil { err = KeyNotFound{key} - return + return &msg, err } - msg, err = m.serializer.Loads(item.Value) - return + err = msg.Unpack(item.Value) + if err != nil { + err = SerializerError{err} + } + return &msg, err } func (m *MemcachedCache) Exists(key string) bool { From 0f184ca72b861f7ba2c3d91ed20170057b08850c Mon Sep 17 00:00:00 2001 From: Dhananjay Balan Date: Wed, 18 Jan 2017 16:07:54 +0100 Subject: [PATCH 4/4] Revert default config changes. --- godns.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/godns.conf b/godns.conf index e6633e8..692a888 100644 --- a/godns.conf +++ b/godns.conf @@ -30,7 +30,7 @@ servers = ["127.0.0.1:11211"] [log] stdout = true file = "./godns.log" -level = "DEBUG" #DEBUG | INFO |NOTICE | WARN | ERROR +level = "INFO" #DEBUG | INFO |NOTICE | WARN | ERROR @@ -38,7 +38,7 @@ level = "DEBUG" #DEBUG | INFO |NOTICE | WARN | ERROR # backend option [memory|memcache|redis] # redis backend not implemented yet backend = "memory" -expire = 6000 # 10 minutes +expire = 600 # 10 minutes maxcount = 0 #If set zero. The Sum of cache itmes will be unlimit. [hosts]