Merge pull request #25 from dbalan/memcached_backend_support

Memcached backend support
This commit is contained in:
kenshin 2017-01-19 12:06:14 +08:00 committed by GitHub
commit 9e3c916046
4 changed files with 94 additions and 10 deletions

View File

@ -7,6 +7,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/bradfitz/gomemcache/memcache"
"github.com/hoisie/redis" "github.com/hoisie/redis"
"github.com/miekg/dns" "github.com/miekg/dns"
) )
@ -35,10 +36,11 @@ func (e CacheIsFull) Error() string {
} }
type SerializerError struct { type SerializerError struct {
err error
} }
func (e SerializerError) Error() string { func (e SerializerError) Error() string {
return "Serializer error" return fmt.Sprintf("Serializer error: got %v", e.err)
} }
type Mesg struct { type Mesg struct {
@ -50,8 +52,8 @@ type Cache interface {
Get(key string) (Msg *dns.Msg, err error) Get(key string) (Msg *dns.Msg, err error)
Set(key string, Msg *dns.Msg) error Set(key string, Msg *dns.Msg) error
Exists(key string) bool Exists(key string) bool
Remove(key string) Remove(key string) error
Length() int Full() bool
} }
type MemoryCache struct { type MemoryCache struct {
@ -91,10 +93,11 @@ func (c *MemoryCache) Set(key string, msg *dns.Msg) error {
return nil return nil
} }
func (c *MemoryCache) Remove(key string) { func (c *MemoryCache) Remove(key string) error {
c.mu.Lock() c.mu.Lock()
delete(c.Backend, key) delete(c.Backend, key)
c.mu.Unlock() c.mu.Unlock()
return nil
} }
func (c *MemoryCache) Exists(key string) bool { func (c *MemoryCache) Exists(key string) bool {
@ -118,6 +121,70 @@ func (c *MemoryCache) Full() bool {
return c.Length() >= c.Maxcount return c.Length() >= c.Maxcount
} }
/*
Memcached backend
*/
func NewMemcachedCache(servers []string, expire int32) *MemcachedCache {
c := memcache.New(servers...)
return &MemcachedCache{
backend: c,
expire: expire,
}
}
type MemcachedCache struct {
backend *memcache.Client
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 = msg.Pack()
}
if err != nil {
err = SerializerError{err}
}
return m.backend.Set(&memcache.Item{Key: key, Value: val, Expiration: m.expire})
}
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 &msg, err
}
err = msg.Unpack(item.Value)
if err != nil {
err = SerializerError{err}
}
return &msg, err
}
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 TODO: Redis cache Backend
*/ */
@ -149,16 +216,18 @@ func KeyGen(q Question) string {
return key return key
} }
/* we need to define marsheling to encode and decode
*/
type JsonSerializer struct { type JsonSerializer struct {
} }
func (*JsonSerializer) Dumps(mesg *dns.Msg) (encoded []byte, err error) { func (*JsonSerializer) Dumps(mesg *dns.Msg) (encoded []byte, err error) {
encoded, err = json.Marshal(mesg) encoded, err = json.Marshal(*mesg)
return return
} }
func (*JsonSerializer) Loads(data []byte, mesg **dns.Msg) error { func (*JsonSerializer) Loads(data []byte) (*dns.Msg, error) {
err := json.Unmarshal(data, mesg) var mesg dns.Msg
return err err := json.Unmarshal(data, &mesg)
return &mesg, err
} }

View File

@ -24,6 +24,9 @@ port = 6379
db = 0 db = 0
password ="" password =""
[memcache]
servers = ["127.0.0.1:11211"]
[log] [log]
stdout = true stdout = true
file = "./godns.log" file = "./godns.log"
@ -32,7 +35,7 @@ level = "INFO" #DEBUG | INFO |NOTICE | WARN | ERROR
[cache] [cache]
# backend option [memory|redis] # backend option [memory|memcache|redis]
# redis backend not implemented yet # redis backend not implemented yet
backend = "memory" backend = "memory"
expire = 600 # 10 minutes expire = 600 # 10 minutes

View File

@ -61,6 +61,13 @@ func NewHandler() *GODNSHandler {
Expire: time.Duration(cacheConfig.Expire) * time.Second / 2, Expire: time.Duration(cacheConfig.Expire) * time.Second / 2,
Maxcount: cacheConfig.Maxcount, Maxcount: cacheConfig.Maxcount,
} }
case "memcache":
cache = NewMemcachedCache(
settings.Memcache.Servers,
int32(cacheConfig.Expire))
negCache = NewMemcachedCache(
settings.Memcache.Servers,
int32(cacheConfig.Expire/2))
case "redis": case "redis":
// cache = &MemoryCache{ // cache = &MemoryCache{
// Backend: make(map[string]*dns.Msg), // Backend: make(map[string]*dns.Msg),

View File

@ -27,6 +27,7 @@ type Settings struct {
Server DNSServerSettings `toml:"server"` Server DNSServerSettings `toml:"server"`
ResolvConfig ResolvSettings `toml:"resolv"` ResolvConfig ResolvSettings `toml:"resolv"`
Redis RedisSettings `toml:"redis"` Redis RedisSettings `toml:"redis"`
Memcache MemcacheSettings `toml:"memcache"`
Log LogSettings `toml:"log"` Log LogSettings `toml:"log"`
Cache CacheSettings `toml:"cache"` Cache CacheSettings `toml:"cache"`
Hosts HostsSettings `toml:"hosts"` Hosts HostsSettings `toml:"hosts"`
@ -50,6 +51,10 @@ type RedisSettings struct {
Password string Password string
} }
type MemcacheSettings struct {
Servers []string
}
func (s RedisSettings) Addr() string { func (s RedisSettings) Addr() string {
return s.Host + ":" + strconv.Itoa(s.Port) return s.Host + ":" + strconv.Itoa(s.Port)
} }