diff --git a/os/gcache/gcache.go b/os/gcache/gcache.go index 4a8a91d7d..552eba5f0 100644 --- a/os/gcache/gcache.go +++ b/os/gcache/gcache.go @@ -21,12 +21,6 @@ func Set(key interface{}, value interface{}, duration time.Duration) { defaultCache.Set(key, value, duration) } -// Update updates the value of without changing its expiration and returns the old value. -// The returned value is false if the does not exist in the cache. -func Update(key interface{}, value interface{}) (oldValue interface{}, exist bool) { - return defaultCache.Update(key, value) -} - // SetIfNotExist sets cache with - pair if does not exist in the cache, // which is expired after . It does not expire if == 0. func SetIfNotExist(key interface{}, value interface{}, duration time.Duration) bool { @@ -124,6 +118,12 @@ func GetExpire(key interface{}) time.Duration { return defaultCache.GetExpire(key) } +// Update updates the value of without changing its expiration and returns the old value. +// The returned value is false if the does not exist in the cache. +func Update(key interface{}, value interface{}) (oldValue interface{}, exist bool) { + return defaultCache.Update(key, value) +} + // UpdateExpire updates the expiration of and returns the old expiration duration value. // It returns -1 if the does not exist in the cache. func UpdateExpire(key interface{}, duration time.Duration) (oldDuration time.Duration) { diff --git a/os/gcache/gcache_adapter.go b/os/gcache/gcache_adapter.go new file mode 100644 index 000000000..1131e5d42 --- /dev/null +++ b/os/gcache/gcache_adapter.go @@ -0,0 +1,108 @@ +// Copyright 2020 gf Author(https://github.com/gogf/gf). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gcache + +import ( + "time" +) + +// Adapter is the adapter for cache features implements. +type Adapter interface { + // Set sets cache with - pair, which is expired after . + // + // It does not expire if == 0. + // It deletes the if < 0. + Set(key interface{}, value interface{}, duration time.Duration) + + // Sets batch sets cache with key-value pairs by , which is expired after . + // + // It does not expire if == 0. + // It deletes the keys of if < 0 or given is nil. + Sets(data map[interface{}]interface{}, duration time.Duration) + + // SetIfNotExist sets cache with - pair which is expired after + // if does not exist in the cache. + // The parameter can be type of , but it dose nothing if its + // result is nil. + // + // It does not expire if == 0. + // It deletes the if < 0 or given is nil. + SetIfNotExist(key interface{}, value interface{}, duration time.Duration) bool + + // Get retrieves and returns the associated value of given . + // It returns nil if it does not exist or its value is nil. + Get(key interface{}) interface{} + + // GetOrSet retrieves and returns the value of , or sets - pair and + // returns if does not exist in the cache. The key-value pair expires + // after . + // + // It does not expire if == 0. + // It deletes the if < 0 or given is nil, but it does nothing + // if is a function and the function result is nil. + GetOrSet(key interface{}, value interface{}, duration time.Duration) interface{} + + // GetOrSetFunc retrieves and returns the value of , or sets with result of + // function and returns its result if does not exist in the cache. The key-value + // pair expires after . + // + // It does not expire if == 0. + // It deletes the if < 0 or given is nil, but it does nothing + // if is a function and the function result is nil. + GetOrSetFunc(key interface{}, f func() interface{}, duration time.Duration) interface{} + + // GetOrSetFuncLock retrieves and returns the value of , or sets with result of + // function and returns its result if does not exist in the cache. The key-value + // pair expires after . + // + // It does not expire if == 0. + // It does nothing if function returns nil. + // + // Note that the function should be executed within writing mutex lock for concurrent + // safety purpose. + GetOrSetFuncLock(key interface{}, f func() interface{}, duration time.Duration) interface{} + + // Remove deletes one or more keys from cache, and returns its value. + // If multiple keys are given, it returns the value of the last deleted item. + Remove(keys ...interface{}) (value interface{}) + + // Update updates the value of without changing its expiration and returns the old value. + // The returned value is false if the does not exist in the cache. + Update(key interface{}, value interface{}) (oldValue interface{}, exist bool) + + // UpdateExpire updates the expiration of and returns the old expiration duration value. + // It returns -1 if the does not exist in the cache. + UpdateExpire(key interface{}, duration time.Duration) (oldDuration time.Duration) + + // Contains checks and returns whether given exists in the cache. + Contains(key interface{}) bool + + // GetExpire retrieves and returns the expiration of in the cache. + // It returns -1 if the does not exist in the cache. + GetExpire(key interface{}) time.Duration + + // Size returns the number of items in the cache. + Size() (size int) + + // Data returns a copy of all key-value pairs in the cache as map type. + // Note that this function may leads lots of memory usage, you can implement this function + // if necessary. + Data() map[interface{}]interface{} + + // Keys returns all keys in the cache as slice. + Keys() []interface{} + + // Values returns all values in the cache as slice. + Values() []interface{} + + // Clear clears all data of the cache. + // Note that this function is sensitive and should be carefully used. + Clear() error + + // Close closes the cache if necessary. + Close() error +} diff --git a/os/gcache/gcache_mem_cache.go b/os/gcache/gcache_adapter_memory.go similarity index 71% rename from os/gcache/gcache_mem_cache.go rename to os/gcache/gcache_adapter_memory.go index b8eccaa77..7bfe36f80 100644 --- a/os/gcache/gcache_mem_cache.go +++ b/os/gcache/gcache_adapter_memory.go @@ -7,7 +7,6 @@ package gcache import ( - "github.com/gogf/gf/container/gvar" "math" "sync" "time" @@ -17,11 +16,10 @@ import ( "github.com/gogf/gf/container/gtype" "github.com/gogf/gf/os/gtime" "github.com/gogf/gf/os/gtimer" - "github.com/gogf/gf/util/gconv" ) // Internal cache object. -type memCache struct { +type adapterMemory struct { // dataMu ensures the concurrent safety of underlying data map. dataMu sync.RWMutex @@ -38,7 +36,7 @@ type memCache struct { cap int // data is the underlying cache data which is stored in a hash table. - data map[interface{}]memCacheItem + data map[interface{}]adapterMemoryItem // expireTimes is the expiring key to its timestamp mapping, // which is used for quick indexing and deleting. @@ -49,7 +47,7 @@ type memCache struct { expireSets map[int64]*gset.Set // lru is the LRU manager, which is enabled when attribute cap > 0. - lru *memCacheLru + lru *adapterMemoryLru // lruGetList is the LRU history according with Get function. lruGetList *glist.List @@ -62,13 +60,13 @@ type memCache struct { } // Internal cache item. -type memCacheItem struct { +type adapterMemoryItem struct { v interface{} // Value. e int64 // Expire timestamp in milliseconds. } // Internal event item. -type memCacheEvent struct { +type adapterMemoryEvent struct { k interface{} // Key. e int64 // Expire time in milliseconds. } @@ -79,11 +77,11 @@ const ( gDEFAULT_MAX_EXPIRE = 9223372036854 ) -// newMemCache creates and returns a new memory cache object. -func newMemCache(lruCap ...int) *memCache { - c := &memCache{ +// newAdapterMemory creates and returns a new memory cache object. +func newAdapterMemory(lruCap ...int) *adapterMemory { + c := &adapterMemory{ lruGetList: glist.New(true), - data: make(map[interface{}]memCacheItem), + data: make(map[interface{}]adapterMemoryItem), expireTimes: make(map[interface{}]int64), expireSets: make(map[int64]*gset.Set), eventList: glist.New(true), @@ -98,15 +96,16 @@ func newMemCache(lruCap ...int) *memCache { // Set sets cache with - pair, which is expired after . // It does not expire if == 0. -func (c *memCache) Set(key interface{}, value interface{}, duration time.Duration) { +// It deletes the if < 0 or given is nil. +func (c *adapterMemory) Set(key interface{}, value interface{}, duration time.Duration) { expireTime := c.getInternalExpire(duration) c.dataMu.Lock() - c.data[key] = memCacheItem{ + c.data[key] = adapterMemoryItem{ v: value, e: expireTime, } c.dataMu.Unlock() - c.eventList.PushBack(&memCacheEvent{ + c.eventList.PushBack(&adapterMemoryEvent{ k: key, e: expireTime, }) @@ -114,11 +113,11 @@ func (c *memCache) Set(key interface{}, value interface{}, duration time.Duratio // Update updates the value of without changing its expiration and returns the old value. // The returned value is false if the does not exist in the cache. -func (c *memCache) Update(key interface{}, value interface{}) (oldValue interface{}, exist bool) { +func (c *adapterMemory) Update(key interface{}, value interface{}) (oldValue interface{}, exist bool) { c.dataMu.Lock() defer c.dataMu.Unlock() if item, ok := c.data[key]; ok { - c.data[key] = memCacheItem{ + c.data[key] = adapterMemoryItem{ v: value, e: item.e, } @@ -129,16 +128,16 @@ func (c *memCache) Update(key interface{}, value interface{}) (oldValue interfac // UpdateExpire updates the expiration of and returns the old expiration duration value. // It returns -1 if the does not exist in the cache. -func (c *memCache) UpdateExpire(key interface{}, duration time.Duration) (oldDuration time.Duration) { +func (c *adapterMemory) UpdateExpire(key interface{}, duration time.Duration) (oldDuration time.Duration) { newExpireTime := c.getInternalExpire(duration) c.dataMu.Lock() defer c.dataMu.Unlock() if item, ok := c.data[key]; ok { - c.data[key] = memCacheItem{ + c.data[key] = adapterMemoryItem{ v: item.v, e: newExpireTime, } - c.eventList.PushBack(&memCacheEvent{ + c.eventList.PushBack(&adapterMemoryEvent{ k: key, e: newExpireTime, }) @@ -149,7 +148,7 @@ func (c *memCache) UpdateExpire(key interface{}, duration time.Duration) (oldDur // GetExpire retrieves and returns the expiration of . // It returns -1 if the does not exist in the cache. -func (c *memCache) GetExpire(key interface{}) time.Duration { +func (c *adapterMemory) GetExpire(key interface{}) time.Duration { c.dataMu.RLock() defer c.dataMu.RUnlock() if item, ok := c.data[key]; ok { @@ -162,12 +161,12 @@ func (c *memCache) GetExpire(key interface{}) time.Duration { // cache, which is expired after . // // It does not expire if == 0. -// The parameter can be type of , but it dose nothing if its -// result is nil. +// The parameter can be type of , but it dose nothing if the +// function result is nil. // // It doubly checks the whether exists in the cache using mutex writing lock // before setting it to the cache. -func (c *memCache) doSetWithLockCheck(key interface{}, value interface{}, duration time.Duration) interface{} { +func (c *adapterMemory) doSetWithLockCheck(key interface{}, value interface{}, duration time.Duration) interface{} { expireTimestamp := c.getInternalExpire(duration) c.dataMu.Lock() defer c.dataMu.Unlock() @@ -180,13 +179,13 @@ func (c *memCache) doSetWithLockCheck(key interface{}, value interface{}, durati return nil } } - c.data[key] = memCacheItem{v: value, e: expireTimestamp} - c.eventList.PushBack(&memCacheEvent{k: key, e: expireTimestamp}) + c.data[key] = adapterMemoryItem{v: value, e: expireTimestamp} + c.eventList.PushBack(&adapterMemoryEvent{k: key, e: expireTimestamp}) return value } // getInternalExpire converts and returns the expire time with given expired duration in milliseconds. -func (c *memCache) getInternalExpire(duration time.Duration) int64 { +func (c *adapterMemory) getInternalExpire(duration time.Duration) int64 { if duration == 0 { return gDEFAULT_MAX_EXPIRE } else { @@ -195,12 +194,12 @@ func (c *memCache) getInternalExpire(duration time.Duration) int64 { } // makeExpireKey groups the in milliseconds to its according seconds. -func (c *memCache) makeExpireKey(expire int64) int64 { +func (c *adapterMemory) makeExpireKey(expire int64) int64 { return int64(math.Ceil(float64(expire/1000)+1) * 1000) } // getExpireSet returns the expire set for given in seconds. -func (c *memCache) getExpireSet(expire int64) (expireSet *gset.Set) { +func (c *adapterMemory) getExpireSet(expire int64) (expireSet *gset.Set) { c.expireSetMu.RLock() expireSet, _ = c.expireSets[expire] c.expireSetMu.RUnlock() @@ -209,7 +208,7 @@ func (c *memCache) getExpireSet(expire int64) (expireSet *gset.Set) { // getOrNewExpireSet returns the expire set for given in seconds. // It creates and returns a new set for if it does not exist. -func (c *memCache) getOrNewExpireSet(expire int64) (expireSet *gset.Set) { +func (c *adapterMemory) getOrNewExpireSet(expire int64) (expireSet *gset.Set) { if expireSet = c.getExpireSet(expire); expireSet == nil { expireSet = gset.New(true) c.expireSetMu.Lock() @@ -225,7 +224,7 @@ func (c *memCache) getOrNewExpireSet(expire int64) (expireSet *gset.Set) { // SetIfNotExist sets cache with - pair if does not exist in the cache, // which is expired after . It does not expire if == 0. -func (c *memCache) SetIfNotExist(key interface{}, value interface{}, duration time.Duration) bool { +func (c *adapterMemory) SetIfNotExist(key interface{}, value interface{}, duration time.Duration) bool { if !c.Contains(key) { c.doSetWithLockCheck(key, value, duration) return true @@ -236,25 +235,26 @@ func (c *memCache) SetIfNotExist(key interface{}, value interface{}, duration ti // Sets batch sets cache with key-value pairs by , which is expired after . // // It does not expire if == 0. -func (c *memCache) Sets(data map[interface{}]interface{}, duration time.Duration) { +// It deletes the keys of if < 0 or given is nil. +func (c *adapterMemory) Sets(data map[interface{}]interface{}, duration time.Duration) { expireTime := c.getInternalExpire(duration) for k, v := range data { c.dataMu.Lock() - c.data[k] = memCacheItem{ + c.data[k] = adapterMemoryItem{ v: v, e: expireTime, } c.dataMu.Unlock() - c.eventList.PushBack(&memCacheEvent{ + c.eventList.PushBack(&adapterMemoryEvent{ k: k, e: expireTime, }) } } -// Get returns the value of . +// Get retrieves and returns the associated value of given . // It returns nil if it does not exist or its value is nil. -func (c *memCache) Get(key interface{}) interface{} { +func (c *adapterMemory) Get(key interface{}) interface{} { c.dataMu.RLock() item, ok := c.data[key] c.dataMu.RUnlock() @@ -268,15 +268,14 @@ func (c *memCache) Get(key interface{}) interface{} { return nil } -// GetVar retrieves and returns the value of as gvar.Var. -func (c *memCache) GetVar(key interface{}) *gvar.Var { - return gvar.New(c.Get(key)) -} - -// GetOrSet returns the value of , or sets - pair and returns if -// does not exist in the cache. The key-value pair expires after . It does not expire -// if == 0. -func (c *memCache) GetOrSet(key interface{}, value interface{}, duration time.Duration) interface{} { +// GetOrSet retrieves and returns the value of , or sets - pair and +// returns if does not exist in the cache. The key-value pair expires +// after . +// +// It does not expire if == 0. +// It deletes the if < 0 or given is nil, but it does nothing +// if is a function and the function result is nil. +func (c *adapterMemory) GetOrSet(key interface{}, value interface{}, duration time.Duration) interface{} { if v := c.Get(key); v == nil { return c.doSetWithLockCheck(key, value, duration) } else { @@ -284,13 +283,14 @@ func (c *memCache) GetOrSet(key interface{}, value interface{}, duration time.Du } } -// GetOrSetFunc returns the value of , or sets with result of function -// and returns its result if does not exist in the cache. The key-value pair expires -// after . +// GetOrSetFunc retrieves and returns the value of , or sets with result of +// function and returns its result if does not exist in the cache. The key-value +// pair expires after . // // It does not expire if == 0. -// It does nothing if function returns nil. -func (c *memCache) GetOrSetFunc(key interface{}, f func() interface{}, duration time.Duration) interface{} { +// It deletes the if < 0 or given is nil, but it does nothing +// if is a function and the function result is nil. +func (c *adapterMemory) GetOrSetFunc(key interface{}, f func() interface{}, duration time.Duration) interface{} { if v := c.Get(key); v == nil { value := f() if value == nil { @@ -302,15 +302,16 @@ func (c *memCache) GetOrSetFunc(key interface{}, f func() interface{}, duration } } -// GetOrSetFuncLock returns the value of , or sets with result of function -// and returns its result if does not exist in the cache. The key-value pair expires -// after . +// GetOrSetFuncLock retrieves and returns the value of , or sets with result of +// function and returns its result if does not exist in the cache. The key-value +// pair expires after . // // It does not expire if == 0. // It does nothing if function returns nil. // -// Note that the function is executed within writing mutex lock. -func (c *memCache) GetOrSetFuncLock(key interface{}, f func() interface{}, duration time.Duration) interface{} { +// Note that the function should be executed within writing mutex lock for concurrent +// safety purpose. +func (c *adapterMemory) GetOrSetFuncLock(key interface{}, f func() interface{}, duration time.Duration) interface{} { if v := c.Get(key); v == nil { return c.doSetWithLockCheck(key, f, duration) } else { @@ -319,13 +320,13 @@ func (c *memCache) GetOrSetFuncLock(key interface{}, f func() interface{}, durat } // Contains returns true if exists in the cache, or else returns false. -func (c *memCache) Contains(key interface{}) bool { +func (c *adapterMemory) Contains(key interface{}) bool { return c.Get(key) != nil } // Remove deletes the one or more keys from cache, and returns its value. // If multiple keys are given, it returns the value of the deleted last item. -func (c *memCache) Remove(keys ...interface{}) (value interface{}) { +func (c *adapterMemory) Remove(keys ...interface{}) (value interface{}) { c.dataMu.Lock() defer c.dataMu.Unlock() for _, key := range keys { @@ -333,7 +334,7 @@ func (c *memCache) Remove(keys ...interface{}) (value interface{}) { if ok { value = item.v delete(c.data, key) - c.eventList.PushBack(&memCacheEvent{ + c.eventList.PushBack(&adapterMemoryEvent{ k: key, e: gtime.TimestampMilli() - 1000, }) @@ -342,14 +343,8 @@ func (c *memCache) Remove(keys ...interface{}) (value interface{}) { return } -// Removes deletes in the cache. -// Deprecated, use Remove instead. -func (c *memCache) Removes(keys []interface{}) { - c.Remove(keys...) -} - // Data returns a copy of all key-value pairs in the cache as map type. -func (c *memCache) Data() map[interface{}]interface{} { +func (c *adapterMemory) Data() map[interface{}]interface{} { m := make(map[interface{}]interface{}) c.dataMu.RLock() for k, v := range c.data { @@ -362,7 +357,7 @@ func (c *memCache) Data() map[interface{}]interface{} { } // Keys returns all keys in the cache as slice. -func (c *memCache) Keys() []interface{} { +func (c *adapterMemory) Keys() []interface{} { keys := make([]interface{}, 0) c.dataMu.RLock() for k, v := range c.data { @@ -374,13 +369,8 @@ func (c *memCache) Keys() []interface{} { return keys } -// KeyStrings returns all keys in the cache as string slice. -func (c *memCache) KeyStrings() []string { - return gconv.Strings(c.Keys()) -} - // Values returns all values in the cache as slice. -func (c *memCache) Values() []interface{} { +func (c *adapterMemory) Values() []interface{} { values := make([]interface{}, 0) c.dataMu.RLock() for _, v := range c.data { @@ -393,32 +383,42 @@ func (c *memCache) Values() []interface{} { } // Size returns the size of the cache. -func (c *memCache) Size() (size int) { +func (c *adapterMemory) Size() (size int) { c.dataMu.RLock() size = len(c.data) c.dataMu.RUnlock() return } +// Clear clears all data of the cache. +// Note that this function is sensitive and should be carefully used. +func (c *adapterMemory) Clear() error { + c.dataMu.Lock() + defer c.dataMu.Unlock() + c.data = make(map[interface{}]adapterMemoryItem) + return nil +} + // Close closes the cache. -func (c *memCache) Close() { +func (c *adapterMemory) Close() error { if c.cap > 0 { c.lru.Close() } c.closed.Set(true) + return nil } // syncEventAndClearExpired does the asynchronous task loop: // 1. Asynchronously process the data in the event list, // and synchronize the results to the and properties. // 2. Clean up the expired key-value pair data. -func (c *memCache) syncEventAndClearExpired() { +func (c *adapterMemory) syncEventAndClearExpired() { if c.closed.Val() { gtimer.Exit() return } var ( - event *memCacheEvent + event *adapterMemoryEvent oldExpireTime int64 newExpireTime int64 ) @@ -430,7 +430,7 @@ func (c *memCache) syncEventAndClearExpired() { if v == nil { break } - event = v.(*memCacheEvent) + event = v.(*adapterMemoryEvent) // Fetching the old expire set. c.expireTimeMu.RLock() oldExpireTime = c.expireTimes[event.k] @@ -487,7 +487,7 @@ func (c *memCache) syncEventAndClearExpired() { // clearByKey deletes the key-value pair with given . // The parameter specifies whether doing this deleting forcibly. -func (c *memCache) clearByKey(key interface{}, force ...bool) { +func (c *adapterMemory) clearByKey(key interface{}, force ...bool) { c.dataMu.Lock() // Doubly check before really deleting it from cache. if item, ok := c.data[key]; (ok && item.IsExpired()) || (len(force) > 0 && force[0]) { diff --git a/os/gcache/gcache_mem_cache_item.go b/os/gcache/gcache_adapter_memory_item.go similarity index 91% rename from os/gcache/gcache_mem_cache_item.go rename to os/gcache/gcache_adapter_memory_item.go index a53c673cb..9865a6d92 100644 --- a/os/gcache/gcache_mem_cache_item.go +++ b/os/gcache/gcache_adapter_memory_item.go @@ -11,7 +11,7 @@ import ( ) // IsExpired checks whether is expired. -func (item *memCacheItem) IsExpired() bool { +func (item *adapterMemoryItem) IsExpired() bool { // Note that it should use greater than or equal judgement here // imagining that the cache time is only 1 millisecond. if item.e >= gtime.TimestampMilli() { diff --git a/os/gcache/gcache_mem_cache_lru.go b/os/gcache/gcache_adapter_memory_lru.go similarity index 75% rename from os/gcache/gcache_mem_cache_lru.go rename to os/gcache/gcache_adapter_memory_lru.go index 4b789cfab..b6f6c1b86 100644 --- a/os/gcache/gcache_mem_cache_lru.go +++ b/os/gcache/gcache_adapter_memory_lru.go @@ -17,17 +17,17 @@ import ( // LRU cache object. // It uses list.List from stdlib for its underlying doubly linked list. -type memCacheLru struct { - cache *memCache // Parent cache object. - data *gmap.Map // Key mapping to the item of the list. - list *glist.List // Key list. - rawList *glist.List // History for key adding. - closed *gtype.Bool // Closed or not. +type adapterMemoryLru struct { + cache *adapterMemory // Parent cache object. + data *gmap.Map // Key mapping to the item of the list. + list *glist.List // Key list. + rawList *glist.List // History for key adding. + closed *gtype.Bool // Closed or not. } // newMemCacheLru creates and returns a new LRU object. -func newMemCacheLru(cache *memCache) *memCacheLru { - lru := &memCacheLru{ +func newMemCacheLru(cache *adapterMemory) *adapterMemoryLru { + lru := &adapterMemoryLru{ cache: cache, data: gmap.New(true), list: glist.New(true), @@ -39,12 +39,12 @@ func newMemCacheLru(cache *memCache) *memCacheLru { } // Close closes the LRU object. -func (lru *memCacheLru) Close() { +func (lru *adapterMemoryLru) Close() { lru.closed.Set(true) } // Remove deletes the FROM . -func (lru *memCacheLru) Remove(key interface{}) { +func (lru *adapterMemoryLru) Remove(key interface{}) { if v := lru.data.Get(key); v != nil { lru.data.Remove(key) lru.list.Remove(v.(*glist.Element)) @@ -52,17 +52,17 @@ func (lru *memCacheLru) Remove(key interface{}) { } // Size returns the size of . -func (lru *memCacheLru) Size() int { +func (lru *adapterMemoryLru) Size() int { return lru.data.Size() } // Push pushes to the tail of . -func (lru *memCacheLru) Push(key interface{}) { +func (lru *adapterMemoryLru) Push(key interface{}) { lru.rawList.PushBack(key) } // Pop deletes and returns the key from tail of . -func (lru *memCacheLru) Pop() interface{} { +func (lru *adapterMemoryLru) Pop() interface{} { if v := lru.list.PopBack(); v != nil { lru.data.Remove(v) return v @@ -71,7 +71,7 @@ func (lru *memCacheLru) Pop() interface{} { } // Print is used for test only. -//func (lru *memCacheLru) Print() { +//func (lru *adapterMemoryLru) Print() { // for _, v := range lru.list.FrontAll() { // fmt.Printf("%v ", v) // } @@ -80,7 +80,7 @@ func (lru *memCacheLru) Pop() interface{} { // SyncAndClear synchronizes the keys from to and // using Least Recently Used algorithm. -func (lru *memCacheLru) SyncAndClear() { +func (lru *adapterMemoryLru) SyncAndClear() { if lru.closed.Val() { gtimer.Exit() return diff --git a/os/gcache/gcache_cache.go b/os/gcache/gcache_cache.go index 1de35a314..50fb2ec81 100644 --- a/os/gcache/gcache_cache.go +++ b/os/gcache/gcache_cache.go @@ -7,31 +7,49 @@ package gcache import ( - "sync/atomic" - "time" - "unsafe" - + "github.com/gogf/gf/container/gvar" "github.com/gogf/gf/os/gtimer" + "github.com/gogf/gf/util/gconv" + "time" ) // Cache struct. type Cache struct { - *memCache + Adapter // Adapter for cache features. } -// New creates and returns a new cache object. +// New creates and returns a new cache object using default memory adapter. +// Note that the LRU feature is only available using memory adapter. func New(lruCap ...int) *Cache { + memAdapter := newAdapterMemory(lruCap...) c := &Cache{ - memCache: newMemCache(lruCap...), + Adapter: memAdapter, } - gtimer.AddSingleton(time.Second, c.syncEventAndClearExpired) + // Here may be a "timer leak" if adapter is manually changed from memory adapter. + // Do not worry about this, as adapter is less changed and it dose nothing if it's not used. + gtimer.AddSingleton(time.Second, memAdapter.syncEventAndClearExpired) return c } -// Clear clears all data of the cache. -func (c *Cache) Clear() { - // atomic swap to ensure atomicity. - old := atomic.SwapPointer((*unsafe.Pointer)(unsafe.Pointer(&c.memCache)), unsafe.Pointer(newMemCache())) - // close the old cache object. - (*memCache)(old).Close() +// SetAdapter changes the adapter for this cache. +// Be very note that, this setting function is not concurrent-safe, which means you should not call +// this setting function concurrently in multiple goroutines. +func (c *Cache) SetAdapter(adapter Adapter) { + c.Adapter = adapter +} + +// GetVar retrieves and returns the value of as gvar.Var. +func (c *Cache) GetVar(key interface{}) *gvar.Var { + return gvar.New(c.Get(key)) +} + +// Removes deletes in the cache. +// Deprecated, use Remove instead. +func (c *Cache) Removes(keys []interface{}) { + c.Remove(keys...) +} + +// KeyStrings returns all keys in the cache as string slice. +func (c *Cache) KeyStrings() []string { + return gconv.Strings(c.Keys()) }