github.com/mattermosttest/mattermost-server/v5@v5.0.0-20200917143240-9dfa12e121f9/store/localcachelayer/user_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 "github.com/mattermost/mattermost-server/v5/model" 8 "github.com/mattermost/mattermost-server/v5/store" 9 ) 10 11 type LocalCacheUserStore struct { 12 store.UserStore 13 rootStore *LocalCacheStore 14 } 15 16 func (s *LocalCacheUserStore) handleClusterInvalidateScheme(msg *model.ClusterMessage) { 17 if msg.Data == CLEAR_CACHE_MESSAGE_DATA { 18 s.rootStore.userProfileByIdsCache.Purge() 19 } else { 20 s.rootStore.userProfileByIdsCache.Remove(msg.Data) 21 } 22 } 23 24 func (s *LocalCacheUserStore) handleClusterInvalidateProfilesInChannel(msg *model.ClusterMessage) { 25 if msg.Data == CLEAR_CACHE_MESSAGE_DATA { 26 s.rootStore.profilesInChannelCache.Purge() 27 } else { 28 s.rootStore.profilesInChannelCache.Remove(msg.Data) 29 } 30 } 31 32 func (s LocalCacheUserStore) ClearCaches() { 33 s.rootStore.userProfileByIdsCache.Purge() 34 s.rootStore.profilesInChannelCache.Purge() 35 36 if s.rootStore.metrics != nil { 37 s.rootStore.metrics.IncrementMemCacheInvalidationCounter("Profile By Ids - Purge") 38 s.rootStore.metrics.IncrementMemCacheInvalidationCounter("Profiles in Channel - Purge") 39 } 40 } 41 42 func (s LocalCacheUserStore) InvalidateProfileCacheForUser(userId string) { 43 s.rootStore.doInvalidateCacheCluster(s.rootStore.userProfileByIdsCache, userId) 44 45 if s.rootStore.metrics != nil { 46 s.rootStore.metrics.IncrementMemCacheInvalidationCounter("Profile By Ids - Remove") 47 } 48 } 49 50 func (s LocalCacheUserStore) InvalidateProfilesInChannelCacheByUser(userId string) { 51 keys, err := s.rootStore.profilesInChannelCache.Keys() 52 if err == nil { 53 for _, key := range keys { 54 var userMap map[string]*model.User 55 if err = s.rootStore.profilesInChannelCache.Get(key, &userMap); err == nil { 56 if _, userInCache := userMap[userId]; userInCache { 57 s.rootStore.doInvalidateCacheCluster(s.rootStore.profilesInChannelCache, key) 58 if s.rootStore.metrics != nil { 59 s.rootStore.metrics.IncrementMemCacheInvalidationCounter("Profiles in Channel - Remove by User") 60 } 61 } 62 } 63 } 64 } 65 } 66 67 func (s LocalCacheUserStore) InvalidateProfilesInChannelCache(channelId string) { 68 s.rootStore.doInvalidateCacheCluster(s.rootStore.profilesInChannelCache, channelId) 69 if s.rootStore.metrics != nil { 70 s.rootStore.metrics.IncrementMemCacheInvalidationCounter("Profiles in Channel - Remove by Channel") 71 } 72 } 73 74 func (s LocalCacheUserStore) GetAllProfilesInChannel(channelId string, allowFromCache bool) (map[string]*model.User, *model.AppError) { 75 if allowFromCache { 76 var cachedMap map[string]*model.User 77 if err := s.rootStore.doStandardReadCache(s.rootStore.profilesInChannelCache, channelId, &cachedMap); err == nil { 78 return deepCopyUserMap(cachedMap), nil 79 } 80 } 81 82 userMap, err := s.UserStore.GetAllProfilesInChannel(channelId, allowFromCache) 83 if err != nil { 84 return nil, err 85 } 86 87 if allowFromCache { 88 s.rootStore.doStandardAddToCache(s.rootStore.profilesInChannelCache, channelId, deepCopyUserMap(userMap)) 89 } 90 91 return userMap, nil 92 } 93 94 func (s LocalCacheUserStore) GetProfileByIds(userIds []string, options *store.UserGetByIdsOpts, allowFromCache bool) ([]*model.User, *model.AppError) { 95 if !allowFromCache { 96 return s.UserStore.GetProfileByIds(userIds, options, false) 97 } 98 99 if options == nil { 100 options = &store.UserGetByIdsOpts{} 101 } 102 103 users := []*model.User{} 104 remainingUserIds := make([]string, 0) 105 106 for _, userId := range userIds { 107 var cacheItem *model.User 108 if err := s.rootStore.doStandardReadCache(s.rootStore.userProfileByIdsCache, userId, &cacheItem); err == nil { 109 if options.Since == 0 || cacheItem.UpdateAt > options.Since { 110 users = append(users, cacheItem.DeepCopy()) 111 } 112 } else { 113 remainingUserIds = append(remainingUserIds, userId) 114 } 115 } 116 117 if s.rootStore.metrics != nil { 118 s.rootStore.metrics.AddMemCacheHitCounter("Profile By Ids", float64(len(users))) 119 s.rootStore.metrics.AddMemCacheMissCounter("Profile By Ids", float64(len(remainingUserIds))) 120 } 121 122 if len(remainingUserIds) > 0 { 123 remainingUsers, err := s.UserStore.GetProfileByIds(remainingUserIds, options, false) 124 if err != nil { 125 return nil, err 126 } 127 for _, user := range remainingUsers { 128 s.rootStore.doStandardAddToCache(s.rootStore.userProfileByIdsCache, user.Id, user) 129 users = append(users, user.DeepCopy()) 130 } 131 } 132 133 return users, nil 134 } 135 136 // Get is a cache wrapper around the SqlStore method to get a user profile by id. 137 // It checks if the user entry is present in the cache, returning the entry from cache 138 // if it is present. Otherwise, it fetches the entry from the store and stores it in the 139 // cache. 140 func (s LocalCacheUserStore) Get(id string) (*model.User, *model.AppError) { 141 var cacheItem *model.User 142 if err := s.rootStore.doStandardReadCache(s.rootStore.userProfileByIdsCache, id, &cacheItem); err == nil { 143 if s.rootStore.metrics != nil { 144 s.rootStore.metrics.AddMemCacheHitCounter("Profile By Id", float64(1)) 145 } 146 return cacheItem.DeepCopy(), nil 147 } 148 if s.rootStore.metrics != nil { 149 s.rootStore.metrics.AddMemCacheMissCounter("Profile By Id", float64(1)) 150 } 151 user, err := s.UserStore.Get(id) 152 if err != nil { 153 return nil, err 154 } 155 u := user.DeepCopy() 156 s.rootStore.doStandardAddToCache(s.rootStore.userProfileByIdsCache, id, u) 157 return user.DeepCopy(), nil 158 } 159 160 func deepCopyUserMap(users map[string]*model.User) map[string]*model.User { 161 copyOfUsers := make(map[string]*model.User) 162 163 for id, user := range users { 164 copyOfUsers[id] = user.DeepCopy() 165 } 166 167 return copyOfUsers 168 }