74 lines
2.3 KiB
Go
74 lines
2.3 KiB
Go
package channels
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"telesrv/internal/app/readmodel"
|
|
"telesrv/internal/domain"
|
|
"telesrv/internal/readmodelcache"
|
|
"telesrv/internal/store"
|
|
)
|
|
|
|
const (
|
|
defaultChannelResolveReadModelTTL = 24 * time.Hour
|
|
channelResolveReadModelMaxEntries = 16384
|
|
)
|
|
|
|
// channelResolveReadModelCache 由统一缓存原语承载(版本闸门 / epoch 守卫 / LRU / clone)。
|
|
type channelResolveReadModelCache struct {
|
|
cache *readmodelcache.Cache[channelViewCacheKey, domain.ChannelView]
|
|
}
|
|
|
|
func newChannelResolveReadModelCache(ttl time.Duration) *channelResolveReadModelCache {
|
|
if ttl <= 0 {
|
|
ttl = defaultChannelResolveReadModelTTL
|
|
}
|
|
return &channelResolveReadModelCache{
|
|
cache: readmodelcache.New[channelViewCacheKey, domain.ChannelView](readmodelcache.Config[channelViewCacheKey, domain.ChannelView]{
|
|
MaxEntries: channelResolveReadModelMaxEntries,
|
|
TTL: ttl,
|
|
Clone: cloneChannelView,
|
|
}),
|
|
}
|
|
}
|
|
|
|
func (c *channelResolveReadModelCache) getOrLoad(ctx context.Context, key channelViewCacheKey, hash int64, load func() (domain.ChannelView, error)) (domain.ChannelView, error) {
|
|
if c == nil {
|
|
return load()
|
|
}
|
|
return c.cache.GetOrLoadVersioned(ctx, key, hash, load)
|
|
}
|
|
|
|
func (s *Service) cachedResolveChannel(ctx context.Context, userID, channelID int64) (domain.ChannelView, error) {
|
|
if s.resolveCache == nil || s.versions == nil {
|
|
return s.channels.ResolveChannel(ctx, userID, channelID)
|
|
}
|
|
hash, err := s.channelResolveHash(ctx, userID, channelID)
|
|
if err != nil {
|
|
return domain.ChannelView{}, err
|
|
}
|
|
if hash == 0 {
|
|
return s.channels.ResolveChannel(ctx, userID, channelID)
|
|
}
|
|
key := channelViewCacheKey{userID: userID, channelID: channelID}
|
|
return s.resolveCache.getOrLoad(ctx, key, hash, func() (domain.ChannelView, error) {
|
|
return s.channels.ResolveChannel(ctx, userID, channelID)
|
|
})
|
|
}
|
|
|
|
func (s *Service) channelResolveHash(ctx context.Context, userID, channelID int64) (int64, error) {
|
|
keys := []store.ReadModelKey{
|
|
{Model: readmodel.ModelChannelBase, 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
|
|
}
|
|
base := rows[keys[0]]
|
|
if base == 0 {
|
|
return 0, nil
|
|
}
|
|
return readmodel.MixHashes(base, rows[keys[1]]), nil
|
|
}
|