diff --git a/api4/apitestlib.go b/api4/apitestlib.go index 7dc756913b..adc6d6b0d6 100644 --- a/api4/apitestlib.go +++ b/api4/apitestlib.go @@ -102,7 +102,11 @@ func setupTestHelper(dbStore store.Store, searchEngine *searchengine.Broker, ent if includeCache { // Adds the cache layer to the test store options = append(options, app.StoreOverride(func(s *app.Server) store.Store { - return localcachelayer.NewLocalCacheLayer(dbStore, s.Metrics, s.Cluster, s.CacheProvider) + lcl, err2 := localcachelayer.NewLocalCacheLayer(dbStore, s.Metrics, s.Cluster, s.CacheProvider) + if err2 != nil { + panic(err2) + } + return lcl })) } else { options = append(options, app.StoreOverride(dbStore)) diff --git a/api4/openGraph.go b/api4/openGraph.go index 818d87f7d8..72ac9135fa 100644 --- a/api4/openGraph.go +++ b/api4/openGraph.go @@ -13,7 +13,7 @@ import ( const OPEN_GRAPH_METADATA_CACHE_SIZE = 10000 -var openGraphDataCache = cache.NewLRU(&cache.LRUOptions{ +var openGraphDataCache = cache.NewLRU(cache.LRUOptions{ Size: OPEN_GRAPH_METADATA_CACHE_SIZE, }) diff --git a/api4/system.go b/api4/system.go index 41b63ccb3c..82b1af0874 100644 --- a/api4/system.go +++ b/api4/system.go @@ -29,7 +29,7 @@ const ( MAX_SERVER_BUSY_SECONDS = 86400 ) -var redirectLocationDataCache = cache.NewLRU(&cache.LRUOptions{ +var redirectLocationDataCache = cache.NewLRU(cache.LRUOptions{ Size: REDIRECT_LOCATION_CACHE_SIZE, }) diff --git a/app/helper_test.go b/app/helper_test.go index d0643b067c..b229e719eb 100644 --- a/app/helper_test.go +++ b/app/helper_test.go @@ -68,7 +68,11 @@ func setupTestHelper(dbStore store.Store, enterprise bool, includeCacheLayer boo if includeCacheLayer { // Adds the cache layer to the test store options = append(options, StoreOverride(func(s *Server) store.Store { - return localcachelayer.NewLocalCacheLayer(dbStore, s.Metrics, s.Cluster, s.CacheProvider) + lcl, err2 := localcachelayer.NewLocalCacheLayer(dbStore, s.Metrics, s.Cluster, s.CacheProvider) + if err2 != nil { + panic(err2) + } + return lcl })) } else { options = append(options, StoreOverride(dbStore)) diff --git a/app/options.go b/app/options.go index 7a5533e312..51302bc26a 100644 --- a/app/options.go +++ b/app/options.go @@ -22,14 +22,14 @@ func StoreOverride(override interface{}) Option { return func(s *Server) error { switch o := override.(type) { case store.Store: - s.newStore = func() store.Store { - return o + s.newStore = func() (store.Store, error) { + return o, nil } return nil case func(*Server) store.Store: - s.newStore = func() store.Store { - return o(s) + s.newStore = func() (store.Store, error) { + return o(s), nil } return nil diff --git a/app/post_metadata.go b/app/post_metadata.go index 02b98fd291..99714d48f8 100644 --- a/app/post_metadata.go +++ b/app/post_metadata.go @@ -31,7 +31,7 @@ const LINK_CACHE_SIZE = 10000 const LINK_CACHE_DURATION = 1 * time.Hour const MaxMetadataImageSize = MaxOpenGraphResponseSize -var linkCache = cache.NewLRU(&cache.LRUOptions{ +var linkCache = cache.NewLRU(cache.LRUOptions{ Size: LINK_CACHE_SIZE, }) diff --git a/app/server.go b/app/server.go index 5a45ef236a..9ddf68cc0d 100644 --- a/app/server.go +++ b/app/server.go @@ -15,6 +15,7 @@ import ( "os/exec" "path" "path/filepath" + "runtime" "strings" "sync" "sync/atomic" @@ -114,7 +115,7 @@ type Server struct { timezones *timezones.Timezones - newStore func() store.Store + newStore func() (store.Store, error) htmlTemplateWatcher *utils.HTMLTemplateWatcher sessionCache cache.Cache @@ -286,34 +287,51 @@ func NewServer(options ...Option) (*Server, error) { return nil, errors.Wrapf(err, "Unable to connect to cache provider") } - s.sessionCache = s.CacheProvider.NewCache(&cache.CacheOptions{ - Size: model.SESSION_CACHE_SIZE, - }) - s.seenPendingPostIdsCache = s.CacheProvider.NewCache(&cache.CacheOptions{ + var err error + if s.sessionCache, err = s.CacheProvider.NewCache(&cache.CacheOptions{ + Size: model.SESSION_CACHE_SIZE, + Striped: true, + StripedBuckets: runtime.NumCPU() - 1, + }); err != nil { + return nil, errors.Wrap(err, "Unable to create session cache") + } + if s.seenPendingPostIdsCache, err = s.CacheProvider.NewCache(&cache.CacheOptions{ Size: PENDING_POST_IDS_CACHE_SIZE, - }) - s.statusCache = s.CacheProvider.NewCache(&cache.CacheOptions{ - Size: model.STATUS_CACHE_SIZE, - }) + }); err != nil { + return nil, errors.Wrap(err, "Unable to create pending post ids cache") + } + if s.statusCache, err = s.CacheProvider.NewCache(&cache.CacheOptions{ + Size: model.STATUS_CACHE_SIZE, + Striped: true, + StripedBuckets: runtime.NumCPU() - 1, + }); err != nil { + return nil, errors.Wrap(err, "Unable to create status cache") + } s.createPushNotificationsHub() - if err := utils.InitTranslations(s.Config().LocalizationSettings); err != nil { - return nil, errors.Wrapf(err, "unable to load Mattermost translation files") + if err2 := utils.InitTranslations(s.Config().LocalizationSettings); err2 != nil { + return nil, errors.Wrapf(err2, "unable to load Mattermost translation files") } s.initEnterprise() if s.newStore == nil { - s.newStore = func() store.Store { + s.newStore = func() (store.Store, error) { s.sqlStore = sqlstore.New(s.Config().SqlSettings, s.Metrics) + + lcl, err2 := localcachelayer.NewLocalCacheLayer( + retrylayer.New(s.sqlStore), + s.Metrics, + s.Cluster, + s.CacheProvider, + ) + if err2 != nil { + return nil, errors.Wrap(err2, "cannot create local cache layer") + } + searchStore := searchlayer.NewSearchLayer( - localcachelayer.NewLocalCacheLayer( - retrylayer.New(s.sqlStore), - s.Metrics, - s.Cluster, - s.CacheProvider, - ), + lcl, s.SearchEngine, s.Config(), ) @@ -330,17 +348,20 @@ func NewServer(options ...Option) (*Server, error) { return timerlayer.New( searchStore, s.Metrics, - ) + ), nil } } - if htmlTemplateWatcher, err := utils.NewHTMLTemplateWatcher("templates"); err != nil { - mlog.Error("Failed to parse server templates", mlog.Err(err)) + if htmlTemplateWatcher, err2 := utils.NewHTMLTemplateWatcher("templates"); err2 != nil { + mlog.Error("Failed to parse server templates", mlog.Err(err2)) } else { s.htmlTemplateWatcher = htmlTemplateWatcher } - s.Store = s.newStore() + s.Store, err = s.newStore() + if err != nil { + return nil, errors.Wrap(err, "cannot create store") + } s.configListenerId = s.AddConfigListener(func(_, _ *model.Config) { s.configOrLicenseListener() diff --git a/app/slashcommands/helper_test.go b/app/slashcommands/helper_test.go index 9a19fb8778..8301b98db6 100644 --- a/app/slashcommands/helper_test.go +++ b/app/slashcommands/helper_test.go @@ -62,7 +62,11 @@ func setupTestHelper(dbStore store.Store, enterprise bool, includeCacheLayer boo options = append(options, app.ConfigStore(memoryStore)) if includeCacheLayer { options = append(options, app.StoreOverride(func(s *app.Server) store.Store { - return localcachelayer.NewLocalCacheLayer(dbStore, s.Metrics, s.Cluster, s.CacheProvider) + lcl, err2 := localcachelayer.NewLocalCacheLayer(dbStore, s.Metrics, s.Cluster, s.CacheProvider) + if err2 != nil { + panic(err2) + } + return lcl })) } else { options = append(options, app.StoreOverride(dbStore)) diff --git a/migrations/helper_test.go b/migrations/helper_test.go index c2309754b8..05d8da1fcf 100644 --- a/migrations/helper_test.go +++ b/migrations/helper_test.go @@ -43,7 +43,10 @@ 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, err = localcachelayer.NewLocalCacheLayer(s.Store, s.Metrics, s.Cluster, s.CacheProvider) + if err != nil { + panic(err) + } th := &TestHelper{ App: app.New(app.ServerConnector(s)), diff --git a/services/cache/lru.go b/services/cache/lru.go index de5d88e784..36265ba0e5 100644 --- a/services/cache/lru.go +++ b/services/cache/lru.go @@ -9,21 +9,22 @@ import ( "time" "github.com/mattermost/mattermost-server/v5/model" + "github.com/tinylib/msgp/msgp" "github.com/vmihailenco/msgpack/v5" ) // LRU is a thread-safe fixed size LRU cache. type LRU struct { - name string + lock sync.RWMutex size int + len int + currentGeneration int64 evictList *list.List items map[string]*list.Element - lock sync.RWMutex defaultExpiry time.Duration + name string invalidateClusterEvent string - currentGeneration int64 - len int } // LRUOptions contains options for initializing LRU cache @@ -32,6 +33,9 @@ type LRUOptions struct { Size int DefaultExpiry time.Duration InvalidateClusterEvent string + // StripedBuckets is used only by LRUStriped and shouldn't be greater than the number + // of CPUs available on the machine running this cache. + StripedBuckets int } // entry is used to hold a value in the evictList. @@ -43,7 +47,7 @@ type entry struct { } // NewLRU creates an LRU of the given size. -func NewLRU(opts *LRUOptions) Cache { +func NewLRU(opts LRUOptions) Cache { return &LRU{ name: opts.Name, size: opts.Size, @@ -141,19 +145,15 @@ func (l *LRU) set(key string, value interface{}, ttl time.Duration) error { var buf []byte var err error - // We use a fast path for hot structs. if msgpVal, ok := value.(msgp.Marshaler); ok { buf, err = msgpVal.MarshalMsg(nil) - if err != nil { - return err - } } else { // Slow path for other structs. buf, err = msgpack.Marshal(value) - if err != nil { - return err - } + } + if err != nil { + return err } l.lock.Lock() diff --git a/services/cache/lru_striped.go b/services/cache/lru_striped.go new file mode 100644 index 0000000000..710cdbeb5a --- /dev/null +++ b/services/cache/lru_striped.go @@ -0,0 +1,149 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +package cache + +import ( + "fmt" + "math" + "time" + + "github.com/cespare/xxhash/v2" +) + +// LRUStriped keeps LRU caches in buckets in order to lower mutex contention. +// This is achieved by hashing the input key to map it to a dedicated bucket. +// Each bucket (an LRU cache) has its own lock that helps distributing the lock +// contention on multiple threads/cores, leading to less wait times. +// +// LRUStriped implements the Cache interface with the same behavior as LRU. +// +// Note that, because of it's distributed nature, the fixed size cannot be strictly respected +// and you may have a tiny bit more space for keys than you defined through LRUOptions. +// Bucket size is computed as follows: (size / nbuckets) + (size % nbuckets) +// +// Because of this size limit per bucket, and because of the nature of the data, you +// may have buckets filled unevenly, and because of this, keys will be evicted from the entire +// cache where a simple LRU wouldn't have. Example: +// +// Two buckets B1 and B2, of max size 2 each, meaning, theoretically, a max size of 4: +// * Say you have a set of 3 keys, they could fill an entire LRU cache. +// * But if all those keys are assigned to a single bucket B1, the first key will be evicted from B1 +// * B2 will remain empty, even though there was enough memory allocated +// +// With 4 buckets and random UUIDs as keys, the amount of false evictions is around 5%. +// +// By default, the number of buckets equals the number of cpus returned from runtime.NumCPU. +// +// This struct is lock-free and intended to be used without lock. +type LRUStriped struct { + buckets []*LRU + name string + invalidateClusterEvent string +} + +func (L LRUStriped) hashkeyMapHash(key string) uint64 { + return xxhash.Sum64String(key) +} + +func (L LRUStriped) keyBucket(key string) *LRU { + return L.buckets[L.hashkeyMapHash(key)%uint64(len(L.buckets))] +} + +// Purge loops through each LRU cache for purging. Since LRUStriped doesn't use any lock, +// each LRU bucket is purged after another one, which means that keys could still +// be present after a call to Purge. +func (L LRUStriped) Purge() error { + for _, lru := range L.buckets { + lru.Purge() // errors from purging LRU can be ignored as they always return nil + } + return nil +} + +// Set does the same as LRU.Set +func (L LRUStriped) Set(key string, value interface{}) error { + return L.keyBucket(key).Set(key, value) +} + +// SetWithDefaultExpiry does the same as LRU.SetWithDefaultExpiry +func (L LRUStriped) SetWithDefaultExpiry(key string, value interface{}) error { + return L.keyBucket(key).SetWithDefaultExpiry(key, value) +} + +// SetWithExpiry does the same as LRU.SetWithExpiry +func (L LRUStriped) SetWithExpiry(key string, value interface{}, ttl time.Duration) error { + return L.keyBucket(key).SetWithExpiry(key, value, ttl) +} + +// Get does the same as LRU.Get +func (L LRUStriped) Get(key string, value interface{}) error { + return L.keyBucket(key).Get(key, value) +} + +// Remove does the same as LRU.Remove +func (L LRUStriped) Remove(key string) error { + return L.keyBucket(key).Remove(key) +} + +// Keys does the same as LRU.Keys. However, because this is lock-free, keys might be +// inserted or removed from a previously scanned LRU cache. +// This is not as precise as using a single LRU instance. +func (L LRUStriped) Keys() ([]string, error) { + var keys []string + for _, lru := range L.buckets { + k, _ := lru.Keys() // Keys never returns any error + keys = append(keys, k...) + } + return keys, nil +} + +// Len does the same as LRU.Len. As for LRUStriped.Keys, this call cannot be precise. +func (L LRUStriped) Len() (int, error) { + var size int + for _, lru := range L.buckets { + s, _ := lru.Len() // Len never returns any error + size += s + } + return size, nil +} + +// GetInvalidateClusterEvent does the same as LRU.GetInvalidateClusterEvent +func (L LRUStriped) GetInvalidateClusterEvent() string { + return L.invalidateClusterEvent +} + +// Name does the same as LRU.Name +func (L LRUStriped) Name() string { + return L.name +} + +// NewLRUStriped creates a striped LRU cache using the special LRUOptions.StripedBuckets value. +// See LRUStriped and LRUOptions for more details. +// +// Not that in order to prevent false eviction, this LRU cache adds 10% (computation is rounded up) of the +// requested size to the total cache size. +func NewLRUStriped(opts LRUOptions) (Cache, error) { + if opts.StripedBuckets == 0 { + return nil, fmt.Errorf("number of buckets is mandatory") + } + + if opts.Size < opts.StripedBuckets { + return nil, fmt.Errorf("cache size must at least be equal to the number of buckets") + } + + // add 10% to the total size, before splitting + opts.Size += int(math.Ceil(float64(opts.Size) * 10.0 / 100.0)) + // now this is the size for each bucket + opts.Size = (opts.Size / opts.StripedBuckets) + (opts.Size % opts.StripedBuckets) + + buckets := make([]*LRU, opts.StripedBuckets) + for i := 0; i < opts.StripedBuckets; i++ { + buckets[i] = NewLRU(opts).(*LRU) + } + + return LRUStriped{ + buckets: buckets, + invalidateClusterEvent: opts.InvalidateClusterEvent, + name: opts.Name, + }, nil +} diff --git a/services/cache/lru_striped_bench_test.go b/services/cache/lru_striped_bench_test.go new file mode 100644 index 0000000000..74cc58b693 --- /dev/null +++ b/services/cache/lru_striped_bench_test.go @@ -0,0 +1,91 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +package cache_test + +import ( + "fmt" + "runtime" + "sync" + "testing" + + "github.com/mattermost/mattermost-server/v5/services/cache" + + "github.com/cespare/xxhash/v2" +) + +const ( + m = 500_000 +) + +func BenchmarkLRUStriped(b *testing.B) { + opts := cache.LRUOptions{ + Name: "", + Size: 128, + DefaultExpiry: 0, + InvalidateClusterEvent: "", + StripedBuckets: runtime.NumCPU() - 1, + } + + cache, err := cache.NewLRUStriped(opts) + if err != nil { + panic(err) + } + // prepare keys and initial cache values and set routine + keys := make([]string, 0, m) + // bucketKeys is to demonstrate that splitted locks is working correctly + // by assigning one sequence of key for each bucket. + bucketKeys := make([][]string, opts.StripedBuckets) + for i := 0; i < m; i++ { + key := fmt.Sprintf("%d-key-%d", i, i) + keys = append(keys, key) + bucketKey := xxhash.Sum64String(key) % uint64(opts.StripedBuckets) + bucketKeys[bucketKey] = append(bucketKeys[bucketKey], key) + } + for i := 0; i < opts.Size; i++ { + cache.Set(keys[i], "preflight") + } + + wgGet := &sync.WaitGroup{} + wgSet := &sync.WaitGroup{} + // need buffered chan because if the set routine finished before we write into the chan, + // we're left without any consumer, making any write to the chan waiting forever. + stopSet := make(chan bool, 1) + set := func() { + defer wgSet.Done() + for i := 0; i < m; i++ { + select { + case <-stopSet: + return + default: + _ = cache.Set(keys[i], "ignored") + } + } + } + + get := func(bucket int) { + defer wgGet.Done() + var out string + for i := 0; i < m; i++ { + _ = cache.Get(bucketKeys[bucket][i%opts.Size], &out) + } + } + + b.StopTimer() + b.ResetTimer() + for i := 0; i < b.N; i++ { + wgSet.Add(1) + go set() + for j := 0; j < opts.StripedBuckets; j++ { + wgGet.Add(1) + go get(j) + } + + b.StartTimer() + wgGet.Wait() + b.StopTimer() + + stopSet <- true + wgSet.Wait() + } +} diff --git a/services/cache/lru_striped_test.go b/services/cache/lru_striped_test.go new file mode 100644 index 0000000000..2cfae041a4 --- /dev/null +++ b/services/cache/lru_striped_test.go @@ -0,0 +1,129 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +package cache + +import ( + "fmt" + "hash/maphash" + "testing" + + "github.com/mattermost/mattermost-server/v5/model" + + "github.com/cespare/xxhash/v2" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func makeLRUPredictibleTestData(num int) [][2]string { + kv := make([][2]string, num) + for i := 0; i < len(kv); i++ { + kv[i] = [2]string{ + fmt.Sprintf("%d-key-%d", i, i), + fmt.Sprintf("%d-val-%d", i, i), + } + } + return kv +} + +func TestNewLRUStriped(t *testing.T) { + scache, err := NewLRUStriped(LRUOptions{StripedBuckets: 3, Size: 20}) + require.NoError(t, err) + + cache := scache.(LRUStriped) + + require.Len(t, cache.buckets, 3) + assert.Equal(t, 8, cache.buckets[0].size) + assert.Equal(t, 8, cache.buckets[1].size) + assert.Equal(t, 8, cache.buckets[2].size) +} + +func TestLRUStripedKeyDistribution(t *testing.T) { + dataset := makeLRUPredictibleTestData(100) + + scache, err := NewLRUStriped(LRUOptions{StripedBuckets: 4, Size: len(dataset)}) + require.NoError(t, err) + cache := scache.(LRUStriped) + for _, kv := range dataset { + require.NoError(t, cache.Set(kv[0], kv[1])) + var out string + require.NoError(t, cache.Get(kv[0], &out)) + require.Equal(t, kv[1], out) + } + + require.Len(t, cache.buckets, 4) + acc := 0 + for i := 0; i < 4; i++ { + clen, err := cache.buckets[i].Len() + acc += clen + assert.NoError(t, err) + assert.GreaterOrEqual(t, clen, len(dataset)/2/4, "at least 50%/nbuckets of all keys in each bucket") + } + // because of the limited size of each bucket and the nature of our data, + // we may have around 10% of our keys evicted in this scenario. removing 1% because we cannot predict + // accurately what is happening with random data. + assert.GreaterOrEqual(t, acc, len(dataset)-(len(dataset)*1.0/100.0)) +} + +func TestLRUStriped_Size(t *testing.T) { + scache, err := NewLRUStriped(LRUOptions{StripedBuckets: 2, Size: 128}) + require.NoError(t, err) + cache := scache.(LRUStriped) + acc := 0 + for _, bucket := range cache.buckets { + acc += bucket.size + } + assert.Equal(t, 128+13+1, acc) // +10% +modulo padding +} + +func TestLRUStriped_HashKey(t *testing.T) { + scache, err := NewLRUStriped(LRUOptions{StripedBuckets: 2, Size: 128}) + require.NoError(t, err) + cache := scache.(LRUStriped) + first := cache.hashkeyMapHash("key") + cache.hashkeyMapHash("other_key_to_ensure_that_result_it’s_not_dependent_on_previous_input") + second := cache.hashkeyMapHash("key") + require.Equal(t, first, second) +} + +func TestLRUStriped_Get(t *testing.T) { + cache, err := NewLRUStriped(LRUOptions{StripedBuckets: 4, Size: 128}) + require.NoError(t, err) + var out string + require.Equal(t, ErrKeyNotFound, cache.Get("key", &out)) + require.Zero(t, out) + + require.NoError(t, cache.Set("key", "value")) + require.NoError(t, cache.Get("key", &out)) + require.Equal(t, "value", out) +} + +var hashSink uint64 + +func BenchmarkSum64(b *testing.B) { + cases := []string{ + "1", + "22", + "333", + model.NewId(), + model.NewId() + model.NewId(), + } + + for _, case_ := range cases { + b.Run(fmt.Sprintf("maphash_string_len_%d", len(case_)), func(b *testing.B) { + seed := maphash.MakeSeed() + b.ResetTimer() + for i := 0; i < b.N; i++ { + var h maphash.Hash + h.SetSeed(seed) + h.WriteString(case_) // documentation and code says it never fails + hashSink = h.Sum64() + } + }) + b.Run(fmt.Sprintf("xxhash_string_len_%d", len(case_)), func(b *testing.B) { + for i := 0; i < b.N; i++ { + hashSink = xxhash.Sum64String(case_) + } + }) + } +} diff --git a/services/cache/lru_test.go b/services/cache/lru_test.go index 641537e97f..3d41af13bf 100644 --- a/services/cache/lru_test.go +++ b/services/cache/lru_test.go @@ -15,7 +15,7 @@ import ( ) func TestLRU(t *testing.T) { - l := NewLRU(&LRUOptions{ + l := NewLRU(LRUOptions{ Size: 128, DefaultExpiry: 0, InvalidateClusterEvent: "", @@ -83,7 +83,7 @@ func TestLRU(t *testing.T) { } func TestLRUExpire(t *testing.T) { - l := NewLRU(&LRUOptions{ + l := NewLRU(LRUOptions{ Size: 128, DefaultExpiry: 1 * time.Second, InvalidateClusterEvent: "", @@ -105,7 +105,7 @@ func TestLRUExpire(t *testing.T) { } func TestLRUMarshalUnMarshal(t *testing.T) { - l := NewLRU(&LRUOptions{ + l := NewLRU(LRUOptions{ Size: 1, DefaultExpiry: 0, InvalidateClusterEvent: "", @@ -299,7 +299,7 @@ func BenchmarkLRU(b *testing.B) { b.Run("simple=new", func(b *testing.B) { for i := 0; i < b.N; i++ { - l2 := NewLRU(&LRUOptions{ + l2 := NewLRU(LRUOptions{ Size: 1, DefaultExpiry: 0, InvalidateClusterEvent: "", @@ -349,7 +349,7 @@ func BenchmarkLRU(b *testing.B) { b.Run("complex=new", func(b *testing.B) { for i := 0; i < b.N; i++ { - l2 := NewLRU(&LRUOptions{ + l2 := NewLRU(LRUOptions{ Size: 1, DefaultExpiry: 0, InvalidateClusterEvent: "", @@ -432,7 +432,7 @@ func BenchmarkLRU(b *testing.B) { b.Run("User=new", func(b *testing.B) { for i := 0; i < b.N; i++ { - l2 := NewLRU(&LRUOptions{ + l2 := NewLRU(LRUOptions{ Size: 1, DefaultExpiry: 0, InvalidateClusterEvent: "", @@ -465,7 +465,7 @@ func BenchmarkLRU(b *testing.B) { b.Run("UserMap=new", func(b *testing.B) { for i := 0; i < b.N; i++ { - l2 := NewLRU(&LRUOptions{ + l2 := NewLRU(LRUOptions{ Size: 1, DefaultExpiry: 0, InvalidateClusterEvent: "", @@ -545,7 +545,7 @@ func BenchmarkLRU(b *testing.B) { b.Run("Post=new", func(b *testing.B) { for i := 0; i < b.N; i++ { - l2 := NewLRU(&LRUOptions{ + l2 := NewLRU(LRUOptions{ Size: 1, DefaultExpiry: 0, InvalidateClusterEvent: "", @@ -569,7 +569,7 @@ func BenchmarkLRU(b *testing.B) { b.Run("Status=new", func(b *testing.B) { for i := 0; i < b.N; i++ { - l2 := NewLRU(&LRUOptions{ + l2 := NewLRU(LRUOptions{ Size: 1, DefaultExpiry: 0, InvalidateClusterEvent: "", @@ -605,7 +605,7 @@ func BenchmarkLRU(b *testing.B) { b.Run("Session=new", func(b *testing.B) { for i := 0; i < b.N; i++ { - l2 := NewLRU(&LRUOptions{ + l2 := NewLRU(LRUOptions{ Size: 1, DefaultExpiry: 0, InvalidateClusterEvent: "", @@ -621,7 +621,7 @@ func BenchmarkLRU(b *testing.B) { } func TestLRURace(t *testing.T) { - l2 := NewLRU(&LRUOptions{ + l2 := NewLRU(LRUOptions{ Size: 1, DefaultExpiry: 0, InvalidateClusterEvent: "", diff --git a/services/cache/mocks/Cache.go b/services/cache/mocks/Cache.go index 93651171b0..feca180bc6 100644 --- a/services/cache/mocks/Cache.go +++ b/services/cache/mocks/Cache.go @@ -2,8 +2,11 @@ package mocks -import mock "github.com/stretchr/testify/mock" -import time "time" +import ( + time "time" + + mock "github.com/stretchr/testify/mock" +) // Cache is an autogenerated mock type for the Cache type type Cache struct { diff --git a/services/cache/mocks/Provider.go b/services/cache/mocks/Provider.go index 60408ad599..d16d8a258a 100644 --- a/services/cache/mocks/Provider.go +++ b/services/cache/mocks/Provider.go @@ -41,7 +41,7 @@ func (_m *Provider) Connect() error { } // NewCache provides a mock function with given fields: opts -func (_m *Provider) NewCache(opts *cache.CacheOptions) cache.Cache { +func (_m *Provider) NewCache(opts *cache.CacheOptions) (cache.Cache, error) { ret := _m.Called(opts) var r0 cache.Cache @@ -53,5 +53,12 @@ func (_m *Provider) NewCache(opts *cache.CacheOptions) cache.Cache { } } - return r0 + var r1 error + if rf, ok := ret.Get(1).(func(*cache.CacheOptions) error); ok { + r1 = rf(opts) + } else { + r1 = ret.Error(1) + } + + return r0, r1 } diff --git a/services/cache/provider.go b/services/cache/provider.go index cb63530248..0fa2040d4a 100644 --- a/services/cache/provider.go +++ b/services/cache/provider.go @@ -11,12 +11,14 @@ type CacheOptions struct { DefaultExpiry time.Duration Name string InvalidateClusterEvent string + Striped bool + StripedBuckets int } // Provider is a provider for Cache type Provider interface { // NewCache creates a new cache with given options. - NewCache(opts *CacheOptions) Cache + NewCache(opts *CacheOptions) (Cache, error) // Connect opens a new connection to the cache using specific provider parameters. Connect() error // Close releases any resources used by the cache provider. @@ -32,13 +34,22 @@ func NewProvider() Provider { } // NewCache creates a new cache with given opts -func (c *cacheProvider) NewCache(opts *CacheOptions) Cache { - return NewLRU(&LRUOptions{ +func (c *cacheProvider) NewCache(opts *CacheOptions) (Cache, error) { + if opts.Striped { + return NewLRUStriped(LRUOptions{ + Name: opts.Name, + Size: opts.Size, + DefaultExpiry: opts.DefaultExpiry, + InvalidateClusterEvent: opts.InvalidateClusterEvent, + StripedBuckets: opts.StripedBuckets, + }) + } + return NewLRU(LRUOptions{ Name: opts.Name, Size: opts.Size, DefaultExpiry: opts.DefaultExpiry, InvalidateClusterEvent: opts.InvalidateClusterEvent, - }) + }), nil } // Connect opens a new connection to the cache using specific provider parameters. diff --git a/services/cache/provider_test.go b/services/cache/provider_test.go index bc85573c5f..a8fdbf60a4 100644 --- a/services/cache/provider_test.go +++ b/services/cache/provider_test.go @@ -15,16 +15,39 @@ func TestNewCache(t *testing.T) { p := NewProvider() size := 1 - c := p.NewCache(&CacheOptions{ + c, err := p.NewCache(&CacheOptions{ Size: size, }) + require.NoError(t, err) - err := c.Set("key1", "val1") - require.Nil(t, err) + err = c.Set("key1", "val1") + require.NoError(t, err) err = c.Set("key2", "val2") - require.Nil(t, err) + require.NoError(t, err) + err = c.Set("key3", "val3") + require.NoError(t, err) l, err := c.Len() - require.Nil(t, err) + require.NoError(t, err) + require.Equal(t, size, l) + }) + + t.Run("with only size option given", func(t *testing.T) { + p := NewProvider() + + size := 1 + c, err := p.NewCache(&CacheOptions{ + Size: size, + }) + require.NoError(t, err) + + err = c.Set("key1", "val1") + require.NoError(t, err) + err = c.Set("key2", "val2") + require.NoError(t, err) + err = c.Set("key3", "val3") + require.NoError(t, err) + l, err := c.Len() + require.NoError(t, err) require.Equal(t, size, l) }) @@ -34,21 +57,24 @@ func TestNewCache(t *testing.T) { size := 1 expiry := 1 * time.Second event := "clusterEvent" - c := p.NewCache(&CacheOptions{ + c, err := p.NewCache(&CacheOptions{ Size: size, Name: "name", DefaultExpiry: expiry, InvalidateClusterEvent: event, }) + require.NoError(t, err) require.Equal(t, event, c.GetInvalidateClusterEvent()) - err := c.SetWithDefaultExpiry("key1", "val1") - require.Nil(t, err) + err = c.SetWithDefaultExpiry("key1", "val1") + require.NoError(t, err) err = c.SetWithDefaultExpiry("key2", "val2") - require.Nil(t, err) + require.NoError(t, err) + err = c.SetWithDefaultExpiry("key3", "val3") + require.NoError(t, err) l, err := c.Len() - require.Nil(t, err) + require.NoError(t, err) require.Equal(t, size, l) time.Sleep(expiry + 1*time.Second) @@ -58,6 +84,93 @@ func TestNewCache(t *testing.T) { require.Equal(t, ErrKeyNotFound, err) err = c.Get("key2", &v) require.Equal(t, ErrKeyNotFound, err) + err = c.Get("key3", &v) + require.Equal(t, ErrKeyNotFound, err) + }) +} + +func TestNewCache_Striped(t *testing.T) { + t.Run("with only size option given", func(t *testing.T) { + p := NewProvider() + + size := 1 + c, err := p.NewCache(&CacheOptions{ + Size: size, + Striped: true, + StripedBuckets: 1, + }) + require.NoError(t, err) + + err = c.Set("key1", "val1") + require.NoError(t, err) + err = c.Set("key2", "val2") + require.NoError(t, err) + err = c.Set("key3", "val3") + require.NoError(t, err) + l, err := c.Len() + require.NoError(t, err) + require.Equal(t, size+1, l) // +10% from striping + }) + + t.Run("with only size option given", func(t *testing.T) { + p := NewProvider() + + size := 1 + c, err := p.NewCache(&CacheOptions{ + Size: size, + Striped: true, + StripedBuckets: 1, + }) + require.NoError(t, err) + + err = c.Set("key1", "val1") + require.NoError(t, err) + err = c.Set("key2", "val2") + require.NoError(t, err) + err = c.Set("key3", "val3") + require.NoError(t, err) + l, err := c.Len() + require.NoError(t, err) + require.Equal(t, size+1, l) // +10% rounded up from striped lru + }) + + t.Run("with all options specified", func(t *testing.T) { + p := NewProvider() + + size := 1 + expiry := 1 * time.Second + event := "clusterEvent" + c, err := p.NewCache(&CacheOptions{ + Size: size, + Name: "name", + DefaultExpiry: expiry, + InvalidateClusterEvent: event, + Striped: true, + StripedBuckets: 1, + }) + require.NoError(t, err) + + require.Equal(t, event, c.GetInvalidateClusterEvent()) + + err = c.SetWithDefaultExpiry("key1", "val1") + require.NoError(t, err) + err = c.SetWithDefaultExpiry("key2", "val2") + require.NoError(t, err) + err = c.SetWithDefaultExpiry("key3", "val3") + require.NoError(t, err) + l, err := c.Len() + require.NoError(t, err) + require.Equal(t, size+1, l) // +10% from striping + + time.Sleep(expiry + 1*time.Second) + + var v string + err = c.Get("key1", &v) + require.Equal(t, ErrKeyNotFound, err) + err = c.Get("key2", &v) + require.Equal(t, ErrKeyNotFound, err) + err = c.Get("key3", &v) + require.Equal(t, ErrKeyNotFound, err) }) } diff --git a/store/localcachelayer/channel_layer_test.go b/store/localcachelayer/channel_layer_test.go index ba2b935cea..b3cc8a020f 100644 --- a/store/localcachelayer/channel_layer_test.go +++ b/store/localcachelayer/channel_layer_test.go @@ -25,7 +25,8 @@ func TestChannelStoreChannelMemberCountsCache(t *testing.T) { t.Run("first call not cached, second cached and returning same data", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) count, err := cachedStore.Channel().GetMemberCount("id", true) require.Nil(t, err) @@ -40,7 +41,8 @@ func TestChannelStoreChannelMemberCountsCache(t *testing.T) { t.Run("first call not cached, second force not cached", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Channel().GetMemberCount("id", true) mockStore.Channel().(*mocks.ChannelStore).AssertNumberOfCalls(t, "GetMemberCount", 1) @@ -51,7 +53,8 @@ func TestChannelStoreChannelMemberCountsCache(t *testing.T) { t.Run("first call force not cached, second not cached, third cached", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Channel().GetMemberCount("id", false) mockStore.Channel().(*mocks.ChannelStore).AssertNumberOfCalls(t, "GetMemberCount", 1) @@ -64,7 +67,8 @@ func TestChannelStoreChannelMemberCountsCache(t *testing.T) { t.Run("first call with GetMemberCountFromCache not cached, second cached and returning same data", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) count := cachedStore.Channel().GetMemberCountFromCache("id") assert.Equal(t, count, countResult) @@ -77,7 +81,8 @@ func TestChannelStoreChannelMemberCountsCache(t *testing.T) { t.Run("first call not cached, clear cache, second call not cached", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Channel().GetMemberCount("id", true) mockStore.Channel().(*mocks.ChannelStore).AssertNumberOfCalls(t, "GetMemberCount", 1) @@ -89,7 +94,8 @@ func TestChannelStoreChannelMemberCountsCache(t *testing.T) { t.Run("first call not cached, invalidate cache, second call not cached", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Channel().GetMemberCount("id", true) mockStore.Channel().(*mocks.ChannelStore).AssertNumberOfCalls(t, "GetMemberCount", 1) @@ -105,7 +111,8 @@ func TestChannelStoreChannelPinnedPostsCountsCache(t *testing.T) { t.Run("first call not cached, second cached and returning same data", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) count, err := cachedStore.Channel().GetPinnedPostCount("id", true) require.Nil(t, err) @@ -120,7 +127,8 @@ func TestChannelStoreChannelPinnedPostsCountsCache(t *testing.T) { t.Run("first call not cached, second force not cached", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Channel().GetPinnedPostCount("id", true) mockStore.Channel().(*mocks.ChannelStore).AssertNumberOfCalls(t, "GetPinnedPostCount", 1) @@ -131,7 +139,8 @@ func TestChannelStoreChannelPinnedPostsCountsCache(t *testing.T) { t.Run("first call force not cached, second not cached, third cached", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Channel().GetPinnedPostCount("id", false) mockStore.Channel().(*mocks.ChannelStore).AssertNumberOfCalls(t, "GetPinnedPostCount", 1) @@ -144,7 +153,8 @@ func TestChannelStoreChannelPinnedPostsCountsCache(t *testing.T) { t.Run("first call not cached, clear cache, second call not cached", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Channel().GetPinnedPostCount("id", true) mockStore.Channel().(*mocks.ChannelStore).AssertNumberOfCalls(t, "GetPinnedPostCount", 1) @@ -156,7 +166,8 @@ func TestChannelStoreChannelPinnedPostsCountsCache(t *testing.T) { t.Run("first call not cached, invalidate cache, second call not cached", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Channel().GetPinnedPostCount("id", true) mockStore.Channel().(*mocks.ChannelStore).AssertNumberOfCalls(t, "GetPinnedPostCount", 1) @@ -172,7 +183,8 @@ func TestChannelStoreGuestCountCache(t *testing.T) { t.Run("first call not cached, second cached and returning same data", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) count, err := cachedStore.Channel().GetGuestCount("id", true) require.Nil(t, err) @@ -187,7 +199,8 @@ func TestChannelStoreGuestCountCache(t *testing.T) { t.Run("first call not cached, second force not cached", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Channel().GetGuestCount("id", true) mockStore.Channel().(*mocks.ChannelStore).AssertNumberOfCalls(t, "GetGuestCount", 1) @@ -198,7 +211,8 @@ func TestChannelStoreGuestCountCache(t *testing.T) { t.Run("first call force not cached, second not cached, third cached", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Channel().GetGuestCount("id", false) mockStore.Channel().(*mocks.ChannelStore).AssertNumberOfCalls(t, "GetGuestCount", 1) @@ -211,7 +225,8 @@ func TestChannelStoreGuestCountCache(t *testing.T) { t.Run("first call not cached, clear cache, second call not cached", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Channel().GetGuestCount("id", true) mockStore.Channel().(*mocks.ChannelStore).AssertNumberOfCalls(t, "GetGuestCount", 1) @@ -223,7 +238,8 @@ func TestChannelStoreGuestCountCache(t *testing.T) { t.Run("first call not cached, invalidate cache, second call not cached", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Channel().GetGuestCount("id", true) mockStore.Channel().(*mocks.ChannelStore).AssertNumberOfCalls(t, "GetGuestCount", 1) @@ -239,7 +255,8 @@ func TestChannelStoreChannel(t *testing.T) { t.Run("first call by id not cached, second cached and returning same data", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) channel, err := cachedStore.Channel().Get(channelId, true) require.Nil(t, err) @@ -254,7 +271,8 @@ func TestChannelStoreChannel(t *testing.T) { t.Run("first call not cached, second force no cached", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Channel().Get(channelId, true) mockStore.Channel().(*mocks.ChannelStore).AssertNumberOfCalls(t, "Get", 1) @@ -265,7 +283,8 @@ func TestChannelStoreChannel(t *testing.T) { t.Run("first call force no cached, second not cached, third cached", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Channel().Get(channelId, false) mockStore.Channel().(*mocks.ChannelStore).AssertNumberOfCalls(t, "Get", 1) cachedStore.Channel().Get(channelId, true) @@ -277,7 +296,8 @@ func TestChannelStoreChannel(t *testing.T) { t.Run("first call not cached, clear cache, second call not cached", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Channel().Get(channelId, true) mockStore.Channel().(*mocks.ChannelStore).AssertNumberOfCalls(t, "Get", 1) @@ -289,7 +309,8 @@ func TestChannelStoreChannel(t *testing.T) { t.Run("first call not cached, invalidate cache, second call not cached", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Channel().Get(channelId, true) mockStore.Channel().(*mocks.ChannelStore).AssertNumberOfCalls(t, "Get", 1) cachedStore.Channel().InvalidateChannel(channelId) diff --git a/store/localcachelayer/emoji_layer_test.go b/store/localcachelayer/emoji_layer_test.go index 5f591093d4..a7a79b19d4 100644 --- a/store/localcachelayer/emoji_layer_test.go +++ b/store/localcachelayer/emoji_layer_test.go @@ -23,7 +23,8 @@ func TestEmojiStoreCache(t *testing.T) { t.Run("first call by id not cached, second cached and returning same data", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) emoji, err := cachedStore.Emoji().Get("123", true) require.Nil(t, err) @@ -38,7 +39,8 @@ func TestEmojiStoreCache(t *testing.T) { t.Run("first call by name not cached, second cached and returning same data", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) emoji, err := cachedStore.Emoji().GetByName("name123", true) require.Nil(t, err) @@ -53,7 +55,8 @@ func TestEmojiStoreCache(t *testing.T) { t.Run("first call by id not cached, second force not cached", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Emoji().Get("123", true) mockStore.Emoji().(*mocks.EmojiStore).AssertNumberOfCalls(t, "Get", 1) @@ -64,7 +67,8 @@ func TestEmojiStoreCache(t *testing.T) { t.Run("first call by name not cached, second force not cached", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Emoji().GetByName("name123", true) mockStore.Emoji().(*mocks.EmojiStore).AssertNumberOfCalls(t, "GetByName", 1) @@ -75,7 +79,8 @@ func TestEmojiStoreCache(t *testing.T) { t.Run("first call by id force not cached, second not cached, third cached", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Emoji().Get("123", false) mockStore.Emoji().(*mocks.EmojiStore).AssertNumberOfCalls(t, "Get", 1) @@ -88,7 +93,8 @@ func TestEmojiStoreCache(t *testing.T) { t.Run("first call by name force not cached, second not cached, third cached", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Emoji().GetByName("name123", false) mockStore.Emoji().(*mocks.EmojiStore).AssertNumberOfCalls(t, "GetByName", 1) @@ -101,7 +107,8 @@ func TestEmojiStoreCache(t *testing.T) { t.Run("first call by id, second call by name cached", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Emoji().Get("123", true) mockStore.Emoji().(*mocks.EmojiStore).AssertNumberOfCalls(t, "Get", 1) @@ -112,7 +119,8 @@ func TestEmojiStoreCache(t *testing.T) { t.Run("first call by name, second call by id cached", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Emoji().GetByName("name123", true) mockStore.Emoji().(*mocks.EmojiStore).AssertNumberOfCalls(t, "GetByName", 1) @@ -123,7 +131,8 @@ func TestEmojiStoreCache(t *testing.T) { t.Run("first call by id not cached, invalidate, and then not cached again", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Emoji().Get("123", true) mockStore.Emoji().(*mocks.EmojiStore).AssertNumberOfCalls(t, "Get", 1) @@ -135,7 +144,8 @@ func TestEmojiStoreCache(t *testing.T) { t.Run("first call by name not cached, invalidate, and then not cached again", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Emoji().GetByName("name123", true) mockStore.Emoji().(*mocks.EmojiStore).AssertNumberOfCalls(t, "GetByName", 1) diff --git a/store/localcachelayer/file_info_layer_test.go b/store/localcachelayer/file_info_layer_test.go index 29e4ef92cb..6888fc1064 100644 --- a/store/localcachelayer/file_info_layer_test.go +++ b/store/localcachelayer/file_info_layer_test.go @@ -23,7 +23,8 @@ func TestFileInfoStoreCache(t *testing.T) { t.Run("first call not cached, second cached and returning same data", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) fileInfos, err := cachedStore.FileInfo().GetForPost("123", true, true, true) require.Nil(t, err) @@ -37,7 +38,8 @@ func TestFileInfoStoreCache(t *testing.T) { t.Run("first call not cached, second force no cached", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.FileInfo().GetForPost("123", true, true, true) mockStore.FileInfo().(*mocks.FileInfoStore).AssertNumberOfCalls(t, "GetForPost", 1) @@ -48,7 +50,8 @@ func TestFileInfoStoreCache(t *testing.T) { t.Run("first call not cached, invalidate, and then not cached again", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.FileInfo().GetForPost("123", true, true, true) mockStore.FileInfo().(*mocks.FileInfoStore).AssertNumberOfCalls(t, "GetForPost", 1) diff --git a/store/localcachelayer/layer.go b/store/localcachelayer/layer.go index 08a9ec7fc0..34b796cdd8 100644 --- a/store/localcachelayer/layer.go +++ b/store/localcachelayer/layer.go @@ -4,6 +4,7 @@ package localcachelayer import ( + "runtime" "time" "github.com/mattermost/mattermost-server/v5/einterfaces" @@ -108,152 +109,191 @@ type LocalCacheStore struct { termsOfServiceCache cache.Cache } -func NewLocalCacheLayer(baseStore store.Store, metrics einterfaces.MetricsInterface, cluster einterfaces.ClusterInterface, cacheProvider cache.Provider) LocalCacheStore { - - localCacheStore := LocalCacheStore{ +func NewLocalCacheLayer(baseStore store.Store, metrics einterfaces.MetricsInterface, cluster einterfaces.ClusterInterface, cacheProvider cache.Provider) (localCacheStore LocalCacheStore, err error) { + localCacheStore = LocalCacheStore{ Store: baseStore, cluster: cluster, metrics: metrics, } // Reactions - localCacheStore.reactionCache = cacheProvider.NewCache(&cache.CacheOptions{ + if localCacheStore.reactionCache, err = cacheProvider.NewCache(&cache.CacheOptions{ Size: REACTION_CACHE_SIZE, Name: "Reaction", DefaultExpiry: REACTION_CACHE_SEC * time.Second, InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_REACTIONS, - }) + }); err != nil { + return + } localCacheStore.reaction = LocalCacheReactionStore{ReactionStore: baseStore.Reaction(), rootStore: &localCacheStore} // Roles - localCacheStore.roleCache = cacheProvider.NewCache(&cache.CacheOptions{ + if localCacheStore.roleCache, err = cacheProvider.NewCache(&cache.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(&cache.CacheOptions{ + Striped: true, + StripedBuckets: runtime.NumCPU() - 1, + }); err != nil { + return + } + if localCacheStore.rolePermissionsCache, err = cacheProvider.NewCache(&cache.CacheOptions{ Size: ROLE_CACHE_SIZE, Name: "RolePermission", DefaultExpiry: ROLE_CACHE_SEC * time.Second, InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_ROLE_PERMISSIONS, - }) + }); err != nil { + return + } localCacheStore.role = LocalCacheRoleStore{RoleStore: baseStore.Role(), rootStore: &localCacheStore} // Schemes - localCacheStore.schemeCache = cacheProvider.NewCache(&cache.CacheOptions{ + if localCacheStore.schemeCache, err = cacheProvider.NewCache(&cache.CacheOptions{ Size: SCHEME_CACHE_SIZE, Name: "Scheme", DefaultExpiry: SCHEME_CACHE_SEC * time.Second, InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_SCHEMES, - }) + }); err != nil { + return + } localCacheStore.scheme = LocalCacheSchemeStore{SchemeStore: baseStore.Scheme(), rootStore: &localCacheStore} // FileInfo - localCacheStore.fileInfoCache = cacheProvider.NewCache(&cache.CacheOptions{ + if localCacheStore.fileInfoCache, err = cacheProvider.NewCache(&cache.CacheOptions{ Size: FILE_INFO_CACHE_SIZE, Name: "FileInfo", DefaultExpiry: FILE_INFO_CACHE_SEC * time.Second, InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_FILE_INFOS, - }) + }); err != nil { + return + } localCacheStore.fileInfo = LocalCacheFileInfoStore{FileInfoStore: baseStore.FileInfo(), rootStore: &localCacheStore} // Webhooks - localCacheStore.webhookCache = cacheProvider.NewCache(&cache.CacheOptions{ + if localCacheStore.webhookCache, err = cacheProvider.NewCache(&cache.CacheOptions{ Size: WEBHOOK_CACHE_SIZE, Name: "Webhook", DefaultExpiry: WEBHOOK_CACHE_SEC * time.Second, InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_WEBHOOKS, - }) + }); err != nil { + return + } localCacheStore.webhook = LocalCacheWebhookStore{WebhookStore: baseStore.Webhook(), rootStore: &localCacheStore} // Emojis - localCacheStore.emojiCacheById = cacheProvider.NewCache(&cache.CacheOptions{ + if localCacheStore.emojiCacheById, err = cacheProvider.NewCache(&cache.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(&cache.CacheOptions{ + }); err != nil { + return + } + if localCacheStore.emojiIdCacheByName, err = cacheProvider.NewCache(&cache.CacheOptions{ Size: EMOJI_CACHE_SIZE, Name: "EmojiByName", DefaultExpiry: EMOJI_CACHE_SEC * time.Second, InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_EMOJIS_ID_BY_NAME, - }) + }); err != nil { + return + } localCacheStore.emoji = LocalCacheEmojiStore{EmojiStore: baseStore.Emoji(), rootStore: &localCacheStore} // Channels - localCacheStore.channelPinnedPostCountsCache = cacheProvider.NewCache(&cache.CacheOptions{ + if localCacheStore.channelPinnedPostCountsCache, err = cacheProvider.NewCache(&cache.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(&cache.CacheOptions{ + }); err != nil { + return + } + if localCacheStore.channelMemberCountsCache, err = cacheProvider.NewCache(&cache.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(&cache.CacheOptions{ + }); err != nil { + return + } + if localCacheStore.channelGuestCountCache, err = cacheProvider.NewCache(&cache.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(&cache.CacheOptions{ + }); err != nil { + return + } + if localCacheStore.channelByIdCache, err = cacheProvider.NewCache(&cache.CacheOptions{ Size: model.CHANNEL_CACHE_SIZE, Name: "channelById", DefaultExpiry: CHANNEL_CACHE_SEC * time.Second, InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL, - }) + }); err != nil { + return + } localCacheStore.channel = LocalCacheChannelStore{ChannelStore: baseStore.Channel(), rootStore: &localCacheStore} // Posts - localCacheStore.postLastPostsCache = cacheProvider.NewCache(&cache.CacheOptions{ + if localCacheStore.postLastPostsCache, err = cacheProvider.NewCache(&cache.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(&cache.CacheOptions{ + }); err != nil { + return + } + if localCacheStore.lastPostTimeCache, err = cacheProvider.NewCache(&cache.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, - }) + }); err != nil { + return + } localCacheStore.post = LocalCachePostStore{PostStore: baseStore.Post(), rootStore: &localCacheStore} // TOS - localCacheStore.termsOfServiceCache = cacheProvider.NewCache(&cache.CacheOptions{ + if localCacheStore.termsOfServiceCache, err = cacheProvider.NewCache(&cache.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, - }) + }); err != nil { + return + } localCacheStore.termsOfService = LocalCacheTermsOfServiceStore{TermsOfServiceStore: baseStore.TermsOfService(), rootStore: &localCacheStore} // Users - localCacheStore.userProfileByIdsCache = cacheProvider.NewCache(&cache.CacheOptions{ + if localCacheStore.userProfileByIdsCache, err = cacheProvider.NewCache(&cache.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(&cache.CacheOptions{ + Striped: true, + StripedBuckets: runtime.NumCPU() - 1, + }); err != nil { + return + } + if localCacheStore.profilesInChannelCache, err = cacheProvider.NewCache(&cache.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, - }) + }); err != nil { + return + } localCacheStore.user = LocalCacheUserStore{UserStore: baseStore.User(), rootStore: &localCacheStore} // Teams - localCacheStore.teamAllTeamIdsForUserCache = cacheProvider.NewCache(&cache.CacheOptions{ + if localCacheStore.teamAllTeamIdsForUserCache, err = cacheProvider.NewCache(&cache.CacheOptions{ Size: TEAM_CACHE_SIZE, Name: "Team", DefaultExpiry: TEAM_CACHE_SEC * time.Second, InvalidateClusterEvent: model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_TEAMS, - }) + }); err != nil { + return + } localCacheStore.team = LocalCacheTeamStore{TeamStore: baseStore.Team(), rootStore: &localCacheStore} if cluster != nil { @@ -276,7 +316,7 @@ func NewLocalCacheLayer(baseStore store.Store, metrics einterfaces.MetricsInterf cluster.RegisterClusterMessageHandler(model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_PROFILE_IN_CHANNEL, localCacheStore.user.handleClusterInvalidateProfilesInChannel) cluster.RegisterClusterMessageHandler(model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_TEAMS, localCacheStore.team.handleClusterInvalidateTeam) } - return localCacheStore + return } func (s LocalCacheStore) Reaction() store.ReactionStore { diff --git a/store/localcachelayer/layer_test.go b/store/localcachelayer/layer_test.go index 44b41a1e85..6123e5f740 100644 --- a/store/localcachelayer/layer_test.go +++ b/store/localcachelayer/layer_test.go @@ -96,9 +96,13 @@ func initStores() { st := st wg.Add(1) go func() { + var err error defer wg.Done() st.SqlStore = sqlstore.New(*st.SqlSettings, nil) - st.Store = NewLocalCacheLayer(st.SqlStore, nil, nil, getMockCacheProvider()) + st.Store, err = NewLocalCacheLayer(st.SqlStore, nil, nil, getMockCacheProvider()) + if err != nil { + panic(err) + } st.Store.DropAllTables() st.Store.MarkSystemRanUnitTests() }() diff --git a/store/localcachelayer/main_test.go b/store/localcachelayer/main_test.go index bbbacba0f5..963003312b 100644 --- a/store/localcachelayer/main_test.go +++ b/store/localcachelayer/main_test.go @@ -23,7 +23,7 @@ var mainHelper *testlib.MainHelper func getMockCacheProvider() cache.Provider { mockCacheProvider := cachemocks.Provider{} mockCacheProvider.On("NewCache", mock.Anything). - Return(cache.NewLRU(&cache.LRUOptions{Size: 128})) + Return(cache.NewLRU(cache.LRUOptions{Size: 128}), nil) return &mockCacheProvider } diff --git a/store/localcachelayer/post_layer_test.go b/store/localcachelayer/post_layer_test.go index b4a05acd5e..7952557d44 100644 --- a/store/localcachelayer/post_layer_test.go +++ b/store/localcachelayer/post_layer_test.go @@ -30,7 +30,8 @@ func TestPostStoreLastPostTimeCache(t *testing.T) { t.Run("GetEtag: first call not cached, second cached and returning same data", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) expectedResult := fmt.Sprintf("%v.%v", model.CurrentVersion, fakeLastTime) @@ -46,7 +47,8 @@ func TestPostStoreLastPostTimeCache(t *testing.T) { t.Run("GetEtag: first call not cached, second force no cached", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Post().GetEtag(channelId, true) mockStore.Post().(*mocks.PostStore).AssertNumberOfCalls(t, "GetEtag", 1) @@ -57,7 +59,8 @@ func TestPostStoreLastPostTimeCache(t *testing.T) { t.Run("GetEtag: first call not cached, invalidate, and then not cached again", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Post().GetEtag(channelId, true) mockStore.Post().(*mocks.PostStore).AssertNumberOfCalls(t, "GetEtag", 1) @@ -69,7 +72,8 @@ func TestPostStoreLastPostTimeCache(t *testing.T) { t.Run("GetEtag: first call not cached, clear caches, and then not cached again", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Post().GetEtag(channelId, true) mockStore.Post().(*mocks.PostStore).AssertNumberOfCalls(t, "GetEtag", 1) @@ -81,7 +85,8 @@ func TestPostStoreLastPostTimeCache(t *testing.T) { t.Run("GetPostsSince: first call not cached, second cached and returning same data", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) expectedResult := model.NewPostList() @@ -99,7 +104,8 @@ func TestPostStoreLastPostTimeCache(t *testing.T) { t.Run("GetPostsSince: first call not cached, second force no cached", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Post().GetPostsSince(fakeOptions, true) mockStore.Post().(*mocks.PostStore).AssertNumberOfCalls(t, "GetPostsSince", 1) @@ -110,7 +116,8 @@ func TestPostStoreLastPostTimeCache(t *testing.T) { t.Run("GetPostsSince: first call not cached, invalidate, and then not cached again", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Post().GetPostsSince(fakeOptions, true) mockStore.Post().(*mocks.PostStore).AssertNumberOfCalls(t, "GetPostsSince", 1) @@ -122,7 +129,8 @@ func TestPostStoreLastPostTimeCache(t *testing.T) { t.Run("GetPostsSince: first call not cached, clear caches, and then not cached again", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Post().GetPostsSince(fakeOptions, true) mockStore.Post().(*mocks.PostStore).AssertNumberOfCalls(t, "GetPostsSince", 1) @@ -139,7 +147,8 @@ func TestPostStoreCache(t *testing.T) { t.Run("first call not cached, second cached and returning same data", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) gotPosts, err := cachedStore.Post().GetPosts(fakeOptions, true) require.Nil(t, err) @@ -153,7 +162,8 @@ func TestPostStoreCache(t *testing.T) { t.Run("first call not cached, second force not cached", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) gotPosts, err := cachedStore.Post().GetPosts(fakeOptions, true) require.Nil(t, err) @@ -167,7 +177,8 @@ func TestPostStoreCache(t *testing.T) { t.Run("first call not cached, invalidate, and then not cached again", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) gotPosts, err := cachedStore.Post().GetPosts(fakeOptions, true) require.Nil(t, err) diff --git a/store/localcachelayer/reaction_layer_test.go b/store/localcachelayer/reaction_layer_test.go index 1895d933fb..a9d49efe55 100644 --- a/store/localcachelayer/reaction_layer_test.go +++ b/store/localcachelayer/reaction_layer_test.go @@ -23,7 +23,8 @@ func TestReactionStoreCache(t *testing.T) { t.Run("first call not cached, second cached and returning same data", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) reaction, err := cachedStore.Reaction().GetForPost("123", true) require.Nil(t, err) @@ -38,7 +39,8 @@ func TestReactionStoreCache(t *testing.T) { t.Run("first call not cached, second force not cached", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Reaction().GetForPost("123", true) mockStore.Reaction().(*mocks.ReactionStore).AssertNumberOfCalls(t, "GetForPost", 1) @@ -49,7 +51,8 @@ func TestReactionStoreCache(t *testing.T) { t.Run("first call not cached, save, and then not cached again", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Reaction().GetForPost("123", true) mockStore.Reaction().(*mocks.ReactionStore).AssertNumberOfCalls(t, "GetForPost", 1) @@ -61,7 +64,8 @@ func TestReactionStoreCache(t *testing.T) { t.Run("first call not cached, delete, and then not cached again", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Reaction().GetForPost("123", true) mockStore.Reaction().(*mocks.ReactionStore).AssertNumberOfCalls(t, "GetForPost", 1) diff --git a/store/localcachelayer/role_layer_test.go b/store/localcachelayer/role_layer_test.go index 97a8a1d1e8..7f89ba790e 100644 --- a/store/localcachelayer/role_layer_test.go +++ b/store/localcachelayer/role_layer_test.go @@ -23,7 +23,8 @@ func TestRoleStoreCache(t *testing.T) { t.Run("first call not cached, second cached and returning same data", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) role, err := cachedStore.Role().GetByName("role-name") require.Nil(t, err) @@ -38,7 +39,8 @@ func TestRoleStoreCache(t *testing.T) { t.Run("first call not cached, save, and then not cached again", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Role().GetByName("role-name") mockStore.Role().(*mocks.RoleStore).AssertNumberOfCalls(t, "GetByName", 1) @@ -50,7 +52,8 @@ func TestRoleStoreCache(t *testing.T) { t.Run("first call not cached, delete, and then not cached again", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Role().GetByName("role-name") mockStore.Role().(*mocks.RoleStore).AssertNumberOfCalls(t, "GetByName", 1) @@ -62,7 +65,8 @@ func TestRoleStoreCache(t *testing.T) { t.Run("first call not cached, permanent delete all, and then not cached again", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Role().GetByName("role-name") mockStore.Role().(*mocks.RoleStore).AssertNumberOfCalls(t, "GetByName", 1) diff --git a/store/localcachelayer/scheme_layer_test.go b/store/localcachelayer/scheme_layer_test.go index 1cc94542f0..0649cc98e7 100644 --- a/store/localcachelayer/scheme_layer_test.go +++ b/store/localcachelayer/scheme_layer_test.go @@ -23,7 +23,8 @@ func TestSchemeStoreCache(t *testing.T) { t.Run("first call not cached, second cached and returning same data", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) scheme, err := cachedStore.Scheme().Get("123") require.Nil(t, err) @@ -38,7 +39,8 @@ func TestSchemeStoreCache(t *testing.T) { t.Run("first call not cached, save, and then not cached again", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Scheme().Get("123") mockStore.Scheme().(*mocks.SchemeStore).AssertNumberOfCalls(t, "Get", 1) @@ -50,7 +52,8 @@ func TestSchemeStoreCache(t *testing.T) { t.Run("first call not cached, delete, and then not cached again", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Scheme().Get("123") mockStore.Scheme().(*mocks.SchemeStore).AssertNumberOfCalls(t, "Get", 1) @@ -62,7 +65,8 @@ func TestSchemeStoreCache(t *testing.T) { t.Run("first call not cached, permanent delete all, and then not cached again", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Scheme().Get("123") mockStore.Scheme().(*mocks.SchemeStore).AssertNumberOfCalls(t, "Get", 1) diff --git a/store/localcachelayer/team_layer_test.go b/store/localcachelayer/team_layer_test.go index c6b1b294ae..e0df7b272d 100644 --- a/store/localcachelayer/team_layer_test.go +++ b/store/localcachelayer/team_layer_test.go @@ -23,7 +23,8 @@ func TestTeamStoreCache(t *testing.T) { t.Run("first call not cached, second cached and returning same data", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) gotUserTeamIds, err := cachedStore.Team().GetUserTeamIds(fakeUserId, true) require.Nil(t, err) @@ -39,7 +40,8 @@ func TestTeamStoreCache(t *testing.T) { t.Run("first call not cached, second force not cached", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) gotUserTeamIds, err := cachedStore.Team().GetUserTeamIds(fakeUserId, true) require.Nil(t, err) @@ -55,7 +57,8 @@ func TestTeamStoreCache(t *testing.T) { t.Run("first call not cached, invalidate, and then not cached again", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) gotUserTeamIds, err := cachedStore.Team().GetUserTeamIds(fakeUserId, true) require.Nil(t, err) diff --git a/store/localcachelayer/terms_of_service_layer_test.go b/store/localcachelayer/terms_of_service_layer_test.go index 466c267081..7c300f0b34 100644 --- a/store/localcachelayer/terms_of_service_layer_test.go +++ b/store/localcachelayer/terms_of_service_layer_test.go @@ -24,7 +24,8 @@ func TestTermsOfServiceStoreTermsOfServiceCache(t *testing.T) { t.Run("first call by latest not cached, second cached and returning same data", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) termsOfService, err := cachedStore.TermsOfService().GetLatest(true) require.Nil(t, err) @@ -39,7 +40,8 @@ func TestTermsOfServiceStoreTermsOfServiceCache(t *testing.T) { t.Run("first call by id not cached, second cached and returning same data", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) termsOfService, err := cachedStore.TermsOfService().Get("123", true) require.Nil(t, err) @@ -54,7 +56,8 @@ func TestTermsOfServiceStoreTermsOfServiceCache(t *testing.T) { t.Run("first call by id not cached, second force no cached", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.TermsOfService().Get("123", true) mockStore.TermsOfService().(*mocks.TermsOfServiceStore).AssertNumberOfCalls(t, "Get", 1) @@ -65,7 +68,8 @@ func TestTermsOfServiceStoreTermsOfServiceCache(t *testing.T) { t.Run("first call latest not cached, second force no cached", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.TermsOfService().GetLatest(true) mockStore.TermsOfService().(*mocks.TermsOfServiceStore).AssertNumberOfCalls(t, "GetLatest", 1) @@ -76,7 +80,8 @@ func TestTermsOfServiceStoreTermsOfServiceCache(t *testing.T) { t.Run("first call by id force no cached, second not cached, third cached", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.TermsOfService().Get("123", false) mockStore.TermsOfService().(*mocks.TermsOfServiceStore).AssertNumberOfCalls(t, "Get", 1) @@ -89,7 +94,8 @@ func TestTermsOfServiceStoreTermsOfServiceCache(t *testing.T) { t.Run("first call latest force no cached, second not cached, third cached", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.TermsOfService().GetLatest(false) mockStore.TermsOfService().(*mocks.TermsOfServiceStore).AssertNumberOfCalls(t, "GetLatest", 1) @@ -102,7 +108,8 @@ func TestTermsOfServiceStoreTermsOfServiceCache(t *testing.T) { t.Run("first call latest, second call by id cached", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.TermsOfService().GetLatest(true) mockStore.TermsOfService().(*mocks.TermsOfServiceStore).AssertNumberOfCalls(t, "GetLatest", 1) @@ -113,7 +120,8 @@ func TestTermsOfServiceStoreTermsOfServiceCache(t *testing.T) { t.Run("first call by id not cached, save, and then not cached again", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.TermsOfService().Get("123", false) mockStore.TermsOfService().(*mocks.TermsOfServiceStore).AssertNumberOfCalls(t, "Get", 1) @@ -125,7 +133,8 @@ func TestTermsOfServiceStoreTermsOfServiceCache(t *testing.T) { t.Run("first get latest not cached, save new, then get latest, returning different data", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.TermsOfService().GetLatest(true) mockStore.TermsOfService().(*mocks.TermsOfServiceStore).AssertNumberOfCalls(t, "GetLatest", 1) diff --git a/store/localcachelayer/user_layer_test.go b/store/localcachelayer/user_layer_test.go index b3cac5a5c0..88cc948bac 100644 --- a/store/localcachelayer/user_layer_test.go +++ b/store/localcachelayer/user_layer_test.go @@ -30,7 +30,8 @@ func TestUserStoreCache(t *testing.T) { t.Run("first call not cached, second cached and returning same data", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) gotUser, err := cachedStore.User().GetProfileByIds(fakeUserIds, &store.UserGetByIdsOpts{}, true) require.Nil(t, err) @@ -44,7 +45,8 @@ func TestUserStoreCache(t *testing.T) { t.Run("first call not cached, second force not cached", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) gotUser, err := cachedStore.User().GetProfileByIds(fakeUserIds, &store.UserGetByIdsOpts{}, true) require.Nil(t, err) @@ -58,7 +60,8 @@ func TestUserStoreCache(t *testing.T) { t.Run("first call not cached, invalidate, and then not cached again", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) gotUser, err := cachedStore.User().GetProfileByIds(fakeUserIds, &store.UserGetByIdsOpts{}, true) require.Nil(t, err) @@ -73,7 +76,8 @@ func TestUserStoreCache(t *testing.T) { t.Run("should always return a copy of the stored data", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) storedUsers, err := mockStore.User().GetProfileByIds(fakeUserIds, &store.UserGetByIdsOpts{}, false) require.Nil(t, err) @@ -122,7 +126,8 @@ func TestUserStoreProfilesInChannelCache(t *testing.T) { t.Run("first call not cached, second cached and returning same data", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) gotMap, err := cachedStore.User().GetAllProfilesInChannel(fakeChannelId, true) require.Nil(t, err) @@ -136,7 +141,8 @@ func TestUserStoreProfilesInChannelCache(t *testing.T) { t.Run("first call not cached, second force not cached", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) gotMap, err := cachedStore.User().GetAllProfilesInChannel(fakeChannelId, true) require.Nil(t, err) @@ -150,7 +156,8 @@ func TestUserStoreProfilesInChannelCache(t *testing.T) { t.Run("first call not cached, invalidate by channel, and then not cached again", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) gotMap, err := cachedStore.User().GetAllProfilesInChannel(fakeChannelId, true) require.Nil(t, err) @@ -166,7 +173,8 @@ func TestUserStoreProfilesInChannelCache(t *testing.T) { t.Run("first call not cached, invalidate by user, and then not cached again", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) gotMap, err := cachedStore.User().GetAllProfilesInChannel(fakeChannelId, true) require.Nil(t, err) @@ -190,7 +198,8 @@ func TestUserStoreGetCache(t *testing.T) { t.Run("first call not cached, second cached and returning same data", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) gotUser, err := cachedStore.User().Get(fakeUserId) require.Nil(t, err) @@ -204,7 +213,8 @@ func TestUserStoreGetCache(t *testing.T) { t.Run("first call not cached, invalidate, and then not cached again", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) gotUser, err := cachedStore.User().Get(fakeUserId) require.Nil(t, err) @@ -220,7 +230,8 @@ func TestUserStoreGetCache(t *testing.T) { t.Run("should always return a copy of the stored data", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) storedUser, err := mockStore.User().Get(fakeUserId) require.Nil(t, err) diff --git a/store/localcachelayer/webhook_layer_test.go b/store/localcachelayer/webhook_layer_test.go index 675135b8a2..b5a3f78df7 100644 --- a/store/localcachelayer/webhook_layer_test.go +++ b/store/localcachelayer/webhook_layer_test.go @@ -24,7 +24,8 @@ func TestWebhookStoreCache(t *testing.T) { t.Run("first call not cached, second cached and returning same data", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) incomingWebhook, err := cachedStore.Webhook().GetIncoming("123", true) require.Nil(t, err) @@ -39,7 +40,8 @@ func TestWebhookStoreCache(t *testing.T) { t.Run("first call not cached, second force not cached", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Webhook().GetIncoming("123", true) mockStore.Webhook().(*mocks.WebhookStore).AssertNumberOfCalls(t, "GetIncoming", 1) @@ -50,7 +52,8 @@ func TestWebhookStoreCache(t *testing.T) { t.Run("first call not cached, invalidate, and then not cached again", func(t *testing.T) { mockStore := getMockStore() mockCacheProvider := getMockCacheProvider() - cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider) + require.NoError(t, err) cachedStore.Webhook().GetIncoming("123", true) mockStore.Webhook().(*mocks.WebhookStore).AssertNumberOfCalls(t, "GetIncoming", 1) diff --git a/store/sqlstore/channel_store.go b/store/sqlstore/channel_store.go index 1eceae75d2..dd4b2fa1e5 100644 --- a/store/sqlstore/channel_store.go +++ b/store/sqlstore/channel_store.go @@ -334,13 +334,13 @@ type publicChannel struct { Purpose string `json:"purpose"` } -var allChannelMembersForUserCache = cache.NewLRU(&cache.LRUOptions{ +var allChannelMembersForUserCache = cache.NewLRU(cache.LRUOptions{ Size: ALL_CHANNEL_MEMBERS_FOR_USER_CACHE_SIZE, }) -var allChannelMembersNotifyPropsForChannelCache = cache.NewLRU(&cache.LRUOptions{ +var allChannelMembersNotifyPropsForChannelCache = cache.NewLRU(cache.LRUOptions{ Size: ALL_CHANNEL_MEMBERS_NOTIFY_PROPS_FOR_CHANNEL_CACHE_SIZE, }) -var channelByNameCache = cache.NewLRU(&cache.LRUOptions{ +var channelByNameCache = cache.NewLRU(cache.LRUOptions{ Size: model.CHANNEL_CACHE_SIZE, }) diff --git a/web/web_test.go b/web/web_test.go index 5f727b1c72..6f7d041933 100644 --- a/web/web_test.go +++ b/web/web_test.go @@ -85,7 +85,10 @@ 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, err = localcachelayer.NewLocalCacheLayer(s.Store, s.Metrics, s.Cluster, s.CacheProvider) + if err != nil { + panic(err) + } } prevListenAddress := *s.Config().ServiceSettings.ListenAddress