2022-09-19 09:39:00 +00:00
|
|
|
package cache
|
|
|
|
|
|
|
|
import (
|
2022-09-20 04:00:09 +00:00
|
|
|
"context"
|
2023-11-29 10:24:41 +00:00
|
|
|
"github.com/fthvgb1/wp-go/helper"
|
2023-01-18 15:02:59 +00:00
|
|
|
"github.com/fthvgb1/wp-go/safety"
|
2022-09-19 09:39:00 +00:00
|
|
|
"sync"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
2023-01-20 10:10:13 +00:00
|
|
|
type VarCache[T any] struct {
|
2023-11-02 14:40:13 +00:00
|
|
|
AnyCache[T]
|
2023-11-29 10:24:41 +00:00
|
|
|
setCacheFunc func(context.Context, ...any) (T, error)
|
|
|
|
mutex sync.Mutex
|
|
|
|
increaseUpdate IncreaseUpdateVar[T]
|
|
|
|
refresh RefreshVar[T]
|
2022-10-14 09:15:43 +00:00
|
|
|
}
|
|
|
|
|
2023-11-29 10:24:41 +00:00
|
|
|
type IncreaseUpdateVar[T any] struct {
|
|
|
|
CycleTime func() time.Duration
|
|
|
|
Fn IncreaseVarFn[T]
|
|
|
|
}
|
|
|
|
|
|
|
|
type IncreaseVarFn[T any] func(c context.Context, currentData T, t time.Time, a ...any) (data T, save bool, refresh bool, err error)
|
|
|
|
|
2023-11-02 14:40:13 +00:00
|
|
|
func (t *VarCache[T]) GetCache(ctx context.Context, timeout time.Duration, params ...any) (T, error) {
|
|
|
|
data, ok := t.Get(ctx)
|
2023-11-29 10:24:41 +00:00
|
|
|
var err error
|
2023-11-02 14:40:13 +00:00
|
|
|
if ok {
|
2023-11-29 10:24:41 +00:00
|
|
|
if t.increaseUpdate.Fn != nil && t.refresh != nil {
|
|
|
|
nowTime := time.Now()
|
|
|
|
if t.increaseUpdate.CycleTime() > nowTime.Sub(t.GetLastSetTime(ctx)) {
|
|
|
|
return data, nil
|
|
|
|
}
|
|
|
|
fn := func() {
|
|
|
|
t.mutex.Lock()
|
|
|
|
defer t.mutex.Unlock()
|
|
|
|
da, save, refresh, er := t.increaseUpdate.Fn(ctx, data, t.GetLastSetTime(ctx), params...)
|
|
|
|
if er != nil {
|
|
|
|
err = er
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if save {
|
|
|
|
t.Set(ctx, da)
|
|
|
|
}
|
|
|
|
if refresh {
|
|
|
|
t.refresh.Refresh(ctx, params...)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if timeout > 0 {
|
|
|
|
er := helper.RunFnWithTimeout(ctx, timeout, fn, "increaseUpdate cache fail")
|
|
|
|
if err == nil && er != nil {
|
|
|
|
err = er
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
fn()
|
|
|
|
}
|
|
|
|
}
|
2023-11-02 14:40:13 +00:00
|
|
|
return data, nil
|
|
|
|
}
|
|
|
|
call := func() {
|
|
|
|
t.mutex.Lock()
|
|
|
|
defer t.mutex.Unlock()
|
|
|
|
dat, ok := t.Get(ctx)
|
|
|
|
if ok {
|
|
|
|
data = dat
|
|
|
|
return
|
|
|
|
}
|
|
|
|
r, er := t.setCacheFunc(ctx, params...)
|
|
|
|
if er != nil {
|
|
|
|
err = er
|
|
|
|
return
|
|
|
|
}
|
|
|
|
t.Set(ctx, r)
|
|
|
|
data = r
|
|
|
|
}
|
|
|
|
if timeout > 0 {
|
2023-11-29 10:24:41 +00:00
|
|
|
er := helper.RunFnWithTimeout(ctx, timeout, call, "get cache fail")
|
|
|
|
if err == nil && er != nil {
|
|
|
|
err = er
|
2023-11-02 14:40:13 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
call()
|
|
|
|
}
|
|
|
|
return data, err
|
2022-09-19 09:39:00 +00:00
|
|
|
}
|
|
|
|
|
2023-11-02 14:40:13 +00:00
|
|
|
type VarMemoryCache[T any] struct {
|
|
|
|
v *safety.Var[vars[T]]
|
|
|
|
expireTime func() time.Duration
|
2022-10-07 12:37:42 +00:00
|
|
|
}
|
|
|
|
|
2023-11-02 14:40:13 +00:00
|
|
|
func (c *VarMemoryCache[T]) ClearExpired(ctx context.Context) {
|
|
|
|
c.Flush(ctx)
|
2022-09-19 09:39:00 +00:00
|
|
|
}
|
|
|
|
|
2023-11-02 14:40:13 +00:00
|
|
|
func NewVarMemoryCache[T any](expireTime func() time.Duration) *VarMemoryCache[T] {
|
|
|
|
return &VarMemoryCache[T]{v: safety.NewVar(vars[T]{}), expireTime: expireTime}
|
2023-01-20 10:10:13 +00:00
|
|
|
}
|
|
|
|
|
2023-11-02 14:40:13 +00:00
|
|
|
func (c *VarMemoryCache[T]) Get(_ context.Context) (T, bool) {
|
2023-01-20 10:43:11 +00:00
|
|
|
v := c.v.Load()
|
2023-11-02 14:40:13 +00:00
|
|
|
return v.data, c.expireTime() >= time.Now().Sub(v.setTime)
|
2022-09-19 14:02:34 +00:00
|
|
|
}
|
|
|
|
|
2023-11-02 14:40:13 +00:00
|
|
|
func (c *VarMemoryCache[T]) Set(_ context.Context, v T) {
|
|
|
|
vv := c.v.Load()
|
|
|
|
vv.data = v
|
|
|
|
vv.setTime = time.Now()
|
|
|
|
vv.incr++
|
|
|
|
c.v.Store(vv)
|
|
|
|
}
|
2022-09-20 04:00:09 +00:00
|
|
|
|
2023-11-02 14:40:13 +00:00
|
|
|
func (c *VarMemoryCache[T]) SetExpiredTime(f func() time.Duration) {
|
|
|
|
c.expireTime = f
|
|
|
|
}
|
|
|
|
|
|
|
|
type vars[T any] struct {
|
|
|
|
data T
|
|
|
|
setTime time.Time
|
|
|
|
incr int
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *VarMemoryCache[T]) GetLastSetTime(_ context.Context) time.Time {
|
|
|
|
return c.v.Load().setTime
|
|
|
|
}
|
2022-09-20 08:11:20 +00:00
|
|
|
|
2023-11-29 10:24:41 +00:00
|
|
|
func NewVarCache[T any](cache AnyCache[T], fn func(context.Context, ...any) (T, error), inc IncreaseUpdateVar[T], ref RefreshVar[T]) *VarCache[T] {
|
2023-11-02 14:40:13 +00:00
|
|
|
return &VarCache[T]{
|
|
|
|
AnyCache: cache, setCacheFunc: fn, mutex: sync.Mutex{},
|
2023-11-29 10:24:41 +00:00
|
|
|
increaseUpdate: inc,
|
|
|
|
refresh: ref,
|
2022-09-19 09:39:00 +00:00
|
|
|
}
|
2023-11-02 14:40:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *VarMemoryCache[T]) Flush(_ context.Context) {
|
|
|
|
c.v.Flush()
|
2022-09-19 09:39:00 +00:00
|
|
|
}
|