github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/framework/cache/memcache/memcache.go (about) 1 // The package is migrated from beego, you can get from following link: 2 // import( 3 // "github.com/beego/beego/v2/client/cache" 4 // ) 5 // Copyright 2023. All Rights Reserved. 6 // 7 // Licensed under the Apache License, Version 2.0 (the "License"); 8 // you may not use this file except in compliance with the License. 9 // You may obtain a copy of the License at 10 // 11 // http://www.apache.org/licenses/LICENSE-2.0 12 // 13 // Unless required by applicable law or agreed to in writing, software 14 // distributed under the License is distributed on an "AS IS" BASIS, 15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 // See the License for the specific language governing permissions and 17 // limitations under the License. 18 19 // Package memcache for cache provider 20 // 21 // depend on github.com/bradfitz/gomemcache/memcache 22 // 23 // go install github.com/bradfitz/gomemcache/memcache 24 // 25 // Usage: 26 // import( 27 // 28 // _ "github.com/beego/beego/v2/client/cache/memcache" 29 // "github.com/beego/beego/v2/client/cache" 30 // 31 // ) 32 // 33 // bm, err := cache.NewCache("memcache", `{"conn":"127.0.0.1:11211"}`) 34 package memcache 35 36 import ( 37 "context" 38 "encoding/json" 39 "fmt" 40 "strings" 41 "time" 42 43 "github.com/bradfitz/gomemcache/memcache" 44 45 "github.com/mdaxf/iac/framework/berror" 46 "github.com/mdaxf/iac/framework/cache" 47 ) 48 49 // Cache Memcache adapter. 50 type Cache struct { 51 conn *memcache.Client 52 conninfo []string 53 } 54 55 // NewMemCache creates a new memcache adapter. 56 func NewMemCache() cache.Cache { 57 return &Cache{} 58 } 59 60 // Get get value from memcache. 61 func (rc *Cache) Get(ctx context.Context, key string) (interface{}, error) { 62 if item, err := rc.conn.Get(key); err == nil { 63 return item.Value, nil 64 } else { 65 return nil, berror.Wrapf(err, cache.MemCacheCurdFailed, 66 "could not read data from memcache, please check your key, network and connection. Root cause: %s", 67 err.Error()) 68 } 69 } 70 71 // GetMulti gets a value from a key in memcache. 72 func (rc *Cache) GetMulti(ctx context.Context, keys []string) ([]interface{}, error) { 73 rv := make([]interface{}, len(keys)) 74 75 mv, err := rc.conn.GetMulti(keys) 76 if err != nil { 77 return rv, berror.Wrapf(err, cache.MemCacheCurdFailed, 78 "could not read multiple key-values from memcache, "+ 79 "please check your keys, network and connection. Root cause: %s", 80 err.Error()) 81 } 82 83 keysErr := make([]string, 0) 84 for i, ki := range keys { 85 if _, ok := mv[ki]; !ok { 86 keysErr = append(keysErr, fmt.Sprintf("key [%s] error: %s", ki, "key not exist")) 87 continue 88 } 89 rv[i] = mv[ki].Value 90 } 91 92 if len(keysErr) == 0 { 93 return rv, nil 94 } 95 return rv, berror.Error(cache.MultiGetFailed, strings.Join(keysErr, "; ")) 96 } 97 98 // Put puts a value into memcache. 99 func (rc *Cache) Put(ctx context.Context, key string, val interface{}, timeout time.Duration) error { 100 item := memcache.Item{Key: key, Expiration: int32(timeout / time.Second)} 101 if v, ok := val.([]byte); ok { 102 item.Value = v 103 } else if str, ok := val.(string); ok { 104 item.Value = []byte(str) 105 } else { 106 return berror.Errorf(cache.InvalidMemCacheValue, 107 "the value must be string or byte[]. key: %s, value:%v", key, val) 108 } 109 return berror.Wrapf(rc.conn.Set(&item), cache.MemCacheCurdFailed, 110 "could not put key-value to memcache, key: %s", key) 111 } 112 113 // Delete deletes a value in memcache. 114 func (rc *Cache) Delete(ctx context.Context, key string) error { 115 return berror.Wrapf(rc.conn.Delete(key), cache.MemCacheCurdFailed, 116 "could not delete key-value from memcache, key: %s", key) 117 } 118 119 // Incr increases counter. 120 func (rc *Cache) Incr(ctx context.Context, key string) error { 121 _, err := rc.conn.Increment(key, 1) 122 return berror.Wrapf(err, cache.MemCacheCurdFailed, 123 "could not increase value for key: %s", key) 124 } 125 126 // Decr decreases counter. 127 func (rc *Cache) Decr(ctx context.Context, key string) error { 128 _, err := rc.conn.Decrement(key, 1) 129 return berror.Wrapf(err, cache.MemCacheCurdFailed, 130 "could not decrease value for key: %s", key) 131 } 132 133 // IsExist checks if a value exists in memcache. 134 func (rc *Cache) IsExist(ctx context.Context, key string) (bool, error) { 135 _, err := rc.Get(ctx, key) 136 return err == nil, err 137 } 138 139 // ClearAll clears all cache in memcache. 140 func (rc *Cache) ClearAll(context.Context) error { 141 return berror.Wrap(rc.conn.FlushAll(), cache.MemCacheCurdFailed, 142 "try to clear all key-value pairs failed") 143 } 144 145 // StartAndGC starts the memcache adapter. 146 // config: must be in the format {"conn":"connection info"}. 147 // If an error occurs during connecting, an error is returned 148 func (rc *Cache) StartAndGC(config string) error { 149 var cf map[string]string 150 if err := json.Unmarshal([]byte(config), &cf); err != nil { 151 return berror.Wrapf(err, cache.InvalidMemCacheCfg, 152 "could not unmarshal this config, it must be valid json stringP: %s", config) 153 } 154 155 if _, ok := cf["conn"]; !ok { 156 return berror.Errorf(cache.InvalidMemCacheCfg, `config must contains "conn" field: %s`, config) 157 } 158 rc.conninfo = strings.Split(cf["conn"], ";") 159 rc.conn = memcache.New(rc.conninfo...) 160 return nil 161 } 162 163 func init() { 164 cache.Register("memcache", NewMemCache) 165 }