Add GetMulti method for Cache interface
Showing
8 changed files
with
258 additions
and
1 deletions
| ... | @@ -47,6 +47,8 @@ import ( | ... | @@ -47,6 +47,8 @@ import ( |
| 47 | type Cache interface { | 47 | type Cache interface { |
| 48 | // get cached value by key. | 48 | // get cached value by key. |
| 49 | Get(key string) interface{} | 49 | Get(key string) interface{} |
| 50 | // GetMulti is a batch version of Get. | ||
| 51 | GetMulti(keys []string) []interface{} | ||
| 50 | // set cached value with key and expire time. | 52 | // set cached value with key and expire time. |
| 51 | Put(key string, val interface{}, timeout int64) error | 53 | Put(key string, val interface{}, timeout int64) error |
| 52 | // delete cached value by key. | 54 | // delete cached value by key. | ... | ... |
| ... | @@ -65,6 +65,35 @@ func TestCache(t *testing.T) { | ... | @@ -65,6 +65,35 @@ func TestCache(t *testing.T) { |
| 65 | if bm.IsExist("astaxie") { | 65 | if bm.IsExist("astaxie") { |
| 66 | t.Error("delete err") | 66 | t.Error("delete err") |
| 67 | } | 67 | } |
| 68 | |||
| 69 | //test GetMulti | ||
| 70 | if err = bm.Put("astaxie", "author", 10); err != nil { | ||
| 71 | t.Error("set Error", err) | ||
| 72 | } | ||
| 73 | if !bm.IsExist("astaxie") { | ||
| 74 | t.Error("check err") | ||
| 75 | } | ||
| 76 | if v := bm.Get("astaxie"); v.(string) != "author" { | ||
| 77 | t.Error("get err") | ||
| 78 | } | ||
| 79 | |||
| 80 | if err = bm.Put("astaxie1", "author1", 10); err != nil { | ||
| 81 | t.Error("set Error", err) | ||
| 82 | } | ||
| 83 | if !bm.IsExist("astaxie1") { | ||
| 84 | t.Error("check err") | ||
| 85 | } | ||
| 86 | |||
| 87 | vv := bm.GetMulti([]string{"astaxie", "astaxie1"}) | ||
| 88 | if len(vv) != 2 { | ||
| 89 | t.Error("GetMulti ERROR") | ||
| 90 | } | ||
| 91 | if vv[0].(string) != "author" { | ||
| 92 | t.Error("GetMulti ERROR") | ||
| 93 | } | ||
| 94 | if vv[1].(string) != "author1" { | ||
| 95 | t.Error("GetMulti ERROR") | ||
| 96 | } | ||
| 68 | } | 97 | } |
| 69 | 98 | ||
| 70 | func TestFileCache(t *testing.T) { | 99 | func TestFileCache(t *testing.T) { |
| ... | @@ -102,6 +131,7 @@ func TestFileCache(t *testing.T) { | ... | @@ -102,6 +131,7 @@ func TestFileCache(t *testing.T) { |
| 102 | if bm.IsExist("astaxie") { | 131 | if bm.IsExist("astaxie") { |
| 103 | t.Error("delete err") | 132 | t.Error("delete err") |
| 104 | } | 133 | } |
| 134 | |||
| 105 | //test string | 135 | //test string |
| 106 | if err = bm.Put("astaxie", "author", 10); err != nil { | 136 | if err = bm.Put("astaxie", "author", 10); err != nil { |
| 107 | t.Error("set Error", err) | 137 | t.Error("set Error", err) |
| ... | @@ -109,9 +139,28 @@ func TestFileCache(t *testing.T) { | ... | @@ -109,9 +139,28 @@ func TestFileCache(t *testing.T) { |
| 109 | if !bm.IsExist("astaxie") { | 139 | if !bm.IsExist("astaxie") { |
| 110 | t.Error("check err") | 140 | t.Error("check err") |
| 111 | } | 141 | } |
| 112 | |||
| 113 | if v := bm.Get("astaxie"); v.(string) != "author" { | 142 | if v := bm.Get("astaxie"); v.(string) != "author" { |
| 114 | t.Error("get err") | 143 | t.Error("get err") |
| 115 | } | 144 | } |
| 145 | |||
| 146 | //test GetMulti | ||
| 147 | if err = bm.Put("astaxie1", "author1", 10); err != nil { | ||
| 148 | t.Error("set Error", err) | ||
| 149 | } | ||
| 150 | if !bm.IsExist("astaxie1") { | ||
| 151 | t.Error("check err") | ||
| 152 | } | ||
| 153 | |||
| 154 | vv := bm.GetMulti([]string{"astaxie", "astaxie1"}) | ||
| 155 | if len(vv) != 2 { | ||
| 156 | t.Error("GetMulti ERROR") | ||
| 157 | } | ||
| 158 | if vv[0].(string) != "author" { | ||
| 159 | t.Error("GetMulti ERROR") | ||
| 160 | } | ||
| 161 | if vv[1].(string) != "author1" { | ||
| 162 | t.Error("GetMulti ERROR") | ||
| 163 | } | ||
| 164 | |||
| 116 | os.RemoveAll("cache") | 165 | os.RemoveAll("cache") |
| 117 | } | 166 | } | ... | ... |
| ... | @@ -132,6 +132,16 @@ func (fc *FileCache) Get(key string) interface{} { | ... | @@ -132,6 +132,16 @@ func (fc *FileCache) Get(key string) interface{} { |
| 132 | return to.Data | 132 | return to.Data |
| 133 | } | 133 | } |
| 134 | 134 | ||
| 135 | // GetMulti gets values from file cache. | ||
| 136 | // if non-exist or expired, return empty string. | ||
| 137 | func (fc *FileCache) GetMulti(keys []string) []interface{} { | ||
| 138 | var rc []interface{} | ||
| 139 | for _, key := range keys { | ||
| 140 | rc = append(rc, fc.Get(key)) | ||
| 141 | } | ||
| 142 | return rc | ||
| 143 | } | ||
| 144 | |||
| 135 | // Put value into file cache. | 145 | // Put value into file cache. |
| 136 | // timeout means how long to keep this file, unit of ms. | 146 | // timeout means how long to keep this file, unit of ms. |
| 137 | // if timeout equals FileCacheEmbedExpiry(default is 0), cache this item forever. | 147 | // if timeout equals FileCacheEmbedExpiry(default is 0), cache this item forever. | ... | ... |
| ... | @@ -63,6 +63,32 @@ func (rc *MemcacheCache) Get(key string) interface{} { | ... | @@ -63,6 +63,32 @@ func (rc *MemcacheCache) Get(key string) interface{} { |
| 63 | return nil | 63 | return nil |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | // get value from memcache. | ||
| 67 | func (rc *MemcacheCache) GetMulti(keys []string) []interface{} { | ||
| 68 | size := len(keys) | ||
| 69 | var rv []interface{} | ||
| 70 | if rc.conn == nil { | ||
| 71 | if err := rc.connectInit(); err != nil { | ||
| 72 | for i := 0; i < size; i++ { | ||
| 73 | rv = append(rv, err) | ||
| 74 | } | ||
| 75 | return rv | ||
| 76 | } | ||
| 77 | } | ||
| 78 | mv, err := rc.conn.GetMulti(keys) | ||
| 79 | if err == nil { | ||
| 80 | for _, v := range mv { | ||
| 81 | rv = append(rv, string(v.Value)) | ||
| 82 | } | ||
| 83 | return rv | ||
| 84 | } else { | ||
| 85 | for i := 0; i < size; i++ { | ||
| 86 | rv = append(rv, err) | ||
| 87 | } | ||
| 88 | return rv | ||
| 89 | } | ||
| 90 | } | ||
| 91 | |||
| 66 | // put value to memcache. only support string. | 92 | // put value to memcache. only support string. |
| 67 | func (rc *MemcacheCache) Put(key string, val interface{}, timeout int64) error { | 93 | func (rc *MemcacheCache) Put(key string, val interface{}, timeout int64) error { |
| 68 | if rc.conn == nil { | 94 | if rc.conn == nil { | ... | ... |
cache/memcache/memcache_test.go
0 → 100644
| 1 | // Copyright 2014 beego Author. All Rights Reserved. | ||
| 2 | // | ||
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 4 | // you may not use this file except in compliance with the License. | ||
| 5 | // You may obtain a copy of the License at | ||
| 6 | // | ||
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 | ||
| 8 | // | ||
| 9 | // Unless required by applicable law or agreed to in writing, software | ||
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, | ||
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 12 | // See the License for the specific language governing permissions and | ||
| 13 | // limitations under the License. | ||
| 14 | |||
| 15 | package memcache | ||
| 16 | |||
| 17 | import ( | ||
| 18 | _ "github.com/bradfitz/gomemcache/memcache" | ||
| 19 | |||
| 20 | "github.com/astaxie/beego/cache" | ||
| 21 | "strconv" | ||
| 22 | "testing" | ||
| 23 | "time" | ||
| 24 | ) | ||
| 25 | |||
| 26 | func TestRedisCache(t *testing.T) { | ||
| 27 | bm, err := cache.NewCache("memcache", `{"conn": "127.0.0.1:11211"}`) | ||
| 28 | if err != nil { | ||
| 29 | t.Error("init err") | ||
| 30 | } | ||
| 31 | if err = bm.Put("astaxie", "1", 10); err != nil { | ||
| 32 | t.Error("set Error", err) | ||
| 33 | } | ||
| 34 | if !bm.IsExist("astaxie") { | ||
| 35 | t.Error("check err") | ||
| 36 | } | ||
| 37 | |||
| 38 | time.Sleep(10 * time.Second) | ||
| 39 | |||
| 40 | if bm.IsExist("astaxie") { | ||
| 41 | t.Error("check err") | ||
| 42 | } | ||
| 43 | if err = bm.Put("astaxie", "1", 10); err != nil { | ||
| 44 | t.Error("set Error", err) | ||
| 45 | } | ||
| 46 | |||
| 47 | if v, err := strconv.Atoi(bm.Get("astaxie").(string)); err != nil || v != 1 { | ||
| 48 | t.Error("get err") | ||
| 49 | } | ||
| 50 | |||
| 51 | if err = bm.Incr("astaxie"); err != nil { | ||
| 52 | t.Error("Incr Error", err) | ||
| 53 | } | ||
| 54 | |||
| 55 | if v, err := strconv.Atoi(bm.Get("astaxie").(string)); err != nil || v != 2 { | ||
| 56 | t.Error("get err") | ||
| 57 | } | ||
| 58 | |||
| 59 | if err = bm.Decr("astaxie"); err != nil { | ||
| 60 | t.Error("Decr Error", err) | ||
| 61 | } | ||
| 62 | |||
| 63 | if v, err := strconv.Atoi(bm.Get("astaxie").(string)); err != nil || v != 1 { | ||
| 64 | t.Error("get err") | ||
| 65 | } | ||
| 66 | bm.Delete("astaxie") | ||
| 67 | if bm.IsExist("astaxie") { | ||
| 68 | t.Error("delete err") | ||
| 69 | } | ||
| 70 | |||
| 71 | //test string | ||
| 72 | if err = bm.Put("astaxie", "author", 10); err != nil { | ||
| 73 | t.Error("set Error", err) | ||
| 74 | } | ||
| 75 | if !bm.IsExist("astaxie") { | ||
| 76 | t.Error("check err") | ||
| 77 | } | ||
| 78 | |||
| 79 | if v := bm.Get("astaxie").(string); v != "author" { | ||
| 80 | t.Error("get err") | ||
| 81 | } | ||
| 82 | |||
| 83 | //test GetMulti | ||
| 84 | if err = bm.Put("astaxie1", "author1", 10); err != nil { | ||
| 85 | t.Error("set Error", err) | ||
| 86 | } | ||
| 87 | if !bm.IsExist("astaxie1") { | ||
| 88 | t.Error("check err") | ||
| 89 | } | ||
| 90 | |||
| 91 | vv := bm.GetMulti([]string{"astaxie", "astaxie1"}) | ||
| 92 | if len(vv) != 2 { | ||
| 93 | t.Error("GetMulti ERROR") | ||
| 94 | } | ||
| 95 | if vv[0].(string) != "author" { | ||
| 96 | t.Error("GetMulti ERROR") | ||
| 97 | } | ||
| 98 | if vv[1].(string) != "author1" { | ||
| 99 | t.Error("GetMulti ERROR") | ||
| 100 | } | ||
| 101 | |||
| 102 | // test clear all | ||
| 103 | if err = bm.ClearAll(); err != nil { | ||
| 104 | t.Error("clear all err") | ||
| 105 | } | ||
| 106 | } |
| ... | @@ -64,6 +64,16 @@ func (bc *MemoryCache) Get(name string) interface{} { | ... | @@ -64,6 +64,16 @@ func (bc *MemoryCache) Get(name string) interface{} { |
| 64 | return nil | 64 | return nil |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | // GetMulti gets caches from memory. | ||
| 68 | // if non-existed or expired, return nil. | ||
| 69 | func (bc *MemoryCache) GetMulti(names []string) []interface{} { | ||
| 70 | var rc []interface{} | ||
| 71 | for _, name := range names { | ||
| 72 | rc = append(rc, bc.Get(name)) | ||
| 73 | } | ||
| 74 | return rc | ||
| 75 | } | ||
| 76 | |||
| 67 | // Put cache to memory. | 77 | // Put cache to memory. |
| 68 | // if expired is 0, it will be cleaned by next gc operation ( default gc clock is 1 minute). | 78 | // if expired is 0, it will be cleaned by next gc operation ( default gc clock is 1 minute). |
| 69 | func (bc *MemoryCache) Put(name string, value interface{}, expired int64) error { | 79 | func (bc *MemoryCache) Put(name string, value interface{}, expired int64) error { | ... | ... |
| ... | @@ -74,6 +74,39 @@ func (rc *RedisCache) Get(key string) interface{} { | ... | @@ -74,6 +74,39 @@ func (rc *RedisCache) Get(key string) interface{} { |
| 74 | return nil | 74 | return nil |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | // GetMulti get cache from redis. | ||
| 78 | func (rc *RedisCache) GetMulti(keys []string) []interface{} { | ||
| 79 | size := len(keys) | ||
| 80 | var rv []interface{} | ||
| 81 | c := rc.p.Get() | ||
| 82 | defer c.Close() | ||
| 83 | var err error | ||
| 84 | for _, key := range keys { | ||
| 85 | err = c.Send("GET", key) | ||
| 86 | if err != nil { | ||
| 87 | goto ERROR | ||
| 88 | } | ||
| 89 | } | ||
| 90 | if err = c.Flush(); err != nil { | ||
| 91 | goto ERROR | ||
| 92 | } | ||
| 93 | for i := 0; i < size; i++ { | ||
| 94 | if v, err := c.Receive(); err == nil { | ||
| 95 | rv = append(rv, v.([]byte)) | ||
| 96 | } else { | ||
| 97 | rv = append(rv, err) | ||
| 98 | } | ||
| 99 | } | ||
| 100 | return rv | ||
| 101 | ERROR: | ||
| 102 | rv = rv[0:0] | ||
| 103 | for i := 0; i < size; i++ { | ||
| 104 | rv = append(rv, nil) | ||
| 105 | } | ||
| 106 | |||
| 107 | return rv | ||
| 108 | } | ||
| 109 | |||
| 77 | // put cache to redis. | 110 | // put cache to redis. |
| 78 | func (rc *RedisCache) Put(key string, val interface{}, timeout int64) error { | 111 | func (rc *RedisCache) Put(key string, val interface{}, timeout int64) error { |
| 79 | var err error | 112 | var err error | ... | ... |
| ... | @@ -67,6 +67,7 @@ func TestRedisCache(t *testing.T) { | ... | @@ -67,6 +67,7 @@ func TestRedisCache(t *testing.T) { |
| 67 | if bm.IsExist("astaxie") { | 67 | if bm.IsExist("astaxie") { |
| 68 | t.Error("delete err") | 68 | t.Error("delete err") |
| 69 | } | 69 | } |
| 70 | |||
| 70 | //test string | 71 | //test string |
| 71 | if err = bm.Put("astaxie", "author", 10); err != nil { | 72 | if err = bm.Put("astaxie", "author", 10); err != nil { |
| 72 | t.Error("set Error", err) | 73 | t.Error("set Error", err) |
| ... | @@ -78,6 +79,26 @@ func TestRedisCache(t *testing.T) { | ... | @@ -78,6 +79,26 @@ func TestRedisCache(t *testing.T) { |
| 78 | if v, _ := redis.String(bm.Get("astaxie"), err); v != "author" { | 79 | if v, _ := redis.String(bm.Get("astaxie"), err); v != "author" { |
| 79 | t.Error("get err") | 80 | t.Error("get err") |
| 80 | } | 81 | } |
| 82 | |||
| 83 | //test GetMulti | ||
| 84 | if err = bm.Put("astaxie1", "author1", 10); err != nil { | ||
| 85 | t.Error("set Error", err) | ||
| 86 | } | ||
| 87 | if !bm.IsExist("astaxie1") { | ||
| 88 | t.Error("check err") | ||
| 89 | } | ||
| 90 | |||
| 91 | vv := bm.GetMulti([]string{"astaxie", "astaxie1"}) | ||
| 92 | if len(vv) != 2 { | ||
| 93 | t.Error("GetMulti ERROR") | ||
| 94 | } | ||
| 95 | if v, _ := redis.String(vv[0], nil); v != "author" { | ||
| 96 | t.Error("GetMulti ERROR") | ||
| 97 | } | ||
| 98 | if v, _ := redis.String(vv[1], nil); v != "author1" { | ||
| 99 | t.Error("GetMulti ERROR") | ||
| 100 | } | ||
| 101 | |||
| 81 | // test clear all | 102 | // test clear all |
| 82 | if err = bm.ClearAll(); err != nil { | 103 | if err = bm.ClearAll(); err != nil { |
| 83 | t.Error("clear all err") | 104 | t.Error("clear all err") | ... | ... |
-
Please register or sign in to post a comment