mirror of
https://github.com/sigcn/pg.git
synced 2025-09-27 07:32:07 +08:00
65 lines
1.4 KiB
Go
65 lines
1.4 KiB
Go
package cache
|
|
|
|
import (
|
|
"cmp"
|
|
"sync"
|
|
"sync/atomic"
|
|
"time"
|
|
|
|
"github.com/sigcn/pg/cache/lru"
|
|
)
|
|
|
|
type CacheValue[T any] struct {
|
|
updateTime atomic.Pointer[time.Time]
|
|
value atomic.Value
|
|
}
|
|
|
|
func (v *CacheValue[T]) LoadTTL(ttl time.Duration, newValue func() T) T {
|
|
if time.Since(*cmp.Or(v.updateTime.Load(), &time.Time{})) > cmp.Or(ttl, time.Second) {
|
|
v.value.Store(newValue())
|
|
now := time.Now()
|
|
v.updateTime.Store(&now)
|
|
}
|
|
return v.value.Load().(T)
|
|
}
|
|
|
|
func (v *CacheValue[T]) Load(newValue func() T) T {
|
|
return v.LoadTTL(0, newValue)
|
|
}
|
|
|
|
var (
|
|
defaultCache *lru.Cache[string, *CacheValue[any]]
|
|
defaultCacheMutex sync.RWMutex
|
|
)
|
|
|
|
func init() {
|
|
defaultCache = lru.New[string, *CacheValue[any]](2048)
|
|
}
|
|
|
|
// LoadTTL load value by key from default cache pool
|
|
// if value's ttl is expired, will exec {newValue} create a new value
|
|
func LoadTTL[T any](key string, ttl time.Duration, newValue func(key string) T) T {
|
|
defaultCacheMutex.RLock()
|
|
val, ok := defaultCache.Get(key)
|
|
defaultCacheMutex.RUnlock()
|
|
if !ok {
|
|
defaultCacheMutex.Lock()
|
|
val, ok = defaultCache.Get(key)
|
|
if !ok {
|
|
val = &CacheValue[any]{}
|
|
defaultCache.Put(key, val)
|
|
}
|
|
defaultCacheMutex.Unlock()
|
|
}
|
|
ret := val.LoadTTL(ttl, func() any {
|
|
return newValue(key)
|
|
})
|
|
return ret.(T)
|
|
}
|
|
|
|
// Load load value by key from default cache pool
|
|
// uses a default ttl value
|
|
func Load[T any](key string, newValue func(key string) T) T {
|
|
return LoadTTL(key, 0, newValue)
|
|
}
|