From b221e8cac96a0c4852a928a3bf4d6f0a515faa5f Mon Sep 17 00:00:00 2001 From: Serge Zaitsev Date: Tue, 6 Dec 2022 15:16:36 +0100 Subject: [PATCH] [v9.2.x] Chore: Remote cache key prefix (#59838) (#59877) Chore: Remote cache key prefix (#59838) * attempt to implement a remote cache key prefix * add a test for the prefix store * oh, linter (cherry picked from commit 3978502d837986a9ad77f4bf303b433f038637b1) --- conf/defaults.ini | 3 ++ conf/sample.ini | 3 ++ pkg/infra/remotecache/remotecache.go | 41 +++++++++++++++++------ pkg/infra/remotecache/remotecache_test.go | 25 ++++++++++++++ pkg/setting/setting.go | 3 ++ 5 files changed, 64 insertions(+), 11 deletions(-) diff --git a/conf/defaults.ini b/conf/defaults.ini index 895a7459764..4d20cc57cd4 100644 --- a/conf/defaults.ini +++ b/conf/defaults.ini @@ -139,6 +139,9 @@ type = database # memcache: 127.0.0.1:11211 connstr = +# prefix prepended to all the keys in the remote cache +prefix = + #################################### Data proxy ########################### [dataproxy] diff --git a/conf/sample.ini b/conf/sample.ini index 93e8257ca76..09b3e0e39c1 100644 --- a/conf/sample.ini +++ b/conf/sample.ini @@ -145,6 +145,9 @@ # memcache: 127.0.0.1:11211 ;connstr = +# prefix prepended to all the keys in the remote cache +; prefix = + #################################### Data proxy ########################### [dataproxy] diff --git a/pkg/infra/remotecache/remotecache.go b/pkg/infra/remotecache/remotecache.go index 62db5b5410f..f7392e50ad4 100644 --- a/pkg/infra/remotecache/remotecache.go +++ b/pkg/infra/remotecache/remotecache.go @@ -97,20 +97,24 @@ func (ds *RemoteCache) Run(ctx context.Context) error { return ctx.Err() } -func createClient(opts *setting.RemoteCacheOptions, sqlstore *sqlstore.SQLStore) (CacheStorage, error) { - if opts.Name == redisCacheType { - return newRedisStorage(opts) +func createClient(opts *setting.RemoteCacheOptions, sqlstore *sqlstore.SQLStore) (cache CacheStorage, err error) { + switch opts.Name { + case redisCacheType: + cache, err = newRedisStorage(opts) + case memcachedCacheType: + cache = newMemcachedStorage(opts) + case databaseCacheType: + cache = newDatabaseCache(sqlstore) + default: + return nil, ErrInvalidCacheType } - - if opts.Name == memcachedCacheType { - return newMemcachedStorage(opts), nil + if err != nil { + return cache, err } - - if opts.Name == databaseCacheType { - return newDatabaseCache(sqlstore), nil + if opts.Prefix != "" { + cache = &prefixCacheStorage{cache: cache, prefix: opts.Prefix} } - - return nil, ErrInvalidCacheType + return cache, nil } // Register records a type, identified by a value for that type, under its @@ -137,3 +141,18 @@ func decodeGob(data []byte, out *cachedItem) error { buf := bytes.NewBuffer(data) return gob.NewDecoder(buf).Decode(&out) } + +type prefixCacheStorage struct { + cache CacheStorage + prefix string +} + +func (pcs *prefixCacheStorage) Get(ctx context.Context, key string) (interface{}, error) { + return pcs.cache.Get(ctx, pcs.prefix+key) +} +func (pcs *prefixCacheStorage) Set(ctx context.Context, key string, value interface{}, expire time.Duration) error { + return pcs.cache.Set(ctx, pcs.prefix+key, value, expire) +} +func (pcs *prefixCacheStorage) Delete(ctx context.Context, key string) error { + return pcs.cache.Delete(ctx, pcs.prefix+key) +} diff --git a/pkg/infra/remotecache/remotecache_test.go b/pkg/infra/remotecache/remotecache_test.go index 093e8791aee..f87ad4f806b 100644 --- a/pkg/infra/remotecache/remotecache_test.go +++ b/pkg/infra/remotecache/remotecache_test.go @@ -5,6 +5,7 @@ import ( "testing" "time" + "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/setting" "github.com/stretchr/testify/assert" @@ -87,3 +88,27 @@ func canNotFetchExpiredItems(t *testing.T, client CacheStorage) { _, err = client.Get(context.Background(), "key1") assert.Equal(t, err, ErrCacheItemNotFound) } + +func TestCachePrefix(t *testing.T) { + db := sqlstore.InitTestDB(t) + cache := &databaseCache{ + SQLStore: db, + log: log.New("remotecache.database"), + } + prefixCache := &prefixCacheStorage{cache: cache, prefix: "test/"} + + // Set a value (with a prefix) + err := prefixCache.Set(context.Background(), "foo", "bar", time.Hour) + require.NoError(t, err) + // Get a value (with a prefix) + v, err := prefixCache.Get(context.Background(), "foo") + require.NoError(t, err) + require.Equal(t, "bar", v) + // Get a value directly from the underlying cache, ensure the prefix is in the key + v, err = cache.Get(context.Background(), "test/foo") + require.NoError(t, err) + require.Equal(t, "bar", v) + // Get a value directly from the underlying cache without a prefix, should not be there + _, err = cache.Get(context.Background(), "foo") + require.Error(t, err) +} diff --git a/pkg/setting/setting.go b/pkg/setting/setting.go index 5b9cd301b97..f68233f0526 100644 --- a/pkg/setting/setting.go +++ b/pkg/setting/setting.go @@ -1072,10 +1072,12 @@ func (cfg *Cfg) Load(args CommandLineArgs) error { cacheServer := iniFile.Section("remote_cache") dbName := valueAsString(cacheServer, "type", "database") connStr := valueAsString(cacheServer, "connstr", "") + prefix := valueAsString(cacheServer, "prefix", "") cfg.RemoteCacheOptions = &RemoteCacheOptions{ Name: dbName, ConnStr: connStr, + Prefix: prefix, } geomapSection := iniFile.Section("geomap") @@ -1111,6 +1113,7 @@ func valueAsString(section *ini.Section, keyName string, defaultValue string) st type RemoteCacheOptions struct { Name string ConnStr string + Prefix string } func (cfg *Cfg) readLDAPConfig() {