owpengram-server/internal/rpc/story_pinned_cache.go

60 lines
1.8 KiB
Go

package rpc
import (
"context"
"time"
"telesrv/internal/domain"
"telesrv/internal/readmodelcache"
)
// storyPinnedAvailableCache 缓存 (viewer,peer)→是否有置顶故事,由统一缓存原语承载
// (LRU 单条驱逐 / epoch 守卫 / 内建 singleflight;纯 TTL,无版本闸门)。
type storyPinnedAvailableCache struct {
cache *readmodelcache.Cache[storyProjectionCacheKey, bool]
}
func newStoryPinnedAvailableCache(now func() time.Time) *storyPinnedAvailableCache {
return &storyPinnedAvailableCache{
cache: readmodelcache.New[storyProjectionCacheKey, bool](readmodelcache.Config[storyProjectionCacheKey, bool]{
MaxEntries: storyProjectionCacheMaxEntries,
TTL: storyPinnedStoriesCacheTTL,
Now: now,
}),
}
}
func (c *storyPinnedAvailableCache) getOrLoad(ctx context.Context, viewerUserID int64, peer domain.Peer, load func() (bool, error)) (bool, error) {
if c == nil || viewerUserID == 0 || peer.ID == 0 {
return load()
}
return c.cache.GetOrLoad(ctx, storyProjectionCacheKey{viewerUserID: viewerUserID, peer: peer}, load)
}
func (c *storyPinnedAvailableCache) Delete(viewerUserID int64, peer domain.Peer) {
if c == nil || viewerUserID == 0 || peer.ID == 0 {
return
}
c.cache.Invalidate(storyProjectionCacheKey{viewerUserID: viewerUserID, peer: peer})
}
func (c *storyPinnedAvailableCache) DeleteViewer(viewerUserID int64) {
if c == nil || viewerUserID == 0 {
return
}
c.cache.InvalidateWhere(func(k storyProjectionCacheKey) bool { return k.viewerUserID == viewerUserID })
}
func (c *storyPinnedAvailableCache) DeletePeer(peer domain.Peer) {
if c == nil || peer.ID == 0 {
return
}
c.cache.InvalidateWhere(func(k storyProjectionCacheKey) bool { return k.peer == peer })
}
func (c *storyPinnedAvailableCache) Flush() {
if c == nil {
return
}
c.cache.Flush()
}