Full Mattermost server source with integrated Community Enterprise features. Includes vendor directory for offline/air-gapped builds. Structure: - enterprise-impl/: Enterprise feature implementations - enterprise-community/: Init files that register implementations - enterprise/: Bridge imports (community_imports.go) - vendor/: All dependencies for offline builds Build (online): go build ./cmd/mattermost Build (offline/air-gapped): go build -mod=vendor ./cmd/mattermost 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
604 lines
23 KiB
Go
604 lines
23 KiB
Go
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
package localcachelayer
|
|
|
|
import (
|
|
"runtime"
|
|
"time"
|
|
|
|
"github.com/mattermost/mattermost/server/public/model"
|
|
"github.com/mattermost/mattermost/server/public/shared/mlog"
|
|
"github.com/mattermost/mattermost/server/v8/channels/store"
|
|
"github.com/mattermost/mattermost/server/v8/einterfaces"
|
|
"github.com/mattermost/mattermost/server/v8/platform/services/cache"
|
|
)
|
|
|
|
const (
|
|
ReactionCacheSize = 20000
|
|
ReactionCacheSec = 30 * 60
|
|
|
|
RoleCacheSize = 20000
|
|
RoleCacheSec = 30 * 60
|
|
|
|
SchemeCacheSize = 20000
|
|
SchemeCacheSec = 30 * 60
|
|
|
|
FileInfoCacheSize = 25000
|
|
FileInfoCacheSec = 30 * 60
|
|
|
|
ChannelGuestCountCacheSize = model.ChannelCacheSize
|
|
ChannelGuestCountCacheSec = 30 * 60
|
|
|
|
WebhookCacheSize = 25000
|
|
WebhookCacheSec = 15 * 60
|
|
|
|
EmojiCacheSize = 5000
|
|
EmojiCacheSec = 30 * 60
|
|
|
|
ChannelPinnedPostsCountsCacheSize = model.ChannelCacheSize
|
|
ChannelPinnedPostsCountsCacheSec = 30 * 60
|
|
AllChannelMembersForUserCacheSize = model.SessionCacheSize
|
|
AllChannelMembersForUserCacheDuration = 15 * time.Minute
|
|
|
|
AllChannelMembersNotifyPropsForChannelCacheSize = model.SessionCacheSize
|
|
AllChannelMembersNotifyPropsForChannelCacheDuration = 30 * time.Minute
|
|
|
|
ChannelCacheDuration = 15 * time.Minute
|
|
|
|
ChannelMembersCountsCacheSize = model.ChannelCacheSize
|
|
ChannelMembersCountsCacheSec = 30 * 60
|
|
|
|
LastPostsCacheSize = 20000
|
|
LastPostsCacheSec = 30 * 60
|
|
PostsUsageCacheSize = 1
|
|
PostsUsageCacheSec = 30 * 60
|
|
|
|
TermsOfServiceCacheSize = 20000
|
|
TermsOfServiceCacheSec = 30 * 60
|
|
LastPostTimeCacheSize = 25000
|
|
LastPostTimeCacheSec = 15 * 60
|
|
|
|
UserProfileByIDCacheSize = 20000
|
|
UserProfileByIDSec = 30 * 60
|
|
|
|
ProfilesInChannelCacheSize = model.ChannelCacheSize
|
|
ProfilesInChannelCacheSec = 15 * 60
|
|
|
|
TeamCacheSize = 20000
|
|
TeamCacheSec = 30 * 60
|
|
|
|
ChannelCacheSec = 15 * 60 // 15 mins
|
|
|
|
ContentFlaggingCacheSize = 100
|
|
)
|
|
|
|
var clearCacheMessageData = []byte("")
|
|
|
|
type LocalCacheStore struct {
|
|
store.Store
|
|
cacheType string
|
|
metrics einterfaces.MetricsInterface
|
|
cluster einterfaces.ClusterInterface
|
|
logger mlog.LoggerIFace
|
|
|
|
reaction LocalCacheReactionStore
|
|
reactionCache cache.Cache
|
|
|
|
fileInfo LocalCacheFileInfoStore
|
|
fileInfoCache cache.Cache
|
|
|
|
role LocalCacheRoleStore
|
|
roleCache cache.Cache
|
|
rolePermissionsCache cache.Cache
|
|
|
|
scheme LocalCacheSchemeStore
|
|
schemeCache cache.Cache
|
|
|
|
emoji *LocalCacheEmojiStore
|
|
emojiCacheById cache.Cache
|
|
emojiIdCacheByName cache.Cache
|
|
|
|
channel LocalCacheChannelStore
|
|
channelMemberCountsCache cache.Cache
|
|
channelGuestCountCache cache.Cache
|
|
channelPinnedPostCountsCache cache.Cache
|
|
channelByIdCache cache.Cache
|
|
channelMembersForUserCache cache.Cache
|
|
channelMembersNotifyPropsCache cache.Cache
|
|
channelByNameCache cache.Cache
|
|
|
|
webhook LocalCacheWebhookStore
|
|
webhookCache cache.Cache
|
|
|
|
post LocalCachePostStore
|
|
postLastPostsCache cache.Cache
|
|
lastPostTimeCache cache.Cache
|
|
postsUsageCache cache.Cache
|
|
|
|
user *LocalCacheUserStore
|
|
allUserCache cache.Cache
|
|
userProfileByIdsCache cache.Cache
|
|
profilesInChannelCache cache.Cache
|
|
|
|
team LocalCacheTeamStore
|
|
teamAllTeamIdsForUserCache cache.Cache
|
|
|
|
termsOfService LocalCacheTermsOfServiceStore
|
|
termsOfServiceCache cache.Cache
|
|
|
|
contentFlagging LocalCacheContentFlaggingStore
|
|
contentFlaggingCache cache.Cache
|
|
}
|
|
|
|
func NewLocalCacheLayer(baseStore store.Store, metrics einterfaces.MetricsInterface, cluster einterfaces.ClusterInterface, cacheProvider cache.Provider, logger mlog.LoggerIFace) (localCacheStore LocalCacheStore, err error) {
|
|
localCacheStore = LocalCacheStore{
|
|
Store: baseStore,
|
|
cluster: cluster,
|
|
metrics: metrics,
|
|
cacheType: cacheProvider.Type(),
|
|
logger: logger,
|
|
}
|
|
// Reactions
|
|
if localCacheStore.reactionCache, err = cacheProvider.NewCache(&cache.CacheOptions{
|
|
Size: ReactionCacheSize,
|
|
Name: "Reaction",
|
|
DefaultExpiry: ReactionCacheSec * time.Second,
|
|
InvalidateClusterEvent: model.ClusterEventInvalidateCacheForReactions,
|
|
}); err != nil {
|
|
return
|
|
}
|
|
localCacheStore.reaction = LocalCacheReactionStore{ReactionStore: baseStore.Reaction(), rootStore: &localCacheStore}
|
|
|
|
// Roles
|
|
if localCacheStore.roleCache, err = cacheProvider.NewCache(&cache.CacheOptions{
|
|
Size: RoleCacheSize,
|
|
Name: "Role",
|
|
DefaultExpiry: RoleCacheSec * time.Second,
|
|
InvalidateClusterEvent: model.ClusterEventInvalidateCacheForRoles,
|
|
Striped: true,
|
|
StripedBuckets: max(runtime.NumCPU()-1, 1),
|
|
}); err != nil {
|
|
return
|
|
}
|
|
if localCacheStore.rolePermissionsCache, err = cacheProvider.NewCache(&cache.CacheOptions{
|
|
Size: RoleCacheSize,
|
|
Name: "RolePermission",
|
|
DefaultExpiry: RoleCacheSec * time.Second,
|
|
InvalidateClusterEvent: model.ClusterEventInvalidateCacheForRolePermissions,
|
|
}); err != nil {
|
|
return
|
|
}
|
|
localCacheStore.role = LocalCacheRoleStore{RoleStore: baseStore.Role(), rootStore: &localCacheStore}
|
|
|
|
// Schemes
|
|
if localCacheStore.schemeCache, err = cacheProvider.NewCache(&cache.CacheOptions{
|
|
Size: SchemeCacheSize,
|
|
Name: "Scheme",
|
|
DefaultExpiry: SchemeCacheSec * time.Second,
|
|
InvalidateClusterEvent: model.ClusterEventInvalidateCacheForSchemes,
|
|
}); err != nil {
|
|
return
|
|
}
|
|
localCacheStore.scheme = LocalCacheSchemeStore{SchemeStore: baseStore.Scheme(), rootStore: &localCacheStore}
|
|
|
|
// FileInfo
|
|
if localCacheStore.fileInfoCache, err = cacheProvider.NewCache(&cache.CacheOptions{
|
|
Size: FileInfoCacheSize,
|
|
Name: "FileInfo",
|
|
DefaultExpiry: FileInfoCacheSec * time.Second,
|
|
InvalidateClusterEvent: model.ClusterEventInvalidateCacheForFileInfos,
|
|
}); err != nil {
|
|
return
|
|
}
|
|
localCacheStore.fileInfo = LocalCacheFileInfoStore{FileInfoStore: baseStore.FileInfo(), rootStore: &localCacheStore}
|
|
|
|
// Webhooks
|
|
if localCacheStore.webhookCache, err = cacheProvider.NewCache(&cache.CacheOptions{
|
|
Size: WebhookCacheSize,
|
|
Name: "Webhook",
|
|
DefaultExpiry: WebhookCacheSec * time.Second,
|
|
InvalidateClusterEvent: model.ClusterEventInvalidateCacheForWebhooks,
|
|
}); err != nil {
|
|
return
|
|
}
|
|
localCacheStore.webhook = LocalCacheWebhookStore{WebhookStore: baseStore.Webhook(), rootStore: &localCacheStore}
|
|
|
|
// Emojis
|
|
if localCacheStore.emojiCacheById, err = cacheProvider.NewCache(&cache.CacheOptions{
|
|
Size: EmojiCacheSize,
|
|
Name: "EmojiById",
|
|
DefaultExpiry: EmojiCacheSec * time.Second,
|
|
InvalidateClusterEvent: model.ClusterEventInvalidateCacheForEmojisById,
|
|
}); err != nil {
|
|
return
|
|
}
|
|
if localCacheStore.emojiIdCacheByName, err = cacheProvider.NewCache(&cache.CacheOptions{
|
|
Size: EmojiCacheSize,
|
|
Name: "EmojiByName",
|
|
DefaultExpiry: EmojiCacheSec * time.Second,
|
|
InvalidateClusterEvent: model.ClusterEventInvalidateCacheForEmojisIdByName,
|
|
}); err != nil {
|
|
return
|
|
}
|
|
localCacheStore.emoji = &LocalCacheEmojiStore{
|
|
EmojiStore: baseStore.Emoji(),
|
|
rootStore: &localCacheStore,
|
|
emojiByIdInvalidations: make(map[string]bool),
|
|
emojiByNameInvalidations: make(map[string]bool),
|
|
}
|
|
|
|
// Channels
|
|
if localCacheStore.channelPinnedPostCountsCache, err = cacheProvider.NewCache(&cache.CacheOptions{
|
|
Size: ChannelPinnedPostsCountsCacheSize,
|
|
Name: "ChannelPinnedPostsCounts",
|
|
DefaultExpiry: ChannelPinnedPostsCountsCacheSec * time.Second,
|
|
InvalidateClusterEvent: model.ClusterEventInvalidateCacheForChannelPinnedpostsCounts,
|
|
}); err != nil {
|
|
return
|
|
}
|
|
if localCacheStore.channelMemberCountsCache, err = cacheProvider.NewCache(&cache.CacheOptions{
|
|
Size: ChannelMembersCountsCacheSize,
|
|
Name: "ChannelMemberCounts",
|
|
DefaultExpiry: ChannelMembersCountsCacheSec * time.Second,
|
|
InvalidateClusterEvent: model.ClusterEventInvalidateCacheForChannelMemberCounts,
|
|
}); err != nil {
|
|
return
|
|
}
|
|
if localCacheStore.channelGuestCountCache, err = cacheProvider.NewCache(&cache.CacheOptions{
|
|
Size: ChannelGuestCountCacheSize,
|
|
Name: "ChannelGuestsCount",
|
|
DefaultExpiry: ChannelGuestCountCacheSec * time.Second,
|
|
InvalidateClusterEvent: model.ClusterEventInvalidateCacheForChannelGuestCount,
|
|
}); err != nil {
|
|
return
|
|
}
|
|
if localCacheStore.channelByIdCache, err = cacheProvider.NewCache(&cache.CacheOptions{
|
|
Size: model.ChannelCacheSize,
|
|
Name: "channelById",
|
|
DefaultExpiry: ChannelCacheSec * time.Second,
|
|
InvalidateClusterEvent: model.ClusterEventInvalidateCacheForChannel,
|
|
}); err != nil {
|
|
return
|
|
}
|
|
|
|
if localCacheStore.channelMembersForUserCache, err = cacheProvider.NewCache(&cache.CacheOptions{
|
|
Size: AllChannelMembersForUserCacheSize,
|
|
Name: "ChannelMembersForUser",
|
|
DefaultExpiry: AllChannelMembersForUserCacheDuration,
|
|
InvalidateClusterEvent: model.ClusterEventInvalidateCacheForUser,
|
|
}); err != nil {
|
|
return
|
|
}
|
|
if localCacheStore.channelMembersNotifyPropsCache, err = cacheProvider.NewCache(&cache.CacheOptions{
|
|
Size: AllChannelMembersNotifyPropsForChannelCacheSize,
|
|
Name: "ChannnelMembersNotifyProps",
|
|
DefaultExpiry: AllChannelMembersNotifyPropsForChannelCacheDuration,
|
|
InvalidateClusterEvent: model.ClusterEventInvalidateCacheForChannelMembersNotifyProps,
|
|
}); err != nil {
|
|
return
|
|
}
|
|
if localCacheStore.channelByNameCache, err = cacheProvider.NewCache(&cache.CacheOptions{
|
|
Size: model.ChannelCacheSize,
|
|
Name: "ChannelByName",
|
|
DefaultExpiry: ChannelCacheDuration,
|
|
InvalidateClusterEvent: model.ClusterEventInvalidateCacheForChannelByName,
|
|
}); err != nil {
|
|
return
|
|
}
|
|
localCacheStore.channel = LocalCacheChannelStore{ChannelStore: baseStore.Channel(), rootStore: &localCacheStore}
|
|
|
|
// Posts
|
|
if localCacheStore.postLastPostsCache, err = cacheProvider.NewCache(&cache.CacheOptions{
|
|
Size: LastPostsCacheSize,
|
|
Name: "LastPost",
|
|
DefaultExpiry: LastPostsCacheSec * time.Second,
|
|
InvalidateClusterEvent: model.ClusterEventInvalidateCacheForLastPosts,
|
|
}); err != nil {
|
|
return
|
|
}
|
|
if localCacheStore.lastPostTimeCache, err = cacheProvider.NewCache(&cache.CacheOptions{
|
|
Size: LastPostTimeCacheSize,
|
|
Name: "LastPostTime",
|
|
DefaultExpiry: LastPostTimeCacheSec * time.Second,
|
|
InvalidateClusterEvent: model.ClusterEventInvalidateCacheForLastPostTime,
|
|
}); err != nil {
|
|
return
|
|
}
|
|
if localCacheStore.postsUsageCache, err = cacheProvider.NewCache(&cache.CacheOptions{
|
|
Size: PostsUsageCacheSize,
|
|
Name: "PostsUsage",
|
|
DefaultExpiry: PostsUsageCacheSec * time.Second,
|
|
InvalidateClusterEvent: model.ClusterEventInvalidateCacheForPostsUsage,
|
|
}); err != nil {
|
|
return
|
|
}
|
|
localCacheStore.post = LocalCachePostStore{PostStore: baseStore.Post(), rootStore: &localCacheStore}
|
|
|
|
// TOS
|
|
if localCacheStore.termsOfServiceCache, err = cacheProvider.NewCache(&cache.CacheOptions{
|
|
Size: TermsOfServiceCacheSize,
|
|
Name: "TermsOfService",
|
|
DefaultExpiry: TermsOfServiceCacheSec * time.Second,
|
|
InvalidateClusterEvent: model.ClusterEventInvalidateCacheForTermsOfService,
|
|
}); err != nil {
|
|
return
|
|
}
|
|
localCacheStore.termsOfService = LocalCacheTermsOfServiceStore{TermsOfServiceStore: baseStore.TermsOfService(), rootStore: &localCacheStore}
|
|
|
|
// Users
|
|
if localCacheStore.allUserCache, err = cacheProvider.NewCache(&cache.CacheOptions{
|
|
Size: 1,
|
|
Name: "AllUserProfiles",
|
|
DefaultExpiry: UserProfileByIDSec * time.Second,
|
|
InvalidateClusterEvent: model.ClusterEventInvalidateCacheForAllProfiles,
|
|
}); err != nil {
|
|
return
|
|
}
|
|
if localCacheStore.userProfileByIdsCache, err = cacheProvider.NewCache(&cache.CacheOptions{
|
|
Size: UserProfileByIDCacheSize,
|
|
Name: "UserProfileByIds",
|
|
DefaultExpiry: UserProfileByIDSec * time.Second,
|
|
InvalidateClusterEvent: model.ClusterEventInvalidateCacheForProfileByIds,
|
|
Striped: true,
|
|
StripedBuckets: max(runtime.NumCPU()-1, 1),
|
|
}); err != nil {
|
|
return
|
|
}
|
|
// Hardcoding this to LRU because of the volume of SCAN calls in case of Redis.
|
|
if localCacheStore.profilesInChannelCache, err = cache.NewProvider().NewCache(&cache.CacheOptions{
|
|
Size: ProfilesInChannelCacheSize,
|
|
Name: "ProfilesInChannel",
|
|
DefaultExpiry: ProfilesInChannelCacheSec * time.Second,
|
|
InvalidateClusterEvent: model.ClusterEventInvalidateCacheForProfileInChannel,
|
|
}); err != nil {
|
|
return
|
|
}
|
|
localCacheStore.user = &LocalCacheUserStore{
|
|
UserStore: baseStore.User(),
|
|
rootStore: &localCacheStore,
|
|
userProfileByIdsInvalidations: make(map[string]bool),
|
|
}
|
|
|
|
// Teams
|
|
if localCacheStore.teamAllTeamIdsForUserCache, err = cacheProvider.NewCache(&cache.CacheOptions{
|
|
Size: TeamCacheSize,
|
|
Name: "Team",
|
|
DefaultExpiry: TeamCacheSec * time.Second,
|
|
InvalidateClusterEvent: model.ClusterEventInvalidateCacheForTeams,
|
|
}); err != nil {
|
|
return
|
|
}
|
|
localCacheStore.team = LocalCacheTeamStore{TeamStore: baseStore.Team(), rootStore: &localCacheStore}
|
|
|
|
if localCacheStore.contentFlaggingCache, err = cacheProvider.NewCache(&cache.CacheOptions{
|
|
Size: ContentFlaggingCacheSize,
|
|
Name: "ContentFlagging",
|
|
InvalidateClusterEvent: model.ClusterEventInvalidateCacheForContentFlagging,
|
|
}); err != nil {
|
|
return
|
|
}
|
|
localCacheStore.contentFlagging = LocalCacheContentFlaggingStore{ContentFlaggingStore: baseStore.ContentFlagging(), rootStore: &localCacheStore}
|
|
|
|
if cluster != nil {
|
|
cluster.RegisterClusterMessageHandler(model.ClusterEventInvalidateCacheForReactions, localCacheStore.reaction.handleClusterInvalidateReaction)
|
|
cluster.RegisterClusterMessageHandler(model.ClusterEventInvalidateCacheForRoles, localCacheStore.role.handleClusterInvalidateRole)
|
|
cluster.RegisterClusterMessageHandler(model.ClusterEventInvalidateCacheForRolePermissions, localCacheStore.role.handleClusterInvalidateRolePermissions)
|
|
cluster.RegisterClusterMessageHandler(model.ClusterEventInvalidateCacheForSchemes, localCacheStore.scheme.handleClusterInvalidateScheme)
|
|
cluster.RegisterClusterMessageHandler(model.ClusterEventInvalidateCacheForFileInfos, localCacheStore.fileInfo.handleClusterInvalidateFileInfo)
|
|
cluster.RegisterClusterMessageHandler(model.ClusterEventInvalidateCacheForLastPostTime, localCacheStore.post.handleClusterInvalidateLastPostTime)
|
|
cluster.RegisterClusterMessageHandler(model.ClusterEventInvalidateCacheForPostsUsage, localCacheStore.post.handleClusterInvalidatePostsUsage)
|
|
cluster.RegisterClusterMessageHandler(model.ClusterEventInvalidateCacheForWebhooks, localCacheStore.webhook.handleClusterInvalidateWebhook)
|
|
cluster.RegisterClusterMessageHandler(model.ClusterEventInvalidateCacheForEmojisById, localCacheStore.emoji.handleClusterInvalidateEmojiById)
|
|
cluster.RegisterClusterMessageHandler(model.ClusterEventInvalidateCacheForEmojisIdByName, localCacheStore.emoji.handleClusterInvalidateEmojiIdByName)
|
|
cluster.RegisterClusterMessageHandler(model.ClusterEventInvalidateCacheForChannelPinnedpostsCounts, localCacheStore.channel.handleClusterInvalidateChannelPinnedPostCount)
|
|
cluster.RegisterClusterMessageHandler(model.ClusterEventInvalidateCacheForChannelMemberCounts, localCacheStore.channel.handleClusterInvalidateChannelMemberCounts)
|
|
cluster.RegisterClusterMessageHandler(model.ClusterEventInvalidateCacheForChannelGuestCount, localCacheStore.channel.handleClusterInvalidateChannelGuestCounts)
|
|
cluster.RegisterClusterMessageHandler(model.ClusterEventInvalidateCacheForChannel, localCacheStore.channel.handleClusterInvalidateChannelById)
|
|
cluster.RegisterClusterMessageHandler(model.ClusterEventInvalidateCacheForUser, localCacheStore.channel.handleClusterInvalidateChannelForUser)
|
|
cluster.RegisterClusterMessageHandler(model.ClusterEventInvalidateCacheForChannelMembersNotifyProps, localCacheStore.channel.handleClusterInvalidateChannelMembersNotifyProps)
|
|
cluster.RegisterClusterMessageHandler(model.ClusterEventInvalidateCacheForChannelByName, localCacheStore.channel.handleClusterInvalidateChannelByName)
|
|
cluster.RegisterClusterMessageHandler(model.ClusterEventInvalidateCacheForLastPosts, localCacheStore.post.handleClusterInvalidateLastPosts)
|
|
cluster.RegisterClusterMessageHandler(model.ClusterEventInvalidateCacheForTermsOfService, localCacheStore.termsOfService.handleClusterInvalidateTermsOfService)
|
|
cluster.RegisterClusterMessageHandler(model.ClusterEventInvalidateCacheForProfileByIds, localCacheStore.user.handleClusterInvalidateScheme)
|
|
cluster.RegisterClusterMessageHandler(model.ClusterEventInvalidateCacheForProfileInChannel, localCacheStore.user.handleClusterInvalidateProfilesInChannel)
|
|
cluster.RegisterClusterMessageHandler(model.ClusterEventInvalidateCacheForAllProfiles, localCacheStore.user.handleClusterInvalidateAllProfiles)
|
|
cluster.RegisterClusterMessageHandler(model.ClusterEventInvalidateCacheForTeams, localCacheStore.team.handleClusterInvalidateTeam)
|
|
cluster.RegisterClusterMessageHandler(model.ClusterEventInvalidateCacheForContentFlagging, localCacheStore.contentFlagging.handleClusterInvalidateContentFlagging)
|
|
}
|
|
return
|
|
}
|
|
|
|
func (s LocalCacheStore) Reaction() store.ReactionStore {
|
|
return s.reaction
|
|
}
|
|
|
|
func (s LocalCacheStore) Role() store.RoleStore {
|
|
return s.role
|
|
}
|
|
|
|
func (s LocalCacheStore) Scheme() store.SchemeStore {
|
|
return s.scheme
|
|
}
|
|
|
|
func (s LocalCacheStore) FileInfo() store.FileInfoStore {
|
|
return s.fileInfo
|
|
}
|
|
|
|
func (s LocalCacheStore) Webhook() store.WebhookStore {
|
|
return s.webhook
|
|
}
|
|
|
|
func (s LocalCacheStore) Emoji() store.EmojiStore {
|
|
return s.emoji
|
|
}
|
|
|
|
func (s LocalCacheStore) Channel() store.ChannelStore {
|
|
return s.channel
|
|
}
|
|
|
|
func (s LocalCacheStore) Post() store.PostStore {
|
|
return s.post
|
|
}
|
|
|
|
func (s LocalCacheStore) TermsOfService() store.TermsOfServiceStore {
|
|
return s.termsOfService
|
|
}
|
|
|
|
func (s LocalCacheStore) User() store.UserStore {
|
|
return s.user
|
|
}
|
|
|
|
func (s LocalCacheStore) Team() store.TeamStore {
|
|
return s.team
|
|
}
|
|
|
|
func (s LocalCacheStore) ContentFlagging() store.ContentFlaggingStore {
|
|
return s.contentFlagging
|
|
}
|
|
|
|
func (s LocalCacheStore) DropAllTables() {
|
|
s.Invalidate()
|
|
s.Store.DropAllTables()
|
|
}
|
|
|
|
func (s *LocalCacheStore) doInvalidateCacheCluster(cache cache.Cache, key string, props map[string]string) {
|
|
err := cache.Remove(key)
|
|
if err != nil {
|
|
s.logger.Warn("Error while removing cache entry", mlog.Err(err), mlog.String("cache_name", cache.Name()))
|
|
}
|
|
if s.cluster != nil && cache.GetInvalidateClusterEvent() != model.ClusterEventNone {
|
|
msg := &model.ClusterMessage{
|
|
Event: cache.GetInvalidateClusterEvent(),
|
|
SendType: model.ClusterSendBestEffort,
|
|
Data: []byte(key),
|
|
}
|
|
if props != nil {
|
|
msg.Props = props
|
|
}
|
|
s.cluster.SendClusterMessage(msg)
|
|
}
|
|
}
|
|
|
|
func (s *LocalCacheStore) doMultiInvalidateCacheCluster(cache cache.Cache, keys []string, props map[string]string) {
|
|
err := cache.RemoveMulti(keys)
|
|
if err != nil {
|
|
s.logger.Warn("Error while removing cache entry", mlog.Err(err), mlog.String("cache_name", cache.Name()))
|
|
}
|
|
if s.cluster != nil && cache.GetInvalidateClusterEvent() != model.ClusterEventNone {
|
|
for _, key := range keys {
|
|
msg := &model.ClusterMessage{
|
|
Event: cache.GetInvalidateClusterEvent(),
|
|
SendType: model.ClusterSendBestEffort,
|
|
Data: []byte(key),
|
|
}
|
|
if props != nil {
|
|
msg.Props = props
|
|
}
|
|
s.cluster.SendClusterMessage(msg)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *LocalCacheStore) doStandardAddToCache(cache cache.Cache, key string, value any) {
|
|
err := cache.SetWithDefaultExpiry(key, value)
|
|
if err != nil {
|
|
s.logger.Warn("Error while setting cache entry", mlog.Err(err), mlog.String("cache_name", cache.Name()))
|
|
}
|
|
}
|
|
|
|
func (s *LocalCacheStore) doStandardReadCache(c cache.Cache, key string, value any) error {
|
|
err := c.Get(key, value)
|
|
if err == nil {
|
|
if s.metrics != nil {
|
|
s.metrics.IncrementMemCacheHitCounter(c.Name())
|
|
}
|
|
return nil
|
|
}
|
|
if err != cache.ErrKeyNotFound {
|
|
s.logger.Warn("Error while reading from cache", mlog.Err(err), mlog.String("cache_name", c.Name()))
|
|
}
|
|
if s.metrics != nil {
|
|
s.metrics.IncrementMemCacheMissCounter(c.Name())
|
|
}
|
|
return err
|
|
}
|
|
|
|
func (s *LocalCacheStore) doMultiReadCache(cache cache.Cache, keys []string, values []any) []error {
|
|
errs := cache.GetMulti(keys, values)
|
|
if s.metrics != nil {
|
|
for _, err := range errs {
|
|
if err == nil {
|
|
s.metrics.IncrementMemCacheHitCounter(cache.Name())
|
|
continue
|
|
}
|
|
s.metrics.IncrementMemCacheMissCounter(cache.Name())
|
|
}
|
|
}
|
|
return errs
|
|
}
|
|
|
|
func (s *LocalCacheStore) doIncrementCache(cache cache.ExternalCache, key string, val int) {
|
|
err := cache.Increment(key, val)
|
|
if err != nil {
|
|
s.logger.Warn("Error while incrementing cache entry", mlog.Err(err), mlog.String("cache_name", cache.Name()))
|
|
}
|
|
}
|
|
|
|
func (s *LocalCacheStore) doDecrementCache(cache cache.ExternalCache, key string, val int) {
|
|
err := cache.Decrement(key, val)
|
|
if err != nil {
|
|
s.logger.Warn("Error while decrementing cache entry", mlog.Err(err), mlog.String("cache_name", cache.Name()))
|
|
}
|
|
}
|
|
|
|
func (s *LocalCacheStore) doClearCacheCluster(cache cache.Cache) {
|
|
err := cache.Purge()
|
|
if err != nil {
|
|
s.logger.Warn("Error while purging cache", mlog.Err(err), mlog.String("cache_name", cache.Name()))
|
|
}
|
|
if s.cluster != nil && cache.GetInvalidateClusterEvent() != model.ClusterEventNone {
|
|
msg := &model.ClusterMessage{
|
|
Event: cache.GetInvalidateClusterEvent(),
|
|
SendType: model.ClusterSendBestEffort,
|
|
Data: clearCacheMessageData,
|
|
}
|
|
s.cluster.SendClusterMessage(msg)
|
|
}
|
|
}
|
|
|
|
func (s *LocalCacheStore) Invalidate() {
|
|
s.doClearCacheCluster(s.reactionCache)
|
|
s.doClearCacheCluster(s.schemeCache)
|
|
s.doClearCacheCluster(s.roleCache)
|
|
s.doClearCacheCluster(s.fileInfoCache)
|
|
s.doClearCacheCluster(s.webhookCache)
|
|
s.doClearCacheCluster(s.emojiCacheById)
|
|
s.doClearCacheCluster(s.emojiIdCacheByName)
|
|
s.doClearCacheCluster(s.channelMemberCountsCache)
|
|
s.doClearCacheCluster(s.channelPinnedPostCountsCache)
|
|
s.doClearCacheCluster(s.channelGuestCountCache)
|
|
s.doClearCacheCluster(s.channelByIdCache)
|
|
s.doClearCacheCluster(s.channelMembersForUserCache)
|
|
s.doClearCacheCluster(s.channelMembersNotifyPropsCache)
|
|
s.doClearCacheCluster(s.channelByNameCache)
|
|
s.doClearCacheCluster(s.postLastPostsCache)
|
|
s.doClearCacheCluster(s.termsOfServiceCache)
|
|
s.doClearCacheCluster(s.lastPostTimeCache)
|
|
s.doClearCacheCluster(s.userProfileByIdsCache)
|
|
s.doClearCacheCluster(s.allUserCache)
|
|
s.doClearCacheCluster(s.profilesInChannelCache)
|
|
s.doClearCacheCluster(s.teamAllTeamIdsForUserCache)
|
|
s.doClearCacheCluster(s.rolePermissionsCache)
|
|
}
|
|
|
|
// allocateCacheTargets is used to fill target value types
|
|
// for getting items from cache.
|
|
func allocateCacheTargets[T any](l int) []any {
|
|
toPass := make([]any, 0, l)
|
|
for range l {
|
|
toPass = append(toPass, new(T))
|
|
}
|
|
return toPass
|
|
}
|