github.com/wangyougui/gf/v2@v2.6.5/os/gcache/gcache_adapter_memory.go (about) 1 // Copyright GoFrame Author(https://goframe.org). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/wangyougui/gf. 6 7 package gcache 8 9 import ( 10 "context" 11 "math" 12 "time" 13 14 "github.com/wangyougui/gf/v2/container/glist" 15 "github.com/wangyougui/gf/v2/container/gset" 16 "github.com/wangyougui/gf/v2/container/gtype" 17 "github.com/wangyougui/gf/v2/container/gvar" 18 "github.com/wangyougui/gf/v2/os/gtime" 19 "github.com/wangyougui/gf/v2/os/gtimer" 20 ) 21 22 // AdapterMemory is an adapter implements using memory. 23 type AdapterMemory struct { 24 // cap limits the size of the cache pool. 25 // If the size of the cache exceeds the cap, 26 // the cache expiration process performs according to the LRU algorithm. 27 // It is 0 in default which means no limits. 28 cap int 29 data *adapterMemoryData // data is the underlying cache data which is stored in a hash table. 30 expireTimes *adapterMemoryExpireTimes // expireTimes is the expiring key to its timestamp mapping, which is used for quick indexing and deleting. 31 expireSets *adapterMemoryExpireSets // expireSets is the expiring timestamp to its key set mapping, which is used for quick indexing and deleting. 32 lru *adapterMemoryLru // lru is the LRU manager, which is enabled when attribute cap > 0. 33 lruGetList *glist.List // lruGetList is the LRU history according to Get function. 34 eventList *glist.List // eventList is the asynchronous event list for internal data synchronization. 35 closed *gtype.Bool // closed controls the cache closed or not. 36 } 37 38 // Internal cache item. 39 type adapterMemoryItem struct { 40 v interface{} // Value. 41 e int64 // Expire timestamp in milliseconds. 42 } 43 44 // Internal event item. 45 type adapterMemoryEvent struct { 46 k interface{} // Key. 47 e int64 // Expire time in milliseconds. 48 } 49 50 const ( 51 // defaultMaxExpire is the default expire time for no expiring items. 52 // It equals to math.MaxInt64/1000000. 53 defaultMaxExpire = 9223372036854 54 ) 55 56 // NewAdapterMemory creates and returns a new memory cache object. 57 func NewAdapterMemory(lruCap ...int) Adapter { 58 c := &AdapterMemory{ 59 data: newAdapterMemoryData(), 60 lruGetList: glist.New(true), 61 expireTimes: newAdapterMemoryExpireTimes(), 62 expireSets: newAdapterMemoryExpireSets(), 63 eventList: glist.New(true), 64 closed: gtype.NewBool(), 65 } 66 if len(lruCap) > 0 { 67 c.cap = lruCap[0] 68 c.lru = newMemCacheLru(c) 69 } 70 // Here may be a "timer leak" if adapter is manually changed from memory adapter. 71 // Do not worry about this, as adapter is less changed, and it does nothing if it's not used. 72 gtimer.AddSingleton(context.Background(), time.Second, c.syncEventAndClearExpired) 73 return c 74 } 75 76 // Set sets cache with `key`-`value` pair, which is expired after `duration`. 77 // 78 // It does not expire if `duration` == 0. 79 // It deletes the keys of `data` if `duration` < 0 or given `value` is nil. 80 func (c *AdapterMemory) Set(ctx context.Context, key interface{}, value interface{}, duration time.Duration) error { 81 expireTime := c.getInternalExpire(duration) 82 c.data.Set(key, adapterMemoryItem{ 83 v: value, 84 e: expireTime, 85 }) 86 c.eventList.PushBack(&adapterMemoryEvent{ 87 k: key, 88 e: expireTime, 89 }) 90 return nil 91 } 92 93 // SetMap batch sets cache with key-value pairs by `data` map, which is expired after `duration`. 94 // 95 // It does not expire if `duration` == 0. 96 // It deletes the keys of `data` if `duration` < 0 or given `value` is nil. 97 func (c *AdapterMemory) SetMap(ctx context.Context, data map[interface{}]interface{}, duration time.Duration) error { 98 var ( 99 expireTime = c.getInternalExpire(duration) 100 err = c.data.SetMap(data, expireTime) 101 ) 102 if err != nil { 103 return err 104 } 105 for k := range data { 106 c.eventList.PushBack(&adapterMemoryEvent{ 107 k: k, 108 e: expireTime, 109 }) 110 } 111 return nil 112 } 113 114 // SetIfNotExist sets cache with `key`-`value` pair which is expired after `duration` 115 // if `key` does not exist in the cache. It returns true the `key` does not exist in the 116 // cache, and it sets `value` successfully to the cache, or else it returns false. 117 // 118 // It does not expire if `duration` == 0. 119 // It deletes the `key` if `duration` < 0 or given `value` is nil. 120 func (c *AdapterMemory) SetIfNotExist(ctx context.Context, key interface{}, value interface{}, duration time.Duration) (bool, error) { 121 isContained, err := c.Contains(ctx, key) 122 if err != nil { 123 return false, err 124 } 125 if !isContained { 126 if _, err = c.doSetWithLockCheck(ctx, key, value, duration); err != nil { 127 return false, err 128 } 129 return true, nil 130 } 131 return false, nil 132 } 133 134 // SetIfNotExistFunc sets `key` with result of function `f` and returns true 135 // if `key` does not exist in the cache, or else it does nothing and returns false if `key` already exists. 136 // 137 // The parameter `value` can be type of `func() interface{}`, but it does nothing if its 138 // result is nil. 139 // 140 // It does not expire if `duration` == 0. 141 // It deletes the `key` if `duration` < 0 or given `value` is nil. 142 func (c *AdapterMemory) SetIfNotExistFunc(ctx context.Context, key interface{}, f Func, duration time.Duration) (bool, error) { 143 isContained, err := c.Contains(ctx, key) 144 if err != nil { 145 return false, err 146 } 147 if !isContained { 148 value, err := f(ctx) 149 if err != nil { 150 return false, err 151 } 152 if _, err = c.doSetWithLockCheck(ctx, key, value, duration); err != nil { 153 return false, err 154 } 155 return true, nil 156 } 157 return false, nil 158 } 159 160 // SetIfNotExistFuncLock sets `key` with result of function `f` and returns true 161 // if `key` does not exist in the cache, or else it does nothing and returns false if `key` already exists. 162 // 163 // It does not expire if `duration` == 0. 164 // It deletes the `key` if `duration` < 0 or given `value` is nil. 165 // 166 // Note that it differs from function `SetIfNotExistFunc` is that the function `f` is executed within 167 // writing mutex lock for concurrent safety purpose. 168 func (c *AdapterMemory) SetIfNotExistFuncLock(ctx context.Context, key interface{}, f Func, duration time.Duration) (bool, error) { 169 isContained, err := c.Contains(ctx, key) 170 if err != nil { 171 return false, err 172 } 173 if !isContained { 174 if _, err = c.doSetWithLockCheck(ctx, key, f, duration); err != nil { 175 return false, err 176 } 177 return true, nil 178 } 179 return false, nil 180 } 181 182 // Get retrieves and returns the associated value of given `key`. 183 // It returns nil if it does not exist, or its value is nil, or it's expired. 184 // If you would like to check if the `key` exists in the cache, it's better using function Contains. 185 func (c *AdapterMemory) Get(ctx context.Context, key interface{}) (*gvar.Var, error) { 186 item, ok := c.data.Get(key) 187 if ok && !item.IsExpired() { 188 // Adding to LRU history if LRU feature is enabled. 189 if c.cap > 0 { 190 c.lruGetList.PushBack(key) 191 } 192 return gvar.New(item.v), nil 193 } 194 return nil, nil 195 } 196 197 // GetOrSet retrieves and returns the value of `key`, or sets `key`-`value` pair and 198 // returns `value` if `key` does not exist in the cache. The key-value pair expires 199 // after `duration`. 200 // 201 // It does not expire if `duration` == 0. 202 // It deletes the `key` if `duration` < 0 or given `value` is nil, but it does nothing 203 // if `value` is a function and the function result is nil. 204 func (c *AdapterMemory) GetOrSet(ctx context.Context, key interface{}, value interface{}, duration time.Duration) (*gvar.Var, error) { 205 v, err := c.Get(ctx, key) 206 if err != nil { 207 return nil, err 208 } 209 if v == nil { 210 return c.doSetWithLockCheck(ctx, key, value, duration) 211 } 212 return v, nil 213 } 214 215 // GetOrSetFunc retrieves and returns the value of `key`, or sets `key` with result of 216 // function `f` and returns its result if `key` does not exist in the cache. The key-value 217 // pair expires after `duration`. 218 // 219 // It does not expire if `duration` == 0. 220 // It deletes the `key` if `duration` < 0 or given `value` is nil, but it does nothing 221 // if `value` is a function and the function result is nil. 222 func (c *AdapterMemory) GetOrSetFunc(ctx context.Context, key interface{}, f Func, duration time.Duration) (*gvar.Var, error) { 223 v, err := c.Get(ctx, key) 224 if err != nil { 225 return nil, err 226 } 227 if v == nil { 228 value, err := f(ctx) 229 if err != nil { 230 return nil, err 231 } 232 if value == nil { 233 return nil, nil 234 } 235 return c.doSetWithLockCheck(ctx, key, value, duration) 236 } 237 return v, nil 238 } 239 240 // GetOrSetFuncLock retrieves and returns the value of `key`, or sets `key` with result of 241 // function `f` and returns its result if `key` does not exist in the cache. The key-value 242 // pair expires after `duration`. 243 // 244 // It does not expire if `duration` == 0. 245 // It deletes the `key` if `duration` < 0 or given `value` is nil, but it does nothing 246 // if `value` is a function and the function result is nil. 247 // 248 // Note that it differs from function `GetOrSetFunc` is that the function `f` is executed within 249 // writing mutex lock for concurrent safety purpose. 250 func (c *AdapterMemory) GetOrSetFuncLock(ctx context.Context, key interface{}, f Func, duration time.Duration) (*gvar.Var, error) { 251 v, err := c.Get(ctx, key) 252 if err != nil { 253 return nil, err 254 } 255 if v == nil { 256 return c.doSetWithLockCheck(ctx, key, f, duration) 257 } 258 return v, nil 259 } 260 261 // Contains checks and returns true if `key` exists in the cache, or else returns false. 262 func (c *AdapterMemory) Contains(ctx context.Context, key interface{}) (bool, error) { 263 v, err := c.Get(ctx, key) 264 if err != nil { 265 return false, err 266 } 267 return v != nil, nil 268 } 269 270 // GetExpire retrieves and returns the expiration of `key` in the cache. 271 // 272 // Note that, 273 // It returns 0 if the `key` does not expire. 274 // It returns -1 if the `key` does not exist in the cache. 275 func (c *AdapterMemory) GetExpire(ctx context.Context, key interface{}) (time.Duration, error) { 276 if item, ok := c.data.Get(key); ok { 277 return time.Duration(item.e-gtime.TimestampMilli()) * time.Millisecond, nil 278 } 279 return -1, nil 280 } 281 282 // Remove deletes one or more keys from cache, and returns its value. 283 // If multiple keys are given, it returns the value of the last deleted item. 284 func (c *AdapterMemory) Remove(ctx context.Context, keys ...interface{}) (*gvar.Var, error) { 285 var removedKeys []interface{} 286 removedKeys, value, err := c.data.Remove(keys...) 287 if err != nil { 288 return nil, err 289 } 290 for _, key := range removedKeys { 291 c.eventList.PushBack(&adapterMemoryEvent{ 292 k: key, 293 e: gtime.TimestampMilli() - 1000000, 294 }) 295 } 296 return gvar.New(value), nil 297 } 298 299 // Update updates the value of `key` without changing its expiration and returns the old value. 300 // The returned value `exist` is false if the `key` does not exist in the cache. 301 // 302 // It deletes the `key` if given `value` is nil. 303 // It does nothing if `key` does not exist in the cache. 304 func (c *AdapterMemory) Update(ctx context.Context, key interface{}, value interface{}) (oldValue *gvar.Var, exist bool, err error) { 305 v, exist, err := c.data.Update(key, value) 306 return gvar.New(v), exist, err 307 } 308 309 // UpdateExpire updates the expiration of `key` and returns the old expiration duration value. 310 // 311 // It returns -1 and does nothing if the `key` does not exist in the cache. 312 // It deletes the `key` if `duration` < 0. 313 func (c *AdapterMemory) UpdateExpire(ctx context.Context, key interface{}, duration time.Duration) (oldDuration time.Duration, err error) { 314 newExpireTime := c.getInternalExpire(duration) 315 oldDuration, err = c.data.UpdateExpire(key, newExpireTime) 316 if err != nil { 317 return 318 } 319 if oldDuration != -1 { 320 c.eventList.PushBack(&adapterMemoryEvent{ 321 k: key, 322 e: newExpireTime, 323 }) 324 } 325 return 326 } 327 328 // Size returns the size of the cache. 329 func (c *AdapterMemory) Size(ctx context.Context) (size int, err error) { 330 return c.data.Size() 331 } 332 333 // Data returns a copy of all key-value pairs in the cache as map type. 334 func (c *AdapterMemory) Data(ctx context.Context) (map[interface{}]interface{}, error) { 335 return c.data.Data() 336 } 337 338 // Keys returns all keys in the cache as slice. 339 func (c *AdapterMemory) Keys(ctx context.Context, regexp ...string) ([]interface{}, error) { 340 return c.data.Keys(regexp...) 341 } 342 343 // Values returns all values in the cache as slice. 344 func (c *AdapterMemory) Values(ctx context.Context) ([]interface{}, error) { 345 return c.data.Values() 346 } 347 348 // Clear clears all data of the cache. 349 // Note that this function is sensitive and should be carefully used. 350 func (c *AdapterMemory) Clear(ctx context.Context) error { 351 return c.data.Clear() 352 } 353 354 // Close closes the cache. 355 func (c *AdapterMemory) Close(ctx context.Context) error { 356 if c.cap > 0 { 357 c.lru.Close() 358 } 359 c.closed.Set(true) 360 return nil 361 } 362 363 // doSetWithLockCheck sets cache with `key`-`value` pair if `key` does not exist in the 364 // cache, which is expired after `duration`. 365 // 366 // It does not expire if `duration` == 0. 367 // The parameter `value` can be type of <func() interface{}>, but it does nothing if the 368 // function result is nil. 369 // 370 // It doubly checks the `key` whether exists in the cache using mutex writing lock 371 // before setting it to the cache. 372 func (c *AdapterMemory) doSetWithLockCheck(ctx context.Context, key interface{}, value interface{}, duration time.Duration) (result *gvar.Var, err error) { 373 expireTimestamp := c.getInternalExpire(duration) 374 v, err := c.data.SetWithLock(ctx, key, value, expireTimestamp) 375 c.eventList.PushBack(&adapterMemoryEvent{k: key, e: expireTimestamp}) 376 return gvar.New(v), err 377 } 378 379 // getInternalExpire converts and returns the expiration time with given expired duration in milliseconds. 380 func (c *AdapterMemory) getInternalExpire(duration time.Duration) int64 { 381 if duration == 0 { 382 return defaultMaxExpire 383 } 384 return gtime.TimestampMilli() + duration.Nanoseconds()/1000000 385 } 386 387 // makeExpireKey groups the `expire` in milliseconds to its according seconds. 388 func (c *AdapterMemory) makeExpireKey(expire int64) int64 { 389 return int64(math.Ceil(float64(expire/1000)+1) * 1000) 390 } 391 392 // syncEventAndClearExpired does the asynchronous task loop: 393 // 1. Asynchronously process the data in the event list, 394 // and synchronize the results to the `expireTimes` and `expireSets` properties. 395 // 2. Clean up the expired key-value pair data. 396 func (c *AdapterMemory) syncEventAndClearExpired(ctx context.Context) { 397 if c.closed.Val() { 398 gtimer.Exit() 399 return 400 } 401 var ( 402 event *adapterMemoryEvent 403 oldExpireTime int64 404 newExpireTime int64 405 ) 406 // ======================== 407 // Data Synchronization. 408 // ======================== 409 for { 410 v := c.eventList.PopFront() 411 if v == nil { 412 break 413 } 414 event = v.(*adapterMemoryEvent) 415 // Fetching the old expire set. 416 oldExpireTime = c.expireTimes.Get(event.k) 417 // Calculating the new expiration time set. 418 newExpireTime = c.makeExpireKey(event.e) 419 if newExpireTime != oldExpireTime { 420 c.expireSets.GetOrNew(newExpireTime).Add(event.k) 421 if oldExpireTime != 0 { 422 c.expireSets.GetOrNew(oldExpireTime).Remove(event.k) 423 } 424 // Updating the expired time for <event.k>. 425 c.expireTimes.Set(event.k, newExpireTime) 426 } 427 // Adding the key the LRU history by writing operations. 428 if c.cap > 0 { 429 c.lru.Push(event.k) 430 } 431 } 432 // Processing expired keys from LRU. 433 if c.cap > 0 { 434 if c.lruGetList.Len() > 0 { 435 for { 436 if v := c.lruGetList.PopFront(); v != nil { 437 c.lru.Push(v) 438 } else { 439 break 440 } 441 } 442 } 443 c.lru.SyncAndClear(ctx) 444 } 445 // ======================== 446 // Data Cleaning up. 447 // ======================== 448 var ( 449 expireSet *gset.Set 450 ek = c.makeExpireKey(gtime.TimestampMilli()) 451 eks = []int64{ek - 1000, ek - 2000, ek - 3000, ek - 4000, ek - 5000} 452 ) 453 for _, expireTime := range eks { 454 if expireSet = c.expireSets.Get(expireTime); expireSet != nil { 455 // Iterating the set to delete all keys in it. 456 expireSet.Iterator(func(key interface{}) bool { 457 c.clearByKey(key) 458 return true 459 }) 460 // Deleting the set after all of its keys are deleted. 461 c.expireSets.Delete(expireTime) 462 } 463 } 464 } 465 466 // clearByKey deletes the key-value pair with given `key`. 467 // The parameter `force` specifies whether doing this deleting forcibly. 468 func (c *AdapterMemory) clearByKey(key interface{}, force ...bool) { 469 // Doubly check before really deleting it from cache. 470 c.data.DeleteWithDoubleCheck(key, force...) 471 472 // Deleting its expiration time from `expireTimes`. 473 c.expireTimes.Delete(key) 474 475 // Deleting it from LRU. 476 if c.cap > 0 { 477 c.lru.Remove(key) 478 } 479 }