diff --git a/cache.go b/cache.go new file mode 100644 index 0000000..09f6556 --- /dev/null +++ b/cache.go @@ -0,0 +1,49 @@ +package storage + +import ( + "os" + "time" + + cache "github.com/patrickmn/go-cache" +) + +type Cache struct { + db *cache.Cache + path string +} + +func NewCache(path ...string) (*Cache, error) { + var err error = nil + c := &Cache{db: cache.New(0, time.Minute*15), path: ""} + if len(path) != 0 { + c.path = path[0] + if _, err := os.Stat(c.path); err == nil { + err = c.db.LoadFile(c.path) + } + } + return c, err +} + +func (c *Cache) Get(key string) ([]byte, error) { + v, ok := c.db.Get(key) + if !ok { + return nil, ErrNotFound + } + b, ok := v.([]byte) + if !ok { + return nil, ErrNotImpl + } + return b, nil +} + +func (c *Cache) Set(key string, value []byte) error { + c.db.Set(key, value, 0) + return nil +} + +func (c *Cache) Close() error { + if c.path != "" { + return c.db.SaveFile(c.path) + } + return nil +} diff --git a/db_test.go b/db_test.go index 3962b72..da22de0 100644 --- a/db_test.go +++ b/db_test.go @@ -42,6 +42,18 @@ func TestImplementations(t *testing.T) { cases = append(cases, &mock{m: make(map[string][]byte)}) cases = append(cases, NewMap()) + if cacheMem, err := NewCache(); err != nil { + t.Errorf("cannot make cache/mem: %v", err) + } else { + cases = append(cases, cacheMem) + } + + if cacheFile, err := NewCache(path.Join(dir, "cache")); err != nil { + t.Errorf("cannot make cache/file: %v", err) + } else { + cases = append(cases, cacheFile) + } + if bolt, err := NewBolt(path.Join(dir, "bolt")); err != nil { t.Errorf("cannot make bolt: %v", err) } else { @@ -92,6 +104,12 @@ func TestImplementations(t *testing.T) { t.Errorf("cannot make mongo: %v", err) } + if memcache, err := NewMemcache("localhost:11211"); err != nil { + t.Errorf("cannot make memcache: %v", err) + } else { + cases = append(cases, memcache) + } + validKey := "key" validValue := []byte("value") diff --git a/memcached.go b/memcached.go new file mode 100644 index 0000000..b23d4f0 --- /dev/null +++ b/memcached.go @@ -0,0 +1,80 @@ +package storage + +import ( + "net" + + "github.com/bradfitz/gomemcache/memcache" +) + +type Memcache struct { + db *memcache.Client +} + +type serverSelector struct { + addrs []string +} + +func (ss *serverSelector) PickServer(key string) (net.Addr, error) { + return &netAddr{ + network: "tcp", + addr: ss.addrs[0], + }, nil +} + +func (ss *serverSelector) Each(each func(net.Addr) error) error { + for _, addr := range ss.addrs { + if err := each(&netAddr{ + network: "tcp", + addr: addr, + }); err != nil { + return err + } + } + return nil +} + +type netAddr struct { + network string + addr string +} + +func (a *netAddr) Network() string { + return a.network +} + +func (a *netAddr) String() string { + return a.addr +} + +func NewMemcache(addr string, addrs ...string) (*Memcache, error) { + ss := &serverSelector{ + addrs: append(addrs, addr), + } + if err := ss.Each(func(addr net.Addr) error { + conn, err := net.Dial("tcp", addr.String()) + if err != nil { + return err + } + return conn.Close() + }); err != nil { + return nil, err + } + db := memcache.NewFromSelector(ss) + return &Memcache{db: db}, nil +} + +func (mc *Memcache) Get(key string) ([]byte, error) { + v, err := mc.db.Get(key) + return v.Value, err +} + +func (mc *Memcache) Set(key string, value []byte) error { + return mc.db.Set(&memcache.Item{ + Key: key, + Value: value, + }) +} + +func (mc *Memcache) Close() error { + return mc.db.FlushAll() +}