diff --git a/client/cache/cache_test.go b/client/cache/cache_test.go index 6066b72d..bd9b0801 100644 --- a/client/cache/cache_test.go +++ b/client/cache/cache_test.go @@ -120,6 +120,20 @@ func TestCache(t *testing.T) { if vv[1].(string) != "author1" { t.Error("GetMulti ERROR") } + + vv, err = bm.GetMulti(context.Background(), []string{"astaxie0", "astaxie1"}) + if len(vv) != 2 { + t.Error("GetMulti ERROR") + } + if vv[0] != nil { + t.Error("GetMulti ERROR") + } + if vv[1].(string) != "author1" { + t.Error("GetMulti ERROR") + } + if err != nil && err.Error() != "key [astaxie0] error: the key isn't exist" { + t.Error("GetMulti ERROR") + } } func TestFileCache(t *testing.T) { @@ -189,5 +203,19 @@ func TestFileCache(t *testing.T) { t.Error("GetMulti ERROR") } + vv, err = bm.GetMulti(context.Background(), []string{"astaxie0", "astaxie1"}) + if len(vv) != 2 { + t.Error("GetMulti ERROR") + } + if vv[0] != nil { + t.Error("GetMulti ERROR") + } + if vv[1].(string) != "author1" { + t.Error("GetMulti ERROR") + } + if err == nil { + t.Error("GetMulti ERROR") + } + os.RemoveAll("cache") } diff --git a/client/cache/file.go b/client/cache/file.go index dc818258..84ac03c8 100644 --- a/client/cache/file.go +++ b/client/cache/file.go @@ -28,6 +28,7 @@ import ( "path/filepath" "reflect" "strconv" + "strings" "time" "github.com/pkg/errors" @@ -144,17 +145,22 @@ func (fc *FileCache) Get(ctx context.Context, key string) (interface{}, error) { // GetMulti gets values from file cache. // if nonexistent or expired return an empty string. func (fc *FileCache) GetMulti(ctx context.Context, keys []string) ([]interface{}, error) { - var rc []interface{} - for _, key := range keys { - val, err := fc.Get(context.Background(), key) - if err != nil { - rc = append(rc, err) - } else { - rc = append(rc, val) - } + rc := make([]interface{}, len(keys)) + keysErr := make([]string, 0) + for i, ki := range keys { + val, err := fc.Get(context.Background(), ki) + if err != nil { + keysErr = append(keysErr, fmt.Sprintf("key [%s] error: %s", ki, err.Error())) + continue + } + rc[i] = val } - return rc, nil + + if len(keysErr) == 0 { + return rc, nil + } + return rc, errors.New(strings.Join(keysErr, "; ")) } // Put value into file cache. diff --git a/client/cache/memcache/memcache.go b/client/cache/memcache/memcache.go index f3774571..67aedc73 100644 --- a/client/cache/memcache/memcache.go +++ b/client/cache/memcache/memcache.go @@ -33,6 +33,7 @@ import ( "context" "encoding/json" "errors" + "fmt" "strings" "time" @@ -68,19 +69,31 @@ func (rc *Cache) Get(ctx context.Context, key string) (interface{}, error) { // GetMulti gets a value from a key in memcache. func (rc *Cache) GetMulti(ctx context.Context, keys []string) ([]interface{}, error) { - var rv []interface{} + rv := make([]interface{}, len(keys)) if rc.conn == nil { if err := rc.connectInit(); err != nil { return rv, err } } + mv, err := rc.conn.GetMulti(keys) - if err == nil { - for _, v := range mv { - rv = append(rv, v.Value) - } + if err != nil { + return rv, err } - return rv, err + + keysErr := make([]string, 0) + for i, ki := range keys { + if _, ok := mv[ki]; !ok { + keysErr = append(keysErr, fmt.Sprintf("key [%s] error: %s", ki, "the key isn't exist")) + continue + } + rv[i] = mv[ki].Value + } + + if len(keysErr) == 0 { + return rv, nil + } + return rv, fmt.Errorf(strings.Join(keysErr, "; ")) } // Put puts a value into memcache. diff --git a/client/cache/memcache/memcache_test.go b/client/cache/memcache/memcache_test.go index bc8936a7..ca86276e 100644 --- a/client/cache/memcache/memcache_test.go +++ b/client/cache/memcache/memcache_test.go @@ -28,7 +28,6 @@ import ( ) func TestMemcacheCache(t *testing.T) { - addr := os.Getenv("MEMCACHE_ADDR") if addr == "" { addr = "127.0.0.1:11211" @@ -114,6 +113,20 @@ func TestMemcacheCache(t *testing.T) { t.Error("GetMulti ERROR") } + vv, err = bm.GetMulti(context.Background(), []string{"astaxie0", "astaxie1"}) + if len(vv) != 2 { + t.Error("GetMulti ERROR") + } + if vv[0] != nil { + t.Error("GetMulti ERROR") + } + if string(vv[1].([]byte)) != "author1" { + t.Error("GetMulti ERROR") + } + if err != nil && err.Error() == "key [astaxie0] error: key isn't exist" { + t.Error("GetMulti ERROR") + } + // test clear all if err = bm.ClearAll(context.Background()); err != nil { t.Error("clear all err") diff --git a/client/cache/memory.go b/client/cache/memory.go index 6f87ec08..28c7d980 100644 --- a/client/cache/memory.go +++ b/client/cache/memory.go @@ -18,6 +18,8 @@ import ( "context" "encoding/json" "errors" + "fmt" + "strings" "sync" "time" ) @@ -68,22 +70,28 @@ func (bc *MemoryCache) Get(ctx context.Context, key string) (interface{}, error) } return itm.val, nil } - return nil, nil + return nil, errors.New("the key isn't exist") } // GetMulti gets caches from memory. // If non-existent or expired, return nil. func (bc *MemoryCache) GetMulti(ctx context.Context, keys []string) ([]interface{}, error) { - var rc []interface{} - for _, name := range keys { - val, err := bc.Get(context.Background(), name) + rc := make([]interface{}, len(keys)) + keysErr := make([]string, 0) + + for i, ki := range keys { + val, err := bc.Get(context.Background(), ki) if err != nil { - rc = append(rc, err) - } else { - rc = append(rc, val) + keysErr = append(keysErr, fmt.Sprintf("key [%s] error: %s", ki, err.Error())) + continue } + rc[i] = val } - return rc, nil + + if len(keysErr) == 0 { + return rc, nil + } + return rc, errors.New(strings.Join(keysErr, "; ")) } // Put puts cache into memory. diff --git a/client/cache/redis/redis_test.go b/client/cache/redis/redis_test.go index f82b2c40..c8cf0024 100644 --- a/client/cache/redis/redis_test.go +++ b/client/cache/redis/redis_test.go @@ -113,6 +113,14 @@ func TestRedisCache(t *testing.T) { t.Error("GetMulti ERROR") } + vv, _ = bm.GetMulti(context.Background(), []string{"astaxie0", "astaxie1"}) + if vv[0] != nil { + t.Error("GetMulti ERROR") + } + if v, _ := redis.String(vv[1], nil); v != "author1" { + t.Error("GetMulti ERROR") + } + // test clear all if err = bm.ClearAll(context.Background()); err != nil { t.Error("clear all err") diff --git a/client/cache/ssdb/ssdb.go b/client/cache/ssdb/ssdb.go index def9273d..8d9d2b35 100644 --- a/client/cache/ssdb/ssdb.go +++ b/client/cache/ssdb/ssdb.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "errors" + "fmt" "strconv" "strings" "time" @@ -41,23 +42,37 @@ func (rc *Cache) Get(ctx context.Context, key string) (interface{}, error) { // GetMulti gets one or keys values from ssdb. func (rc *Cache) GetMulti(ctx context.Context, keys []string) ([]interface{}, error) { size := len(keys) - var values []interface{} + values := make([]interface{}, size) if rc.conn == nil { if err := rc.connectInit(); err != nil { return values, err } } + res, err := rc.conn.Do("multi_get", keys) + if err != nil { + return values, err + } + resSize := len(res) - if err == nil { - for i := 1; i < resSize; i += 2 { - values = append(values, res[i+1]) + keyIdx := make(map[string]int) + for i := 1; i < resSize; i += 2 { + keyIdx[res[i]] = i + } + + keysErr := make([]string, 0) + for i, ki := range keys { + if _, ok := keyIdx[ki]; !ok { + keysErr = append(keysErr, fmt.Sprintf("key [%s] error: %s", ki, "the key isn't exist")) + continue } - return values, nil + values[i] = res[keyIdx[ki]+1] } - for i := 0; i < size; i++ { - values = append(values, err) + + if len(keysErr) != 0 { + return values, fmt.Errorf(strings.Join(keysErr, "; ")) } + return values, nil } diff --git a/client/cache/ssdb/ssdb_test.go b/client/cache/ssdb/ssdb_test.go index cebaa975..b23871ca 100644 --- a/client/cache/ssdb/ssdb_test.go +++ b/client/cache/ssdb/ssdb_test.go @@ -106,6 +106,20 @@ func TestSsdbcacheCache(t *testing.T) { t.Error("getmulti error") } + vv, err = ssdb.GetMulti(context.Background(), []string{"ssdb", "ssdb11"}) + if len(vv) != 2 { + t.Error("getmulti error") + } + if vv[0].(string) != "ssdb" { + t.Error("getmulti error") + } + if vv[1] != nil { + t.Error("getmulti error") + } + if err != nil && err.Error() != "key [ssdb11] error: the key isn't exist" { + t.Error("getmulti error") + } + // test clear all done if err = ssdb.ClearAll(context.Background()); err != nil { t.Error("clear all err")