github.com/mattermosttest/mattermost-server/v5@v5.0.0-20200917143240-9dfa12e121f9/store/localcachelayer/layer.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package localcachelayer
     5  
     6  import (
     7  	"time"
     8  
     9  	"github.com/mattermost/mattermost-server/v5/einterfaces"
    10  	"github.com/mattermost/mattermost-server/v5/model"
    11  	"github.com/mattermost/mattermost-server/v5/services/cache"
    12  	"github.com/mattermost/mattermost-server/v5/store"
    13  )
    14  
    15  const (
    16  	REACTION_CACHE_SIZE = 20000
    17  	REACTION_CACHE_SEC  = 30 * 60
    18  
    19  	ROLE_CACHE_SIZE = 20000
    20  	ROLE_CACHE_SEC  = 30 * 60
    21  
    22  	SCHEME_CACHE_SIZE = 20000
    23  	SCHEME_CACHE_SEC  = 30 * 60
    24  
    25  	FILE_INFO_CACHE_SIZE = 25000
    26  	FILE_INFO_CACHE_SEC  = 30 * 60
    27  
    28  	CHANNEL_GUEST_COUNT_CACHE_SIZE = model.CHANNEL_CACHE_SIZE
    29  	CHANNEL_GUEST_COUNT_CACHE_SEC  = 30 * 60
    30  
    31  	WEBHOOK_CACHE_SIZE = 25000
    32  	WEBHOOK_CACHE_SEC  = 15 * 60
    33  
    34  	EMOJI_CACHE_SIZE = 5000
    35  	EMOJI_CACHE_SEC  = 30 * 60
    36  
    37  	CHANNEL_PINNEDPOSTS_COUNTS_CACHE_SIZE = model.CHANNEL_CACHE_SIZE
    38  	CHANNEL_PINNEDPOSTS_COUNTS_CACHE_SEC  = 30 * 60
    39  
    40  	CHANNEL_MEMBERS_COUNTS_CACHE_SIZE = model.CHANNEL_CACHE_SIZE
    41  	CHANNEL_MEMBERS_COUNTS_CACHE_SEC  = 30 * 60
    42  
    43  	LAST_POSTS_CACHE_SIZE = 20000
    44  	LAST_POSTS_CACHE_SEC  = 30 * 60
    45  
    46  	TERMS_OF_SERVICE_CACHE_SIZE = 20000
    47  	TERMS_OF_SERVICE_CACHE_SEC  = 30 * 60
    48  	LAST_POST_TIME_CACHE_SIZE   = 25000
    49  	LAST_POST_TIME_CACHE_SEC    = 15 * 60
    50  
    51  	USER_PROFILE_BY_ID_CACHE_SIZE = 20000
    52  	USER_PROFILE_BY_ID_SEC        = 30 * 60
    53  
    54  	PROFILES_IN_CHANNEL_CACHE_SIZE = model.CHANNEL_CACHE_SIZE
    55  	PROFILES_IN_CHANNEL_CACHE_SEC  = 15 * 60
    56  
    57  	TEAM_CACHE_SIZE = 20000
    58  	TEAM_CACHE_SEC  = 30 * 60
    59  
    60  	CLEAR_CACHE_MESSAGE_DATA = ""
    61  
    62  	CHANNEL_CACHE_SEC = 15 * 60 // 15 mins
    63  )
    64  
    65  type LocalCacheStore struct {
    66  	store.Store
    67  	metrics einterfaces.MetricsInterface
    68  	cluster einterfaces.ClusterInterface
    69  
    70  	reaction      LocalCacheReactionStore
    71  	reactionCache cache.Cache
    72  
    73  	fileInfo      LocalCacheFileInfoStore
    74  	fileInfoCache cache.Cache
    75  
    76  	role                 LocalCacheRoleStore
    77  	roleCache            cache.Cache
    78  	rolePermissionsCache cache.Cache
    79  
    80  	scheme      LocalCacheSchemeStore
    81  	schemeCache cache.Cache
    82  
    83  	emoji              LocalCacheEmojiStore
    84  	emojiCacheById     cache.Cache
    85  	emojiIdCacheByName cache.Cache
    86  
    87  	channel                      LocalCacheChannelStore
    88  	channelMemberCountsCache     cache.Cache
    89  	channelGuestCountCache       cache.Cache
    90  	channelPinnedPostCountsCache cache.Cache
    91  	channelByIdCache             cache.Cache
    92  
    93  	webhook      LocalCacheWebhookStore
    94  	webhookCache cache.Cache
    95  
    96  	post               LocalCachePostStore
    97  	postLastPostsCache cache.Cache
    98  	lastPostTimeCache  cache.Cache
    99  
   100  	user                   LocalCacheUserStore
   101  	userProfileByIdsCache  cache.Cache
   102  	profilesInChannelCache cache.Cache
   103  
   104  	team                       LocalCacheTeamStore
   105  	teamAllTeamIdsForUserCache cache.Cache
   106  
   107  	termsOfService      LocalCacheTermsOfServiceStore
   108  	termsOfServiceCache cache.Cache
   109  }
   110  
   111  func NewLocalCacheLayer(baseStore store.Store, metrics einterfaces.MetricsInterface, cluster einterfaces.ClusterInterface, cacheProvider cache.Provider) LocalCacheStore {
   112  
   113  	localCacheStore := LocalCacheStore{
   114  		Store:   baseStore,
   115  		cluster: cluster,
   116  		metrics: metrics,
   117  	}
   118  	// Reactions
   119  	localCacheStore.reactionCache = cacheProvider.NewCache(&cache.CacheOptions{
   120  		Size:                   REACTION_CACHE_SIZE,
   121  		Name:                   "Reaction",
   122  		DefaultExpiry:          REACTION_CACHE_SEC * time.Second,
   123  		InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_REACTIONS,
   124  	})
   125  	localCacheStore.reaction = LocalCacheReactionStore{ReactionStore: baseStore.Reaction(), rootStore: &localCacheStore}
   126  
   127  	// Roles
   128  	localCacheStore.roleCache = cacheProvider.NewCache(&cache.CacheOptions{
   129  		Size:                   ROLE_CACHE_SIZE,
   130  		Name:                   "Role",
   131  		DefaultExpiry:          ROLE_CACHE_SEC * time.Second,
   132  		InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_ROLES,
   133  	})
   134  	localCacheStore.rolePermissionsCache = cacheProvider.NewCache(&cache.CacheOptions{
   135  		Size:                   ROLE_CACHE_SIZE,
   136  		Name:                   "RolePermission",
   137  		DefaultExpiry:          ROLE_CACHE_SEC * time.Second,
   138  		InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_ROLE_PERMISSIONS,
   139  	})
   140  	localCacheStore.role = LocalCacheRoleStore{RoleStore: baseStore.Role(), rootStore: &localCacheStore}
   141  
   142  	// Schemes
   143  	localCacheStore.schemeCache = cacheProvider.NewCache(&cache.CacheOptions{
   144  		Size:                   SCHEME_CACHE_SIZE,
   145  		Name:                   "Scheme",
   146  		DefaultExpiry:          SCHEME_CACHE_SEC * time.Second,
   147  		InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_SCHEMES,
   148  	})
   149  	localCacheStore.scheme = LocalCacheSchemeStore{SchemeStore: baseStore.Scheme(), rootStore: &localCacheStore}
   150  
   151  	// FileInfo
   152  	localCacheStore.fileInfoCache = cacheProvider.NewCache(&cache.CacheOptions{
   153  		Size:                   FILE_INFO_CACHE_SIZE,
   154  		Name:                   "FileInfo",
   155  		DefaultExpiry:          FILE_INFO_CACHE_SEC * time.Second,
   156  		InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_FILE_INFOS,
   157  	})
   158  	localCacheStore.fileInfo = LocalCacheFileInfoStore{FileInfoStore: baseStore.FileInfo(), rootStore: &localCacheStore}
   159  
   160  	// Webhooks
   161  	localCacheStore.webhookCache = cacheProvider.NewCache(&cache.CacheOptions{
   162  		Size:                   WEBHOOK_CACHE_SIZE,
   163  		Name:                   "Webhook",
   164  		DefaultExpiry:          WEBHOOK_CACHE_SEC * time.Second,
   165  		InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_WEBHOOKS,
   166  	})
   167  	localCacheStore.webhook = LocalCacheWebhookStore{WebhookStore: baseStore.Webhook(), rootStore: &localCacheStore}
   168  
   169  	// Emojis
   170  	localCacheStore.emojiCacheById = cacheProvider.NewCache(&cache.CacheOptions{
   171  		Size:                   EMOJI_CACHE_SIZE,
   172  		Name:                   "EmojiById",
   173  		DefaultExpiry:          EMOJI_CACHE_SEC * time.Second,
   174  		InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_EMOJIS_BY_ID,
   175  	})
   176  	localCacheStore.emojiIdCacheByName = cacheProvider.NewCache(&cache.CacheOptions{
   177  		Size:                   EMOJI_CACHE_SIZE,
   178  		Name:                   "EmojiByName",
   179  		DefaultExpiry:          EMOJI_CACHE_SEC * time.Second,
   180  		InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_EMOJIS_ID_BY_NAME,
   181  	})
   182  	localCacheStore.emoji = LocalCacheEmojiStore{EmojiStore: baseStore.Emoji(), rootStore: &localCacheStore}
   183  
   184  	// Channels
   185  	localCacheStore.channelPinnedPostCountsCache = cacheProvider.NewCache(&cache.CacheOptions{
   186  		Size:                   CHANNEL_PINNEDPOSTS_COUNTS_CACHE_SIZE,
   187  		Name:                   "ChannelPinnedPostsCounts",
   188  		DefaultExpiry:          CHANNEL_PINNEDPOSTS_COUNTS_CACHE_SEC * time.Second,
   189  		InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL_PINNEDPOSTS_COUNTS,
   190  	})
   191  	localCacheStore.channelMemberCountsCache = cacheProvider.NewCache(&cache.CacheOptions{
   192  		Size:                   CHANNEL_MEMBERS_COUNTS_CACHE_SIZE,
   193  		Name:                   "ChannelMemberCounts",
   194  		DefaultExpiry:          CHANNEL_MEMBERS_COUNTS_CACHE_SEC * time.Second,
   195  		InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL_MEMBER_COUNTS,
   196  	})
   197  	localCacheStore.channelGuestCountCache = cacheProvider.NewCache(&cache.CacheOptions{
   198  		Size:                   CHANNEL_GUEST_COUNT_CACHE_SIZE,
   199  		Name:                   "ChannelGuestsCount",
   200  		DefaultExpiry:          CHANNEL_GUEST_COUNT_CACHE_SEC * time.Second,
   201  		InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL_GUEST_COUNT,
   202  	})
   203  	localCacheStore.channelByIdCache = cacheProvider.NewCache(&cache.CacheOptions{
   204  		Size:                   model.CHANNEL_CACHE_SIZE,
   205  		Name:                   "channelById",
   206  		DefaultExpiry:          CHANNEL_CACHE_SEC * time.Second,
   207  		InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL,
   208  	})
   209  	localCacheStore.channel = LocalCacheChannelStore{ChannelStore: baseStore.Channel(), rootStore: &localCacheStore}
   210  
   211  	// Posts
   212  	localCacheStore.postLastPostsCache = cacheProvider.NewCache(&cache.CacheOptions{
   213  		Size:                   LAST_POSTS_CACHE_SIZE,
   214  		Name:                   "LastPost",
   215  		DefaultExpiry:          LAST_POSTS_CACHE_SEC * time.Second,
   216  		InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_LAST_POSTS,
   217  	})
   218  	localCacheStore.lastPostTimeCache = cacheProvider.NewCache(&cache.CacheOptions{
   219  		Size:                   LAST_POST_TIME_CACHE_SIZE,
   220  		Name:                   "LastPostTime",
   221  		DefaultExpiry:          LAST_POST_TIME_CACHE_SEC * time.Second,
   222  		InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_LAST_POST_TIME,
   223  	})
   224  	localCacheStore.post = LocalCachePostStore{PostStore: baseStore.Post(), rootStore: &localCacheStore}
   225  
   226  	// TOS
   227  	localCacheStore.termsOfServiceCache = cacheProvider.NewCache(&cache.CacheOptions{
   228  		Size:                   TERMS_OF_SERVICE_CACHE_SIZE,
   229  		Name:                   "TermsOfService",
   230  		DefaultExpiry:          TERMS_OF_SERVICE_CACHE_SEC * time.Second,
   231  		InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_TERMS_OF_SERVICE,
   232  	})
   233  	localCacheStore.termsOfService = LocalCacheTermsOfServiceStore{TermsOfServiceStore: baseStore.TermsOfService(), rootStore: &localCacheStore}
   234  
   235  	// Users
   236  	localCacheStore.userProfileByIdsCache = cacheProvider.NewCache(&cache.CacheOptions{
   237  		Size:                   USER_PROFILE_BY_ID_CACHE_SIZE,
   238  		Name:                   "UserProfileByIds",
   239  		DefaultExpiry:          USER_PROFILE_BY_ID_SEC * time.Second,
   240  		InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_PROFILE_BY_IDS,
   241  	})
   242  	localCacheStore.profilesInChannelCache = cacheProvider.NewCache(&cache.CacheOptions{
   243  		Size:                   PROFILES_IN_CHANNEL_CACHE_SIZE,
   244  		Name:                   "ProfilesInChannel",
   245  		DefaultExpiry:          PROFILES_IN_CHANNEL_CACHE_SEC * time.Second,
   246  		InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_PROFILE_IN_CHANNEL,
   247  	})
   248  	localCacheStore.user = LocalCacheUserStore{UserStore: baseStore.User(), rootStore: &localCacheStore}
   249  
   250  	// Teams
   251  	localCacheStore.teamAllTeamIdsForUserCache = cacheProvider.NewCache(&cache.CacheOptions{
   252  		Size:                   TEAM_CACHE_SIZE,
   253  		Name:                   "Team",
   254  		DefaultExpiry:          TEAM_CACHE_SEC * time.Second,
   255  		InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_TEAMS,
   256  	})
   257  	localCacheStore.team = LocalCacheTeamStore{TeamStore: baseStore.Team(), rootStore: &localCacheStore}
   258  
   259  	if cluster != nil {
   260  		cluster.RegisterClusterMessageHandler(model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_REACTIONS, localCacheStore.reaction.handleClusterInvalidateReaction)
   261  		cluster.RegisterClusterMessageHandler(model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_ROLES, localCacheStore.role.handleClusterInvalidateRole)
   262  		cluster.RegisterClusterMessageHandler(model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_ROLE_PERMISSIONS, localCacheStore.role.handleClusterInvalidateRolePermissions)
   263  		cluster.RegisterClusterMessageHandler(model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_SCHEMES, localCacheStore.scheme.handleClusterInvalidateScheme)
   264  		cluster.RegisterClusterMessageHandler(model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_FILE_INFOS, localCacheStore.fileInfo.handleClusterInvalidateFileInfo)
   265  		cluster.RegisterClusterMessageHandler(model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_LAST_POST_TIME, localCacheStore.post.handleClusterInvalidateLastPostTime)
   266  		cluster.RegisterClusterMessageHandler(model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_WEBHOOKS, localCacheStore.webhook.handleClusterInvalidateWebhook)
   267  		cluster.RegisterClusterMessageHandler(model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_EMOJIS_BY_ID, localCacheStore.emoji.handleClusterInvalidateEmojiById)
   268  		cluster.RegisterClusterMessageHandler(model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_EMOJIS_ID_BY_NAME, localCacheStore.emoji.handleClusterInvalidateEmojiIdByName)
   269  		cluster.RegisterClusterMessageHandler(model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL_PINNEDPOSTS_COUNTS, localCacheStore.channel.handleClusterInvalidateChannelPinnedPostCount)
   270  		cluster.RegisterClusterMessageHandler(model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL_MEMBER_COUNTS, localCacheStore.channel.handleClusterInvalidateChannelMemberCounts)
   271  		cluster.RegisterClusterMessageHandler(model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL_GUEST_COUNT, localCacheStore.channel.handleClusterInvalidateChannelGuestCounts)
   272  		cluster.RegisterClusterMessageHandler(model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL, localCacheStore.channel.handleClusterInvalidateChannelById)
   273  		cluster.RegisterClusterMessageHandler(model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_LAST_POSTS, localCacheStore.post.handleClusterInvalidateLastPosts)
   274  		cluster.RegisterClusterMessageHandler(model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_TERMS_OF_SERVICE, localCacheStore.termsOfService.handleClusterInvalidateTermsOfService)
   275  		cluster.RegisterClusterMessageHandler(model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_PROFILE_BY_IDS, localCacheStore.user.handleClusterInvalidateScheme)
   276  		cluster.RegisterClusterMessageHandler(model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_PROFILE_IN_CHANNEL, localCacheStore.user.handleClusterInvalidateProfilesInChannel)
   277  		cluster.RegisterClusterMessageHandler(model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_TEAMS, localCacheStore.team.handleClusterInvalidateTeam)
   278  	}
   279  	return localCacheStore
   280  }
   281  
   282  func (s LocalCacheStore) Reaction() store.ReactionStore {
   283  	return s.reaction
   284  }
   285  
   286  func (s LocalCacheStore) Role() store.RoleStore {
   287  	return s.role
   288  }
   289  
   290  func (s LocalCacheStore) Scheme() store.SchemeStore {
   291  	return s.scheme
   292  }
   293  
   294  func (s LocalCacheStore) FileInfo() store.FileInfoStore {
   295  	return s.fileInfo
   296  }
   297  
   298  func (s LocalCacheStore) Webhook() store.WebhookStore {
   299  	return s.webhook
   300  }
   301  
   302  func (s LocalCacheStore) Emoji() store.EmojiStore {
   303  	return s.emoji
   304  }
   305  
   306  func (s LocalCacheStore) Channel() store.ChannelStore {
   307  	return s.channel
   308  }
   309  
   310  func (s LocalCacheStore) Post() store.PostStore {
   311  	return s.post
   312  }
   313  
   314  func (s LocalCacheStore) TermsOfService() store.TermsOfServiceStore {
   315  	return s.termsOfService
   316  }
   317  
   318  func (s LocalCacheStore) User() store.UserStore {
   319  	return s.user
   320  }
   321  
   322  func (s LocalCacheStore) Team() store.TeamStore {
   323  	return s.team
   324  }
   325  
   326  func (s LocalCacheStore) DropAllTables() {
   327  	s.Invalidate()
   328  	s.Store.DropAllTables()
   329  }
   330  
   331  func (s *LocalCacheStore) doInvalidateCacheCluster(cache cache.Cache, key string) {
   332  	cache.Remove(key)
   333  	if s.cluster != nil {
   334  		msg := &model.ClusterMessage{
   335  			Event:    cache.GetInvalidateClusterEvent(),
   336  			SendType: model.CLUSTER_SEND_BEST_EFFORT,
   337  			Data:     key,
   338  		}
   339  		s.cluster.SendClusterMessage(msg)
   340  	}
   341  }
   342  
   343  func (s *LocalCacheStore) doStandardAddToCache(cache cache.Cache, key string, value interface{}) {
   344  	cache.SetWithDefaultExpiry(key, value)
   345  }
   346  
   347  func (s *LocalCacheStore) doStandardReadCache(cache cache.Cache, key string, value interface{}) error {
   348  	if err := cache.Get(key, value); err == nil {
   349  		if s.metrics != nil {
   350  			s.metrics.IncrementMemCacheHitCounter(cache.Name())
   351  		}
   352  		return nil
   353  	} else {
   354  		if s.metrics != nil {
   355  			s.metrics.IncrementMemCacheMissCounter(cache.Name())
   356  		}
   357  		return err
   358  	}
   359  }
   360  
   361  func (s *LocalCacheStore) doClearCacheCluster(cache cache.Cache) {
   362  	cache.Purge()
   363  	if s.cluster != nil {
   364  		msg := &model.ClusterMessage{
   365  			Event:    cache.GetInvalidateClusterEvent(),
   366  			SendType: model.CLUSTER_SEND_BEST_EFFORT,
   367  			Data:     CLEAR_CACHE_MESSAGE_DATA,
   368  		}
   369  		s.cluster.SendClusterMessage(msg)
   370  	}
   371  }
   372  
   373  func (s *LocalCacheStore) Invalidate() {
   374  	s.doClearCacheCluster(s.reactionCache)
   375  	s.doClearCacheCluster(s.schemeCache)
   376  	s.doClearCacheCluster(s.roleCache)
   377  	s.doClearCacheCluster(s.fileInfoCache)
   378  	s.doClearCacheCluster(s.webhookCache)
   379  	s.doClearCacheCluster(s.emojiCacheById)
   380  	s.doClearCacheCluster(s.emojiIdCacheByName)
   381  	s.doClearCacheCluster(s.channelMemberCountsCache)
   382  	s.doClearCacheCluster(s.channelPinnedPostCountsCache)
   383  	s.doClearCacheCluster(s.channelGuestCountCache)
   384  	s.doClearCacheCluster(s.channelByIdCache)
   385  	s.doClearCacheCluster(s.postLastPostsCache)
   386  	s.doClearCacheCluster(s.termsOfServiceCache)
   387  	s.doClearCacheCluster(s.lastPostTimeCache)
   388  	s.doClearCacheCluster(s.userProfileByIdsCache)
   389  	s.doClearCacheCluster(s.profilesInChannelCache)
   390  	s.doClearCacheCluster(s.teamAllTeamIdsForUserCache)
   391  	s.doClearCacheCluster(s.rolePermissionsCache)
   392  }