完善map缓存,优化部分post缓存
This commit is contained in:
parent
528e8e9348
commit
10efcc9711
|
@ -20,18 +20,21 @@ var PostContextCache sync.Map
|
||||||
var archivesCaches *Arch
|
var archivesCaches *Arch
|
||||||
var categoryCaches *cache.SliceCache[models.WpTermsMy]
|
var categoryCaches *cache.SliceCache[models.WpTermsMy]
|
||||||
var recentPostsCaches *cache.SliceCache[models.WpPosts]
|
var recentPostsCaches *cache.SliceCache[models.WpPosts]
|
||||||
var monthCaches *cache.MapCache[string, []models.WpPosts]
|
|
||||||
var recentCommentsCaches *cache.SliceCache[models.WpComments]
|
var recentCommentsCaches *cache.SliceCache[models.WpComments]
|
||||||
var postCommentCaches *cache.MapCache[uint64, []models.WpComments]
|
var postCommentCaches *cache.MapCache[uint64, []models.WpComments]
|
||||||
|
var postsCache *cache.MapCache[uint64, models.WpPosts]
|
||||||
|
|
||||||
func InitCache() {
|
func InitActionsCommonCache() {
|
||||||
archivesCaches = &Arch{
|
archivesCaches = &Arch{
|
||||||
mutex: &sync.Mutex{},
|
mutex: &sync.Mutex{},
|
||||||
setCacheFunc: archives,
|
setCacheFunc: archives,
|
||||||
}
|
}
|
||||||
|
postsCache = cache.NewMapBatchCache[uint64, models.WpPosts](getPosts, time.Hour)
|
||||||
|
|
||||||
categoryCaches = cache.NewSliceCache[models.WpTermsMy](categories, vars.Conf.CategoryCacheTime)
|
categoryCaches = cache.NewSliceCache[models.WpTermsMy](categories, vars.Conf.CategoryCacheTime)
|
||||||
|
|
||||||
recentPostsCaches = cache.NewSliceCache[models.WpPosts](recentPosts, vars.Conf.RecentPostCacheTime)
|
recentPostsCaches = cache.NewSliceCache[models.WpPosts](recentPosts, vars.Conf.RecentPostCacheTime)
|
||||||
monthCaches = cache.NewMapCache[string, []models.WpPosts](getMonthPost, 30*time.Minute)
|
|
||||||
recentCommentsCaches = cache.NewSliceCache[models.WpComments](recentComments, vars.Conf.RecentCommentsCacheTime)
|
recentCommentsCaches = cache.NewSliceCache[models.WpComments](recentComments, vars.Conf.RecentCommentsCacheTime)
|
||||||
postCommentCaches = cache.NewMapCache[uint64, []models.WpComments](postComments, time.Minute*5)
|
postCommentCaches = cache.NewMapCache[uint64, []models.WpComments](postComments, time.Minute*5)
|
||||||
}
|
}
|
||||||
|
@ -43,7 +46,7 @@ type Arch struct {
|
||||||
month time.Month
|
month time.Month
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Arch) GetCache() []models.PostArchive {
|
func (c *Arch) getArchiveCache() []models.PostArchive {
|
||||||
l := len(c.data)
|
l := len(c.data)
|
||||||
m := time.Now().Month()
|
m := time.Now().Month()
|
||||||
if l > 0 && c.month != m || l < 1 {
|
if l > 0 && c.month != m || l < 1 {
|
||||||
|
@ -67,10 +70,6 @@ type PostContext struct {
|
||||||
setTime time.Time
|
setTime time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetMonthPost(ctx context.Context, year, month string) ([]models.WpPosts, error) {
|
|
||||||
return monthCaches.GetCache(ctx, fmt.Sprintf("%s%s", year, month), time.Second, year, month)
|
|
||||||
}
|
|
||||||
|
|
||||||
func PostComments(ctx context.Context, Id uint64) ([]models.WpComments, error) {
|
func PostComments(ctx context.Context, Id uint64) ([]models.WpComments, error) {
|
||||||
return postCommentCaches.GetCache(ctx, Id, time.Second, Id)
|
return postCommentCaches.GetCache(ctx, Id, time.Second, Id)
|
||||||
}
|
}
|
||||||
|
@ -151,14 +150,6 @@ func getPostContext(t time.Time) (prev, next models.WpPosts, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetPostFromCache(Id uint64) (r models.WpPosts) {
|
|
||||||
p, ok := PostsCache.Load(Id)
|
|
||||||
if ok {
|
|
||||||
r = *p.(*models.WpPosts)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func QueryAndSetPostCache(postIds []models.WpPosts) (err error) {
|
func QueryAndSetPostCache(postIds []models.WpPosts) (err error) {
|
||||||
var all []uint64
|
var all []uint64
|
||||||
var needQuery []any
|
var needQuery []any
|
||||||
|
@ -223,7 +214,7 @@ func archives() ([]models.PostArchive, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Archives() (r []models.PostArchive) {
|
func Archives() (r []models.PostArchive) {
|
||||||
return archivesCaches.GetCache()
|
return archivesCaches.getArchiveCache()
|
||||||
}
|
}
|
||||||
|
|
||||||
func Categories(ctx context.Context) []models.WpTermsMy {
|
func Categories(ctx context.Context) []models.WpTermsMy {
|
||||||
|
|
34
actions/common/posts.go
Normal file
34
actions/common/posts.go
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github/fthvgb1/wp-go/helper"
|
||||||
|
"github/fthvgb1/wp-go/models"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetPostById(ctx context.Context, id uint64, ids ...uint64) (models.WpPosts, error) {
|
||||||
|
|
||||||
|
return postsCache.GetCacheBatch(ctx, id, time.Second, ids)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPosts(ids ...any) (m map[uint64]models.WpPosts, err error) {
|
||||||
|
m = make(map[uint64]models.WpPosts)
|
||||||
|
id := ids[0].([]uint64)
|
||||||
|
arg := helper.SliceMap(id, helper.ToAny[uint64])
|
||||||
|
rawPosts, err := models.Find[models.WpPosts](models.SqlBuilder{{
|
||||||
|
"Id", "in", "",
|
||||||
|
}}, "a.*,ifnull(d.name,'') category_name,ifnull(taxonomy,'') `taxonomy`", "", nil, models.SqlBuilder{{
|
||||||
|
"a", "left join", "wp_term_relationships b", "a.Id=b.object_id",
|
||||||
|
}, {
|
||||||
|
"left join", "wp_term_taxonomy c", "b.term_taxonomy_id=c.term_taxonomy_id",
|
||||||
|
}, {
|
||||||
|
"left join", "wp_terms d", "c.term_id=d.term_id",
|
||||||
|
}}, 0, arg)
|
||||||
|
if err == nil {
|
||||||
|
for _, v := range rawPosts {
|
||||||
|
m[v.Id] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
|
@ -55,17 +55,9 @@ func Detail(c *gin.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ID := uint64(Id)
|
ID := uint64(Id)
|
||||||
post := common.GetPostFromCache(ID)
|
post, err := common.GetPostById(c, ID, ID)
|
||||||
if post.Id == 0 {
|
if post.Id == 0 || err != nil {
|
||||||
er := common.QueryAndSetPostCache([]models.WpPosts{{Id: ID}})
|
return
|
||||||
if er != nil {
|
|
||||||
err = er
|
|
||||||
return
|
|
||||||
}
|
|
||||||
post = common.GetPostFromCache(ID)
|
|
||||||
if post.Id == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pw := sessions.Default(c).Get("post_password")
|
pw := sessions.Default(c).Get("post_password")
|
||||||
showComment := false
|
showComment := false
|
||||||
|
|
140
cache/map.go
vendored
140
cache/map.go
vendored
|
@ -9,12 +9,17 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type MapCache[K comparable, V any] struct {
|
type MapCache[K comparable, V any] struct {
|
||||||
data map[K]V
|
data map[K]mapCacheStruct[V]
|
||||||
mutex *sync.Mutex
|
mutex *sync.Mutex
|
||||||
setCacheFunc func(...any) (V, error)
|
setCacheFunc func(...any) (V, error)
|
||||||
expireTime time.Duration
|
setBatchCacheFn func(...any) (map[K]V, error)
|
||||||
setTime time.Time
|
expireTime time.Duration
|
||||||
incr int
|
}
|
||||||
|
|
||||||
|
type mapCacheStruct[T any] struct {
|
||||||
|
setTime time.Time
|
||||||
|
incr int
|
||||||
|
data T
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMapCache[K comparable, V any](fun func(...any) (V, error), expireTime time.Duration) *MapCache[K, V] {
|
func NewMapCache[K comparable, V any](fun func(...any) (V, error), expireTime time.Duration) *MapCache[K, V] {
|
||||||
|
@ -22,41 +27,79 @@ func NewMapCache[K comparable, V any](fun func(...any) (V, error), expireTime ti
|
||||||
mutex: &sync.Mutex{},
|
mutex: &sync.Mutex{},
|
||||||
setCacheFunc: fun,
|
setCacheFunc: fun,
|
||||||
expireTime: expireTime,
|
expireTime: expireTime,
|
||||||
data: make(map[K]V),
|
data: make(map[K]mapCacheStruct[V]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func NewMapBatchCache[K comparable, V any](fn func(...any) (map[K]V, error), expireTime time.Duration) *MapCache[K, V] {
|
||||||
|
return &MapCache[K, V]{
|
||||||
|
mutex: &sync.Mutex{},
|
||||||
|
setBatchCacheFn: fn,
|
||||||
|
expireTime: expireTime,
|
||||||
|
data: make(map[K]mapCacheStruct[V]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *MapCache[K, V]) FlushCache(k any) {
|
func (m *MapCache[K, V]) FlushCache(k any) {
|
||||||
c.mutex.Lock()
|
m.mutex.Lock()
|
||||||
defer c.mutex.Unlock()
|
defer m.mutex.Unlock()
|
||||||
key := k.(K)
|
key := k.(K)
|
||||||
delete(c.data, key)
|
delete(m.data, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *MapCache[K, V]) GetCache(ctx context.Context, key K, timeout time.Duration, params ...any) (V, error) {
|
func (m *MapCache[K, V]) Get(k K) V {
|
||||||
_, ok := c.data[key]
|
return m.data[k].data
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MapCache[K, V]) Set(k K, v V) {
|
||||||
|
m.mutex.Lock()
|
||||||
|
defer m.mutex.Unlock()
|
||||||
|
m.set(k, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MapCache[K, V]) set(k K, v V) {
|
||||||
|
data, ok := m.data[k]
|
||||||
|
t := time.Now()
|
||||||
|
if !ok {
|
||||||
|
data.data = v
|
||||||
|
data.setTime = t
|
||||||
|
data.incr++
|
||||||
|
m.data[k] = data
|
||||||
|
} else {
|
||||||
|
m.data[k] = mapCacheStruct[V]{
|
||||||
|
data: v,
|
||||||
|
setTime: t,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MapCache[K, V]) GetCache(c context.Context, key K, timeout time.Duration, params ...any) (V, error) {
|
||||||
|
data, ok := m.data[key]
|
||||||
|
if !ok {
|
||||||
|
data = mapCacheStruct[V]{}
|
||||||
|
}
|
||||||
var err error
|
var err error
|
||||||
expired := time.Duration(c.setTime.Unix())+c.expireTime/time.Second < time.Duration(time.Now().Unix())
|
expired := time.Duration(data.setTime.Unix())+m.expireTime/time.Second < time.Duration(time.Now().Unix())
|
||||||
//todo 这里应该判断下取出的值是否为零值,不过怎么操作呢?
|
//todo 这里应该判断下取出的值是否为零值,不过怎么操作呢?
|
||||||
if !ok || (c.expireTime >= 0 && expired) {
|
if !ok || (ok && m.expireTime >= 0 && expired) {
|
||||||
t := c.incr
|
t := data.incr
|
||||||
call := func() {
|
call := func() {
|
||||||
c.mutex.Lock()
|
m.mutex.Lock()
|
||||||
defer c.mutex.Unlock()
|
defer m.mutex.Unlock()
|
||||||
if c.incr > t {
|
if data.incr > t {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
r, er := c.setCacheFunc(params...)
|
r, er := m.setCacheFunc(params...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = er
|
err = er
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.setTime = time.Now()
|
data.setTime = time.Now()
|
||||||
c.data[key] = r
|
data.data = r
|
||||||
c.incr++
|
m.data[key] = data
|
||||||
|
data.incr++
|
||||||
}
|
}
|
||||||
if timeout > 0 {
|
if timeout > 0 {
|
||||||
ctx, cancel := context.WithTimeout(ctx, timeout)
|
ctx, cancel := context.WithTimeout(c, timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
go func() {
|
go func() {
|
||||||
|
@ -73,5 +116,52 @@ func (c *MapCache[K, V]) GetCache(ctx context.Context, key K, timeout time.Durat
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return c.data[key], err
|
return data.data, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MapCache[K, V]) GetCacheBatch(c context.Context, key K, timeout time.Duration, params ...any) (V, error) {
|
||||||
|
data, ok := m.data[key]
|
||||||
|
if !ok {
|
||||||
|
data = mapCacheStruct[V]{}
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
expired := time.Duration(data.setTime.Unix())+m.expireTime/time.Second < time.Duration(time.Now().Unix())
|
||||||
|
//todo 这里应该判断下取出的值是否为零值,不过怎么操作呢?
|
||||||
|
if !ok || (ok && m.expireTime >= 0 && expired) {
|
||||||
|
t := data.incr
|
||||||
|
call := func() {
|
||||||
|
m.mutex.Lock()
|
||||||
|
defer m.mutex.Unlock()
|
||||||
|
if data.incr > t {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r, er := m.setBatchCacheFn(params...)
|
||||||
|
if err != nil {
|
||||||
|
err = er
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for k, v := range r {
|
||||||
|
m.set(k, v)
|
||||||
|
}
|
||||||
|
data.data = m.data[key].data
|
||||||
|
}
|
||||||
|
if timeout > 0 {
|
||||||
|
ctx, cancel := context.WithTimeout(c, timeout)
|
||||||
|
defer cancel()
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
call()
|
||||||
|
done <- struct{}{}
|
||||||
|
}()
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
err = errors.New(fmt.Sprintf("get cache %v %s", key, ctx.Err().Error()))
|
||||||
|
case <-done:
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
call()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return data.data, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,10 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func ToAny[T any](v T) any {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
func IsContainInArr[T comparable](a T, arr []T) bool {
|
func IsContainInArr[T comparable](a T, arr []T) bool {
|
||||||
for _, v := range arr {
|
for _, v := range arr {
|
||||||
if a == v {
|
if a == v {
|
||||||
|
|
|
@ -449,3 +449,27 @@ func TestSliceReverse(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestToInterface(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
v int
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want any
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "t1",
|
||||||
|
args: args{v: 1},
|
||||||
|
want: any(1),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if got := ToAny(tt.args.v); !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("ToAny() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
4
main.go
4
main.go
|
@ -30,8 +30,8 @@ func init() {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
common.InitCache()
|
common.InitActionsCommonCache()
|
||||||
plugins.InitDigest()
|
plugins.InitDigestCache()
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
@ -18,8 +18,8 @@ var more = regexp.MustCompile("<!--more(.*?)?-->")
|
||||||
var digestCache *cache.MapCache[uint64, string]
|
var digestCache *cache.MapCache[uint64, string]
|
||||||
var quto = regexp.MustCompile(`" *|& *|< *|> ?| *`)
|
var quto = regexp.MustCompile(`" *|& *|< *|> ?| *`)
|
||||||
|
|
||||||
func InitDigest() {
|
func InitDigestCache() {
|
||||||
digestCache = cache.NewMapCache[uint64](digestRaw, time.Second)
|
digestCache = cache.NewMapCache[uint64](digestRaw, vars.Conf.DigestCacheTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
func digestRaw(arg ...any) (string, error) {
|
func digestRaw(arg ...any) (string, error) {
|
||||||
|
@ -108,6 +108,5 @@ func Digest(p *Plugin[models.WpPosts], c *gin.Context, post *models.WpPosts, sce
|
||||||
if scene == Detail {
|
if scene == Detail {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//post.PostContent = DigestCache(c, post.Id, post.PostContent)
|
post.PostContent = DigestCache(c, post.Id, post.PostContent)
|
||||||
post.PostContent = DigestRaw(post.PostContent, vars.Conf.DigestWordCount, post.Id)
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user