github.com/vicanso/lru-ttl@v1.5.1/l2cache.go (about) 1 // Copyright 2020 tree xie 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 // L2Cache use lru cache for the first cache, and slow cache for the second cache. 16 // LRU cache should be set max entries for less memory usage but faster, 17 // slow cache is slower and using more space, but it can store more data 18 19 package lruttl 20 21 import ( 22 "bytes" 23 "context" 24 "encoding/json" 25 "errors" 26 "time" 27 ) 28 29 type SlowCache interface { 30 Get(ctx context.Context, key string) ([]byte, error) 31 Set(ctx context.Context, key string, value []byte, ttl time.Duration) error 32 TTL(ctx context.Context, key string) (time.Duration, error) 33 Del(ctx context.Context, key string) (int64, error) 34 } 35 36 // L2CacheOption l2cache option 37 type L2CacheOption func(c *L2Cache) 38 39 type L2CacheMarshal func(v interface{}) ([]byte, error) 40 type L2CacheUnmarshal func(data []byte, v interface{}) error 41 42 // A l2cache for frequently visited data 43 type L2Cache struct { 44 // prefix is the prefix of all key, it will auto prepend to the key 45 prefix string 46 // ttl is the duration for cache 47 ttl time.Duration 48 // ttlCache is the ttl lru cache 49 ttlCache *Cache 50 // slowCache is the slow cache for more data 51 slowCache SlowCache 52 // marshal is custom marshal function. 53 // It will be json.Marshal if not set 54 marshal L2CacheMarshal 55 // unmarshal is custom unmarshal function. 56 // It will be json.Unmarshal if not set 57 unmarshal L2CacheUnmarshal 58 59 nilErr error 60 } 61 62 // ErrIsNil is the error of nil cache 63 var ErrIsNil = errors.New("cache is nil") 64 65 // ErrKeyIsNil is the error of nil key 66 var ErrKeyIsNil = errors.New("key is nil") 67 68 // ErrInvalidType is the error of invalid type 69 var ErrInvalidType = errors.New("invalid type") 70 71 // BufferMarshal converts *bytes.Buffer to bytes, 72 // it returns a ErrInvalidType if restult is not *bytes.Buffer 73 func BufferMarshal(result interface{}) ([]byte, error) { 74 buf, ok := result.(*bytes.Buffer) 75 if !ok { 76 return nil, ErrInvalidType 77 } 78 return buf.Bytes(), nil 79 } 80 81 // BufferUnmarshal writes the data to buffer, 82 // it returns a ErrInvalidType if restult is not *bytes.Buffer 83 func BufferUnmarshal(data []byte, result interface{}) error { 84 buf, ok := result.(*bytes.Buffer) 85 if !ok { 86 return ErrInvalidType 87 } 88 _, err := buf.Write(data) 89 return err 90 } 91 92 // NewL2Cache return a new L2Cache, 93 // it returns panic if maxEntries or defaultTTL is nil 94 func NewL2Cache(slowCache SlowCache, maxEntries int, defaultTTL time.Duration, opts ...L2CacheOption) *L2Cache { 95 if defaultTTL < time.Second { 96 panic("default ttl should be gt one second") 97 } 98 c := &L2Cache{ 99 ttl: defaultTTL, 100 ttlCache: New(maxEntries, defaultTTL), 101 slowCache: slowCache, 102 } 103 for _, opt := range opts { 104 opt(c) 105 } 106 return c 107 } 108 109 // L2CacheMarshalOption sets custom marshal function for l2cache 110 func L2CacheMarshalOption(fn L2CacheMarshal) L2CacheOption { 111 return func(c *L2Cache) { 112 c.marshal = fn 113 } 114 } 115 116 // L2CacheUnmarshalOption sets custom unmarshal function for l2cache 117 func L2CacheUnmarshalOption(fn L2CacheUnmarshal) L2CacheOption { 118 return func(c *L2Cache) { 119 c.unmarshal = fn 120 } 121 } 122 123 // L2CachePrefixOption sets prefix for l2cache 124 func L2CachePrefixOption(prefix string) L2CacheOption { 125 return func(c *L2Cache) { 126 c.prefix = prefix 127 } 128 } 129 130 // L2CacheNilErrOption set nil error for l2cache 131 func L2CacheNilErrOption(nilErr error) L2CacheOption { 132 return func(c *L2Cache) { 133 c.nilErr = nilErr 134 } 135 } 136 137 func (l2 *L2Cache) getKey(key string) (string, error) { 138 if key == "" { 139 return "", ErrKeyIsNil 140 } 141 return l2.prefix + key, nil 142 } 143 144 // TTL returns the ttl for key 145 func (l2 *L2Cache) TTL(ctx context.Context, key string) (time.Duration, error) { 146 key, err := l2.getKey(key) 147 if err != nil { 148 return 0, err 149 } 150 d := l2.ttlCache.TTL(key) 151 // 小于0的表示不存在 152 // 由于lru有大小限制,可能由于空间不够导致不存在 153 // 不存在时则从slow cache获取 154 if d >= 0 { 155 return d, nil 156 } 157 return l2.slowCache.TTL(ctx, key) 158 } 159 160 // getBytes gets data from lru cache first, if not exists, 161 // then gets the data from slow cache. 162 func (l2 *L2Cache) getBytes(ctx context.Context, key string) ([]byte, error) { 163 v, ok := l2.ttlCache.Get(key) 164 var buf []byte 165 // 获取成功,而数据不为nil 166 // ok为false时,数据也可能不为空(已过期) 167 if ok && v != nil { 168 buf, _ = v.([]byte) 169 } 170 // 从lru中获取到可用数据 171 // lru中数据不存在(数据不存在或过期都有可能) 172 // 有可能数据未过期但lru空间较小,因此被删除 173 // 也有可能lru中数据过期但 slow cache中数据已更新 174 if len(buf) == 0 { 175 b, err := l2.slowCache.Get(ctx, key) 176 if err != nil { 177 return nil, err 178 } 179 buf = b 180 // 成功从slowcache获取缓存,则将数据设置回lru ttl 181 if len(buf) != 0 { 182 // 获取ttl失败时忽略不设置lru cache即可 183 // 因此忽略错误 184 ttl, _ := l2.slowCache.TTL(ctx, key) 185 if ttl != 0 { 186 l2.ttlCache.Add(key, buf, ttl) 187 } 188 } 189 } 190 return buf, nil 191 } 192 193 // GetBytes gets data from lur cache first, if not exists, 194 // then gets the data from slow cache. 195 func (l2 *L2Cache) GetBytes(ctx context.Context, key string) ([]byte, error) { 196 // 由公有函数来生成key,避免私有调用生成时如果循环调用多次添加prefix 197 key, err := l2.getKey(key) 198 if err != nil { 199 return nil, err 200 } 201 return l2.getBytes(ctx, key) 202 } 203 204 // setBytes sets data to lru cache and slow cache 205 func (l2 *L2Cache) setBytes(ctx context.Context, key string, value []byte, ttl ...time.Duration) error { 206 t := l2.ttl 207 if len(ttl) != 0 && ttl[0] != 0 { 208 t = ttl[0] 209 } 210 // 先设置较慢的缓存 211 err := l2.slowCache.Set(ctx, key, value, t) 212 if err != nil { 213 return err 214 } 215 l2.ttlCache.Add(key, value, t) 216 return nil 217 } 218 219 // SetBytes sets data to lru cache and slow cache 220 func (l2 *L2Cache) SetBytes(ctx context.Context, key string, value []byte, ttl ...time.Duration) error { 221 // 由公有函数来生成key,避免私有调用生成时如果循环调用多次添加prefix 222 key, err := l2.getKey(key) 223 if err != nil { 224 return err 225 } 226 return l2.setBytes(ctx, key, value, ttl...) 227 } 228 229 // Get gets data from lru cache first, if not exists, 230 // then gets the data from slow cache. 231 // Use unmarshal function coverts the data to result 232 func (l2 *L2Cache) Get(ctx context.Context, key string, result interface{}) error { 233 return l2.get(ctx, key, result) 234 } 235 236 // Get gets data from lru cache first, if not exists, 237 // then gets the data from slow cache. 238 // Use unmarshal function coverts the data to result. 239 // It will not return nil error. 240 func (l2 *L2Cache) GetIgnoreNilErr(ctx context.Context, key string, result interface{}) error { 241 err := l2.get(ctx, key, result) 242 if err != nil && err == l2.nilErr { 243 err = nil 244 } 245 return err 246 } 247 248 func (l2 *L2Cache) get(ctx context.Context, key string, result interface{}) error { 249 // 由公有函数来生成key,避免私有调用生成时如果循环调用多次添加prefix 250 key, err := l2.getKey(key) 251 if err != nil { 252 return err 253 } 254 buf, err := l2.getBytes(ctx, key) 255 if err != nil { 256 return err 257 } 258 259 fn := l2.unmarshal 260 if fn == nil { 261 fn = json.Unmarshal 262 } 263 err = fn(buf, result) 264 if err != nil { 265 return err 266 } 267 return nil 268 } 269 270 // Set converts the value to bytes, then sets it to lru cache and slow cache 271 func (l2 *L2Cache) Set(ctx context.Context, key string, value interface{}, ttl ...time.Duration) error { 272 key, err := l2.getKey(key) 273 if err != nil { 274 return err 275 } 276 fn := l2.marshal 277 if fn == nil { 278 fn = json.Marshal 279 } 280 buf, err := fn(value) 281 if err != nil { 282 return err 283 } 284 return l2.setBytes(ctx, key, buf, ttl...) 285 } 286 287 // Del deletes data from lru cache and slow cache 288 func (l2 *L2Cache) Del(ctx context.Context, key string) (int64, error) { 289 key, err := l2.getKey(key) 290 if err != nil { 291 return 0, err 292 } 293 // 先清除ttl cache 294 l2.ttlCache.Remove(key) 295 return l2.slowCache.Del(ctx, key) 296 }