完善缓存
This commit is contained in:
parent
086de50dcf
commit
fa7fc10a6c
|
@ -5,6 +5,7 @@ import (
|
|||
"database/sql"
|
||||
"fmt"
|
||||
"github/fthvgb1/wp-go/cache"
|
||||
"github/fthvgb1/wp-go/helper"
|
||||
"github/fthvgb1/wp-go/logs"
|
||||
"github/fthvgb1/wp-go/models"
|
||||
"github/fthvgb1/wp-go/vars"
|
||||
|
@ -20,6 +21,7 @@ var recentPostsCaches *cache.SliceCache[models.WpPosts]
|
|||
var recentCommentsCaches *cache.SliceCache[models.WpComments]
|
||||
var postCommentCaches *cache.MapCache[uint64, []models.WpComments]
|
||||
var postsCache *cache.MapCache[uint64, models.WpPosts]
|
||||
var monthPostsCache *cache.MapCache[string, []uint64]
|
||||
|
||||
func InitActionsCommonCache() {
|
||||
archivesCaches = &Arch{
|
||||
|
@ -27,9 +29,12 @@ func InitActionsCommonCache() {
|
|||
setCacheFunc: archives,
|
||||
}
|
||||
|
||||
monthPostsCache = cache.NewMapCache[string, []uint64](monthPost, time.Hour)
|
||||
|
||||
postContextCache = cache.NewMapCache[uint64, PostContext](getPostContext, vars.Conf.ContextPostCacheTime)
|
||||
|
||||
postsCache = cache.NewMapBatchCache[uint64, models.WpPosts](getPosts, time.Hour)
|
||||
postsCache.SetCacheFunc(getPost)
|
||||
|
||||
categoryCaches = cache.NewSliceCache[models.WpTermsMy](categories, vars.Conf.CategoryCacheTime)
|
||||
|
||||
|
@ -39,6 +44,45 @@ func InitActionsCommonCache() {
|
|||
postCommentCaches = cache.NewMapCache[uint64, []models.WpComments](postComments, time.Minute*5)
|
||||
}
|
||||
|
||||
func GetMonthPostIds(ctx context.Context, year, month string, page, limit int, order string) (r []models.WpPosts, total int, err error) {
|
||||
res, err := monthPostsCache.GetCache(ctx, fmt.Sprintf("%s%s", year, month), time.Second, year, month)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if order == "desc" {
|
||||
res = helper.SliceReverse(res)
|
||||
}
|
||||
total = len(res)
|
||||
rr := helper.SlicePagination(res, page, limit)
|
||||
r, err = GetPosts(ctx, rr)
|
||||
return
|
||||
}
|
||||
|
||||
func monthPost(args ...any) (r []uint64, err error) {
|
||||
year, month := args[0].(string), args[1].(string)
|
||||
where := models.SqlBuilder{
|
||||
{"post_type", "in", ""},
|
||||
{"post_status", "in", ""},
|
||||
{"year(post_date)", year},
|
||||
{"month(post_date)", month},
|
||||
}
|
||||
postType := []any{"post"}
|
||||
status := []any{"publish"}
|
||||
ids, err := models.Find[models.WpPosts](where, "ID", "", models.SqlBuilder{{"Id", "asc"}}, nil, 0, postType, status)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, post := range ids {
|
||||
r = append(r, post.Id)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type PostIds struct {
|
||||
Ids []uint64
|
||||
Length int
|
||||
}
|
||||
|
||||
type Arch struct {
|
||||
data []models.PostArchive
|
||||
mutex *sync.Mutex
|
||||
|
|
|
@ -9,15 +9,19 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
func GetPostAndCache(ctx context.Context, id uint64, ids ...uint64) (models.WpPosts, error) {
|
||||
func GetPostAndCache(ctx context.Context, id uint64) (models.WpPosts, error) {
|
||||
|
||||
return postsCache.GetCacheBatch(ctx, id, time.Second, ids)
|
||||
return postsCache.GetCache(ctx, id, time.Second, id)
|
||||
}
|
||||
|
||||
func GetPost(id uint64) models.WpPosts {
|
||||
return postsCache.Get(id)
|
||||
}
|
||||
|
||||
func GetPosts(ctx context.Context, ids []uint64) ([]models.WpPosts, error) {
|
||||
return postsCache.GetCacheBatch(ctx, ids, time.Second, ids)
|
||||
}
|
||||
|
||||
func SetPostCache(ids []models.WpPosts) error {
|
||||
var arg []uint64
|
||||
for _, posts := range ids {
|
||||
|
@ -26,6 +30,16 @@ func SetPostCache(ids []models.WpPosts) error {
|
|||
return postsCache.SetByBatchFn(arg)
|
||||
}
|
||||
|
||||
func getPost(id ...any) (post models.WpPosts, err error) {
|
||||
Id := id[0].(uint64)
|
||||
posts, err := getPosts([]uint64{Id})
|
||||
if err != nil {
|
||||
return models.WpPosts{}, err
|
||||
}
|
||||
post = posts[Id]
|
||||
return
|
||||
}
|
||||
|
||||
func getPosts(ids ...any) (m map[uint64]models.WpPosts, err error) {
|
||||
m = make(map[uint64]models.WpPosts)
|
||||
id := ids[0].([]uint64)
|
||||
|
|
|
@ -56,7 +56,7 @@ func Detail(c *gin.Context) {
|
|||
}
|
||||
}
|
||||
ID := uint64(Id)
|
||||
post, err := common.GetPostAndCache(c, ID, ID)
|
||||
post, err := common.GetPostAndCache(c, ID)
|
||||
if post.Id == 0 || err != nil {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -168,12 +168,25 @@ func Index(c *gin.Context) {
|
|||
"title": h.getTitle(),
|
||||
"recentComments": recentComments,
|
||||
}
|
||||
postIds, totalRaw, err := models.SimplePagination[models.WpPosts](h.where, "ID", "", h.page, h.pageSize, h.orderBy, h.join, h.postType, h.status)
|
||||
var postIds []models.WpPosts
|
||||
var totalRaw int
|
||||
var err error
|
||||
if c.Param("month") != "" {
|
||||
postIds, totalRaw, err = common.GetMonthPostIds(c, c.Param("year"), c.Param("month"), h.page, h.pageSize, h.order)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
postIds, totalRaw, err = models.SimplePagination[models.WpPosts](h.where, "ID", "", h.page, h.pageSize, h.orderBy, h.join, h.postType, h.status)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
c.HTML(http.StatusOK, "posts/index.gohtml", ginH)
|
||||
stat := http.StatusOK
|
||||
if err != nil {
|
||||
c.Error(err)
|
||||
stat = http.StatusInternalServerError
|
||||
}
|
||||
c.HTML(stat, "posts/index.gohtml", ginH)
|
||||
}()
|
||||
if err != nil {
|
||||
return
|
||||
|
@ -181,10 +194,7 @@ func Index(c *gin.Context) {
|
|||
if len(postIds) < 1 && h.category != "" {
|
||||
h.titleL = "未找到页面"
|
||||
}
|
||||
err = common.SetPostCache(postIds)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
pw := h.session.Get("post_password")
|
||||
plug := plugins.NewPostPlugin(c, h.scene)
|
||||
for i, v := range postIds {
|
||||
|
@ -203,6 +213,9 @@ func Index(c *gin.Context) {
|
|||
}
|
||||
}
|
||||
q := c.Request.URL.Query().Encode()
|
||||
if q != "" {
|
||||
q = fmt.Sprintf("?%s", q)
|
||||
}
|
||||
ginH["posts"] = postIds
|
||||
ginH["totalPage"] = h.getTotalPage(totalRaw)
|
||||
ginH["pagination"] = pagination(h.page, h.totalPage, h.paginationStep, c.Request.URL.Path, q)
|
||||
|
|
47
cache/map.go
vendored
47
cache/map.go
vendored
|
@ -22,6 +22,14 @@ type mapCacheStruct[T any] struct {
|
|||
data T
|
||||
}
|
||||
|
||||
func (m *MapCache[K, V]) SetCacheFunc(fn func(...any) (V, error)) {
|
||||
m.setCacheFunc = fn
|
||||
}
|
||||
|
||||
func (m *MapCache[K, V]) SetCacheBatchFunc(fn func(...any) (map[K]V, error)) {
|
||||
m.setBatchCacheFn = fn
|
||||
}
|
||||
|
||||
func NewMapCache[K comparable, V any](fun func(...any) (V, error), expireTime time.Duration) *MapCache[K, V] {
|
||||
return &MapCache[K, V]{
|
||||
mutex: &sync.Mutex{},
|
||||
|
@ -133,20 +141,35 @@ func (m *MapCache[K, V]) GetCache(c context.Context, key K, timeout time.Duratio
|
|||
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]{}
|
||||
func (m *MapCache[K, V]) GetCacheBatch(c context.Context, key []K, timeout time.Duration, params ...any) ([]V, error) {
|
||||
var needFlush []K
|
||||
var res []V
|
||||
t := 0
|
||||
for _, k := range key {
|
||||
d, ok := m.data[k]
|
||||
if !ok {
|
||||
needFlush = append(needFlush, k)
|
||||
continue
|
||||
}
|
||||
expired := time.Duration(d.setTime.Unix())+m.expireTime/time.Second < time.Duration(time.Now().Unix())
|
||||
if expired {
|
||||
needFlush = append(needFlush, k)
|
||||
}
|
||||
t = t + d.incr
|
||||
}
|
||||
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
|
||||
if len(needFlush) > 0 {
|
||||
call := func() {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
if data.incr > t {
|
||||
tt := 0
|
||||
for _, dd := range needFlush {
|
||||
if ddd, ok := m.data[dd]; ok {
|
||||
tt = tt + ddd.incr
|
||||
}
|
||||
}
|
||||
if tt > t {
|
||||
return
|
||||
}
|
||||
r, er := m.setBatchCacheFn(params...)
|
||||
|
@ -157,7 +180,6 @@ func (m *MapCache[K, V]) GetCacheBatch(c context.Context, key K, timeout time.Du
|
|||
for k, v := range r {
|
||||
m.set(k, v)
|
||||
}
|
||||
data.data = m.data[key].data
|
||||
}
|
||||
if timeout > 0 {
|
||||
ctx, cancel := context.WithTimeout(c, timeout)
|
||||
|
@ -175,7 +197,10 @@ func (m *MapCache[K, V]) GetCacheBatch(c context.Context, key K, timeout time.Du
|
|||
} else {
|
||||
call()
|
||||
}
|
||||
|
||||
}
|
||||
return data.data, err
|
||||
for _, k := range key {
|
||||
d := m.data[k]
|
||||
res = append(res, d.data)
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
|
|
|
@ -34,6 +34,9 @@ func StructColumn[T any, M any](arr []M, field string) (r []T) {
|
|||
}
|
||||
|
||||
func RangeSlice[T ~int | ~uint | ~int64 | ~int8 | ~int16 | ~int32 | ~uint64](start, end, step T) []T {
|
||||
if step == 0 {
|
||||
panic("step can't be 0")
|
||||
}
|
||||
l := int((end-start+1)/step + 1)
|
||||
if l < 0 {
|
||||
l = 0 - l
|
||||
|
@ -218,3 +221,12 @@ func SliceReverse[T any](arr []T) []T {
|
|||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func SliceSelfReverse[T any](arr []T) []T {
|
||||
l := len(arr)
|
||||
half := l / 2
|
||||
for i := 0; i < half; i++ {
|
||||
arr[i], arr[l-i-1] = arr[l-i-1], arr[i]
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
|
|
@ -473,3 +473,35 @@ func TestToInterface(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSliceSelfReverse(t *testing.T) {
|
||||
type args struct {
|
||||
arr []int
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want []int
|
||||
}{
|
||||
{
|
||||
name: "t1",
|
||||
args: args{
|
||||
arr: RangeSlice(1, 10, 1),
|
||||
},
|
||||
want: RangeSlice(10, 1, -1),
|
||||
}, {
|
||||
name: "t2",
|
||||
args: args{
|
||||
arr: RangeSlice(1, 9, 1),
|
||||
},
|
||||
want: RangeSlice(9, 1, -1),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := SliceSelfReverse(tt.args.arr); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("SliceSelfReverse() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user