optimize reload package add append executed once func when reload and add hook scheme

This commit is contained in:
xing 2024-04-14 22:49:40 +08:00
parent 6f51f1c295
commit daa7101493
2 changed files with 104 additions and 31 deletions

View File

@ -8,6 +8,7 @@ import (
"github.com/fthvgb1/wp-go/app/pkg/dao" "github.com/fthvgb1/wp-go/app/pkg/dao"
"github.com/fthvgb1/wp-go/app/theme/wp" "github.com/fthvgb1/wp-go/app/theme/wp"
"github.com/fthvgb1/wp-go/cache/cachemanager" "github.com/fthvgb1/wp-go/cache/cachemanager"
"github.com/fthvgb1/wp-go/cache/reload"
"github.com/fthvgb1/wp-go/helper/number" "github.com/fthvgb1/wp-go/helper/number"
"github.com/fthvgb1/wp-go/helper/slice" "github.com/fthvgb1/wp-go/helper/slice"
"github.com/fthvgb1/wp-go/helper/strings" "github.com/fthvgb1/wp-go/helper/strings"
@ -94,6 +95,9 @@ func Re(h *wp.Handle) {
return return
} }
} }
reload.AppendOnceFn(func() {
cachemanager.SetMapCache("listPostIds",vv)
})
rdm := redis.NewClient(&redis.Options{ rdm := redis.NewClient(&redis.Options{
Addr: "localhost:6379", Addr: "localhost:6379",
Password: "", // no password set Password: "", // no password set

131
cache/reload/reload.go vendored
View File

@ -9,10 +9,12 @@ import (
"sync/atomic" "sync/atomic"
) )
type queue struct { type Queue struct {
fn func() Fn func()
order float64 Order float64
name string Name string
AutoExec bool
Once bool
} }
var mut = &sync.Mutex{} var mut = &sync.Mutex{}
@ -21,11 +23,55 @@ func GetGlobeMutex() *sync.Mutex {
return mut return mut
} }
var waitReloadCalls = safety.NewSlice(make([]queue, 0)) var reloadQueues = safety.NewSlice(make([]Queue, 0))
var callMap = safety.NewMap[string, func()]()
var reloadQueueHookFns = safety.NewVar[[]func(queue Queue) (Queue, bool)](nil)
var setFnVal = safety.NewMap[string, any]() var setFnVal = safety.NewMap[string, any]()
func DeleteReloadQueue(names ...string) {
hooks := reloadQueueHookFns.Load()
for _, name := range names {
hooks = append(hooks, func(queue Queue) (Queue, bool) {
if name != queue.Name {
return queue, true
}
return queue, false
})
}
reloadQueueHookFns.Store(hooks)
}
func HookReloadQueue(fn func(queue Queue) (Queue, bool)) {
a := reloadQueueHookFns.Load()
a = append(a, fn)
reloadQueueHookFns.Store(a)
}
func GetReloadFn(name string) func() {
hookQueue()
i, queue := slice.SearchFirst(reloadQueues.Load(), func(queue Queue) bool {
return queue.Name == name
})
if i > -1 && queue.Fn != nil {
return queue.Fn
}
return nil
}
func hookQueue() {
hooks := reloadQueueHookFns.Load()
queues := reloadQueues.Load()
length := len(queues)
for _, hook := range hooks {
queues = slice.FilterAndMap(queues, hook)
}
if len(queues) != length {
reloadQueues.Store(queues)
}
reloadQueueHookFns.Flush()
}
type SafetyVar[T, A any] struct { type SafetyVar[T, A any] struct {
Val *safety.Var[Val[T]] Val *safety.Var[Val[T]]
Mutex sync.Mutex Mutex sync.Mutex
@ -65,12 +111,20 @@ func DeleteMapVal[T any](namespace string, key ...T) {
func Reloads(namespaces ...string) { func Reloads(namespaces ...string) {
mut.Lock() mut.Lock()
defer mut.Unlock() defer mut.Unlock()
for _, namespace := range namespaces { hookQueue()
fn, ok := callMap.Load(namespace) queues := reloadQueues.Load()
if !ok { for _, name := range namespaces {
i, queue := slice.SearchFirst(queues, func(queue Queue) bool {
return name == queue.Name
})
if i < 0 {
continue continue
} }
fn() queue.Fn()
if queue.Once {
slice.Delete(&queues, i)
reloadQueues.Store(queues)
}
} }
} }
@ -190,7 +244,7 @@ func GetAnyValMapBy[K comparable, V, A any](namespace string, key K, a A, fn fun
return v return v
} }
func BuildAnyVal[T, A any](namespace string, counter bool, args ...any) *SafetyVar[T, A] { func BuildAnyVal[T, A any](namespace string, args ...any) *SafetyVar[T, A] {
var vv *SafetyVar[T, A] var vv *SafetyVar[T, A]
vvv, ok := safetyMaps.Load(namespace) vvv, ok := safetyMaps.Load(namespace)
if ok { if ok {
@ -212,7 +266,7 @@ func BuildAnyVal[T, A any](namespace string, counter bool, args ...any) *SafetyV
} }
func GetAnyValBys[T, A any](namespace string, a A, fn func(A) (T, bool), args ...any) T { func GetAnyValBys[T, A any](namespace string, a A, fn func(A) (T, bool), args ...any) T {
var vv = BuildAnyVal[T, A](namespace, false, args...) var vv = BuildAnyVal[T, A](namespace, args...)
v := vv.Val.Load() v := vv.Val.Load()
if v.Ok { if v.Ok {
return v.V return v.V
@ -232,7 +286,7 @@ func GetAnyValBys[T, A any](namespace string, a A, fn func(A) (T, bool), args ..
// //
// if give a int and value bigger than 1 will be a times which built fn called return false // if give a int and value bigger than 1 will be a times which built fn called return false
func BuildValFnWithConfirm[T, A any](namespace string, fn func(A) (T, bool), args ...any) func(A) T { func BuildValFnWithConfirm[T, A any](namespace string, fn func(A) (T, bool), args ...any) func(A) T {
var vv = BuildAnyVal[T, A](namespace, false, args...) var vv = BuildAnyVal[T, A](namespace, args...)
tryTimes := helper.ParseArgs(1, args...) tryTimes := helper.ParseArgs(1, args...)
var counter int64 var counter int64
if tryTimes > 1 { if tryTimes > 1 {
@ -277,7 +331,7 @@ func BuildValFnWithConfirm[T, A any](namespace string, fn func(A) (T, bool), arg
// //
// if give a bool false will not flushed when called Reload, but can call GetValMap or Reloads to flush manually // if give a bool false will not flushed when called Reload, but can call GetValMap or Reloads to flush manually
func BuildValFn[T, A any](namespace string, fn func(A) T, args ...any) func(A) T { func BuildValFn[T, A any](namespace string, fn func(A) T, args ...any) func(A) T {
var vv = BuildAnyVal[T, A](namespace, false, args...) var vv = BuildAnyVal[T, A](namespace, args...)
return func(a A) T { return func(a A) T {
v := vv.Val.Load() v := vv.Val.Load()
if v.Ok { if v.Ok {
@ -298,7 +352,7 @@ func BuildValFn[T, A any](namespace string, fn func(A) T, args ...any) func(A) T
// BuildValFnWithAnyParams same as BuildValFn use multiple params // BuildValFnWithAnyParams same as BuildValFn use multiple params
func BuildValFnWithAnyParams[T any](namespace string, fn func(...any) T, args ...any) func(...any) T { func BuildValFnWithAnyParams[T any](namespace string, fn func(...any) T, args ...any) func(...any) T {
var vv = BuildAnyVal[T, any](namespace, false, args...) var vv = BuildAnyVal[T, any](namespace, args...)
return func(a ...any) T { return func(a ...any) T {
v := vv.Val.Load() v := vv.Val.Load()
if v.Ok { if v.Ok {
@ -326,6 +380,8 @@ func BuildValFnWithAnyParams[T any](namespace string, fn func(...any) T, args ..
// if give a float then can be reloaded early or lately, more bigger more earlier // if give a float then can be reloaded early or lately, more bigger more earlier
// //
// if give a bool false will not flushed when called Reload, but can call GetValMap or Reloads to flush manually // if give a bool false will not flushed when called Reload, but can call GetValMap or Reloads to flush manually
//
// if give a int 1 will only execute once when called Reload or Reloads and then delete the flush fn
func Vars[T any](defaults T, args ...any) *safety.Var[T] { func Vars[T any](defaults T, args ...any) *safety.Var[T] {
ss := safety.NewVar(defaults) ss := safety.NewVar(defaults)
@ -388,32 +444,45 @@ func SafeMap[K comparable, T any](args ...any) *safety.Map[K, T] {
// //
// if give a float then can be called early or lately when called Reload, more bigger more earlier // if give a float then can be called early or lately when called Reload, more bigger more earlier
// //
// if give a bool false will not flushed when called Reload, then can called GetValMap to flush manually // if give a bool false will not execute when called Reload, then can called Reloads to execute manually
//
// if give a int 1 will only execute once when called Reload or Reloads and then delete the Queue
func Append(fn func(), a ...any) { func Append(fn func(), a ...any) {
ord, name := parseArgs(a...) ord, name := parseArgs(a...)
auto := helper.ParseArgs(true, a...) autoExec := helper.ParseArgs(true, a...)
if name != "" && !auto { once := helper.ParseArgs(0, a...)
callMap.Store(name, fn) queue := Queue{fn, ord, name, autoExec, once == 1}
return reloadQueues.Append(queue)
} }
waitReloadCalls.Append(queue{fn, ord, name})
if name != "" { // AppendOnceFn function and args same as Append, but func will execute only once when called Reload or Reloads and then will be deleted. Especially suitable for using to develop plugins, when uninstall plugin can clean or recover some progress's self relative data or behavior which was changed by plugin.
callMap.Store(name, fn) func AppendOnceFn(fn func(), a ...any) {
} a = append([]any{1}, a...)
Append(fn, a...)
} }
func Reload() { func Reload() {
mut.Lock() mut.Lock()
defer mut.Unlock() defer mut.Unlock()
deleteMapFn.Flush() deleteMapFn.Flush()
reloadCalls := waitReloadCalls.Load() hookQueue()
slice.SimpleSort(reloadCalls, slice.DESC, func(t queue) float64 { queues := reloadQueues.Load()
return t.order length := len(queues)
slice.SimpleSort(queues, slice.DESC, func(t Queue) float64 {
return t.Order
}) })
for _, call := range reloadCalls { for i, queue := range queues {
call.fn() if !queue.AutoExec {
continue
}
queue.Fn()
if queue.Once {
slice.Delete(&queues, i)
}
}
if length != len(queues) {
reloadQueues.Store(queues)
} }
return
} }
type Any[T any] struct { type Any[T any] struct {