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),