351 lines
8.7 KiB
Go
351 lines
8.7 KiB
Go
package cachemanager
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"github.com/fthvgb1/wp-go/cache"
|
|
"github.com/fthvgb1/wp-go/cache/reload"
|
|
"github.com/fthvgb1/wp-go/helper"
|
|
str "github.com/fthvgb1/wp-go/helper/strings"
|
|
"github.com/fthvgb1/wp-go/safety"
|
|
"runtime"
|
|
"time"
|
|
)
|
|
|
|
var mapFlush = safety.NewMap[string, func(any)]()
|
|
var anyFlush = safety.NewMap[string, func()]()
|
|
|
|
var varCache = safety.NewMap[string, any]()
|
|
var mapCache = safety.NewMap[string, any]()
|
|
|
|
func SetVarCache[T any](name string, v *cache.VarCache[T]) error {
|
|
vv, ok := varCache.Load(name)
|
|
if !ok {
|
|
varCache.Store(name, v)
|
|
return nil
|
|
}
|
|
_, ok = vv.(*cache.VarCache[T])
|
|
if ok {
|
|
varCache.Store(name, v)
|
|
return nil
|
|
}
|
|
return errors.New(str.Join("cache ", name, " type err"))
|
|
}
|
|
|
|
func SetMapCache[K comparable, V any](name string, ca *cache.MapCache[K, V]) error {
|
|
v, ok := mapCache.Load(name)
|
|
if !ok {
|
|
mapCache.Store(name, ca)
|
|
return nil
|
|
}
|
|
_, ok = v.(*cache.MapCache[K, V])
|
|
if !ok {
|
|
return errors.New(str.Join("cache ", name, " type err"))
|
|
}
|
|
mapCache.Store(name, ca)
|
|
return nil
|
|
}
|
|
|
|
type flush interface {
|
|
Flush(ctx context.Context)
|
|
}
|
|
|
|
type clearExpired interface {
|
|
ClearExpired(ctx context.Context)
|
|
}
|
|
|
|
var clears []clearExpired
|
|
|
|
var flushes []flush
|
|
|
|
func Flush() {
|
|
ctx := context.WithValue(context.Background(), "execFlushBy", "mangerFlushFn")
|
|
for _, f := range flushes {
|
|
f.Flush(ctx)
|
|
}
|
|
}
|
|
|
|
func FlushMapVal[T any](name string, keys ...T) {
|
|
v, ok := mapFlush.Load(name)
|
|
if !ok || len(keys) < 1 {
|
|
return
|
|
}
|
|
v(keys)
|
|
}
|
|
|
|
func FlushAnyVal(name ...string) {
|
|
for _, s := range name {
|
|
v, ok := anyFlush.Load(s)
|
|
if ok {
|
|
v()
|
|
}
|
|
}
|
|
}
|
|
|
|
func PushMangerMap[K comparable, V any](name string, m *cache.MapCache[K, V]) {
|
|
if name == "" {
|
|
return
|
|
}
|
|
mapCache.Store(name, m)
|
|
anyFlush.Store(name, func() {
|
|
ctx := context.WithValue(context.Background(), "ctx", "registerFlush")
|
|
m.Flush(ctx)
|
|
})
|
|
mapFlush.Store(name, func(a any) {
|
|
k, ok := a.([]K)
|
|
if ok && len(k) > 0 {
|
|
ctx := context.WithValue(context.Background(), "ctx", "registerFlush")
|
|
m.Del(ctx, k...)
|
|
}
|
|
})
|
|
}
|
|
|
|
func GetBy[T any, K comparable](name string, ct context.Context, key K, timeout time.Duration, params ...any) (r T, err error) {
|
|
ct = context.WithValue(ct, "getCache", name)
|
|
ca, err := getMap[K, T](name)
|
|
if err != nil {
|
|
return r, err
|
|
}
|
|
vv, err := ca.GetCache(ct, key, timeout, params...)
|
|
if err != nil {
|
|
return r, err
|
|
}
|
|
r = vv
|
|
return
|
|
}
|
|
|
|
func getMap[K comparable, T any](name string) (*cache.MapCache[K, T], error) {
|
|
m, ok := mapCache.Load(name)
|
|
if !ok {
|
|
return nil, errors.New(str.Join("cache ", name, " doesn't exist"))
|
|
}
|
|
vk, ok := m.(*cache.MapCache[K, T])
|
|
if !ok {
|
|
return nil, errors.New(str.Join("cache ", name, " type error"))
|
|
}
|
|
return vk, nil
|
|
}
|
|
func GetBatchBy[T any, K comparable](name string, ct context.Context, key []K, timeout time.Duration, params ...any) (r []T, err error) {
|
|
ct = context.WithValue(ct, "getCache", name)
|
|
ca, err := getMap[K, T](name)
|
|
if err != nil {
|
|
return r, err
|
|
}
|
|
vv, err := ca.GetCacheBatch(ct, key, timeout, params...)
|
|
if err != nil {
|
|
return r, err
|
|
}
|
|
r = vv
|
|
return
|
|
}
|
|
func GetBatchByToMap[T any, K comparable](name string, ct context.Context, key []K, timeout time.Duration, params ...any) (r map[K]T, err error) {
|
|
ct = context.WithValue(ct, "getCache", name)
|
|
ca, err := getMap[K, T](name)
|
|
if err != nil {
|
|
return r, err
|
|
}
|
|
vv, err := ca.GetBatchToMap(ct, key, timeout, params...)
|
|
if err != nil {
|
|
return r, err
|
|
}
|
|
r = vv
|
|
return
|
|
}
|
|
|
|
func parseArgs(args ...any) (string, func() time.Duration) {
|
|
var name string
|
|
var fn func() time.Duration
|
|
for _, arg := range args {
|
|
v, ok := arg.(string)
|
|
if ok {
|
|
name = v
|
|
continue
|
|
}
|
|
vv, ok := arg.(func() time.Duration)
|
|
if ok {
|
|
fn = vv
|
|
}
|
|
|
|
}
|
|
return name, fn
|
|
}
|
|
|
|
func NewPaginationCache[K comparable, V any](m *cache.MapCache[string, helper.PaginationData[V]], maxNum int,
|
|
dbFn cache.DbFn[K, V], localFn cache.LocalFn[K, V], dbKeyFn, localKeyFn func(K, ...any) string, fetchNum int, name string, a ...any) *cache.Pagination[K, V] {
|
|
fn := helper.ParseArgs([]func() int(nil), a...)
|
|
var ma, fet func() int
|
|
if len(fn) > 0 {
|
|
ma = fn[0]
|
|
if len(fn) > 1 {
|
|
fet = fn[1]
|
|
}
|
|
}
|
|
if ma == nil {
|
|
ma = reload.BuildFnVal(str.Join("paginationCache-", name, "-maxNum"), maxNum, nil)
|
|
}
|
|
if fet == nil {
|
|
fet = reload.BuildFnVal(str.Join("paginationCache-", name, "-fetchNum"), fetchNum, nil)
|
|
}
|
|
p := cache.NewPagination(m, ma, dbFn, localFn, dbKeyFn, localKeyFn, fet, name)
|
|
mapCache.Store(name, p)
|
|
return p
|
|
}
|
|
|
|
func NewMapCache[K comparable, V any](data cache.Cache[K, V], batchFn cache.MapBatchFn[K, V], fn cache.MapSingleFn[K, V], args ...any) *cache.MapCache[K, V] {
|
|
inc := helper.ParseArgs((*cache.IncreaseUpdate[K, V])(nil), args...)
|
|
m := cache.NewMapCache[K, V](data, fn, batchFn, inc, buildLockFn[K](args...), args...)
|
|
FlushPush(m)
|
|
ClearPush(m)
|
|
name, f := parseArgs(args...)
|
|
if name != "" {
|
|
PushMangerMap(name, m)
|
|
}
|
|
if f != nil && name != "" {
|
|
SetExpireTime(any(data).(cache.SetTime), name, 0, f)
|
|
}
|
|
return m
|
|
}
|
|
|
|
func buildLockFn[K comparable](args ...any) cache.LockFn[K] {
|
|
lockFn := helper.ParseArgs(cache.LockFn[K](nil), args...)
|
|
name := helper.ParseArgs("", args...)
|
|
num := helper.ParseArgs(runtime.NumCPU(), args...)
|
|
loFn := func() int {
|
|
return num
|
|
}
|
|
loFn = helper.ParseArgs(loFn, args...)
|
|
if name != "" {
|
|
loFn = reload.BuildFnVal(str.Join("cachesLocksNum-", name), num, loFn)
|
|
}
|
|
if lockFn == nil {
|
|
looo := helper.ParseArgs(cache.Lockss[K](nil), args...)
|
|
if looo != nil {
|
|
lockFn = looo.GetLock
|
|
loo, ok := any(looo).(cache.LocksNum)
|
|
if ok && loo != nil {
|
|
loo.SetLockNum(num)
|
|
}
|
|
} else {
|
|
lo := cache.NewLocks[K](loFn)
|
|
lockFn = lo.GetLock
|
|
FlushPush(lo)
|
|
}
|
|
|
|
}
|
|
return lockFn
|
|
}
|
|
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] {
|
|
|
|
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
|
|
}
|
|
fn := reload.BuildFnVal(str.Join("cacheManger-", name, "-expiredTime"), expireTime, expireTimeFn)
|
|
c.SetExpiredTime(fn)
|
|
}
|
|
|
|
func ChangeExpireTime(t time.Duration, coverConf bool, name ...string) {
|
|
for _, s := range name {
|
|
reload.SetFnVal(s, t, coverConf)
|
|
}
|
|
}
|
|
|
|
func FlushPush(f ...flush) {
|
|
flushes = append(flushes, f...)
|
|
}
|
|
func ClearPush(c ...clearExpired) {
|
|
clears = append(clears, c...)
|
|
}
|
|
|
|
func ClearExpired() {
|
|
ctx := context.WithValue(context.Background(), "execClearExpired", "mangerClearExpiredFn")
|
|
for _, c := range clears {
|
|
c.ClearExpired(ctx)
|
|
}
|
|
}
|
|
|
|
func NewVarCache[T any](c cache.AnyCache[T], fn func(context.Context, ...any) (T, error), a ...any) *cache.VarCache[T] {
|
|
inc := helper.ParseArgs((*cache.IncreaseUpdateVar[T])(nil), a...)
|
|
ref := helper.ParseArgs(cache.RefreshVar[T](nil), a...)
|
|
v := cache.NewVarCache(c, fn, inc, ref, a...)
|
|
FlushPush(v)
|
|
name, _ := parseArgs(a...)
|
|
if name != "" {
|
|
varCache.Store(name, v)
|
|
}
|
|
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)
|
|
ca, ok := GetVarCache[T](name)
|
|
if !ok {
|
|
err = errors.New(str.Join("cache ", name, " is not exist"))
|
|
return
|
|
}
|
|
v, err := ca.GetCache(ctx, duration, a...)
|
|
if err != nil {
|
|
return
|
|
}
|
|
r = v
|
|
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) {
|
|
vv, err := getMap[K, V](name)
|
|
return vv, err == nil
|
|
}
|
|
|
|
func GetPaginationCache[K comparable, V any](name string) (*cache.Pagination[K, V], bool) {
|
|
v, err := getPagination[K, V](name)
|
|
return v, err == nil
|
|
}
|
|
|
|
func Pagination[V any, K comparable](name string, ctx context.Context, timeout time.Duration, k K, page, limit int, a ...any) ([]V, int, error) {
|
|
v, err := getPagination[K, V](name)
|
|
if err != nil {
|
|
return nil, 0, err
|
|
}
|
|
return v.Pagination(ctx, timeout, k, page, limit, a...)
|
|
}
|
|
|
|
func getPagination[K comparable, T any](name string) (*cache.Pagination[K, T], error) {
|
|
m, ok := mapCache.Load(name)
|
|
if !ok {
|
|
return nil, errors.New(str.Join("cache ", name, " doesn't exist"))
|
|
}
|
|
vk, ok := m.(*cache.Pagination[K, T])
|
|
if !ok {
|
|
return nil, errors.New(str.Join("cache ", name, " type error"))
|
|
}
|
|
return vk, nil
|
|
}
|