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  }