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 }