完善map缓存,优化部分post缓存
This commit is contained in:
parent
528e8e9348
commit
10efcc9711
|
@ -20,18 +20,21 @@ var PostContextCache sync.Map
|
|||
var archivesCaches *Arch
|
||||
var categoryCaches *cache.SliceCache[models.WpTermsMy]
|
||||
var recentPostsCaches *cache.SliceCache[models.WpPosts]
|
||||
var monthCaches *cache.MapCache[string, []models.WpPosts]
|
||||
var recentCommentsCaches *cache.SliceCache[models.WpComments]
|
||||
var postCommentCaches *cache.MapCache[uint64, []models.WpComments]
|
||||
var postsCache *cache.MapCache[uint64, models.WpPosts]
|
||||
|
||||
func InitCache() {
|
||||
func InitActionsCommonCache() {
|
||||
archivesCaches = &Arch{
|
||||
mutex: &sync.Mutex{},
|
||||
setCacheFunc: archives,
|
||||
}
|
||||
postsCache = cache.NewMapBatchCache[uint64, models.WpPosts](getPosts, time.Hour)
|
||||
|
||||
categoryCaches = cache.NewSliceCache[models.WpTermsMy](categories, vars.Conf.CategoryCacheTime)
|
||||
|
||||
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)
|
||||
postCommentCaches = cache.NewMapCache[uint64, []models.WpComments](postComments, time.Minute*5)
|
||||
}
|
||||
|
@ -43,7 +46,7 @@ type Arch struct {
|
|||
month time.Month
|
||||
}
|
||||
|
||||
func (c *Arch) GetCache() []models.PostArchive {
|
||||
func (c *Arch) getArchiveCache() []models.PostArchive {
|
||||
l := len(c.data)
|
||||
m := time.Now().Month()
|
||||
if l > 0 && c.month != m || l < 1 {
|
||||
|
@ -67,10 +70,6 @@ type PostContext struct {
|
|||
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) {
|
||||
return postCommentCaches.GetCache(ctx, Id, time.Second, Id)
|
||||
}
|
||||
|
@ -151,14 +150,6 @@ func getPostContext(t time.Time) (prev, next models.WpPosts, err error) {
|
|||
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) {
|
||||
var all []uint64
|
||||
var needQuery []any
|
||||
|
@ -223,7 +214,7 @@ func archives() ([]models.PostArchive, error) {
|
|||
}
|
||||
|
||||
func Archives() (r []models.PostArchive) {
|
||||
return archivesCaches.GetCache()
|
||||
return archivesCaches.getArchiveCache()
|
||||
}
|
||||
|
||||
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,18 +55,10 @@ func Detail(c *gin.Context) {
|
|||
}
|
||||
}
|
||||
ID := uint64(Id)
|
||||
post := common.GetPostFromCache(ID)
|
||||
if post.Id == 0 {
|
||||
er := common.QueryAndSetPostCache([]models.WpPosts{{Id: ID}})
|
||||
if er != nil {
|
||||
err = er
|
||||
post, err := common.GetPostById(c, ID, ID)
|
||||
if post.Id == 0 || err != nil {
|
||||
return
|
||||
}
|
||||
post = common.GetPostFromCache(ID)
|
||||
if post.Id == 0 {
|
||||
return
|
||||
}
|
||||
}
|
||||
pw := sessions.Default(c).Get("post_password")
|
||||
showComment := false
|
||||
if post.CommentCount > 0 || post.CommentStatus == "open" {
|
||||
|
|
130
cache/map.go
vendored
130
cache/map.go
vendored
|
@ -9,12 +9,17 @@ import (
|
|||
)
|
||||
|
||||
type MapCache[K comparable, V any] struct {
|
||||
data map[K]V
|
||||
data map[K]mapCacheStruct[V]
|
||||
mutex *sync.Mutex
|
||||
setCacheFunc func(...any) (V, error)
|
||||
setBatchCacheFn func(...any) (map[K]V, error)
|
||||
expireTime time.Duration
|
||||
}
|
||||
|
||||
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] {
|
||||
|
@ -22,41 +27,79 @@ func NewMapCache[K comparable, V any](fun func(...any) (V, error), expireTime ti
|
|||
mutex: &sync.Mutex{},
|
||||
setCacheFunc: fun,
|
||||
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) {
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
func (m *MapCache[K, V]) FlushCache(k any) {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
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) {
|
||||
_, ok := c.data[key]
|
||||
func (m *MapCache[K, V]) Get(k K) V {
|
||||
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
|
||||
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 这里应该判断下取出的值是否为零值,不过怎么操作呢?
|
||||
if !ok || (c.expireTime >= 0 && expired) {
|
||||
t := c.incr
|
||||
if !ok || (ok && m.expireTime >= 0 && expired) {
|
||||
t := data.incr
|
||||
call := func() {
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
if c.incr > t {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
if data.incr > t {
|
||||
return
|
||||
}
|
||||
r, er := c.setCacheFunc(params...)
|
||||
r, er := m.setCacheFunc(params...)
|
||||
if err != nil {
|
||||
err = er
|
||||
return
|
||||
}
|
||||
c.setTime = time.Now()
|
||||
c.data[key] = r
|
||||
c.incr++
|
||||
data.setTime = time.Now()
|
||||
data.data = r
|
||||
m.data[key] = data
|
||||
data.incr++
|
||||
}
|
||||
if timeout > 0 {
|
||||
ctx, cancel := context.WithTimeout(ctx, timeout)
|
||||
ctx, cancel := context.WithTimeout(c, timeout)
|
||||
defer cancel()
|
||||
done := make(chan struct{})
|
||||
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"
|
||||
)
|
||||
|
||||
func ToAny[T any](v T) any {
|
||||
return v
|
||||
}
|
||||
|
||||
func IsContainInArr[T comparable](a T, arr []T) bool {
|
||||
for _, v := range arr {
|
||||
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)
|
||||
}
|
||||
|
||||
common.InitCache()
|
||||
plugins.InitDigest()
|
||||
common.InitActionsCommonCache()
|
||||
plugins.InitDigestCache()
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
|
|
@ -18,8 +18,8 @@ var more = regexp.MustCompile("<!--more(.*?)?-->")
|
|||
var digestCache *cache.MapCache[uint64, string]
|
||||
var quto = regexp.MustCompile(`" *|& *|< *|> ?| *`)
|
||||
|
||||
func InitDigest() {
|
||||
digestCache = cache.NewMapCache[uint64](digestRaw, time.Second)
|
||||
func InitDigestCache() {
|
||||
digestCache = cache.NewMapCache[uint64](digestRaw, vars.Conf.DigestCacheTime)
|
||||
}
|
||||
|
||||
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 {
|
||||
return
|
||||
}
|
||||
//post.PostContent = DigestCache(c, post.Id, post.PostContent)
|
||||
post.PostContent = DigestRaw(post.PostContent, vars.Conf.DigestWordCount, post.Id)
|
||||
post.PostContent = DigestCache(c, post.Id, post.PostContent)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user