optimize cachemanger improve var cache

This commit is contained in:
xing 2023-11-02 22:40:13 +08:00
parent d1fb560578
commit 041d06104b
13 changed files with 271 additions and 190 deletions

View File

@ -25,19 +25,20 @@ func isCacheExpired(c *gin.Context, lastTime time.Time) bool {
} }
func Feed(c *gin.Context) { func Feed(c *gin.Context) {
if !isCacheExpired(c, cache.FeedCache().GetLastSetTime()) { feed := cache.FeedCache()
if !isCacheExpired(c, feed.GetLastSetTime(c)) {
c.Status(http.StatusNotModified) c.Status(http.StatusNotModified)
return return
} }
r, err := cache.FeedCache().GetCache(c, time.Second, c) r, err := feed.GetCache(c, time.Second, c)
if err != nil { if err != nil {
c.Status(http.StatusInternalServerError) c.Status(http.StatusInternalServerError)
c.Abort() c.Abort()
c.Error(err) c.Error(err)
return return
} }
setFeed(r[0], c, cache.FeedCache().GetLastSetTime()) setFeed(r[0], c, feed.GetLastSetTime(c))
} }
func setFeed(s string, c *gin.Context, t time.Time) { func setFeed(s string, c *gin.Context, t time.Time) {
@ -51,31 +52,33 @@ func setFeed(s string, c *gin.Context, t time.Time) {
func PostFeed(c *gin.Context) { func PostFeed(c *gin.Context) {
id := c.Param("id") id := c.Param("id")
if !isCacheExpired(c, cache.PostFeedCache().GetLastSetTime(c, id)) { postFeed := cache.PostFeedCache()
if !isCacheExpired(c, postFeed.GetLastSetTime(c, id)) {
c.Status(http.StatusNotModified) c.Status(http.StatusNotModified)
return return
} }
s, err := cache.PostFeedCache().GetCache(c, id, time.Second, c, id) s, err := postFeed.GetCache(c, id, time.Second, c, id)
if err != nil { if err != nil {
c.Status(http.StatusInternalServerError) c.Status(http.StatusInternalServerError)
c.Abort() c.Abort()
c.Error(err) c.Error(err)
return return
} }
setFeed(s, c, cache.PostFeedCache().GetLastSetTime(c, id)) setFeed(s, c, postFeed.GetLastSetTime(c, id))
} }
func CommentsFeed(c *gin.Context) { func CommentsFeed(c *gin.Context) {
if !isCacheExpired(c, cache.CommentsFeedCache().GetLastSetTime()) { feed := cache.CommentsFeedCache()
if !isCacheExpired(c, feed.GetLastSetTime(c)) {
c.Status(http.StatusNotModified) c.Status(http.StatusNotModified)
return return
} }
r, err := cache.CommentsFeedCache().GetCache(c, time.Second, c) r, err := feed.GetCache(c, time.Second, c)
if err != nil { if err != nil {
c.Status(http.StatusInternalServerError) c.Status(http.StatusInternalServerError)
c.Abort() c.Abort()
c.Error(err) c.Error(err)
return return
} }
setFeed(r[0], c, cache.CommentsFeedCache().GetLastSetTime()) setFeed(r[0], c, feed.GetLastSetTime(c))
} }

View File

@ -17,8 +17,13 @@ var getSingleFn = safety.NewMap[string, func(context.Context, any, time.Duration
var getBatchFn = safety.NewMap[string, func(context.Context, any, time.Duration, ...any) (any, error)]() var getBatchFn = safety.NewMap[string, func(context.Context, any, time.Duration, ...any) (any, error)]()
var anyFlush = safety.NewMap[string, func()]() var anyFlush = safety.NewMap[string, func()]()
var getVar = safety.NewMap[string, func(context.Context, time.Duration, ...any) (any, error)]()
var expiredTime = safety.NewMap[string, expire]() var expiredTime = safety.NewMap[string, expire]()
var varCache = safety.NewMap[string, any]()
var mapCache = safety.NewMap[string, any]()
type expire struct { type expire struct {
fn func() time.Duration fn func() time.Duration
p *safety.Var[time.Duration] p *safety.Var[time.Duration]
@ -62,35 +67,38 @@ func FlushAnyVal(name ...string) {
func pushFlushMap[K comparable, V any](m *cache.MapCache[K, V], args ...any) { func pushFlushMap[K comparable, V any](m *cache.MapCache[K, V], args ...any) {
name, _ := parseArgs(args...) name, _ := parseArgs(args...)
if name != "" { if name == "" {
anyFlush.Store(name, func() { return
m.Flush(ctx)
})
mapFlush.Store(name, func(a any) {
k, ok := a.([]K)
if ok && len(k) > 0 {
m.Del(ctx, k...)
}
})
getSingleFn.Store(name, func(ct context.Context, k any, t time.Duration, a ...any) (any, error) {
kk, ok := k.(K)
if !ok {
return nil, errors.New(str.Join("cache ", name, " key type err"))
}
return m.GetCache(ct, kk, t, a...)
})
getBatchFn.Store(name, func(ct context.Context, k any, t time.Duration, a ...any) (any, error) {
kk, ok := k.([]K)
if !ok {
return nil, errors.New(str.Join("cache ", name, " key type err"))
}
return m.GetCacheBatch(ct, kk, t, a...)
})
FlushPush()
} }
mapCache.Store(name, m)
anyFlush.Store(name, func() {
m.Flush(ctx)
})
mapFlush.Store(name, func(a any) {
k, ok := a.([]K)
if ok && len(k) > 0 {
m.Del(ctx, k...)
}
})
getSingleFn.Store(name, func(ct context.Context, k any, t time.Duration, a ...any) (any, error) {
kk, ok := k.(K)
if !ok {
return nil, errors.New(str.Join("cache ", name, " key type err"))
}
return m.GetCache(ct, kk, t, a...)
})
getBatchFn.Store(name, func(ct context.Context, k any, t time.Duration, a ...any) (any, error) {
kk, ok := k.([]K)
if !ok {
return nil, errors.New(str.Join("cache ", name, " key type err"))
}
return m.GetCacheBatch(ct, kk, t, a...)
})
FlushPush()
} }
func Get[T, K any](name string, ct context.Context, key K, timeout time.Duration, params ...any) (r T, err error) { func Get[T, K any](name string, ct context.Context, key K, timeout time.Duration, params ...any) (r T, err error) {
ct = context.WithValue(ct, "getCache", name)
v, ok := getSingleFn.Load(name) v, ok := getSingleFn.Load(name)
if !ok { if !ok {
err = errors.New(str.Join("cache ", name, " doesn't exist")) err = errors.New(str.Join("cache ", name, " doesn't exist"))
@ -104,6 +112,7 @@ func Get[T, K any](name string, ct context.Context, key K, timeout time.Duration
return return
} }
func GetMultiple[T, K any](name string, ct context.Context, key []K, timeout time.Duration, params ...any) (r []T, err error) { func GetMultiple[T, K any](name string, ct context.Context, key []K, timeout time.Duration, params ...any) (r []T, err error) {
ct = context.WithValue(ct, "getCache", name)
v, ok := getBatchFn.Load(name) v, ok := getBatchFn.Load(name)
if !ok { if !ok {
err = errors.New(str.Join("cache ", name, " doesn't exist")) err = errors.New(str.Join("cache ", name, " doesn't exist"))
@ -140,42 +149,53 @@ func NewMapCache[K comparable, V any](data cache.Cache[K, V], batchFn cache.MapB
pushFlushMap(m, args...) pushFlushMap(m, args...)
FlushPush(m) FlushPush(m)
ClearPush(m) ClearPush(m)
name, f := parseArgs(args...)
if f != nil && name != "" {
SetExpireTime(any(data).(cache.SetTime), name, 0, f)
}
return m return m
} }
func NewMemoryMapCache[K comparable, V any](batchFn cache.MapBatchFn[K, V], func NewMemoryMapCache[K comparable, V any](batchFn cache.MapBatchFn[K, V],
fn cache.MapSingleFn[K, V], expireTime time.Duration, args ...any) *cache.MapCache[K, V] { fn cache.MapSingleFn[K, V], expireTime time.Duration, args ...any) *cache.MapCache[K, V] {
name, f := parseArgs(args...)
c := NewMapCache[K, V](cache.NewMemoryMapCache[K, V](func() time.Duration {
return expireTime
}), batchFn, fn, args...)
return c
}
func SetExpireTime(c cache.SetTime, name string, expireTime time.Duration, expireTimeFn func() time.Duration) {
if name == "" {
return
}
var t, tt func() time.Duration var t, tt func() time.Duration
t = f t = expireTimeFn
if t == nil { if t == nil {
t = func() time.Duration { t = func() time.Duration {
return expireTime return expireTime
} }
} }
tt = t tt = t
if name != "" { expireTime = t()
expireTime = t() p := safety.NewVar(expireTime)
p := safety.NewVar(expireTime) e := expire{
e := expire{ fn: t,
fn: t, p: p,
p: p, isUseManger: safety.NewVar(false),
isUseManger: safety.NewVar(false),
}
expiredTime.Store(name, e)
reload.Push(func() {
if !e.isUseManger.Load() {
e.p.Store(tt())
}
}, str.Join("cacheManger-", name, "-expiredTime"))
t = func() time.Duration {
return e.p.Load()
}
} }
expiredTime.Store(name, e)
return NewMapCache[K, V](cache.NewMemoryMapCache[K, V](t), batchFn, fn, args...) reload.Push(func() {
if !e.isUseManger.Load() {
e.p.Store(tt())
}
}, str.Join("cacheManger-", name, "-expiredTime"))
t = func() time.Duration {
return e.p.Load()
}
c.SetExpiredTime(t)
} }
func SetExpireTime(t time.Duration, name ...string) { func ChangeExpireTime(t time.Duration, name ...string) {
for _, s := range name { for _, s := range name {
v, ok := expiredTime.Load(s) v, ok := expiredTime.Load(s)
if !ok { if !ok {
@ -200,3 +220,66 @@ func ClearExpired() {
c.ClearExpired(ctx) c.ClearExpired(ctx)
} }
} }
func NewVarCache[T any](c cache.AnyCache[T], fn func(context.Context, ...any) (T, error), a ...any) *cache.VarCache[T] {
v := cache.NewVarCache(c, fn)
FlushPush(v)
name, _ := parseArgs(a...)
if name != "" {
varCache.Store(name, v)
getVar.Store(name, func(c context.Context, duration time.Duration, a ...any) (any, error) {
return v.GetCache(c, duration, a...)
})
}
cc, ok := any(c).(clearExpired)
if ok {
ClearPush(cc)
}
return v
}
func GetVarVal[T any](name string, ctx context.Context, duration time.Duration, a ...any) (r T, err error) {
ctx = context.WithValue(ctx, "getCache", name)
fn, ok := getVar.Load(name)
if !ok {
err = errors.New(str.Join("cache ", name, " is not exist"))
return
}
v, err := fn(ctx, duration, a...)
if err != nil {
return
}
vv, ok := v.(T)
if !ok {
err = errors.New(str.Join("cache ", name, " value wanted can't match got"))
return
}
r = vv
return
}
func NewVarMemoryCache[T any](fn func(context.Context, ...any) (T, error), expired time.Duration, a ...any) *cache.VarCache[T] {
c := cache.NewVarMemoryCache[T](nil)
name, e := parseArgs(a...)
SetExpireTime(c, name, expired, e)
v := NewVarCache[T](c, fn, a...)
return v
}
func GetVarCache[T any](name string) (*cache.VarCache[T], bool) {
v, ok := varCache.Load(name)
if !ok {
return nil, false
}
vv, ok := v.(*cache.VarCache[T])
return vv, ok
}
func GetMapCache[K comparable, V any](name string) (*cache.MapCache[K, V], bool) {
v, ok := mapCache.Load(name)
if !ok {
return nil, false
}
vv, ok := v.(*cache.MapCache[K, V])
return vv, ok
}

View File

@ -61,7 +61,7 @@ func TestSetExpireTime(t *testing.T) {
fmt.Println(c.Get(ctx, "xx")) fmt.Println(c.Get(ctx, "xx"))
time.Sleep(time.Second) time.Sleep(time.Second)
fmt.Println(c.Get(ctx, "xx")) fmt.Println(c.Get(ctx, "xx"))
SetExpireTime(3*time.Second, "xx") ChangeExpireTime(3*time.Second, "xx")
c.Set(ctx, "xx", "yyy") c.Set(ctx, "xx", "yyy")
time.Sleep(time.Second) time.Sleep(time.Second)
fmt.Println(c.Get(ctx, "xx")) fmt.Println(c.Get(ctx, "xx"))

View File

@ -69,15 +69,21 @@ func InitActionsCommonCache() {
return config.GetConfig().CacheTime.CategoryCacheTime return config.GetConfig().CacheTime.CategoryCacheTime
}) })
recentPostsCaches = cache.NewVarCache(dao.RecentPosts, c.CacheTime.RecentPostCacheTime) recentPostsCaches = cachemanager.NewVarMemoryCache(dao.RecentPosts, c.CacheTime.RecentPostCacheTime, "recentPosts", func() time.Duration {
return config.GetConfig().CacheTime.RecentPostCacheTime
})
recentCommentsCaches = cache.NewVarCache(dao.RecentComments, c.CacheTime.RecentCommentsCacheTime) recentCommentsCaches = cachemanager.NewVarMemoryCache(dao.RecentComments, c.CacheTime.RecentCommentsCacheTime, "recentComments", func() time.Duration {
return config.GetConfig().CacheTime.RecentCommentsCacheTime
})
postCommentCaches = cachemanager.NewMemoryMapCache(nil, dao.PostComments, c.CacheTime.PostCommentsCacheTime, "postCommentIds", func() time.Duration { postCommentCaches = cachemanager.NewMemoryMapCache(nil, dao.PostComments, c.CacheTime.PostCommentsCacheTime, "postCommentIds", func() time.Duration {
return config.GetConfig().CacheTime.PostCommentsCacheTime return config.GetConfig().CacheTime.PostCommentsCacheTime
}) })
maxPostIdCache = cache.NewVarCache(dao.GetMaxPostId, c.CacheTime.MaxPostIdCacheTime) maxPostIdCache = cachemanager.NewVarMemoryCache(dao.GetMaxPostId, c.CacheTime.MaxPostIdCacheTime, "maxPostId", func() time.Duration {
return config.GetConfig().CacheTime.MaxPostIdCacheTime
})
cachemanager.NewMemoryMapCache(nil, dao.GetUserById, c.CacheTime.UserInfoCacheTime, "userData", func() time.Duration { cachemanager.NewMemoryMapCache(nil, dao.GetUserById, c.CacheTime.UserInfoCacheTime, "userData", func() time.Duration {
return config.GetConfig().CacheTime.UserInfoCacheTime return config.GetConfig().CacheTime.UserInfoCacheTime
@ -91,13 +97,15 @@ func InitActionsCommonCache() {
return config.GetConfig().CacheTime.CommentsCacheTime return config.GetConfig().CacheTime.CommentsCacheTime
}) })
allUsernameCache = cache.NewVarCache(dao.AllUsername, c.CacheTime.UserInfoCacheTime) allUsernameCache = cachemanager.NewVarMemoryCache(dao.AllUsername, c.CacheTime.UserInfoCacheTime, "allUsername", func() time.Duration {
return config.GetConfig().CacheTime.UserInfoCacheTime
})
feedCache = cache.NewVarCache(feed, time.Hour) feedCache = cachemanager.NewVarMemoryCache(feed, time.Hour, "feed")
postFeedCache = cachemanager.NewMemoryMapCache(nil, postFeed, time.Hour, "postFeed") postFeedCache = cachemanager.NewMemoryMapCache(nil, postFeed, time.Hour, "postFeed")
commentsFeedCache = cache.NewVarCache(commentsFeed, time.Hour) commentsFeedCache = cachemanager.NewVarMemoryCache(commentsFeed, time.Hour, "commentsFeed")
newCommentCache = cachemanager.NewMemoryMapCache[string, string](nil, nil, 15*time.Minute, "NewComment") newCommentCache = cachemanager.NewMemoryMapCache[string, string](nil, nil, 15*time.Minute, "NewComment")

View File

@ -13,7 +13,6 @@ import (
str "github.com/fthvgb1/wp-go/helper/strings" str "github.com/fthvgb1/wp-go/helper/strings"
"github.com/fthvgb1/wp-go/plugin/digest" "github.com/fthvgb1/wp-go/plugin/digest"
"github.com/fthvgb1/wp-go/rss2" "github.com/fthvgb1/wp-go/rss2"
"github.com/gin-gonic/gin"
"strings" "strings"
"time" "time"
) )
@ -46,8 +45,7 @@ func PostFeedCache() *cache.MapCache[string, string] {
return postFeedCache return postFeedCache
} }
func feed(arg ...any) (xml []string, err error) { func feed(c context.Context, _ ...any) (xml []string, err error) {
c := arg[0].(*gin.Context)
r := RecentPosts(c, 10) r := RecentPosts(c, 10)
ids := slice.Map(r, func(t models.Posts) uint64 { ids := slice.Map(r, func(t models.Posts) uint64 {
return t.Id return t.Id
@ -150,8 +148,7 @@ func postFeed(c context.Context, id string, arg ...any) (x string, err error) {
return return
} }
func commentsFeed(args ...any) (r []string, err error) { func commentsFeed(c context.Context, _ ...any) (r []string, err error) {
c := args[0].(*gin.Context)
commens := RecentComments(c, 10) commens := RecentComments(c, 10)
rs := templateRss rs := templateRss
rs.Title = fmt.Sprintf("\"%s\"的评论", wpconfig.GetOption("blogname")) rs.Title = fmt.Sprintf("\"%s\"的评论", wpconfig.GetOption("blogname"))

View File

@ -10,8 +10,7 @@ import (
// RecentComments // RecentComments
// param context.Context // param context.Context
func RecentComments(a ...any) (r []models.Comments, err error) { func RecentComments(ctx context.Context, a ...any) (r []models.Comments, err error) {
ctx := a[0].(context.Context)
n := a[1].(int) n := a[1].(int)
return model.Finds[models.Comments](ctx, model.Conditions( return model.Finds[models.Comments](ctx, model.Conditions(
model.Where(model.SqlBuilder{ model.Where(model.SqlBuilder{

View File

@ -116,8 +116,7 @@ func SearchPostIds(ctx context.Context, _ string, args ...any) (ids PostIds, err
return return
} }
func GetMaxPostId(a ...any) (uint64, error) { func GetMaxPostId(ctx context.Context, a ...any) (uint64, error) {
ctx := a[0].(context.Context)
r, err := model.SimpleFind[models.Posts](ctx, r, err := model.SimpleFind[models.Posts](ctx,
model.SqlBuilder{{"post_type", "post"}, {"post_status", "publish"}}, model.SqlBuilder{{"post_type", "post"}, {"post_status", "publish"}},
"max(ID) ID", "max(ID) ID",
@ -129,8 +128,7 @@ func GetMaxPostId(a ...any) (uint64, error) {
return id, err return id, err
} }
func RecentPosts(a ...any) (r []models.Posts, err error) { func RecentPosts(ctx context.Context, a ...any) (r []models.Posts, err error) {
ctx := a[0].(context.Context)
num := a[1].(int) num := a[1].(int)
r, err = model.Finds[models.Posts](ctx, model.Conditions( r, err = model.Finds[models.Posts](ctx, model.Conditions(
model.Where(model.SqlBuilder{ model.Where(model.SqlBuilder{

View File

@ -12,8 +12,7 @@ func GetUserById(ctx context.Context, uid uint64, _ ...any) (r models.Users, err
return return
} }
func AllUsername(a ...any) (map[string]struct{}, error) { func AllUsername(ctx context.Context, _ ...any) (map[string]struct{}, error) {
ctx := a[0].(context.Context)
r, err := model.SimpleFind[models.Users](ctx, model.SqlBuilder{ r, err := model.SimpleFind[models.Users](ctx, model.SqlBuilder{
{"user_status", "=", "0", "int"}, {"user_status", "=", "0", "int"},
}, "user_login") }, "user_login")

View File

@ -118,7 +118,7 @@ func InitHandle(fn func(*Handle), h *Handle) {
h.C.Set("inited", true) h.C.Set("inited", true)
inited = true inited = true
return *h return *h
}, float64(-100)) })
h.ginH = maps.Copy(hh.ginH) h.ginH = maps.Copy(hh.ginH)
h.ginH["calPostClass"] = postClass(h) h.ginH["calPostClass"] = postClass(h)
h.ginH["calBodyClass"] = bodyClass(h) h.ginH["calBodyClass"] = bodyClass(h)

11
cache/cache.go vendored
View File

@ -19,3 +19,14 @@ type Expend[K comparable, V any] interface {
Gets(ctx context.Context, k []K) (map[K]V, error) Gets(ctx context.Context, k []K) (map[K]V, error)
Sets(ctx context.Context, m map[K]V) Sets(ctx context.Context, m map[K]V)
} }
type SetTime interface {
SetExpiredTime(func() time.Duration)
}
type AnyCache[T any] interface {
Get(ctx context.Context) (T, bool)
Set(ctx context.Context, v T)
Flush(ctx context.Context)
GetLastSetTime(ctx context.Context) time.Time
}

View File

@ -24,6 +24,10 @@ type mapVal[T any] struct {
data T data T
} }
func (m *MemoryMapCache[K, V]) SetExpiredTime(f func() time.Duration) {
m.expireTime = f
}
func (m *MemoryMapCache[K, V]) GetExpireTime(_ context.Context) time.Duration { func (m *MemoryMapCache[K, V]) GetExpireTime(_ context.Context) time.Duration {
return m.expireTime() return m.expireTime()
} }

164
cache/vars.go vendored
View File

@ -10,90 +10,100 @@ import (
) )
type VarCache[T any] struct { type VarCache[T any] struct {
v *safety.Var[vars[T]] AnyCache[T]
setCacheFunc func(context.Context, ...any) (T, error)
mutex sync.Mutex
} }
type vars[T any] struct { func (t *VarCache[T]) GetCache(ctx context.Context, timeout time.Duration, params ...any) (T, error) {
data T data, ok := t.Get(ctx)
mutex *sync.Mutex if ok {
setCacheFunc func(...any) (T, error) return data, nil
expireTime time.Duration
setTime time.Time
incr int
}
func (c *VarCache[T]) GetLastSetTime() time.Time {
return c.v.Load().setTime
}
func NewVarCache[T any](fun func(...any) (T, error), duration time.Duration) *VarCache[T] {
return &VarCache[T]{
v: safety.NewVar(vars[T]{
mutex: &sync.Mutex{},
setCacheFunc: fun,
expireTime: duration,
}),
} }
}
func (c *VarCache[T]) IsExpired() bool {
v := c.v.Load()
return time.Duration(v.setTime.UnixNano())+v.expireTime < time.Duration(time.Now().UnixNano())
}
func (c *VarCache[T]) Flush() {
v := c.v.Load()
mu := v.mutex
mu.Lock()
defer mu.Unlock()
var vv T
v.data = vv
c.v.Store(v)
}
func (c *VarCache[T]) GetCache(ctx context.Context, timeout time.Duration, params ...any) (T, error) {
v := c.v.Load()
data := v.data
var err error var err error
if v.expireTime <= 0 || ((time.Duration(v.setTime.UnixNano()) + v.expireTime) < time.Duration(time.Now().UnixNano())) { call := func() {
t := v.incr t.mutex.Lock()
call := func() { defer t.mutex.Unlock()
v.mutex.Lock() dat, ok := t.Get(ctx)
defer v.mutex.Unlock() if ok {
vv := c.v.Load() data = dat
if vv.incr > t { return
return
}
r, er := vv.setCacheFunc(params...)
if err != nil {
err = er
return
}
vv.setTime = time.Now()
vv.data = r
data = r
vv.incr++
c.v.Store(vv)
} }
if timeout > 0 { r, er := t.setCacheFunc(ctx, params...)
ctx, cancel := context.WithTimeout(ctx, timeout) if er != nil {
defer cancel() err = er
done := make(chan struct{}, 1) return
go func() { }
call() t.Set(ctx, r)
done <- struct{}{} data = r
close(done) }
}() if timeout > 0 {
select { ctx, cancel := context.WithTimeout(ctx, timeout)
case <-ctx.Done(): defer cancel()
err = errors.New(fmt.Sprintf("get cache %s", ctx.Err().Error())) done := make(chan struct{}, 1)
case <-done: go func() {
}
} else {
call() call()
} done <- struct{}{}
close(done)
}()
select {
case <-ctx.Done():
err = errors.New(fmt.Sprintf("get cache %s", ctx.Err().Error()))
case <-done:
}
} else {
call()
} }
return data, err return data, err
} }
type VarMemoryCache[T any] struct {
v *safety.Var[vars[T]]
expireTime func() time.Duration
}
func (c *VarMemoryCache[T]) ClearExpired(ctx context.Context) {
c.Flush(ctx)
}
func NewVarMemoryCache[T any](expireTime func() time.Duration) *VarMemoryCache[T] {
return &VarMemoryCache[T]{v: safety.NewVar(vars[T]{}), expireTime: expireTime}
}
func (c *VarMemoryCache[T]) Get(_ context.Context) (T, bool) {
v := c.v.Load()
return v.data, c.expireTime() >= time.Now().Sub(v.setTime)
}
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)
}
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
}
func NewVarCache[T any](cache AnyCache[T], fn func(context.Context, ...any) (T, error)) *VarCache[T] {
return &VarCache[T]{
AnyCache: cache, setCacheFunc: fn, mutex: sync.Mutex{},
}
}
func (c *VarMemoryCache[T]) Flush(_ context.Context) {
c.v.Flush()
}

41
cache/vars_test.go vendored
View File

@ -7,9 +7,11 @@ import (
"time" "time"
) )
var cc = *NewVarCache(func(a ...any) (int, error) { var cc = *NewVarCache[int](NewVarMemoryCache[int](func() time.Duration {
return time.Minute
}), func(ctx context.Context, a ...any) (int, error) {
return 1, nil return 1, nil
}, time.Minute) })
func TestVarCache_Flush(t *testing.T) { func TestVarCache_Flush(t *testing.T) {
type testCase[T any] struct { type testCase[T any] struct {
@ -26,41 +28,8 @@ func TestVarCache_Flush(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
fmt.Println(tt.c.GetCache(c, time.Second)) fmt.Println(tt.c.GetCache(c, time.Second))
tt.c.Flush() tt.c.Flush(ctx)
fmt.Println(tt.c.GetCache(c, time.Second)) fmt.Println(tt.c.GetCache(c, time.Second))
}) })
} }
} }
func TestVarCache_IsExpired(t *testing.T) {
type testCase[T any] struct {
name string
c VarCache[T]
want bool
}
tests := []testCase[int]{
{
name: "expired",
c: cc,
want: true,
},
{
name: "not expired",
c: func() VarCache[int] {
v := *NewVarCache(func(a ...any) (int, error) {
return 1, nil
}, time.Minute)
_, _ = v.GetCache(context.Background(), time.Second)
return v
}(),
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.c.IsExpired(); got != tt.want {
t.Errorf("IsExpired() = %v, want %v", got, tt.want)
}
})
}
}