diff --git a/api4/apitestlib.go b/api4/apitestlib.go index e48dbfdcae..22d3d2a2c7 100644 --- a/api4/apitestlib.go +++ b/api4/apitestlib.go @@ -98,7 +98,7 @@ func setupTestHelper(dbStore store.Store, searchEngine *searchengine.Broker, ent } if includeCache { // Adds the cache layer to the test store - s.Store = localcachelayer.NewLocalCacheLayer(s.Store, s.Metrics, s.Cluster, s.CacheProvider) + s.Store = localcachelayer.NewLocalCacheLayer(s.Store, s.Metrics, s.Cluster, s.CacheProvider2) } th := &TestHelper{ diff --git a/app/helper_test.go b/app/helper_test.go index 273631e677..4b77a7f38c 100644 --- a/app/helper_test.go +++ b/app/helper_test.go @@ -76,7 +76,7 @@ func setupTestHelper(dbStore store.Store, enterprise bool, includeCacheLayer boo if includeCacheLayer { // Adds the cache layer to the test store - s.Store = localcachelayer.NewLocalCacheLayer(s.Store, s.Metrics, s.Cluster, s.CacheProvider) + s.Store = localcachelayer.NewLocalCacheLayer(s.Store, s.Metrics, s.Cluster, s.CacheProvider2) } th := &TestHelper{ diff --git a/app/server.go b/app/server.go index 4799933f37..94667c36b1 100644 --- a/app/server.go +++ b/app/server.go @@ -320,7 +320,7 @@ func NewServer(options ...Option) (*Server, error) { s.sqlStore, s.Metrics, s.Cluster, - s.CacheProvider, + s.CacheProvider2, ), s.SearchEngine, s.Config(), diff --git a/migrations/helper_test.go b/migrations/helper_test.go index 89c6463206..b9cde39607 100644 --- a/migrations/helper_test.go +++ b/migrations/helper_test.go @@ -47,7 +47,7 @@ func setupTestHelper(enterprise bool) *TestHelper { panic(err) } // Adds the cache layer to the test store - s.Store = localcachelayer.NewLocalCacheLayer(s.Store, s.Metrics, s.Cluster, s.CacheProvider) + s.Store = localcachelayer.NewLocalCacheLayer(s.Store, s.Metrics, s.Cluster, s.CacheProvider2) th := &TestHelper{ App: app.New(app.ServerConnector(s)), diff --git a/services/cache2/cache.go b/services/cache2/cache.go index 416c333d3d..8c88f0a56e 100644 --- a/services/cache2/cache.go +++ b/services/cache2/cache.go @@ -43,4 +43,7 @@ type Cache interface { // GetInvalidateClusterEvent returns the cluster event configured when this cache was created. GetInvalidateClusterEvent() string + + // Name returns the name of the cache + Name() string } diff --git a/services/cache2/lru.go b/services/cache2/lru.go index 41303aa690..b059149e17 100644 --- a/services/cache2/lru.go +++ b/services/cache2/lru.go @@ -13,6 +13,7 @@ import ( // LRU is a thread-safe fixed size LRU cache. type LRU struct { + name string size int evictList *list.List items map[string]*list.Element @@ -25,6 +26,7 @@ type LRU struct { // LRUOptions contains options for initializing LRU cache type LRUOptions struct { + Name string Size int DefaultExpiry time.Duration InvalidateClusterEvent string @@ -41,6 +43,7 @@ type entry struct { // NewLRU creates an LRU of the given size. func NewLRU(opts *LRUOptions) Cache { return &LRU{ + name: opts.Name, size: opts.Size, evictList: list.New(), items: make(map[string]*list.Element, opts.Size), @@ -127,6 +130,11 @@ func (l *LRU) GetInvalidateClusterEvent() string { return l.invalidateClusterEvent } +// Name returns the name of the cache +func (l *LRU) Name() string { + return l.name +} + func (l *LRU) set(key string, value interface{}, ttl time.Duration) error { var expires time.Time if ttl > 0 { diff --git a/services/cache2/mocks/Cache.go b/services/cache2/mocks/Cache.go new file mode 100644 index 0000000000..93651171b0 --- /dev/null +++ b/services/cache2/mocks/Cache.go @@ -0,0 +1,167 @@ +// Code generated by mockery v1.0.0. DO NOT EDIT. + +package mocks + +import mock "github.com/stretchr/testify/mock" +import time "time" + +// Cache is an autogenerated mock type for the Cache type +type Cache struct { + mock.Mock +} + +// Get provides a mock function with given fields: key, value +func (_m *Cache) Get(key string, value interface{}) error { + ret := _m.Called(key, value) + + var r0 error + if rf, ok := ret.Get(0).(func(string, interface{}) error); ok { + r0 = rf(key, value) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// GetInvalidateClusterEvent provides a mock function with given fields: +func (_m *Cache) GetInvalidateClusterEvent() string { + ret := _m.Called() + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// Keys provides a mock function with given fields: +func (_m *Cache) Keys() ([]string, error) { + ret := _m.Called() + + var r0 []string + if rf, ok := ret.Get(0).(func() []string); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]string) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Len provides a mock function with given fields: +func (_m *Cache) Len() (int, error) { + ret := _m.Called() + + var r0 int + if rf, ok := ret.Get(0).(func() int); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(int) + } + + var r1 error + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Name provides a mock function with given fields: +func (_m *Cache) Name() string { + ret := _m.Called() + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// Purge provides a mock function with given fields: +func (_m *Cache) Purge() error { + ret := _m.Called() + + var r0 error + if rf, ok := ret.Get(0).(func() error); ok { + r0 = rf() + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Remove provides a mock function with given fields: key +func (_m *Cache) Remove(key string) error { + ret := _m.Called(key) + + var r0 error + if rf, ok := ret.Get(0).(func(string) error); ok { + r0 = rf(key) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Set provides a mock function with given fields: key, value +func (_m *Cache) Set(key string, value interface{}) error { + ret := _m.Called(key, value) + + var r0 error + if rf, ok := ret.Get(0).(func(string, interface{}) error); ok { + r0 = rf(key, value) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// SetWithDefaultExpiry provides a mock function with given fields: key, value +func (_m *Cache) SetWithDefaultExpiry(key string, value interface{}) error { + ret := _m.Called(key, value) + + var r0 error + if rf, ok := ret.Get(0).(func(string, interface{}) error); ok { + r0 = rf(key, value) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// SetWithExpiry provides a mock function with given fields: key, value, ttl +func (_m *Cache) SetWithExpiry(key string, value interface{}, ttl time.Duration) error { + ret := _m.Called(key, value, ttl) + + var r0 error + if rf, ok := ret.Get(0).(func(string, interface{}, time.Duration) error); ok { + r0 = rf(key, value, ttl) + } else { + r0 = ret.Error(0) + } + + return r0 +} diff --git a/services/cache2/mocks/Provider.go b/services/cache2/mocks/Provider.go new file mode 100644 index 0000000000..940f9ddc81 --- /dev/null +++ b/services/cache2/mocks/Provider.go @@ -0,0 +1,55 @@ +// Code generated by mockery v1.0.0. DO NOT EDIT. + +package mocks + +import cache2 "github.com/mattermost/mattermost-server/v5/services/cache2" +import mock "github.com/stretchr/testify/mock" + +// Provider is an autogenerated mock type for the Provider type +type Provider struct { + mock.Mock +} + +// Close provides a mock function with given fields: +func (_m *Provider) Close() error { + ret := _m.Called() + + var r0 error + if rf, ok := ret.Get(0).(func() error); ok { + r0 = rf() + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Connect provides a mock function with given fields: +func (_m *Provider) Connect() error { + ret := _m.Called() + + var r0 error + if rf, ok := ret.Get(0).(func() error); ok { + r0 = rf() + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// NewCache provides a mock function with given fields: opts +func (_m *Provider) NewCache(opts *cache2.CacheOptions) cache2.Cache { + ret := _m.Called(opts) + + var r0 cache2.Cache + if rf, ok := ret.Get(0).(func(*cache2.CacheOptions) cache2.Cache); ok { + r0 = rf(opts) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(cache2.Cache) + } + } + + return r0 +} diff --git a/services/cache2/provider.go b/services/cache2/provider.go index 284c43993e..23409c73cd 100644 --- a/services/cache2/provider.go +++ b/services/cache2/provider.go @@ -34,6 +34,7 @@ func NewProvider() Provider { // NewCache creates a new cache with given opts func (c *cacheProvider) NewCache(opts *CacheOptions) Cache { return NewLRU(&LRUOptions{ + Name: opts.Name, Size: opts.Size, DefaultExpiry: opts.DefaultExpiry, InvalidateClusterEvent: opts.InvalidateClusterEvent, diff --git a/store/localcachelayer/channel_layer.go b/store/localcachelayer/channel_layer.go index d97a6d7a2a..32e72c6810 100644 --- a/store/localcachelayer/channel_layer.go +++ b/store/localcachelayer/channel_layer.go @@ -89,8 +89,9 @@ func (s LocalCacheChannelStore) InvalidateChannel(channelId string) { func (s LocalCacheChannelStore) GetMemberCount(channelId string, allowFromCache bool) (int64, *model.AppError) { if allowFromCache { - if count := s.rootStore.doStandardReadCache(s.rootStore.channelMemberCountsCache, channelId); count != nil { - return count.(int64), nil + var count int64 + if err := s.rootStore.doStandardReadCache(s.rootStore.channelMemberCountsCache, channelId, &count); err == nil { + return count, nil } } count, err := s.ChannelStore.GetMemberCount(channelId, allowFromCache) @@ -104,8 +105,9 @@ func (s LocalCacheChannelStore) GetMemberCount(channelId string, allowFromCache func (s LocalCacheChannelStore) GetGuestCount(channelId string, allowFromCache bool) (int64, *model.AppError) { if allowFromCache { - if count := s.rootStore.doStandardReadCache(s.rootStore.channelGuestCountCache, channelId); count != nil { - return count.(int64), nil + var count int64 + if err := s.rootStore.doStandardReadCache(s.rootStore.channelGuestCountCache, channelId, &count); err == nil { + return count, nil } } count, err := s.ChannelStore.GetGuestCount(channelId, allowFromCache) @@ -118,8 +120,9 @@ func (s LocalCacheChannelStore) GetGuestCount(channelId string, allowFromCache b } func (s LocalCacheChannelStore) GetMemberCountFromCache(channelId string) int64 { - if count := s.rootStore.doStandardReadCache(s.rootStore.channelMemberCountsCache, channelId); count != nil { - return count.(int64) + var count int64 + if err := s.rootStore.doStandardReadCache(s.rootStore.channelMemberCountsCache, channelId, &count); err == nil { + return count } count, err := s.GetMemberCount(channelId, true) @@ -132,8 +135,9 @@ func (s LocalCacheChannelStore) GetMemberCountFromCache(channelId string) int64 func (s LocalCacheChannelStore) GetPinnedPostCount(channelId string, allowFromCache bool) (int64, *model.AppError) { if allowFromCache { - if count := s.rootStore.doStandardReadCache(s.rootStore.channelPinnedPostCountsCache, channelId); count != nil { - return count.(int64), nil + var count int64 + if err := s.rootStore.doStandardReadCache(s.rootStore.channelPinnedPostCountsCache, channelId, &count); err == nil { + return count, nil } } @@ -153,8 +157,9 @@ func (s LocalCacheChannelStore) GetPinnedPostCount(channelId string, allowFromCa func (s LocalCacheChannelStore) Get(id string, allowFromCache bool) (*model.Channel, error) { if allowFromCache { - if cacheItem := s.rootStore.doStandardReadCache(s.rootStore.channelByIdCache, id); cacheItem != nil { - ch := cacheItem.(*model.Channel).DeepCopy() + var cacheItem *model.Channel + if err := s.rootStore.doStandardReadCache(s.rootStore.channelByIdCache, id, &cacheItem); err == nil { + ch := cacheItem.DeepCopy() return ch, nil } } diff --git a/store/localcachelayer/channel_layer_test.go b/store/localcachelayer/channel_layer_test.go index ef3046d2ac..ba2b935cea 100644 --- a/store/localcachelayer/channel_layer_test.go +++ b/store/localcachelayer/channel_layer_test.go @@ -4,9 +4,10 @@ package localcachelayer import ( - "github.com/mattermost/mattermost-server/v5/model" "testing" + "github.com/mattermost/mattermost-server/v5/model" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/store/localcachelayer/emoji_layer.go b/store/localcachelayer/emoji_layer.go index 7aaeb4062c..5c74e31f51 100644 --- a/store/localcachelayer/emoji_layer.go +++ b/store/localcachelayer/emoji_layer.go @@ -81,15 +81,17 @@ func (es LocalCacheEmojiStore) addToCache(emoji *model.Emoji) { } func (es LocalCacheEmojiStore) getFromCacheById(id string) (*model.Emoji, bool) { - if emoji := es.rootStore.doStandardReadCache(es.rootStore.emojiCacheById, id); emoji != nil { - return emoji.(*model.Emoji), true + var emoji *model.Emoji + if err := es.rootStore.doStandardReadCache(es.rootStore.emojiCacheById, id, &emoji); err == nil { + return emoji, true } return nil, false } func (es LocalCacheEmojiStore) getFromCacheByName(name string) (*model.Emoji, bool) { - if emojiId := es.rootStore.doStandardReadCache(es.rootStore.emojiIdCacheByName, name); emojiId != nil { - return es.getFromCacheById(emojiId.(string)) + var emojiId string + if err := es.rootStore.doStandardReadCache(es.rootStore.emojiIdCacheByName, name, &emojiId); err == nil { + return es.getFromCacheById(emojiId) } return nil, false } diff --git a/store/localcachelayer/file_info_layer.go b/store/localcachelayer/file_info_layer.go index 1d02a5cbd7..d6bf768f77 100644 --- a/store/localcachelayer/file_info_layer.go +++ b/store/localcachelayer/file_info_layer.go @@ -31,8 +31,9 @@ func (s LocalCacheFileInfoStore) GetForPost(postId string, readFromMaster, inclu cacheKey += "_deleted" } - if fileInfo := s.rootStore.doStandardReadCache(s.rootStore.fileInfoCache, cacheKey); fileInfo != nil { - return fileInfo.([]*model.FileInfo), nil + var fileInfo []*model.FileInfo + if err := s.rootStore.doStandardReadCache(s.rootStore.fileInfoCache, cacheKey, &fileInfo); err == nil { + return fileInfo, nil } fileInfos, err := s.FileInfoStore.GetForPost(postId, readFromMaster, includeDeleted, allowFromCache) diff --git a/store/localcachelayer/layer.go b/store/localcachelayer/layer.go index db4251e237..feb2a10ddd 100644 --- a/store/localcachelayer/layer.go +++ b/store/localcachelayer/layer.go @@ -4,9 +4,11 @@ package localcachelayer import ( + "time" + "github.com/mattermost/mattermost-server/v5/einterfaces" "github.com/mattermost/mattermost-server/v5/model" - "github.com/mattermost/mattermost-server/v5/services/cache" + "github.com/mattermost/mattermost-server/v5/services/cache2" "github.com/mattermost/mattermost-server/v5/store" ) @@ -66,47 +68,47 @@ type LocalCacheStore struct { cluster einterfaces.ClusterInterface reaction LocalCacheReactionStore - reactionCache cache.Cache + reactionCache cache2.Cache fileInfo LocalCacheFileInfoStore - fileInfoCache cache.Cache + fileInfoCache cache2.Cache role LocalCacheRoleStore - roleCache cache.Cache - rolePermissionsCache cache.Cache + roleCache cache2.Cache + rolePermissionsCache cache2.Cache scheme LocalCacheSchemeStore - schemeCache cache.Cache + schemeCache cache2.Cache emoji LocalCacheEmojiStore - emojiCacheById cache.Cache - emojiIdCacheByName cache.Cache + emojiCacheById cache2.Cache + emojiIdCacheByName cache2.Cache channel LocalCacheChannelStore - channelMemberCountsCache cache.Cache - channelGuestCountCache cache.Cache - channelPinnedPostCountsCache cache.Cache - channelByIdCache cache.Cache + channelMemberCountsCache cache2.Cache + channelGuestCountCache cache2.Cache + channelPinnedPostCountsCache cache2.Cache + channelByIdCache cache2.Cache webhook LocalCacheWebhookStore - webhookCache cache.Cache + webhookCache cache2.Cache post LocalCachePostStore - postLastPostsCache cache.Cache - lastPostTimeCache cache.Cache + postLastPostsCache cache2.Cache + lastPostTimeCache cache2.Cache user LocalCacheUserStore - userProfileByIdsCache cache.Cache - profilesInChannelCache cache.Cache + userProfileByIdsCache cache2.Cache + profilesInChannelCache cache2.Cache team LocalCacheTeamStore - teamAllTeamIdsForUserCache cache.Cache + teamAllTeamIdsForUserCache cache2.Cache termsOfService LocalCacheTermsOfServiceStore - termsOfServiceCache cache.Cache + termsOfServiceCache cache2.Cache } -func NewLocalCacheLayer(baseStore store.Store, metrics einterfaces.MetricsInterface, cluster einterfaces.ClusterInterface, cacheProvider cache.Provider) LocalCacheStore { +func NewLocalCacheLayer(baseStore store.Store, metrics einterfaces.MetricsInterface, cluster einterfaces.ClusterInterface, cacheProvider cache2.Provider) LocalCacheStore { localCacheStore := LocalCacheStore{ Store: baseStore, @@ -114,54 +116,144 @@ func NewLocalCacheLayer(baseStore store.Store, metrics einterfaces.MetricsInterf metrics: metrics, } // Reactions - localCacheStore.reactionCache = cacheProvider.NewCacheWithParams(REACTION_CACHE_SIZE, "Reaction", REACTION_CACHE_SEC, model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_REACTIONS) + localCacheStore.reactionCache = cacheProvider.NewCache(&cache2.CacheOptions{ + Size: REACTION_CACHE_SIZE, + Name: "Reaction", + DefaultExpiry: REACTION_CACHE_SEC * time.Second, + InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_REACTIONS, + }) localCacheStore.reaction = LocalCacheReactionStore{ReactionStore: baseStore.Reaction(), rootStore: &localCacheStore} // Roles - localCacheStore.roleCache = cacheProvider.NewCacheWithParams(ROLE_CACHE_SIZE, "Role", ROLE_CACHE_SEC, model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_ROLES) - localCacheStore.rolePermissionsCache = cacheProvider.NewCacheWithParams(ROLE_CACHE_SIZE, "RolePermission", ROLE_CACHE_SEC, model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_ROLE_PERMISSIONS) + localCacheStore.roleCache = cacheProvider.NewCache(&cache2.CacheOptions{ + Size: ROLE_CACHE_SIZE, + Name: "Role", + DefaultExpiry: ROLE_CACHE_SEC * time.Second, + InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_ROLES, + }) + localCacheStore.rolePermissionsCache = cacheProvider.NewCache(&cache2.CacheOptions{ + Size: ROLE_CACHE_SIZE, + Name: "RolePermission", + DefaultExpiry: ROLE_CACHE_SEC * time.Second, + InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_ROLE_PERMISSIONS, + }) localCacheStore.role = LocalCacheRoleStore{RoleStore: baseStore.Role(), rootStore: &localCacheStore} // Schemes - localCacheStore.schemeCache = cacheProvider.NewCacheWithParams(SCHEME_CACHE_SIZE, "Scheme", SCHEME_CACHE_SEC, model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_SCHEMES) + localCacheStore.schemeCache = cacheProvider.NewCache(&cache2.CacheOptions{ + Size: SCHEME_CACHE_SIZE, + Name: "Scheme", + DefaultExpiry: SCHEME_CACHE_SEC * time.Second, + InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_SCHEMES, + }) localCacheStore.scheme = LocalCacheSchemeStore{SchemeStore: baseStore.Scheme(), rootStore: &localCacheStore} // FileInfo - localCacheStore.fileInfoCache = cacheProvider.NewCacheWithParams(FILE_INFO_CACHE_SIZE, "FileInfo", FILE_INFO_CACHE_SEC, model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_FILE_INFOS) + localCacheStore.fileInfoCache = cacheProvider.NewCache(&cache2.CacheOptions{ + Size: FILE_INFO_CACHE_SIZE, + Name: "FileInfo", + DefaultExpiry: FILE_INFO_CACHE_SEC * time.Second, + InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_FILE_INFOS, + }) localCacheStore.fileInfo = LocalCacheFileInfoStore{FileInfoStore: baseStore.FileInfo(), rootStore: &localCacheStore} // Webhooks - localCacheStore.webhookCache = cacheProvider.NewCacheWithParams(WEBHOOK_CACHE_SIZE, "Webhook", WEBHOOK_CACHE_SEC, model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_WEBHOOKS) + localCacheStore.webhookCache = cacheProvider.NewCache(&cache2.CacheOptions{ + Size: WEBHOOK_CACHE_SIZE, + Name: "Webhook", + DefaultExpiry: WEBHOOK_CACHE_SEC * time.Second, + InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_WEBHOOKS, + }) localCacheStore.webhook = LocalCacheWebhookStore{WebhookStore: baseStore.Webhook(), rootStore: &localCacheStore} // Emojis - localCacheStore.emojiCacheById = cacheProvider.NewCacheWithParams(EMOJI_CACHE_SIZE, "EmojiById", EMOJI_CACHE_SEC, model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_EMOJIS_BY_ID) - localCacheStore.emojiIdCacheByName = cacheProvider.NewCacheWithParams(EMOJI_CACHE_SIZE, "EmojiByName", EMOJI_CACHE_SEC, model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_EMOJIS_ID_BY_NAME) + localCacheStore.emojiCacheById = cacheProvider.NewCache(&cache2.CacheOptions{ + Size: EMOJI_CACHE_SIZE, + Name: "EmojiById", + DefaultExpiry: EMOJI_CACHE_SEC * time.Second, + InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_EMOJIS_BY_ID, + }) + localCacheStore.emojiIdCacheByName = cacheProvider.NewCache(&cache2.CacheOptions{ + Size: EMOJI_CACHE_SIZE, + Name: "EmojiByName", + DefaultExpiry: EMOJI_CACHE_SEC * time.Second, + InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_EMOJIS_ID_BY_NAME, + }) localCacheStore.emoji = LocalCacheEmojiStore{EmojiStore: baseStore.Emoji(), rootStore: &localCacheStore} // Channels - localCacheStore.channelPinnedPostCountsCache = cacheProvider.NewCacheWithParams(CHANNEL_PINNEDPOSTS_COUNTS_CACHE_SIZE, "ChannelPinnedPostsCounts", CHANNEL_PINNEDPOSTS_COUNTS_CACHE_SEC, model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL_PINNEDPOSTS_COUNTS) - localCacheStore.channelMemberCountsCache = cacheProvider.NewCacheWithParams(CHANNEL_MEMBERS_COUNTS_CACHE_SIZE, "ChannelMemberCounts", CHANNEL_MEMBERS_COUNTS_CACHE_SEC, model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL_MEMBER_COUNTS) - localCacheStore.channelGuestCountCache = cacheProvider.NewCacheWithParams(CHANNEL_GUEST_COUNT_CACHE_SIZE, "ChannelGuestsCount", CHANNEL_GUEST_COUNT_CACHE_SEC, model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL_GUEST_COUNT) - localCacheStore.channelByIdCache = cacheProvider.NewCacheWithParams(model.CHANNEL_CACHE_SIZE, "channelById", CHANNEL_CACHE_SEC, model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL) + localCacheStore.channelPinnedPostCountsCache = cacheProvider.NewCache(&cache2.CacheOptions{ + Size: CHANNEL_PINNEDPOSTS_COUNTS_CACHE_SIZE, + Name: "ChannelPinnedPostsCounts", + DefaultExpiry: CHANNEL_PINNEDPOSTS_COUNTS_CACHE_SEC * time.Second, + InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL_PINNEDPOSTS_COUNTS, + }) + localCacheStore.channelMemberCountsCache = cacheProvider.NewCache(&cache2.CacheOptions{ + Size: CHANNEL_MEMBERS_COUNTS_CACHE_SIZE, + Name: "ChannelMemberCounts", + DefaultExpiry: CHANNEL_MEMBERS_COUNTS_CACHE_SEC * time.Second, + InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL_MEMBER_COUNTS, + }) + localCacheStore.channelGuestCountCache = cacheProvider.NewCache(&cache2.CacheOptions{ + Size: CHANNEL_GUEST_COUNT_CACHE_SIZE, + Name: "ChannelGuestsCount", + DefaultExpiry: CHANNEL_GUEST_COUNT_CACHE_SEC * time.Second, + InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL_GUEST_COUNT, + }) + localCacheStore.channelByIdCache = cacheProvider.NewCache(&cache2.CacheOptions{ + Size: model.CHANNEL_CACHE_SIZE, + Name: "channelById", + DefaultExpiry: CHANNEL_CACHE_SEC * time.Second, + InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL, + }) localCacheStore.channel = LocalCacheChannelStore{ChannelStore: baseStore.Channel(), rootStore: &localCacheStore} // Posts - localCacheStore.postLastPostsCache = cacheProvider.NewCacheWithParams(LAST_POSTS_CACHE_SIZE, "LastPost", LAST_POSTS_CACHE_SEC, model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_LAST_POSTS) - localCacheStore.lastPostTimeCache = cacheProvider.NewCacheWithParams(LAST_POST_TIME_CACHE_SIZE, "LastPostTime", LAST_POST_TIME_CACHE_SEC, model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_LAST_POST_TIME) + localCacheStore.postLastPostsCache = cacheProvider.NewCache(&cache2.CacheOptions{ + Size: LAST_POSTS_CACHE_SIZE, + Name: "LastPost", + DefaultExpiry: LAST_POSTS_CACHE_SEC * time.Second, + InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_LAST_POSTS, + }) + localCacheStore.lastPostTimeCache = cacheProvider.NewCache(&cache2.CacheOptions{ + Size: LAST_POST_TIME_CACHE_SIZE, + Name: "LastPostTime", + DefaultExpiry: LAST_POST_TIME_CACHE_SEC * time.Second, + InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_LAST_POST_TIME, + }) localCacheStore.post = LocalCachePostStore{PostStore: baseStore.Post(), rootStore: &localCacheStore} // TOS - localCacheStore.termsOfServiceCache = cacheProvider.NewCacheWithParams(TERMS_OF_SERVICE_CACHE_SIZE, "TermsOfService", TERMS_OF_SERVICE_CACHE_SEC, model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_TERMS_OF_SERVICE) + localCacheStore.termsOfServiceCache = cacheProvider.NewCache(&cache2.CacheOptions{ + Size: TERMS_OF_SERVICE_CACHE_SIZE, + Name: "TermsOfService", + DefaultExpiry: TERMS_OF_SERVICE_CACHE_SEC * time.Second, + InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_TERMS_OF_SERVICE, + }) localCacheStore.termsOfService = LocalCacheTermsOfServiceStore{TermsOfServiceStore: baseStore.TermsOfService(), rootStore: &localCacheStore} // Users - localCacheStore.userProfileByIdsCache = cacheProvider.NewCacheWithParams(USER_PROFILE_BY_ID_CACHE_SIZE, "UserProfileByIds", USER_PROFILE_BY_ID_SEC, model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_PROFILE_BY_IDS) - localCacheStore.profilesInChannelCache = cacheProvider.NewCacheWithParams(PROFILES_IN_CHANNEL_CACHE_SIZE, "ProfilesInChannel", PROFILES_IN_CHANNEL_CACHE_SEC, model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_PROFILE_IN_CHANNEL) + localCacheStore.userProfileByIdsCache = cacheProvider.NewCache(&cache2.CacheOptions{ + Size: USER_PROFILE_BY_ID_CACHE_SIZE, + Name: "UserProfileByIds", + DefaultExpiry: USER_PROFILE_BY_ID_SEC * time.Second, + InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_PROFILE_BY_IDS, + }) + localCacheStore.profilesInChannelCache = cacheProvider.NewCache(&cache2.CacheOptions{ + Size: PROFILES_IN_CHANNEL_CACHE_SIZE, + Name: "ProfilesInChannel", + DefaultExpiry: PROFILES_IN_CHANNEL_CACHE_SEC * time.Second, + InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_PROFILE_IN_CHANNEL, + }) localCacheStore.user = LocalCacheUserStore{UserStore: baseStore.User(), rootStore: &localCacheStore} // Teams - localCacheStore.teamAllTeamIdsForUserCache = cacheProvider.NewCacheWithParams(TEAM_CACHE_SIZE, "Team", TEAM_CACHE_SEC, model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_TEAMS) + localCacheStore.teamAllTeamIdsForUserCache = cacheProvider.NewCache(&cache2.CacheOptions{ + Size: TEAM_CACHE_SIZE, + Name: "Team", + DefaultExpiry: TEAM_CACHE_SEC * time.Second, + InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_TEAMS, + }) localCacheStore.team = LocalCacheTeamStore{TeamStore: baseStore.Team(), rootStore: &localCacheStore} if cluster != nil { @@ -236,7 +328,7 @@ func (s LocalCacheStore) DropAllTables() { s.Store.DropAllTables() } -func (s *LocalCacheStore) doInvalidateCacheCluster(cache cache.Cache, key string) { +func (s *LocalCacheStore) doInvalidateCacheCluster(cache cache2.Cache, key string) { cache.Remove(key) if s.cluster != nil { msg := &model.ClusterMessage{ @@ -248,26 +340,25 @@ func (s *LocalCacheStore) doInvalidateCacheCluster(cache cache.Cache, key string } } -func (s *LocalCacheStore) doStandardAddToCache(cache cache.Cache, key string, value interface{}) { - cache.AddWithDefaultExpires(key, value) +func (s *LocalCacheStore) doStandardAddToCache(cache cache2.Cache, key string, value interface{}) { + cache.SetWithDefaultExpiry(key, value) } -func (s *LocalCacheStore) doStandardReadCache(cache cache.Cache, key string) interface{} { - if cacheItem, ok := cache.Get(key); ok { +func (s *LocalCacheStore) doStandardReadCache(cache cache2.Cache, key string, value interface{}) error { + if err := cache.Get(key, value); err == nil { if s.metrics != nil { s.metrics.IncrementMemCacheHitCounter(cache.Name()) } - return cacheItem + return nil + } else { + if s.metrics != nil { + s.metrics.IncrementMemCacheMissCounter(cache.Name()) + } + return err } - - if s.metrics != nil { - s.metrics.IncrementMemCacheMissCounter(cache.Name()) - } - - return nil } -func (s *LocalCacheStore) doClearCacheCluster(cache cache.Cache) { +func (s *LocalCacheStore) doClearCacheCluster(cache cache2.Cache) { cache.Purge() if s.cluster != nil { msg := &model.ClusterMessage{ diff --git a/store/localcachelayer/main_test.go b/store/localcachelayer/main_test.go index 294622b3de..272c65a521 100644 --- a/store/localcachelayer/main_test.go +++ b/store/localcachelayer/main_test.go @@ -7,8 +7,10 @@ import ( "fmt" "testing" + "github.com/mattermost/mattermost-server/v5/services/cache2" + "github.com/mattermost/mattermost-server/v5/model" - "github.com/mattermost/mattermost-server/v5/services/cache/lru" + cachemocks "github.com/mattermost/mattermost-server/v5/services/cache2/mocks" "github.com/mattermost/mattermost-server/v5/store" "github.com/mattermost/mattermost-server/v5/store/storetest/mocks" "github.com/mattermost/mattermost-server/v5/testlib" @@ -17,117 +19,10 @@ import ( var mainHelper *testlib.MainHelper -func getMockCacheProvider() *mocks.CacheProvider { - mockCacheProvider := mocks.CacheProvider{} - //todo: replace this line with mocks for all tests - mockCacheProvider.On("NewCacheWithParams", - mock.AnythingOfType("int"), - "Reaction", - mock.AnythingOfType("int64"), - mock.AnythingOfType("string")).Return(lru.New(128)) - - mockCacheProvider.On("NewCacheWithParams", - mock.AnythingOfType("int"), - "Role", - mock.AnythingOfType("int64"), - mock.AnythingOfType("string")).Return(lru.New(128)) - - mockCacheProvider.On("NewCacheWithParams", - mock.AnythingOfType("int"), - "RolePermission", - mock.AnythingOfType("int64"), - mock.AnythingOfType("string")).Return(lru.New(128)) - - mockCacheProvider.On("NewCacheWithParams", - mock.AnythingOfType("int"), - "Scheme", - mock.AnythingOfType("int64"), - mock.AnythingOfType("string")).Return(lru.New(128)) - - mockCacheProvider.On("NewCacheWithParams", - mock.AnythingOfType("int"), - "Webhook", - mock.AnythingOfType("int64"), - mock.AnythingOfType("string")).Return(lru.New(128)) - - mockCacheProvider.On("NewCacheWithParams", - mock.AnythingOfType("int"), - "EmojiById", - mock.AnythingOfType("int64"), - mock.AnythingOfType("string")).Return(lru.New(128)) - - mockCacheProvider.On("NewCacheWithParams", - mock.AnythingOfType("int"), - "EmojiByName", - mock.AnythingOfType("int64"), - mock.AnythingOfType("string")).Return(lru.New(128)) - - mockCacheProvider.On("NewCacheWithParams", - mock.AnythingOfType("int"), - "ChannelPinnedPostsCounts", - mock.AnythingOfType("int64"), - mock.AnythingOfType("string")).Return(lru.New(128)) - - mockCacheProvider.On("NewCacheWithParams", - mock.AnythingOfType("int"), - "ChannelMemberCounts", - mock.AnythingOfType("int64"), - mock.AnythingOfType("string")).Return(lru.New(128)) - - mockCacheProvider.On("NewCacheWithParams", - mock.AnythingOfType("int"), - "ChannelGuestsCount", - mock.AnythingOfType("int64"), - mock.AnythingOfType("string")).Return(lru.New(128)) - - mockCacheProvider.On("NewCacheWithParams", - mock.AnythingOfType("int"), - "channelById", - mock.AnythingOfType("int64"), - mock.AnythingOfType("string")).Return(lru.New(128)) - - mockCacheProvider.On("NewCacheWithParams", - mock.AnythingOfType("int"), - "LastPost", - mock.AnythingOfType("int64"), - mock.AnythingOfType("string")).Return(lru.New(128)) - - mockCacheProvider.On("NewCacheWithParams", - mock.AnythingOfType("int"), - "LastPostTime", - mock.AnythingOfType("int64"), - mock.AnythingOfType("string")).Return(lru.New(128)) - - mockCacheProvider.On("NewCacheWithParams", - mock.AnythingOfType("int"), - "TermsOfService", - mock.AnythingOfType("int64"), - mock.AnythingOfType("string")).Return(lru.New(128)) - - mockCacheProvider.On("NewCacheWithParams", - mock.AnythingOfType("int"), - "UserProfileByIds", - mock.AnythingOfType("int64"), - mock.AnythingOfType("string")).Return(lru.New(128)) - - mockCacheProvider.On("NewCacheWithParams", - mock.AnythingOfType("int"), - "ProfilesInChannel", - mock.AnythingOfType("int64"), - mock.AnythingOfType("string")).Return(lru.New(128)) - - mockCacheProvider.On("NewCacheWithParams", - mock.AnythingOfType("int"), - "Team", - mock.AnythingOfType("int64"), - mock.AnythingOfType("string")).Return(lru.New(128)) - - mockCacheProvider.On("NewCacheWithParams", - mock.AnythingOfType("int"), - "FileInfo", - mock.AnythingOfType("int64"), - mock.AnythingOfType("string")).Return(lru.New(128)) - +func getMockCacheProvider() cache2.Provider { + mockCacheProvider := cachemocks.Provider{} + mockCacheProvider.On("NewCache", mock.Anything). + Return(cache2.NewLRU(&cache2.LRUOptions{Size: 128})) return &mockCacheProvider } @@ -230,7 +125,11 @@ func getMockStore() *mocks.Store { mockTermsOfServiceStore.On("Get", "123", false).Return(&fakeTermsOfService, nil) mockStore.On("TermsOfService").Return(&mockTermsOfServiceStore) - fakeUser := []*model.User{{Id: "123", AuthData: model.NewString("")}} + fakeUser := []*model.User{{ + Id: "123", + AuthData: model.NewString("authData"), + AuthService: "authService", + }} mockUserStore := mocks.UserStore{} mockUserStore.On("GetProfileByIds", []string{"123"}, &store.UserGetByIdsOpts{}, true).Return(fakeUser, nil) mockUserStore.On("GetProfileByIds", []string{"123"}, &store.UserGetByIdsOpts{}, false).Return(fakeUser, nil) diff --git a/store/localcachelayer/post_layer.go b/store/localcachelayer/post_layer.go index c5219f48d9..685543418e 100644 --- a/store/localcachelayer/post_layer.go +++ b/store/localcachelayer/post_layer.go @@ -62,8 +62,9 @@ func (s LocalCachePostStore) InvalidateLastPostTimeCache(channelId string) { func (s LocalCachePostStore) GetEtag(channelId string, allowFromCache bool) string { if allowFromCache { - if lastTime := s.rootStore.doStandardReadCache(s.rootStore.lastPostTimeCache, channelId); lastTime != nil { - return fmt.Sprintf("%v.%v", model.CurrentVersion, lastTime.(int64)) + var lastTime int64 + if err := s.rootStore.doStandardReadCache(s.rootStore.lastPostTimeCache, channelId, &lastTime); err == nil { + return fmt.Sprintf("%v.%v", model.CurrentVersion, lastTime) } } @@ -82,7 +83,8 @@ func (s LocalCachePostStore) GetPostsSince(options model.GetPostsSinceOptions, a if allowFromCache { // If the last post in the channel's time is less than or equal to the time we are getting posts since, // we can safely return no posts. - if lastTime := s.rootStore.doStandardReadCache(s.rootStore.lastPostTimeCache, options.ChannelId); lastTime != nil && lastTime.(int64) <= options.Time { + var lastTime int64 + if err := s.rootStore.doStandardReadCache(s.rootStore.lastPostTimeCache, options.ChannelId, &lastTime); err == nil && lastTime <= options.Time { list := model.NewPostList() return list, nil } @@ -111,8 +113,9 @@ func (s LocalCachePostStore) GetPosts(options model.GetPostsOptions, allowFromCa offset := options.PerPage * options.Page // Caching only occurs on limits of 30 and 60, the common limits requested by MM clients if offset == 0 && (options.PerPage == 60 || options.PerPage == 30) { - if cacheItem := s.rootStore.doStandardReadCache(s.rootStore.postLastPostsCache, fmt.Sprintf("%s%v", options.ChannelId, options.PerPage)); cacheItem != nil { - return cacheItem.(*model.PostList), nil + var cacheItem *model.PostList + if err := s.rootStore.doStandardReadCache(s.rootStore.postLastPostsCache, fmt.Sprintf("%s%v", options.ChannelId, options.PerPage), &cacheItem); err == nil { + return cacheItem, nil } } diff --git a/store/localcachelayer/reaction_layer.go b/store/localcachelayer/reaction_layer.go index 7497b6c8ea..d53569005e 100644 --- a/store/localcachelayer/reaction_layer.go +++ b/store/localcachelayer/reaction_layer.go @@ -36,8 +36,9 @@ func (s LocalCacheReactionStore) GetForPost(postId string, allowFromCache bool) return s.ReactionStore.GetForPost(postId, false) } - if reaction := s.rootStore.doStandardReadCache(s.rootStore.reactionCache, postId); reaction != nil { - return reaction.([]*model.Reaction), nil + var reaction []*model.Reaction + if err := s.rootStore.doStandardReadCache(s.rootStore.reactionCache, postId, &reaction); err == nil { + return reaction, nil } reaction, err := s.ReactionStore.GetForPost(postId, false) diff --git a/store/localcachelayer/role_layer.go b/store/localcachelayer/role_layer.go index 0af6a7d5bd..f19d59a95e 100644 --- a/store/localcachelayer/role_layer.go +++ b/store/localcachelayer/role_layer.go @@ -41,8 +41,9 @@ func (s LocalCacheRoleStore) Save(role *model.Role) (*model.Role, *model.AppErro } func (s LocalCacheRoleStore) GetByName(name string) (*model.Role, *model.AppError) { - if role := s.rootStore.doStandardReadCache(s.rootStore.roleCache, name); role != nil { - return role.(*model.Role), nil + var role *model.Role + if err := s.rootStore.doStandardReadCache(s.rootStore.roleCache, name, &role); err == nil { + return role, nil } role, err := s.RoleStore.GetByName(name) @@ -58,8 +59,9 @@ func (s LocalCacheRoleStore) GetByNames(names []string) ([]*model.Role, *model.A var rolesToQuery []string for _, roleName := range names { - if role := s.rootStore.doStandardReadCache(s.rootStore.roleCache, roleName); role != nil { - foundRoles = append(foundRoles, role.(*model.Role)) + var role *model.Role + if err := s.rootStore.doStandardReadCache(s.rootStore.roleCache, roleName, &role); err == nil { + foundRoles = append(foundRoles, role) } else { rolesToQuery = append(rolesToQuery, roleName) } @@ -95,8 +97,9 @@ func (s LocalCacheRoleStore) PermanentDeleteAll() *model.AppError { func (s LocalCacheRoleStore) ChannelHigherScopedPermissions(roleNames []string) (map[string]*model.RolePermissions, *model.AppError) { sort.Strings(roleNames) cacheKey := strings.Join(roleNames, "/") - if rolePermissionsMap := s.rootStore.doStandardReadCache(s.rootStore.rolePermissionsCache, cacheKey); rolePermissionsMap != nil { - return rolePermissionsMap.(map[string]*model.RolePermissions), nil + var rolePermissionsMap map[string]*model.RolePermissions + if err := s.rootStore.doStandardReadCache(s.rootStore.rolePermissionsCache, cacheKey, &rolePermissionsMap); err == nil { + return rolePermissionsMap, nil } rolePermissionsMap, err := s.RoleStore.ChannelHigherScopedPermissions(roleNames) diff --git a/store/localcachelayer/scheme_layer.go b/store/localcachelayer/scheme_layer.go index f31a1f62c9..bb213f8406 100644 --- a/store/localcachelayer/scheme_layer.go +++ b/store/localcachelayer/scheme_layer.go @@ -29,8 +29,9 @@ func (s LocalCacheSchemeStore) Save(scheme *model.Scheme) (*model.Scheme, error) } func (s LocalCacheSchemeStore) Get(schemeId string) (*model.Scheme, error) { - if scheme := s.rootStore.doStandardReadCache(s.rootStore.schemeCache, schemeId); scheme != nil { - return scheme.(*model.Scheme), nil + var scheme *model.Scheme + if err := s.rootStore.doStandardReadCache(s.rootStore.schemeCache, schemeId, &scheme); err == nil { + return scheme, nil } scheme, err := s.SchemeStore.Get(schemeId) diff --git a/store/localcachelayer/team_layer.go b/store/localcachelayer/team_layer.go index 457827d24f..588d0a8c66 100644 --- a/store/localcachelayer/team_layer.go +++ b/store/localcachelayer/team_layer.go @@ -40,8 +40,9 @@ func (s LocalCacheTeamStore) GetUserTeamIds(userID string, allowFromCache bool) return s.TeamStore.GetUserTeamIds(userID, allowFromCache) } - if userTeamIds := s.rootStore.doStandardReadCache(s.rootStore.teamAllTeamIdsForUserCache, userID); userTeamIds != nil { - return userTeamIds.([]string), nil + var userTeamIds []string + if err := s.rootStore.doStandardReadCache(s.rootStore.teamAllTeamIdsForUserCache, userID, &userTeamIds); err == nil { + return userTeamIds, nil } userTeamIds, err := s.TeamStore.GetUserTeamIds(userID, allowFromCache) diff --git a/store/localcachelayer/terms_of_service_layer.go b/store/localcachelayer/terms_of_service_layer.go index 2a25a93303..f5bbcbbc67 100644 --- a/store/localcachelayer/terms_of_service_layer.go +++ b/store/localcachelayer/terms_of_service_layer.go @@ -45,9 +45,10 @@ func (s LocalCacheTermsOfServiceStore) Save(termsOfService *model.TermsOfService func (s LocalCacheTermsOfServiceStore) GetLatest(allowFromCache bool) (*model.TermsOfService, error) { if allowFromCache { - if s.rootStore.termsOfServiceCache.Len() != 0 { - if cacheItem := s.rootStore.doStandardReadCache(s.rootStore.termsOfServiceCache, LATEST_KEY); cacheItem != nil { - return cacheItem.(*model.TermsOfService), nil + if len, err := s.rootStore.termsOfServiceCache.Len(); err == nil && len != 0 { + var cacheItem *model.TermsOfService + if err := s.rootStore.doStandardReadCache(s.rootStore.termsOfServiceCache, LATEST_KEY, &cacheItem); err == nil { + return cacheItem, nil } } } @@ -64,8 +65,9 @@ func (s LocalCacheTermsOfServiceStore) GetLatest(allowFromCache bool) (*model.Te func (s LocalCacheTermsOfServiceStore) Get(id string, allowFromCache bool) (*model.TermsOfService, error) { if allowFromCache { - if cacheItem := s.rootStore.doStandardReadCache(s.rootStore.termsOfServiceCache, id); cacheItem != nil { - return cacheItem.(*model.TermsOfService), nil + var cacheItem *model.TermsOfService + if err := s.rootStore.doStandardReadCache(s.rootStore.termsOfServiceCache, id, &cacheItem); err == nil { + return cacheItem, nil } } diff --git a/store/localcachelayer/user_layer.go b/store/localcachelayer/user_layer.go index 88586c1ef8..c437296e2e 100644 --- a/store/localcachelayer/user_layer.go +++ b/store/localcachelayer/user_layer.go @@ -48,15 +48,16 @@ func (s LocalCacheUserStore) InvalidateProfileCacheForUser(userId string) { } func (s LocalCacheUserStore) InvalidateProfilesInChannelCacheByUser(userId string) { - keys := s.rootStore.profilesInChannelCache.Keys() - - for _, key := range keys { - if cacheItem, ok := s.rootStore.profilesInChannelCache.Get(key); ok { - userMap := cacheItem.(map[string]*model.User) - if _, userInCache := userMap[userId]; userInCache { - s.rootStore.doInvalidateCacheCluster(s.rootStore.profilesInChannelCache, key) - if s.rootStore.metrics != nil { - s.rootStore.metrics.IncrementMemCacheInvalidationCounter("Profiles in Channel - Remove by User") + keys, err := s.rootStore.profilesInChannelCache.Keys() + if err == nil { + for _, key := range keys { + var userMap map[string]*model.User + if err = s.rootStore.profilesInChannelCache.Get(key, &userMap); err == nil { + if _, userInCache := userMap[userId]; userInCache { + s.rootStore.doInvalidateCacheCluster(s.rootStore.profilesInChannelCache, key) + if s.rootStore.metrics != nil { + s.rootStore.metrics.IncrementMemCacheInvalidationCounter("Profiles in Channel - Remove by User") + } } } } @@ -72,8 +73,8 @@ func (s LocalCacheUserStore) InvalidateProfilesInChannelCache(channelId string) func (s LocalCacheUserStore) GetAllProfilesInChannel(channelId string, allowFromCache bool) (map[string]*model.User, *model.AppError) { if allowFromCache { - if cacheItem := s.rootStore.doStandardReadCache(s.rootStore.profilesInChannelCache, channelId); cacheItem != nil { - cachedMap := cacheItem.(map[string]*model.User) + var cachedMap map[string]*model.User + if err := s.rootStore.doStandardReadCache(s.rootStore.profilesInChannelCache, channelId, &cachedMap); err == nil { return deepCopyUserMap(cachedMap), nil } } @@ -103,10 +104,10 @@ func (s LocalCacheUserStore) GetProfileByIds(userIds []string, options *store.Us remainingUserIds := make([]string, 0) for _, userId := range userIds { - if cacheItem := s.rootStore.doStandardReadCache(s.rootStore.userProfileByIdsCache, userId); cacheItem != nil { - u := cacheItem.(*model.User) - if options.Since == 0 || u.UpdateAt > options.Since { - users = append(users, u.DeepCopy()) + var cacheItem *model.User + if err := s.rootStore.doStandardReadCache(s.rootStore.userProfileByIdsCache, userId, &cacheItem); err == nil { + if options.Since == 0 || cacheItem.UpdateAt > options.Since { + users = append(users, cacheItem.DeepCopy()) } } else { remainingUserIds = append(remainingUserIds, userId) @@ -137,13 +138,12 @@ func (s LocalCacheUserStore) GetProfileByIds(userIds []string, options *store.Us // if it is present. Otherwise, it fetches the entry from the store and stores it in the // cache. func (s LocalCacheUserStore) Get(id string) (*model.User, *model.AppError) { - cacheItem := s.rootStore.doStandardReadCache(s.rootStore.userProfileByIdsCache, id) - if cacheItem != nil { + var cacheItem *model.User + if err := s.rootStore.doStandardReadCache(s.rootStore.userProfileByIdsCache, id, &cacheItem); err == nil { if s.rootStore.metrics != nil { s.rootStore.metrics.AddMemCacheHitCounter("Profile By Id", float64(1)) } - u := cacheItem.(*model.User) - return u.DeepCopy(), nil + return cacheItem.DeepCopy(), nil } if s.rootStore.metrics != nil { s.rootStore.metrics.AddMemCacheMissCounter("Profile By Id", float64(1)) diff --git a/store/localcachelayer/user_layer_test.go b/store/localcachelayer/user_layer_test.go index a627a24539..d789cbbe73 100644 --- a/store/localcachelayer/user_layer_test.go +++ b/store/localcachelayer/user_layer_test.go @@ -21,7 +21,11 @@ func TestUserStore(t *testing.T) { func TestUserStoreCache(t *testing.T) { fakeUserIds := []string{"123"} - fakeUser := []*model.User{{Id: "123", AuthData: model.NewString("")}} + fakeUser := []*model.User{{ + Id: "123", + AuthData: model.NewString("authData"), + AuthService: "authService", + }} t.Run("first call not cached, second cached and returning same data", func(t *testing.T) { mockStore := getMockStore() @@ -181,7 +185,11 @@ func TestUserStoreProfilesInChannelCache(t *testing.T) { func TestUserStoreGetCache(t *testing.T) { fakeUserId := "123" - fakeUser := &model.User{Id: "123", AuthData: model.NewString("")} + fakeUser := &model.User{ + Id: "123", + AuthData: model.NewString("authData"), + AuthService: "authService", + } t.Run("first call not cached, second cached and returning same data", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() diff --git a/store/localcachelayer/webhook_layer.go b/store/localcachelayer/webhook_layer.go index fa7729b980..00ef688f6b 100644 --- a/store/localcachelayer/webhook_layer.go +++ b/store/localcachelayer/webhook_layer.go @@ -41,8 +41,9 @@ func (s LocalCacheWebhookStore) GetIncoming(id string, allowFromCache bool) (*mo return s.WebhookStore.GetIncoming(id, allowFromCache) } - if incomingWebhook := s.rootStore.doStandardReadCache(s.rootStore.webhookCache, id); incomingWebhook != nil { - return incomingWebhook.(*model.IncomingWebhook), nil + var incomingWebhook *model.IncomingWebhook + if err := s.rootStore.doStandardReadCache(s.rootStore.webhookCache, id, &incomingWebhook); err == nil { + return incomingWebhook, nil } incomingWebhook, err := s.WebhookStore.GetIncoming(id, allowFromCache) diff --git a/store/storetest/mocks/Cache.go b/store/storetest/mocks/Cache.go deleted file mode 100644 index f900f2211a..0000000000 --- a/store/storetest/mocks/Cache.go +++ /dev/null @@ -1,145 +0,0 @@ -// Code generated by mockery v1.0.0. DO NOT EDIT. - -// Regenerate this file using `make store-mocks`. - -package mocks - -import ( - mock "github.com/stretchr/testify/mock" - - time "time" -) - -// Cache is an autogenerated mock type for the Cache type -type Cache struct { - mock.Mock -} - -// Add provides a mock function with given fields: key, value -func (_m *Cache) Add(key interface{}, value interface{}) { - _m.Called(key, value) -} - -// AddWithDefaultExpires provides a mock function with given fields: key, value -func (_m *Cache) AddWithDefaultExpires(key interface{}, value interface{}) { - _m.Called(key, value) -} - -// AddWithExpiresInSecs provides a mock function with given fields: key, value, expireAtSecs -func (_m *Cache) AddWithExpiresInSecs(key interface{}, value interface{}, expireAtSecs int64) { - _m.Called(key, value, expireAtSecs) -} - -// Get provides a mock function with given fields: key -func (_m *Cache) Get(key interface{}) (interface{}, bool) { - ret := _m.Called(key) - - var r0 interface{} - if rf, ok := ret.Get(0).(func(interface{}) interface{}); ok { - r0 = rf(key) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(interface{}) - } - } - - var r1 bool - if rf, ok := ret.Get(1).(func(interface{}) bool); ok { - r1 = rf(key) - } else { - r1 = ret.Get(1).(bool) - } - - return r0, r1 -} - -// GetInvalidateClusterEvent provides a mock function with given fields: -func (_m *Cache) GetInvalidateClusterEvent() string { - ret := _m.Called() - - var r0 string - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - return r0 -} - -// GetOrAdd provides a mock function with given fields: key, value, ttl -func (_m *Cache) GetOrAdd(key interface{}, value interface{}, ttl time.Duration) (interface{}, bool) { - ret := _m.Called(key, value, ttl) - - var r0 interface{} - if rf, ok := ret.Get(0).(func(interface{}, interface{}, time.Duration) interface{}); ok { - r0 = rf(key, value, ttl) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(interface{}) - } - } - - var r1 bool - if rf, ok := ret.Get(1).(func(interface{}, interface{}, time.Duration) bool); ok { - r1 = rf(key, value, ttl) - } else { - r1 = ret.Get(1).(bool) - } - - return r0, r1 -} - -// Keys provides a mock function with given fields: -func (_m *Cache) Keys() []interface{} { - ret := _m.Called() - - var r0 []interface{} - if rf, ok := ret.Get(0).(func() []interface{}); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]interface{}) - } - } - - return r0 -} - -// Len provides a mock function with given fields: -func (_m *Cache) Len() int { - ret := _m.Called() - - var r0 int - if rf, ok := ret.Get(0).(func() int); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(int) - } - - return r0 -} - -// Name provides a mock function with given fields: -func (_m *Cache) Name() string { - ret := _m.Called() - - var r0 string - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - return r0 -} - -// Purge provides a mock function with given fields: -func (_m *Cache) Purge() { - _m.Called() -} - -// Remove provides a mock function with given fields: key -func (_m *Cache) Remove(key interface{}) { - _m.Called(key) -} diff --git a/store/storetest/mocks/CacheProvider.go b/store/storetest/mocks/CacheProvider.go deleted file mode 100644 index b03cfc6e71..0000000000 --- a/store/storetest/mocks/CacheProvider.go +++ /dev/null @@ -1,57 +0,0 @@ -// Code generated by mockery v1.0.0. DO NOT EDIT. - -// Regenerate this file using `make store-mocks`. - -package mocks - -import ( - cache "github.com/mattermost/mattermost-server/v5/services/cache" - mock "github.com/stretchr/testify/mock" -) - -// CacheProvider is an autogenerated mock type for the CacheProvider type -type CacheProvider struct { - mock.Mock -} - -// NewCache provides a mock function with given fields: size -func (_m *CacheProvider) NewCache(size int) cache.Cache { - ret := _m.Called(size) - - var r0 cache.Cache - if rf, ok := ret.Get(0).(func(int) cache.Cache); ok { - r0 = rf(size) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(cache.Cache) - } - } - - return r0 -} - -// Connect provides a mock function with given fields: -func (_m *CacheProvider) Connect() { - _m.Called() -} - -// Close provides a mock function with given fields: -func (_m *CacheProvider) Close() { - _m.Called() -} - -// NewCacheWithParams provides a mock function with given fields: size, name, defaultExpiry, invalidateClusterEvent -func (_m *CacheProvider) NewCacheWithParams(size int, name string, defaultExpiry int64, invalidateClusterEvent string) cache.Cache { - ret := _m.Called(size, name, defaultExpiry, invalidateClusterEvent) - - var r0 cache.Cache - if rf, ok := ret.Get(0).(func(int, string, int64, string) cache.Cache); ok { - r0 = rf(size, name, defaultExpiry, invalidateClusterEvent) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(cache.Cache) - } - } - - return r0 -} diff --git a/web/web_test.go b/web/web_test.go index 5c888bb5c7..a0725efa46 100644 --- a/web/web_test.go +++ b/web/web_test.go @@ -82,7 +82,7 @@ func setupTestHelper(t testing.TB, store store.Store, includeCacheLayer bool) *T } if includeCacheLayer { // Adds the cache layer to the test store - s.Store = localcachelayer.NewLocalCacheLayer(s.Store, s.Metrics, s.Cluster, s.CacheProvider) + s.Store = localcachelayer.NewLocalCacheLayer(s.Store, s.Metrics, s.Cluster, s.CacheProvider2) } prevListenAddress := *s.Config().ServiceSettings.ListenAddress