Files
team/server/platform/services/cache/lru_striped_bench_test.go
Agniva De SarkerandGitHub 3561ba2fac MM-59932: Migrate remaining caches to Redis (#27880)
- We introduce 2 new APIs:
1. Scan: this allows incremental iteration
without blocking the Redis server and is the
recommended way to iterate over keys. With this,
we have entirely removed the need for Keys.
2. RemoveMulti: this allows deletion of multiple
keys in a single operation which optimizes
network round trips.

- While here, we make a small improvement to
GetStatusFromCache, where we remove the shallow
copy which wasn't necessary because we always
serialize the data from the cache.
- We do not use Redis for session cache because of
frequent requests to iterate the entire cache which leads
to a lot of `SCAN` calls.
- Avoid broadcasting status update messages for Redis case.
- Setting cache expiry for status cache
- Removing .Set method altogether to prevent
any chances of setting an item with no expiry.

https://mattermost.atlassian.net/browse/MM-59932

```release-note
NONE
```
2024-08-13 14:18:25 +05:30

92 lines
2.0 KiB
Go

// 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/cespare/xxhash/v2"
"github.com/mattermost/mattermost/server/v8/platform/services/cache"
)
const (
m = 500_000
)
func BenchmarkLRUStriped(b *testing.B) {
opts := cache.CacheOptions{
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.SetWithDefaultExpiry(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.SetWithDefaultExpiry(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()
}
}