From b7a231feafa6fb9206a5d1ea345939a89988957d Mon Sep 17 00:00:00 2001 From: Bel LaPointe Date: Wed, 20 Mar 2019 09:54:26 -0600 Subject: [PATCH] Implement namespace optional arg --- bolt.go | 10 ++++++---- cache.go | 11 +++++++---- db.go | 12 ++++++++++-- db_test.go | 16 ++++++++++++---- leveldb.go | 12 ++++++++---- map.go | 30 ++++++++++++++++++++---------- memcache.go | 24 +++++++++++++++++++----- memcachecluster.go | 11 +++++++---- mongo.go | 10 ++++++---- riak.go | 10 ++++++---- 10 files changed, 101 insertions(+), 45 deletions(-) diff --git a/bolt.go b/bolt.go index f45b260..f23e5a6 100644 --- a/bolt.go +++ b/bolt.go @@ -13,10 +13,11 @@ func NewBolt(path string) (*Bolt, error) { }, err } -func (b *Bolt) Get(key string) ([]byte, error) { +func (b *Bolt) Get(key string, ns ...string) ([]byte, error) { + namespace := resolveNamespace(ns) var result []byte err := b.db.View(func(tx *bolt.Tx) error { - bkt := tx.Bucket([]byte(DefaultNamespace)) + bkt := tx.Bucket([]byte(namespace)) if bkt == nil { return ErrNotFound } @@ -29,9 +30,10 @@ func (b *Bolt) Get(key string) ([]byte, error) { return result, err } -func (b *Bolt) Set(key string, value []byte) error { +func (b *Bolt) Set(key string, value []byte, ns ...string) error { + namespace := resolveNamespace(ns) return b.db.Update(func(tx *bolt.Tx) error { - bkt, err := tx.CreateBucketIfNotExists([]byte(DefaultNamespace)) + bkt, err := tx.CreateBucketIfNotExists([]byte(namespace)) if err != nil { return err } diff --git a/cache.go b/cache.go index 09f6556..0bf958a 100644 --- a/cache.go +++ b/cache.go @@ -2,6 +2,7 @@ package storage import ( "os" + "path" "time" cache "github.com/patrickmn/go-cache" @@ -24,8 +25,9 @@ func NewCache(path ...string) (*Cache, error) { return c, err } -func (c *Cache) Get(key string) ([]byte, error) { - v, ok := c.db.Get(key) +func (c *Cache) Get(key string, ns ...string) ([]byte, error) { + namespace := resolveNamespace(ns) + v, ok := c.db.Get(path.Join(namespace, key)) if !ok { return nil, ErrNotFound } @@ -36,8 +38,9 @@ func (c *Cache) Get(key string) ([]byte, error) { return b, nil } -func (c *Cache) Set(key string, value []byte) error { - c.db.Set(key, value, 0) +func (c *Cache) Set(key string, value []byte, ns ...string) error { + namespace := resolveNamespace(ns) + c.db.Set(path.Join(namespace, key), value, 0) return nil } diff --git a/db.go b/db.go index af7d1ea..c6bd033 100644 --- a/db.go +++ b/db.go @@ -5,8 +5,8 @@ import ( ) type DB interface { - Get(string) ([]byte, error) - Set(string, []byte) error + Get(string, ...string) ([]byte, error) + Set(string, []byte, ...string) error Close() error } @@ -38,3 +38,11 @@ func New(key Type, params ...string) (db DB, err error) { } return } + +func resolveNamespace(ns []string) string { + namespace := DefaultNamespace + if len(ns) > 0 { + namespace = ns[0] + } + return namespace +} diff --git a/db_test.go b/db_test.go index 5db0fde..b3efbe1 100644 --- a/db_test.go +++ b/db_test.go @@ -15,16 +15,18 @@ type mock struct { m map[string][]byte } -func (mock *mock) Get(key string) ([]byte, error) { - v, ok := mock.m[key] +func (mock *mock) Get(key string, ns ...string) ([]byte, error) { + namespace := resolveNamespace(ns) + v, ok := mock.m[path.Join(namespace, key)] if ok { return v, nil } return nil, ErrNotFound } -func (mock *mock) Set(key string, value []byte) error { - mock.m[key] = value +func (mock *mock) Set(key string, value []byte, ns ...string) error { + namespace := resolveNamespace(ns) + mock.m[path.Join(namespace, key)] = value return nil } @@ -118,6 +120,12 @@ func TestImplementations(t *testing.T) { cases = append(cases, memcacheCluster) } + if minio, err := NewMinio("localhost:9000", "accesskey", "secretkey"); err != nil { + t.Errorf("cannot make minio: %v", err) + } else { + cases = append(cases, minio) + } + validKey := "key" validValue := []byte("value") diff --git a/leveldb.go b/leveldb.go index 7ece14d..b985567 100644 --- a/leveldb.go +++ b/leveldb.go @@ -1,6 +1,8 @@ package storage import ( + "path" + "github.com/syndtr/goleveldb/leveldb" "github.com/syndtr/goleveldb/leveldb/filter" "github.com/syndtr/goleveldb/leveldb/opt" @@ -19,14 +21,15 @@ func NewLevelDB(path string) (*LevelDB, error) { }, err } -func (ldb *LevelDB) Get(key string) ([]byte, error) { +func (ldb *LevelDB) Get(key string, ns ...string) ([]byte, error) { + namespace := resolveNamespace(ns) snapshot, err := ldb.db.GetSnapshot() if err != nil { return nil, err } defer snapshot.Release() - v, err := snapshot.Get([]byte(key), nil) + v, err := snapshot.Get([]byte(path.Join(namespace, key)), nil) if err == leveldb.ErrNotFound { err = ErrNotFound } else if err != nil { @@ -36,9 +39,10 @@ func (ldb *LevelDB) Get(key string) ([]byte, error) { return v, err } -func (ldb *LevelDB) Set(key string, value []byte) error { +func (ldb *LevelDB) Set(key string, value []byte, ns ...string) error { + namespace := resolveNamespace(ns) batch := &leveldb.Batch{} - batch.Put([]byte(key), value) + batch.Put([]byte(path.Join(namespace, key)), value) return ldb.db.Write(batch, nil) } diff --git a/map.go b/map.go index 55a3e38..c33ee22 100644 --- a/map.go +++ b/map.go @@ -4,10 +4,10 @@ import ( "fmt" ) -type Map map[string][]byte +type Map map[string]map[string][]byte func NewMap() *Map { - m := make(map[string][]byte) + m := make(map[string]map[string][]byte) n := Map(m) return &n } @@ -28,20 +28,30 @@ func (m *Map) Close() error { return nil } -func (m *Map) Get(key string) ([]byte, error) { - if _, ok := (*m)[key]; !ok { +func (m *Map) Get(key string, ns ...string) ([]byte, error) { + namespace := resolveNamespace(ns) + if _, ok := (*m)[namespace]; !ok { return nil, ErrNotFound } - return (*m)[key], nil + if _, ok := (*m)[namespace][key]; !ok { + return nil, ErrNotFound + } + return (*m)[namespace][key], nil } -func (m *Map) Set(key string, value []byte) error { +func (m *Map) Set(key string, value []byte, ns ...string) error { + namespace := resolveNamespace(ns) if value == nil { - if _, ok := (*m)[key]; ok { - delete(*m, key) + if _, ok := (*m)[namespace]; !ok { + return nil + } else if _, ok := (*m)[namespace][key]; ok { + delete((*m)[namespace], key) } - return nil + } else { + if _, ok := (*m)[namespace]; !ok { + (*m)[namespace] = make(map[string][]byte) + } + (*m)[namespace][key] = value } - (*m)[key] = value return nil } diff --git a/memcache.go b/memcache.go index 4b1752f..17392b7 100644 --- a/memcache.go +++ b/memcache.go @@ -2,6 +2,7 @@ package storage import ( "net" + "path" "github.com/bradfitz/gomemcache/memcache" ) @@ -24,8 +25,13 @@ func (a *netAddr) String() string { } func NewMemcache(addr string, addrs ...string) (*Memcache, error) { + for i := len(addrs) - 1; i >= 0; i-- { + if len(addrs[i]) == 0 { + addrs = append(addrs[:i], addrs[i+1:]...) + } + } ss := &memcache.ServerList{} - if err := ss.SetServers(append(addrs, addr)...); err != nil { + if err := ss.SetServers(append([]string{addr}, addrs...)...); err != nil { return nil, err } if err := ss.Each(func(addr net.Addr) error { @@ -41,14 +47,22 @@ func NewMemcache(addr string, addrs ...string) (*Memcache, error) { return &Memcache{db: db}, nil } -func (mc *Memcache) Get(key string) ([]byte, error) { - v, err := mc.db.Get(key) +func (mc *Memcache) Get(key string, ns ...string) ([]byte, error) { + namespace := resolveNamespace(ns) + v, err := mc.db.Get(path.Join(namespace, key)) + if err != nil { + return nil, err + } + if v == nil { + return nil, ErrNotFound + } return v.Value, err } -func (mc *Memcache) Set(key string, value []byte) error { +func (mc *Memcache) Set(key string, value []byte, ns ...string) error { + namespace := resolveNamespace(ns) return mc.db.Set(&memcache.Item{ - Key: key, + Key: path.Join(namespace, key), Value: value, }) } diff --git a/memcachecluster.go b/memcachecluster.go index 09e6731..260473d 100644 --- a/memcachecluster.go +++ b/memcachecluster.go @@ -2,6 +2,7 @@ package storage import ( "net" + "path" "github.com/bradfitz/gomemcache/memcache" "github.com/buraksezer/consistent" @@ -68,14 +69,16 @@ func NewMemcacheCluster(addr string, addrs ...string) (*MemcacheCluster, error) return &MemcacheCluster{db: db}, nil } -func (mc *MemcacheCluster) Get(key string) ([]byte, error) { - v, err := mc.db.Get(key) +func (mc *MemcacheCluster) Get(key string, ns ...string) ([]byte, error) { + namespace := resolveNamespace(ns) + v, err := mc.db.Get(path.Join(namespace, key)) return v.Value, err } -func (mc *MemcacheCluster) Set(key string, value []byte) error { +func (mc *MemcacheCluster) Set(key string, value []byte, ns ...string) error { + namespace := resolveNamespace(ns) return mc.db.Set(&memcache.Item{ - Key: key, + Key: path.Join(namespace, key), Value: value, }) } diff --git a/mongo.go b/mongo.go index 6256e5d..ca698e9 100644 --- a/mongo.go +++ b/mongo.go @@ -53,10 +53,11 @@ func NewMongo(addr string, auth ...string) (*Mongo, error) { return &Mongo{db: db}, nil } -func (mg *Mongo) Get(key string) ([]byte, error) { +func (mg *Mongo) Get(key string, ns ...string) ([]byte, error) { + namespace := resolveNamespace(ns) ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() - collection := mg.db.Database(DefaultNamespace).Collection(DefaultNamespace) + collection := mg.db.Database(DefaultNamespace).Collection(namespace) filter := bson.M{"_id": key} cursor, err := collection.Find(ctx, filter) if err != nil { @@ -82,10 +83,11 @@ func (mg *Mongo) Get(key string) ([]byte, error) { return b, nil } -func (mg *Mongo) Set(key string, value []byte) error { +func (mg *Mongo) Set(key string, value []byte, ns ...string) error { + namespace := resolveNamespace(ns) ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() - collection := mg.db.Database(DefaultNamespace).Collection(DefaultNamespace) + collection := mg.db.Database(DefaultNamespace).Collection(namespace) filter := bson.M{"_id": key} document := bson.M{"value": value} _, err := collection.ReplaceOne(ctx, filter, document, options.Replace().SetUpsert(true)) diff --git a/riak.go b/riak.go index 87dc2eb..67b67b3 100644 --- a/riak.go +++ b/riak.go @@ -28,11 +28,12 @@ func NewRiak(addr string, addrs ...string) (*Riak, error) { }, err } -func (r *Riak) Get(key string) ([]byte, error) { +func (r *Riak) Get(key string, ns ...string) ([]byte, error) { + namespace := resolveNamespace(ns) obj := &riak.Object{} cmd, err := riak.NewFetchValueCommandBuilder(). - WithBucket(DefaultNamespace). + WithBucket(namespace). WithKey(key). Build() if err != nil { @@ -43,13 +44,14 @@ func (r *Riak) Get(key string) ([]byte, error) { return obj.Value, err } -func (r *Riak) Set(key string, value []byte) error { +func (r *Riak) Set(key string, value []byte, ns ...string) error { + namespace := resolveNamespace(ns) obj := &riak.Object{ Value: value, } cmd, err := riak.NewStoreValueCommandBuilder(). - WithBucket(DefaultNamespace). + WithBucket(namespace). WithContent(obj). Build() if err != nil {