mirror of
https://gitee.com/johng/gf
synced 2026-06-06 02:25:47 +08:00
improve package gcache
This commit is contained in:
@ -36,7 +36,7 @@ type Adapter interface {
|
||||
SetIfNotExist(key interface{}, value interface{}, duration time.Duration) (bool, error)
|
||||
|
||||
// Get retrieves and returns the associated value of given <key>.
|
||||
// It returns nil if it does not exist or its value is nil.
|
||||
// It returns nil if it does not exist, its value is nil or it's expired.
|
||||
Get(key interface{}) (interface{}, error)
|
||||
|
||||
// GetOrSet retrieves and returns the value of <key>, or sets <key>-<value> pair and
|
||||
|
||||
@ -8,7 +8,6 @@ package gcache
|
||||
|
||||
import (
|
||||
"math"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/container/glist"
|
||||
@ -20,43 +19,18 @@ import (
|
||||
|
||||
// Internal cache object.
|
||||
type adapterMemory struct {
|
||||
// dataMu ensures the concurrent safety of underlying data map.
|
||||
dataMu sync.RWMutex
|
||||
|
||||
// expireTimeMu ensures the concurrent safety of expireTimes map.
|
||||
expireTimeMu sync.RWMutex
|
||||
|
||||
// expireSetMu ensures the concurrent safety of expireSets map.
|
||||
expireSetMu sync.RWMutex
|
||||
|
||||
// cap limits the size of the cache pool.
|
||||
// If the size of the cache exceeds the cap,
|
||||
// the cache expiration process performs according to the LRU algorithm.
|
||||
// It is 0 in default which means no limits.
|
||||
cap int
|
||||
|
||||
// data is the underlying cache data which is stored in a hash table.
|
||||
data map[interface{}]adapterMemoryItem
|
||||
|
||||
// expireTimes is the expiring key to its timestamp mapping,
|
||||
// which is used for quick indexing and deleting.
|
||||
expireTimes map[interface{}]int64
|
||||
|
||||
// expireSets is the expiring timestamp to its key set mapping,
|
||||
// which is used for quick indexing and deleting.
|
||||
expireSets map[int64]*gset.Set
|
||||
|
||||
// lru is the LRU manager, which is enabled when attribute cap > 0.
|
||||
lru *adapterMemoryLru
|
||||
|
||||
// lruGetList is the LRU history according with Get function.
|
||||
lruGetList *glist.List
|
||||
|
||||
// eventList is the asynchronous event list for internal data synchronization.
|
||||
eventList *glist.List
|
||||
|
||||
// closed controls the cache closed or not.
|
||||
closed *gtype.Bool
|
||||
cap int
|
||||
data *adapterMemoryData // data is the underlying cache data which is stored in a hash table.
|
||||
expireTimes *adapterMemoryExpireTimes // expireTimes is the expiring key to its timestamp mapping, which is used for quick indexing and deleting.
|
||||
expireSets *adapterMemoryExpireSets // expireSets is the expiring timestamp to its key set mapping, which is used for quick indexing and deleting.
|
||||
lru *adapterMemoryLru // lru is the LRU manager, which is enabled when attribute cap > 0.
|
||||
lruGetList *glist.List // lruGetList is the LRU history according with Get function.
|
||||
eventList *glist.List // eventList is the asynchronous event list for internal data synchronization.
|
||||
closed *gtype.Bool // closed controls the cache closed or not.
|
||||
}
|
||||
|
||||
// Internal cache item.
|
||||
@ -72,18 +46,18 @@ type adapterMemoryEvent struct {
|
||||
}
|
||||
|
||||
const (
|
||||
// gDEFAULT_MAX_EXPIRE is the default expire time for no expiring items.
|
||||
// defaultMaxExpire is the default expire time for no expiring items.
|
||||
// It equals to math.MaxInt64/1000000.
|
||||
gDEFAULT_MAX_EXPIRE = 9223372036854
|
||||
defaultMaxExpire = 9223372036854
|
||||
)
|
||||
|
||||
// newAdapterMemory creates and returns a new memory cache object.
|
||||
func newAdapterMemory(lruCap ...int) *adapterMemory {
|
||||
c := &adapterMemory{
|
||||
data: newAdapterMemoryData(),
|
||||
lruGetList: glist.New(true),
|
||||
data: make(map[interface{}]adapterMemoryItem),
|
||||
expireTimes: make(map[interface{}]int64),
|
||||
expireSets: make(map[int64]*gset.Set),
|
||||
expireTimes: newAdapterMemoryExpireTimes(),
|
||||
expireSets: newAdapterMemoryExpireSets(),
|
||||
eventList: glist.New(true),
|
||||
closed: gtype.NewBool(),
|
||||
}
|
||||
@ -100,12 +74,10 @@ func newAdapterMemory(lruCap ...int) *adapterMemory {
|
||||
// It deletes the <key> if <duration> < 0.
|
||||
func (c *adapterMemory) Set(key interface{}, value interface{}, duration time.Duration) error {
|
||||
expireTime := c.getInternalExpire(duration)
|
||||
c.dataMu.Lock()
|
||||
c.data[key] = adapterMemoryItem{
|
||||
c.data.Set(key, adapterMemoryItem{
|
||||
v: value,
|
||||
e: expireTime,
|
||||
}
|
||||
c.dataMu.Unlock()
|
||||
})
|
||||
c.eventList.PushBack(&adapterMemoryEvent{
|
||||
k: key,
|
||||
e: expireTime,
|
||||
@ -119,16 +91,7 @@ func (c *adapterMemory) Set(key interface{}, value interface{}, duration time.Du
|
||||
// It deletes the <key> if given <value> is nil.
|
||||
// It does nothing if <key> does not exist in the cache.
|
||||
func (c *adapterMemory) Update(key interface{}, value interface{}) (oldValue interface{}, exist bool, err error) {
|
||||
c.dataMu.Lock()
|
||||
defer c.dataMu.Unlock()
|
||||
if item, ok := c.data[key]; ok {
|
||||
c.data[key] = adapterMemoryItem{
|
||||
v: value,
|
||||
e: item.e,
|
||||
}
|
||||
return item.v, true, nil
|
||||
}
|
||||
return nil, false, nil
|
||||
return c.data.Update(key, value)
|
||||
}
|
||||
|
||||
// UpdateExpire updates the expiration of <key> and returns the old expiration duration value.
|
||||
@ -137,20 +100,17 @@ func (c *adapterMemory) Update(key interface{}, value interface{}) (oldValue int
|
||||
// It deletes the <key> if <duration> < 0.
|
||||
func (c *adapterMemory) UpdateExpire(key interface{}, duration time.Duration) (oldDuration time.Duration, err error) {
|
||||
newExpireTime := c.getInternalExpire(duration)
|
||||
c.dataMu.Lock()
|
||||
defer c.dataMu.Unlock()
|
||||
if item, ok := c.data[key]; ok {
|
||||
c.data[key] = adapterMemoryItem{
|
||||
v: item.v,
|
||||
e: newExpireTime,
|
||||
}
|
||||
oldDuration, err = c.data.UpdateExpire(key, newExpireTime)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if oldDuration != -1 {
|
||||
c.eventList.PushBack(&adapterMemoryEvent{
|
||||
k: key,
|
||||
e: newExpireTime,
|
||||
})
|
||||
return time.Duration(item.e-gtime.TimestampMilli()) * time.Millisecond, nil
|
||||
}
|
||||
return -1, nil
|
||||
return
|
||||
}
|
||||
|
||||
// GetExpire retrieves and returns the expiration of <key> in the cache.
|
||||
@ -158,9 +118,7 @@ func (c *adapterMemory) UpdateExpire(key interface{}, duration time.Duration) (o
|
||||
// It returns 0 if the <key> does not expire.
|
||||
// It returns -1 if the <key> does not exist in the cache.
|
||||
func (c *adapterMemory) GetExpire(key interface{}) (time.Duration, error) {
|
||||
c.dataMu.RLock()
|
||||
defer c.dataMu.RUnlock()
|
||||
if item, ok := c.data[key]; ok {
|
||||
if item, ok := c.data.Get(key); ok {
|
||||
return time.Duration(item.e-gtime.TimestampMilli()) * time.Millisecond, nil
|
||||
}
|
||||
return -1, nil
|
||||
@ -194,14 +152,14 @@ func (c *adapterMemory) SetIfNotExist(key interface{}, value interface{}, durati
|
||||
// It does not expire if <duration> == 0.
|
||||
// It deletes the keys of <data> if <duration> < 0 or given <value> is nil.
|
||||
func (c *adapterMemory) Sets(data map[interface{}]interface{}, duration time.Duration) error {
|
||||
expireTime := c.getInternalExpire(duration)
|
||||
for k, v := range data {
|
||||
c.dataMu.Lock()
|
||||
c.data[k] = adapterMemoryItem{
|
||||
v: v,
|
||||
e: expireTime,
|
||||
}
|
||||
c.dataMu.Unlock()
|
||||
var (
|
||||
expireTime = c.getInternalExpire(duration)
|
||||
err = c.data.Sets(data, expireTime)
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for k, _ := range data {
|
||||
c.eventList.PushBack(&adapterMemoryEvent{
|
||||
k: k,
|
||||
e: expireTime,
|
||||
@ -213,9 +171,7 @@ func (c *adapterMemory) Sets(data map[interface{}]interface{}, duration time.Dur
|
||||
// Get retrieves and returns the associated value of given <key>.
|
||||
// It returns nil if it does not exist or its value is nil.
|
||||
func (c *adapterMemory) Get(key interface{}) (interface{}, error) {
|
||||
c.dataMu.RLock()
|
||||
item, ok := c.data[key]
|
||||
c.dataMu.RUnlock()
|
||||
item, ok := c.data.Get(key)
|
||||
if ok && !item.IsExpired() {
|
||||
// Adding to LRU history if LRU feature is enabled.
|
||||
if c.cap > 0 {
|
||||
@ -304,76 +260,44 @@ func (c *adapterMemory) Contains(key interface{}) (bool, error) {
|
||||
// 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 *adapterMemory) Remove(keys ...interface{}) (value interface{}, err error) {
|
||||
c.dataMu.Lock()
|
||||
defer c.dataMu.Unlock()
|
||||
for _, key := range keys {
|
||||
item, ok := c.data[key]
|
||||
if ok {
|
||||
value = item.v
|
||||
delete(c.data, key)
|
||||
c.eventList.PushBack(&adapterMemoryEvent{
|
||||
k: key,
|
||||
e: gtime.TimestampMilli() - 1000,
|
||||
})
|
||||
}
|
||||
var removedKeys []interface{}
|
||||
removedKeys, value, err = c.data.Remove(keys...)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return value, nil
|
||||
for _, key := range removedKeys {
|
||||
c.eventList.PushBack(&adapterMemoryEvent{
|
||||
k: key,
|
||||
e: gtime.TimestampMilli() - 1000000,
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Data returns a copy of all key-value pairs in the cache as map type.
|
||||
func (c *adapterMemory) Data() (map[interface{}]interface{}, error) {
|
||||
m := make(map[interface{}]interface{})
|
||||
c.dataMu.RLock()
|
||||
for k, v := range c.data {
|
||||
if !v.IsExpired() {
|
||||
m[k] = v.v
|
||||
}
|
||||
}
|
||||
c.dataMu.RUnlock()
|
||||
return m, nil
|
||||
return c.data.Data()
|
||||
}
|
||||
|
||||
// Keys returns all keys in the cache as slice.
|
||||
func (c *adapterMemory) Keys() ([]interface{}, error) {
|
||||
keys := make([]interface{}, 0)
|
||||
c.dataMu.RLock()
|
||||
for k, v := range c.data {
|
||||
if !v.IsExpired() {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
}
|
||||
c.dataMu.RUnlock()
|
||||
return keys, nil
|
||||
return c.data.Keys()
|
||||
}
|
||||
|
||||
// Values returns all values in the cache as slice.
|
||||
func (c *adapterMemory) Values() ([]interface{}, error) {
|
||||
values := make([]interface{}, 0)
|
||||
c.dataMu.RLock()
|
||||
for _, v := range c.data {
|
||||
if !v.IsExpired() {
|
||||
values = append(values, v.v)
|
||||
}
|
||||
}
|
||||
c.dataMu.RUnlock()
|
||||
return values, nil
|
||||
return c.data.Values()
|
||||
}
|
||||
|
||||
// Size returns the size of the cache.
|
||||
func (c *adapterMemory) Size() (size int, err error) {
|
||||
c.dataMu.RLock()
|
||||
size = len(c.data)
|
||||
c.dataMu.RUnlock()
|
||||
return size, nil
|
||||
return c.data.Size()
|
||||
}
|
||||
|
||||
// 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
|
||||
return c.data.Clear()
|
||||
}
|
||||
|
||||
// Close closes the cache.
|
||||
@ -394,33 +318,17 @@ func (c *adapterMemory) Close() error {
|
||||
//
|
||||
// It doubly checks the <key> whether exists in the cache using mutex writing lock
|
||||
// before setting it to the cache.
|
||||
func (c *adapterMemory) doSetWithLockCheck(key interface{}, value interface{}, duration time.Duration) (interface{}, error) {
|
||||
func (c *adapterMemory) doSetWithLockCheck(key interface{}, value interface{}, duration time.Duration) (result interface{}, err error) {
|
||||
expireTimestamp := c.getInternalExpire(duration)
|
||||
c.dataMu.Lock()
|
||||
defer c.dataMu.Unlock()
|
||||
if v, ok := c.data[key]; ok && !v.IsExpired() {
|
||||
return v.v, nil
|
||||
}
|
||||
if f, ok := value.(func() (interface{}, error)); ok {
|
||||
v, err := f()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if v == nil {
|
||||
return nil, nil
|
||||
} else {
|
||||
value = v
|
||||
}
|
||||
}
|
||||
c.data[key] = adapterMemoryItem{v: value, e: expireTimestamp}
|
||||
result, err = c.data.SetWithLock(key, value, expireTimestamp)
|
||||
c.eventList.PushBack(&adapterMemoryEvent{k: key, e: expireTimestamp})
|
||||
return value, nil
|
||||
return
|
||||
}
|
||||
|
||||
// getInternalExpire converts and returns the expire time with given expired duration in milliseconds.
|
||||
func (c *adapterMemory) getInternalExpire(duration time.Duration) int64 {
|
||||
if duration == 0 {
|
||||
return gDEFAULT_MAX_EXPIRE
|
||||
return defaultMaxExpire
|
||||
} else {
|
||||
return gtime.TimestampMilli() + duration.Nanoseconds()/1000000
|
||||
}
|
||||
@ -431,30 +339,6 @@ func (c *adapterMemory) makeExpireKey(expire int64) int64 {
|
||||
return int64(math.Ceil(float64(expire/1000)+1) * 1000)
|
||||
}
|
||||
|
||||
// getExpireSet returns the expire set for given <expire> in seconds.
|
||||
func (c *adapterMemory) getExpireSet(expire int64) (expireSet *gset.Set) {
|
||||
c.expireSetMu.RLock()
|
||||
expireSet, _ = c.expireSets[expire]
|
||||
c.expireSetMu.RUnlock()
|
||||
return
|
||||
}
|
||||
|
||||
// getOrNewExpireSet returns the expire set for given <expire> in seconds.
|
||||
// It creates and returns a new set for <expire> if it does not exist.
|
||||
func (c *adapterMemory) getOrNewExpireSet(expire int64) (expireSet *gset.Set) {
|
||||
if expireSet = c.getExpireSet(expire); expireSet == nil {
|
||||
expireSet = gset.New(true)
|
||||
c.expireSetMu.Lock()
|
||||
if es, ok := c.expireSets[expire]; ok {
|
||||
expireSet = es
|
||||
} else {
|
||||
c.expireSets[expire] = expireSet
|
||||
}
|
||||
c.expireSetMu.Unlock()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// syncEventAndClearExpired does the asynchronous task loop:
|
||||
// 1. Asynchronously process the data in the event list,
|
||||
// and synchronize the results to the <expireTimes> and <expireSets> properties.
|
||||
@ -479,20 +363,16 @@ func (c *adapterMemory) syncEventAndClearExpired() {
|
||||
}
|
||||
event = v.(*adapterMemoryEvent)
|
||||
// Fetching the old expire set.
|
||||
c.expireTimeMu.RLock()
|
||||
oldExpireTime = c.expireTimes[event.k]
|
||||
c.expireTimeMu.RUnlock()
|
||||
oldExpireTime = c.expireTimes.Get(event.k)
|
||||
// Calculating the new expire set.
|
||||
newExpireTime = c.makeExpireKey(event.e)
|
||||
if newExpireTime != oldExpireTime {
|
||||
c.getOrNewExpireSet(newExpireTime).Add(event.k)
|
||||
c.expireSets.GetOrNew(newExpireTime).Add(event.k)
|
||||
if oldExpireTime != 0 {
|
||||
c.getOrNewExpireSet(oldExpireTime).Remove(event.k)
|
||||
c.expireSets.GetOrNew(oldExpireTime).Remove(event.k)
|
||||
}
|
||||
// Updating the expire time for <event.k>.
|
||||
c.expireTimeMu.Lock()
|
||||
c.expireTimes[event.k] = newExpireTime
|
||||
c.expireTimeMu.Unlock()
|
||||
c.expireTimes.Set(event.k, newExpireTime)
|
||||
}
|
||||
// Adding the key the LRU history by writing operations.
|
||||
if c.cap > 0 {
|
||||
@ -518,16 +398,14 @@ func (c *adapterMemory) syncEventAndClearExpired() {
|
||||
eks = []int64{ek - 1000, ek - 2000, ek - 3000, ek - 4000, ek - 5000}
|
||||
)
|
||||
for _, expireTime := range eks {
|
||||
if expireSet = c.getExpireSet(expireTime); expireSet != nil {
|
||||
if expireSet = c.expireSets.Get(expireTime); expireSet != nil {
|
||||
// Iterating the set to delete all keys in it.
|
||||
expireSet.Iterator(func(key interface{}) bool {
|
||||
c.clearByKey(key)
|
||||
return true
|
||||
})
|
||||
// Deleting the set after all of its keys are deleted.
|
||||
c.expireSetMu.Lock()
|
||||
delete(c.expireSets, expireTime)
|
||||
c.expireSetMu.Unlock()
|
||||
c.expireSets.Delete(expireTime)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -535,17 +413,11 @@ func (c *adapterMemory) syncEventAndClearExpired() {
|
||||
// clearByKey deletes the key-value pair with given <key>.
|
||||
// The parameter <force> specifies whether doing this deleting forcibly.
|
||||
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]) {
|
||||
delete(c.data, key)
|
||||
}
|
||||
c.dataMu.Unlock()
|
||||
c.data.DeleteWithDoubleCheck(key, force...)
|
||||
|
||||
// Deleting its expire time from <expireTimes>.
|
||||
c.expireTimeMu.Lock()
|
||||
delete(c.expireTimes, key)
|
||||
c.expireTimeMu.Unlock()
|
||||
c.expireTimes.Delete(key)
|
||||
|
||||
// Deleting it from LRU.
|
||||
if c.cap > 0 {
|
||||
|
||||
199
os/gcache/gcache_adapter_memory_data.go
Normal file
199
os/gcache/gcache_adapter_memory_data.go
Normal file
@ -0,0 +1,199 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). 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 (
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type adapterMemoryData struct {
|
||||
mu sync.RWMutex // dataMu ensures the concurrent safety of underlying data map.
|
||||
data map[interface{}]adapterMemoryItem // data is the underlying cache data which is stored in a hash table.
|
||||
}
|
||||
|
||||
func newAdapterMemoryData() *adapterMemoryData {
|
||||
return &adapterMemoryData{
|
||||
data: make(map[interface{}]adapterMemoryItem),
|
||||
}
|
||||
}
|
||||
|
||||
// Update updates the value of <key> without changing its expiration and returns the old value.
|
||||
// The returned value <exist> is false if the <key> does not exist in the cache.
|
||||
//
|
||||
// It deletes the <key> if given <value> is nil.
|
||||
// It does nothing if <key> does not exist in the cache.
|
||||
func (d *adapterMemoryData) Update(key interface{}, value interface{}) (oldValue interface{}, exist bool, err error) {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
if item, ok := d.data[key]; ok {
|
||||
d.data[key] = adapterMemoryItem{
|
||||
v: value,
|
||||
e: item.e,
|
||||
}
|
||||
return item.v, true, nil
|
||||
}
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
// UpdateExpire updates the expiration of <key> and returns the old expiration duration value.
|
||||
//
|
||||
// It returns -1 and does nothing if the <key> does not exist in the cache.
|
||||
// It deletes the <key> if <duration> < 0.
|
||||
func (d *adapterMemoryData) UpdateExpire(key interface{}, expireTime int64) (oldDuration time.Duration, err error) {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
if item, ok := d.data[key]; ok {
|
||||
d.data[key] = adapterMemoryItem{
|
||||
v: item.v,
|
||||
e: expireTime,
|
||||
}
|
||||
return time.Duration(item.e-gtime.TimestampMilli()) * time.Millisecond, nil
|
||||
}
|
||||
return -1, 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 (d *adapterMemoryData) Remove(keys ...interface{}) (removedKeys []interface{}, value interface{}, err error) {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
removedKeys = make([]interface{}, 0)
|
||||
for _, key := range keys {
|
||||
item, ok := d.data[key]
|
||||
if ok {
|
||||
value = item.v
|
||||
delete(d.data, key)
|
||||
removedKeys = append(removedKeys, key)
|
||||
}
|
||||
}
|
||||
return removedKeys, value, nil
|
||||
}
|
||||
|
||||
// Data returns a copy of all key-value pairs in the cache as map type.
|
||||
func (d *adapterMemoryData) Data() (map[interface{}]interface{}, error) {
|
||||
d.mu.RLock()
|
||||
m := make(map[interface{}]interface{}, len(d.data))
|
||||
for k, v := range d.data {
|
||||
if !v.IsExpired() {
|
||||
m[k] = v.v
|
||||
}
|
||||
}
|
||||
d.mu.RUnlock()
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// Keys returns all keys in the cache as slice.
|
||||
func (d *adapterMemoryData) Keys() ([]interface{}, error) {
|
||||
d.mu.RLock()
|
||||
var (
|
||||
index = 0
|
||||
keys = make([]interface{}, len(d.data))
|
||||
)
|
||||
for k, v := range d.data {
|
||||
if !v.IsExpired() {
|
||||
keys[index] = k
|
||||
index++
|
||||
}
|
||||
}
|
||||
d.mu.RUnlock()
|
||||
return keys, nil
|
||||
}
|
||||
|
||||
// Values returns all values in the cache as slice.
|
||||
func (d *adapterMemoryData) Values() ([]interface{}, error) {
|
||||
d.mu.RLock()
|
||||
var (
|
||||
index = 0
|
||||
values = make([]interface{}, len(d.data))
|
||||
)
|
||||
for _, v := range d.data {
|
||||
if !v.IsExpired() {
|
||||
values[index] = v.v
|
||||
index++
|
||||
}
|
||||
}
|
||||
d.mu.RUnlock()
|
||||
return values, nil
|
||||
}
|
||||
|
||||
// Size returns the size of the cache.
|
||||
func (d *adapterMemoryData) Size() (size int, err error) {
|
||||
d.mu.RLock()
|
||||
size = len(d.data)
|
||||
d.mu.RUnlock()
|
||||
return size, nil
|
||||
}
|
||||
|
||||
// Clear clears all data of the cache.
|
||||
// Note that this function is sensitive and should be carefully used.
|
||||
func (d *adapterMemoryData) Clear() error {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
d.data = make(map[interface{}]adapterMemoryItem)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *adapterMemoryData) Get(key interface{}) (item adapterMemoryItem, ok bool) {
|
||||
d.mu.RLock()
|
||||
item, ok = d.data[key]
|
||||
d.mu.RUnlock()
|
||||
return
|
||||
}
|
||||
|
||||
func (d *adapterMemoryData) Set(key interface{}, value adapterMemoryItem) {
|
||||
d.mu.Lock()
|
||||
d.data[key] = value
|
||||
d.mu.Unlock()
|
||||
}
|
||||
|
||||
// Sets batch sets cache with key-value pairs by <data>, which is expired after <duration>.
|
||||
//
|
||||
// It does not expire if <duration> == 0.
|
||||
// It deletes the keys of <data> if <duration> < 0 or given <value> is nil.
|
||||
func (d *adapterMemoryData) Sets(data map[interface{}]interface{}, expireTime int64) error {
|
||||
d.mu.Lock()
|
||||
for k, v := range data {
|
||||
d.data[k] = adapterMemoryItem{
|
||||
v: v,
|
||||
e: expireTime,
|
||||
}
|
||||
}
|
||||
d.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *adapterMemoryData) SetWithLock(key interface{}, value interface{}, expireTimestamp int64) (interface{}, error) {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
if v, ok := d.data[key]; ok && !v.IsExpired() {
|
||||
return v.v, nil
|
||||
}
|
||||
if f, ok := value.(func() (interface{}, error)); ok {
|
||||
v, err := f()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if v == nil {
|
||||
return nil, nil
|
||||
} else {
|
||||
value = v
|
||||
}
|
||||
}
|
||||
d.data[key] = adapterMemoryItem{v: value, e: expireTimestamp}
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (d *adapterMemoryData) DeleteWithDoubleCheck(key interface{}, force ...bool) {
|
||||
d.mu.Lock()
|
||||
// Doubly check before really deleting it from cache.
|
||||
if item, ok := d.data[key]; (ok && item.IsExpired()) || (len(force) > 0 && force[0]) {
|
||||
delete(d.data, key)
|
||||
}
|
||||
d.mu.Unlock()
|
||||
}
|
||||
51
os/gcache/gcache_adapter_memory_expire_sets.go
Normal file
51
os/gcache/gcache_adapter_memory_expire_sets.go
Normal file
@ -0,0 +1,51 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). 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 (
|
||||
"github.com/gogf/gf/container/gset"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type adapterMemoryExpireSets struct {
|
||||
mu sync.RWMutex // expireSetMu ensures the concurrent safety of expireSets map.
|
||||
expireSets map[int64]*gset.Set // expireSets is the expiring timestamp to its key set mapping, which is used for quick indexing and deleting.
|
||||
}
|
||||
|
||||
func newAdapterMemoryExpireSets() *adapterMemoryExpireSets {
|
||||
return &adapterMemoryExpireSets{
|
||||
expireSets: make(map[int64]*gset.Set),
|
||||
}
|
||||
}
|
||||
|
||||
func (d *adapterMemoryExpireSets) Get(key int64) (result *gset.Set) {
|
||||
d.mu.RLock()
|
||||
result = d.expireSets[key]
|
||||
d.mu.RUnlock()
|
||||
return
|
||||
}
|
||||
|
||||
func (d *adapterMemoryExpireSets) GetOrNew(key int64) (result *gset.Set) {
|
||||
if result = d.Get(key); result != nil {
|
||||
return
|
||||
}
|
||||
d.mu.Lock()
|
||||
if es, ok := d.expireSets[key]; ok {
|
||||
result = es
|
||||
} else {
|
||||
result = gset.New(true)
|
||||
d.expireSets[key] = result
|
||||
}
|
||||
d.mu.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
func (d *adapterMemoryExpireSets) Delete(key int64) {
|
||||
d.mu.Lock()
|
||||
delete(d.expireSets, key)
|
||||
d.mu.Unlock()
|
||||
}
|
||||
41
os/gcache/gcache_adapter_memory_expire_times.go
Normal file
41
os/gcache/gcache_adapter_memory_expire_times.go
Normal file
@ -0,0 +1,41 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). 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 (
|
||||
"sync"
|
||||
)
|
||||
|
||||
type adapterMemoryExpireTimes struct {
|
||||
mu sync.RWMutex // expireTimeMu ensures the concurrent safety of expireTimes map.
|
||||
expireTimes map[interface{}]int64 // expireTimes is the expiring key to its timestamp mapping, which is used for quick indexing and deleting.
|
||||
}
|
||||
|
||||
func newAdapterMemoryExpireTimes() *adapterMemoryExpireTimes {
|
||||
return &adapterMemoryExpireTimes{
|
||||
expireTimes: make(map[interface{}]int64),
|
||||
}
|
||||
}
|
||||
|
||||
func (d *adapterMemoryExpireTimes) Get(key interface{}) (value int64) {
|
||||
d.mu.RLock()
|
||||
value = d.expireTimes[key]
|
||||
d.mu.RUnlock()
|
||||
return
|
||||
}
|
||||
|
||||
func (d *adapterMemoryExpireTimes) Set(key interface{}, value int64) {
|
||||
d.mu.Lock()
|
||||
d.expireTimes[key] = value
|
||||
d.mu.Unlock()
|
||||
}
|
||||
|
||||
func (d *adapterMemoryExpireTimes) Delete(key interface{}) {
|
||||
d.mu.Lock()
|
||||
delete(d.expireTimes, key)
|
||||
d.mu.Unlock()
|
||||
}
|
||||
Reference in New Issue
Block a user