chore: refresh gramsrv public release
This commit is contained in:
parent
75cebe8dbf
commit
70b6820474
1274 changed files with 378751 additions and 59919 deletions
134
internal/app/channels/media_count_cache.go
Normal file
134
internal/app/channels/media_count_cache.go
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
package channels
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"telesrv/internal/app/readmodel"
|
||||
"telesrv/internal/domain"
|
||||
"telesrv/internal/readmodelcache"
|
||||
"telesrv/internal/store"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultMediaCountReadModelTTL = 24 * time.Hour
|
||||
mediaCountReadModelMaxEntries = 8192
|
||||
)
|
||||
|
||||
type mediaCountCacheKey struct {
|
||||
userID int64
|
||||
channelID int64
|
||||
}
|
||||
|
||||
// mediaCountReadModelCache 由统一缓存原语承载(版本闸门 / epoch 守卫 / LRU / clone)。
|
||||
type mediaCountReadModelCache struct {
|
||||
cache *readmodelcache.Cache[mediaCountCacheKey, domain.MediaCategoryCounts]
|
||||
}
|
||||
|
||||
func newMediaCountReadModelCache(ttl time.Duration) *mediaCountReadModelCache {
|
||||
if ttl <= 0 {
|
||||
ttl = defaultMediaCountReadModelTTL
|
||||
}
|
||||
return &mediaCountReadModelCache{
|
||||
cache: readmodelcache.New[mediaCountCacheKey, domain.MediaCategoryCounts](readmodelcache.Config[mediaCountCacheKey, domain.MediaCategoryCounts]{
|
||||
MaxEntries: mediaCountReadModelMaxEntries,
|
||||
TTL: ttl,
|
||||
Clone: cloneMediaCategoryCounts,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *mediaCountReadModelCache) getOrLoad(ctx context.Context, key mediaCountCacheKey, hash int64, load func() (domain.MediaCategoryCounts, error)) (domain.MediaCategoryCounts, error) {
|
||||
if c == nil {
|
||||
return load()
|
||||
}
|
||||
return c.cache.GetOrLoadVersioned(ctx, key, hash, load)
|
||||
}
|
||||
|
||||
func (c *mediaCountReadModelCache) invalidateChannel(channelID int64) {
|
||||
if c == nil || c.cache == nil || channelID == 0 {
|
||||
return
|
||||
}
|
||||
c.cache.InvalidateWhere(func(key mediaCountCacheKey) bool {
|
||||
return key.channelID == channelID
|
||||
})
|
||||
}
|
||||
|
||||
func (c *mediaCountReadModelCache) invalidateViewer(userID, channelID int64) {
|
||||
if c == nil || c.cache == nil || userID == 0 || channelID == 0 {
|
||||
return
|
||||
}
|
||||
c.cache.Invalidate(mediaCountCacheKey{userID: userID, channelID: channelID})
|
||||
}
|
||||
|
||||
func (c *mediaCountReadModelCache) flush() {
|
||||
if c == nil || c.cache == nil {
|
||||
return
|
||||
}
|
||||
c.cache.Flush()
|
||||
}
|
||||
|
||||
func (s *Service) InvalidateChannelMediaCountReadModel(channelID int64) {
|
||||
if s == nil || s.mediaCountCache == nil {
|
||||
return
|
||||
}
|
||||
s.mediaCountCache.invalidateChannel(channelID)
|
||||
}
|
||||
|
||||
func (s *Service) InvalidateChannelMediaCountReadModelForViewer(userID, channelID int64) {
|
||||
if s == nil || s.mediaCountCache == nil {
|
||||
return
|
||||
}
|
||||
s.mediaCountCache.invalidateViewer(userID, channelID)
|
||||
}
|
||||
|
||||
func (s *Service) FlushChannelMediaCountReadModel() {
|
||||
if s == nil || s.mediaCountCache == nil {
|
||||
return
|
||||
}
|
||||
s.mediaCountCache.flush()
|
||||
}
|
||||
|
||||
func (s *Service) cachedChannelMediaCounts(ctx context.Context, userID, channelID int64) (domain.MediaCategoryCounts, error) {
|
||||
if s.mediaCountCache == nil || s.versions == nil {
|
||||
return s.channels.CountChannelMediaCategories(ctx, userID, channelID)
|
||||
}
|
||||
hash, err := s.channelMediaCountHash(ctx, userID, channelID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if hash == 0 {
|
||||
return s.channels.CountChannelMediaCategories(ctx, userID, channelID)
|
||||
}
|
||||
key := mediaCountCacheKey{userID: userID, channelID: channelID}
|
||||
return s.mediaCountCache.getOrLoad(ctx, key, hash, func() (domain.MediaCategoryCounts, error) {
|
||||
return s.channels.CountChannelMediaCategories(ctx, userID, channelID)
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Service) channelMediaCountHash(ctx context.Context, userID, channelID int64) (int64, error) {
|
||||
keys := []store.ReadModelKey{
|
||||
{Model: readmodel.ModelChannelMediaCounts, OwnerUserID: 0, PeerType: domain.PeerTypeChannel, PeerID: channelID},
|
||||
{Model: readmodel.ModelChannelMember, OwnerUserID: userID, PeerType: domain.PeerTypeChannel, PeerID: channelID},
|
||||
}
|
||||
rows, err := s.versions.ReadModelHashes(ctx, keys)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
media := rows[keys[0]]
|
||||
if media == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
return readmodel.MixHashes(media, rows[keys[1]]), nil
|
||||
}
|
||||
|
||||
func cloneMediaCategoryCounts(in domain.MediaCategoryCounts) domain.MediaCategoryCounts {
|
||||
if len(in) == 0 {
|
||||
return domain.MediaCategoryCounts{}
|
||||
}
|
||||
out := make(domain.MediaCategoryCounts, len(in))
|
||||
for category, count := range in {
|
||||
out[category] = count
|
||||
}
|
||||
return out
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue