From 40181c10421d0a2f316e7b27a8b00dd2d1985981 Mon Sep 17 00:00:00 2001 From: huija <1150555483@qq.com> Date: Fri, 19 Jun 2020 14:21:12 +0800 Subject: [PATCH 1/3] Update redis.go use `scan` instead of `keys` --- cache/redis/redis.go | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/cache/redis/redis.go b/cache/redis/redis.go index 372dd48b..e70c745b 100644 --- a/cache/redis/redis.go +++ b/cache/redis/redis.go @@ -139,7 +139,7 @@ func (rc *Cache) Decr(key string) error { func (rc *Cache) ClearAll() error { c := rc.p.Get() defer c.Close() - cachedKeys, err := redis.Strings(c.Do("KEYS", rc.key+":*")) + cachedKeys, err := rc.Scan(rc.key + ":*") if err != nil { return err } @@ -151,6 +151,34 @@ func (rc *Cache) ClearAll() error { return err } +func (rc *Cache) Scan(pattern string) (keys []string, err error) { + c := rc.p.Get() + defer c.Close() + var ( + cursor uint64 = 0 // start + result []interface{} + list []string + ) + for { + result, err = redis.Values(c.Do("SCAN", cursor, "MATCH", pattern, "COUNT", 1024)) + if err != nil { + return + } + list, err = redis.Strings(result[1], nil) + if err != nil { + return + } + keys = append(keys, list...) + cursor, err = redis.Uint64(result[0], nil) + if err != nil { + return + } + if cursor == 0 { // over + return + } + } +} + // StartAndGC start redis cache adapter. // config is like {"key":"collection key","conn":"connection info","dbNum":"0"} // the cache item in redis are stored forever, From f2bae3e367aaeae22588789bde32f1631d0b8303 Mon Sep 17 00:00:00 2001 From: huija <1150555483@qq.com> Date: Fri, 19 Jun 2020 22:55:40 +0800 Subject: [PATCH 2/3] add UT for Scan function --- cache/redis/redis.go | 4 ++-- cache/redis/redis_test.go | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/cache/redis/redis.go b/cache/redis/redis.go index e70c745b..a1ea7b49 100644 --- a/cache/redis/redis.go +++ b/cache/redis/redis.go @@ -137,12 +137,12 @@ func (rc *Cache) Decr(key string) error { // ClearAll clean all cache in redis. delete this redis collection. func (rc *Cache) ClearAll() error { - c := rc.p.Get() - defer c.Close() cachedKeys, err := rc.Scan(rc.key + ":*") if err != nil { return err } + c := rc.p.Get() + defer c.Close() for _, str := range cachedKeys { if _, err = c.Do("DEL", str); err != nil { return err diff --git a/cache/redis/redis_test.go b/cache/redis/redis_test.go index 56877f6b..7ac88f87 100644 --- a/cache/redis/redis_test.go +++ b/cache/redis/redis_test.go @@ -15,6 +15,7 @@ package redis import ( + "fmt" "testing" "time" @@ -104,3 +105,40 @@ func TestRedisCache(t *testing.T) { t.Error("clear all err") } } + +func TestCache_Scan(t *testing.T) { + timeoutDuration := 10 * time.Second + // init + bm, err := cache.NewCache("redis", `{"conn": "127.0.0.1:6379"}`) + if err != nil { + t.Error("init err") + } + // insert all + for i := 0; i < 10000; i++ { + if err = bm.Put(fmt.Sprintf("astaxie%d", i), fmt.Sprintf("author%d", i), timeoutDuration); err != nil { + t.Error("set Error", err) + } + } + // scan all for the first time + keys, err := bm.(*Cache).Scan(DefaultKey + ":*") + if err != nil { + t.Error("scan Error", err) + } + if len(keys) != 10000 { + t.Error("scan all err") + } + + // clear all + if err = bm.ClearAll(); err != nil { + t.Error("clear all err") + } + + // scan all for the second time + keys, err = bm.(*Cache).Scan(DefaultKey + ":*") + if err != nil { + t.Error("scan Error", err) + } + if len(keys) != 0 { + t.Error("scan all err") + } +} From f70fd5babfcb206fb5aab3d2e771052345337a7b Mon Sep 17 00:00:00 2001 From: huija <1150555483@qq.com> Date: Tue, 23 Jun 2020 12:32:26 +0800 Subject: [PATCH 3/3] add comments on Scan func --- cache/redis/redis.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cache/redis/redis.go b/cache/redis/redis.go index a1ea7b49..7a14b012 100644 --- a/cache/redis/redis.go +++ b/cache/redis/redis.go @@ -151,6 +151,7 @@ func (rc *Cache) ClearAll() error { return err } +// Scan scan all keys matching the pattern. a better choice than `keys` func (rc *Cache) Scan(pattern string) (keys []string, err error) { c := rc.p.Get() defer c.Close()