godns/cache.go

236 lines
3.9 KiB
Go
Raw Normal View History

2013-07-23 11:10:38 +00:00
package main
2013-07-24 10:29:38 +00:00
import (
"crypto/md5"
"encoding/json"
"fmt"
2013-12-12 12:31:26 +00:00
"sync"
2013-07-24 10:29:38 +00:00
"time"
"github.com/bradfitz/gomemcache/memcache"
"github.com/hoisie/redis"
"github.com/miekg/dns"
2013-07-24 10:29:38 +00:00
)
type KeyNotFound struct {
key string
}
func (e KeyNotFound) Error() string {
return e.key + " " + "not found"
}
type KeyExpired struct {
Key string
}
func (e KeyExpired) Error() string {
return e.Key + " " + "expired"
}
type CacheIsFull struct {
}
func (e CacheIsFull) Error() string {
return "Cache is Full"
}
type SerializerError struct {
}
func (e SerializerError) Error() string {
return "Serializer error"
}
2013-07-24 16:09:07 +00:00
type Mesg struct {
Msg *dns.Msg
Expire time.Time
}
2013-07-24 10:29:38 +00:00
type Cache interface {
2013-07-24 16:09:07 +00:00
Get(key string) (Msg *dns.Msg, err error)
Set(key string, Msg *dns.Msg) error
2013-07-24 14:47:39 +00:00
Exists(key string) bool
Remove(key string) error
Full() bool
}
type Serializer interface {
Loads([]byte) (*dns.Msg, error)
Dumps(*dns.Msg) ([]byte, error)
2013-07-24 10:29:38 +00:00
}
type MemoryCache struct {
2013-07-24 16:09:07 +00:00
Backend map[string]Mesg
Expire time.Duration
Maxcount int
mu sync.RWMutex
2013-07-24 10:29:38 +00:00
}
2013-07-24 10:48:43 +00:00
func (c *MemoryCache) Get(key string) (*dns.Msg, error) {
2013-12-12 12:31:26 +00:00
c.mu.RLock()
2013-07-24 16:09:07 +00:00
mesg, ok := c.Backend[key]
2013-12-12 12:31:26 +00:00
c.mu.RUnlock()
2013-07-24 10:29:38 +00:00
if !ok {
return nil, KeyNotFound{key}
}
2013-07-24 16:09:07 +00:00
if mesg.Expire.Before(time.Now()) {
c.Remove(key)
return nil, KeyExpired{key}
}
return mesg.Msg, nil
2013-07-24 10:29:38 +00:00
2013-07-23 11:10:38 +00:00
}
2013-07-24 16:09:07 +00:00
func (c *MemoryCache) Set(key string, msg *dns.Msg) error {
2013-07-24 10:29:38 +00:00
if c.Full() && !c.Exists(key) {
return CacheIsFull{}
}
2013-07-24 16:09:07 +00:00
expire := time.Now().Add(c.Expire)
mesg := Mesg{msg, expire}
2013-12-12 12:31:26 +00:00
c.mu.Lock()
2013-07-24 16:09:07 +00:00
c.Backend[key] = mesg
2013-12-12 12:31:26 +00:00
c.mu.Unlock()
2013-07-24 10:29:38 +00:00
return nil
}
func (c *MemoryCache) Remove(key string) error {
c.mu.Lock()
2013-07-24 16:09:07 +00:00
delete(c.Backend, key)
c.mu.Unlock()
return nil
2013-07-24 10:29:38 +00:00
}
func (c *MemoryCache) Exists(key string) bool {
2013-12-12 12:31:26 +00:00
c.mu.RLock()
2013-07-24 16:09:07 +00:00
_, ok := c.Backend[key]
2013-12-12 12:31:26 +00:00
c.mu.RUnlock()
2013-07-24 10:29:38 +00:00
return ok
}
func (c *MemoryCache) Length() int {
2013-12-12 12:31:26 +00:00
c.mu.RLock()
defer c.mu.RUnlock()
2013-07-24 16:09:07 +00:00
return len(c.Backend)
2013-07-24 10:29:38 +00:00
}
func (c *MemoryCache) Full() bool {
2013-07-24 16:09:07 +00:00
// if Maxcount is zero. the cache will never be full.
if c.Maxcount == 0 {
2013-07-24 10:29:38 +00:00
return false
}
2013-07-24 16:09:07 +00:00
return c.Length() >= c.Maxcount
2013-07-24 10:29:38 +00:00
}
/*
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
}
2013-07-24 14:40:18 +00:00
/*
2013-07-24 16:09:07 +00:00
TODO: Redis cache Backend
2013-07-24 14:40:18 +00:00
*/
2013-07-24 10:29:38 +00:00
2013-07-24 14:40:18 +00:00
type RedisCache struct {
2013-07-24 16:09:07 +00:00
Backend *redis.Client
Serializer JsonSerializer
Expire time.Duration
Maxcount int
2013-07-24 14:40:18 +00:00
}
2013-07-24 10:29:38 +00:00
2013-07-24 14:40:18 +00:00
func (c *RedisCache) Get() {
2013-07-24 10:29:38 +00:00
2013-07-24 14:40:18 +00:00
}
2013-07-24 10:29:38 +00:00
2013-07-24 14:40:18 +00:00
func (c *RedisCache) Set() {
2013-07-24 10:29:38 +00:00
2013-07-24 14:40:18 +00:00
}
2013-07-24 10:29:38 +00:00
2013-07-24 14:40:18 +00:00
func (c *RedisCache) Remove() {
}
2013-07-24 10:29:38 +00:00
func KeyGen(q Question) string {
h := md5.New()
h.Write([]byte(q.String()))
x := h.Sum(nil)
key := fmt.Sprintf("%x", x)
return key
}
/* we need to define marsheling to encode and decode
*/
2013-07-24 10:29:38 +00:00
type JsonSerializer struct {
}
2013-07-23 11:10:38 +00:00
2013-07-24 10:29:38 +00:00
func (*JsonSerializer) Dumps(mesg *dns.Msg) (encoded []byte, err error) {
encoded, err = json.Marshal(*mesg)
2013-07-24 10:29:38 +00:00
return
2013-07-23 11:10:38 +00:00
}
func (*JsonSerializer) Loads(data []byte) (*dns.Msg, error) {
var mesg dns.Msg
err := json.Unmarshal(data, &mesg)
return &mesg, err
2013-07-23 11:10:38 +00:00
}