完善缓存
This commit is contained in:
parent
086de50dcf
commit
fa7fc10a6c
|
@ -5,6 +5,7 @@ import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github/fthvgb1/wp-go/cache"
|
"github/fthvgb1/wp-go/cache"
|
||||||
|
"github/fthvgb1/wp-go/helper"
|
||||||
"github/fthvgb1/wp-go/logs"
|
"github/fthvgb1/wp-go/logs"
|
||||||
"github/fthvgb1/wp-go/models"
|
"github/fthvgb1/wp-go/models"
|
||||||
"github/fthvgb1/wp-go/vars"
|
"github/fthvgb1/wp-go/vars"
|
||||||
|
@ -20,6 +21,7 @@ var recentPostsCaches *cache.SliceCache[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]
|
var postsCache *cache.MapCache[uint64, models.WpPosts]
|
||||||
|
var monthPostsCache *cache.MapCache[string, []uint64]
|
||||||
|
|
||||||
func InitActionsCommonCache() {
|
func InitActionsCommonCache() {
|
||||||
archivesCaches = &Arch{
|
archivesCaches = &Arch{
|
||||||
|
@ -27,9 +29,12 @@ func InitActionsCommonCache() {
|
||||||
setCacheFunc: archives,
|
setCacheFunc: archives,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
monthPostsCache = cache.NewMapCache[string, []uint64](monthPost, time.Hour)
|
||||||
|
|
||||||
postContextCache = cache.NewMapCache[uint64, PostContext](getPostContext, vars.Conf.ContextPostCacheTime)
|
postContextCache = cache.NewMapCache[uint64, PostContext](getPostContext, vars.Conf.ContextPostCacheTime)
|
||||||
|
|
||||||
postsCache = cache.NewMapBatchCache[uint64, models.WpPosts](getPosts, time.Hour)
|
postsCache = cache.NewMapBatchCache[uint64, models.WpPosts](getPosts, time.Hour)
|
||||||
|
postsCache.SetCacheFunc(getPost)
|
||||||
|
|
||||||
categoryCaches = cache.NewSliceCache[models.WpTermsMy](categories, vars.Conf.CategoryCacheTime)
|
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)
|
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 {
|
type Arch struct {
|
||||||
data []models.PostArchive
|
data []models.PostArchive
|
||||||
mutex *sync.Mutex
|
mutex *sync.Mutex
|
||||||
|
|
|
@ -9,15 +9,19 @@ import (
|
||||||
"time"
|
"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 {
|
func GetPost(id uint64) models.WpPosts {
|
||||||
return postsCache.Get(id)
|
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 {
|
func SetPostCache(ids []models.WpPosts) error {
|
||||||
var arg []uint64
|
var arg []uint64
|
||||||
for _, posts := range ids {
|
for _, posts := range ids {
|
||||||
|
@ -26,6 +30,16 @@ func SetPostCache(ids []models.WpPosts) error {
|
||||||
return postsCache.SetByBatchFn(arg)
|
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) {
|
func getPosts(ids ...any) (m map[uint64]models.WpPosts, err error) {
|
||||||
m = make(map[uint64]models.WpPosts)
|
m = make(map[uint64]models.WpPosts)
|
||||||
id := ids[0].([]uint64)
|
id := ids[0].([]uint64)
|
||||||
|
|
|
@ -56,7 +56,7 @@ func Detail(c *gin.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ID := uint64(Id)
|
ID := uint64(Id)
|
||||||
post, err := common.GetPostAndCache(c, ID, ID)
|
post, err := common.GetPostAndCache(c, ID)
|
||||||
if post.Id == 0 || err != nil {
|
if post.Id == 0 || err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -168,12 +168,25 @@ func Index(c *gin.Context) {
|
||||||
"title": h.getTitle(),
|
"title": h.getTitle(),
|
||||||
"recentComments": recentComments,
|
"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() {
|
defer func() {
|
||||||
c.HTML(http.StatusOK, "posts/index.gohtml", ginH)
|
stat := http.StatusOK
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Error(err)
|
c.Error(err)
|
||||||
|
stat = http.StatusInternalServerError
|
||||||
}
|
}
|
||||||
|
c.HTML(stat, "posts/index.gohtml", ginH)
|
||||||
}()
|
}()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -181,10 +194,7 @@ func Index(c *gin.Context) {
|
||||||
if len(postIds) < 1 && h.category != "" {
|
if len(postIds) < 1 && h.category != "" {
|
||||||
h.titleL = "未找到页面"
|
h.titleL = "未找到页面"
|
||||||
}
|
}
|
||||||
err = common.SetPostCache(postIds)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
pw := h.session.Get("post_password")
|
pw := h.session.Get("post_password")
|
||||||
plug := plugins.NewPostPlugin(c, h.scene)
|
plug := plugins.NewPostPlugin(c, h.scene)
|
||||||
for i, v := range postIds {
|
for i, v := range postIds {
|
||||||
|
@ -203,6 +213,9 @@ func Index(c *gin.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
q := c.Request.URL.Query().Encode()
|
q := c.Request.URL.Query().Encode()
|
||||||
|
if q != "" {
|
||||||
|
q = fmt.Sprintf("?%s", q)
|
||||||
|
}
|
||||||
ginH["posts"] = postIds
|
ginH["posts"] = postIds
|
||||||
ginH["totalPage"] = h.getTotalPage(totalRaw)
|
ginH["totalPage"] = h.getTotalPage(totalRaw)
|
||||||
ginH["pagination"] = pagination(h.page, h.totalPage, h.paginationStep, c.Request.URL.Path, q)
|
ginH["pagination"] = pagination(h.page, h.totalPage, h.paginationStep, c.Request.URL.Path, q)
|
||||||
|
|
45
cache/map.go
vendored
45
cache/map.go
vendored
|
@ -22,6 +22,14 @@ type mapCacheStruct[T any] struct {
|
||||||
data T
|
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] {
|
func NewMapCache[K comparable, V any](fun func(...any) (V, error), expireTime time.Duration) *MapCache[K, V] {
|
||||||
return &MapCache[K, V]{
|
return &MapCache[K, V]{
|
||||||
mutex: &sync.Mutex{},
|
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
|
return data.data, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MapCache[K, V]) GetCacheBatch(c context.Context, key K, timeout time.Duration, params ...any) (V, error) {
|
func (m *MapCache[K, V]) GetCacheBatch(c context.Context, key []K, timeout time.Duration, params ...any) ([]V, error) {
|
||||||
data, ok := m.data[key]
|
var needFlush []K
|
||||||
|
var res []V
|
||||||
|
t := 0
|
||||||
|
for _, k := range key {
|
||||||
|
d, ok := m.data[k]
|
||||||
if !ok {
|
if !ok {
|
||||||
data = mapCacheStruct[V]{}
|
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
|
var err error
|
||||||
expired := time.Duration(data.setTime.Unix())+m.expireTime/time.Second < time.Duration(time.Now().Unix())
|
|
||||||
//todo 这里应该判断下取出的值是否为零值,不过怎么操作呢?
|
//todo 这里应该判断下取出的值是否为零值,不过怎么操作呢?
|
||||||
if !ok || (ok && m.expireTime >= 0 && expired) {
|
if len(needFlush) > 0 {
|
||||||
t := data.incr
|
|
||||||
call := func() {
|
call := func() {
|
||||||
m.mutex.Lock()
|
m.mutex.Lock()
|
||||||
defer m.mutex.Unlock()
|
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
|
return
|
||||||
}
|
}
|
||||||
r, er := m.setBatchCacheFn(params...)
|
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 {
|
for k, v := range r {
|
||||||
m.set(k, v)
|
m.set(k, v)
|
||||||
}
|
}
|
||||||
data.data = m.data[key].data
|
|
||||||
}
|
}
|
||||||
if timeout > 0 {
|
if timeout > 0 {
|
||||||
ctx, cancel := context.WithTimeout(c, timeout)
|
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 {
|
} else {
|
||||||
call()
|
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 {
|
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)
|
l := int((end-start+1)/step + 1)
|
||||||
if l < 0 {
|
if l < 0 {
|
||||||
l = 0 - l
|
l = 0 - l
|
||||||
|
@ -218,3 +221,12 @@ func SliceReverse[T any](arr []T) []T {
|
||||||
}
|
}
|
||||||
return r
|
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