diff --git a/pkg/storage/tsdb/index_cache.go b/pkg/storage/tsdb/index_cache.go index 1f1825fcc8f..889672e8639 100644 --- a/pkg/storage/tsdb/index_cache.go +++ b/pkg/storage/tsdb/index_cache.go @@ -36,6 +36,7 @@ var ( supportedIndexCacheBackends = []string{IndexCacheBackendInMemory, IndexCacheBackendMemcached, IndexCacheBackendRedis} errUnsupportedIndexCacheBackend = errors.New("unsupported index cache backend") + errDuplicatedIndexCacheBackend = errors.New("duplicated index cache backend") errNoIndexCacheAddresses = errors.New("no index cache backend addresses") ) @@ -51,10 +52,10 @@ func (cfg *IndexCacheConfig) RegisterFlags(f *flag.FlagSet) { } func (cfg *IndexCacheConfig) RegisterFlagsWithPrefix(f *flag.FlagSet, prefix string) { - f.StringVar(&cfg.Backend, prefix+"backend", IndexCacheBackendDefault, fmt.Sprintf("The index cache backend type. " + - "Multiple cache backend can be provided as a comma-separated ordered list to enable the implementation of a cache hierarchy. " + + f.StringVar(&cfg.Backend, prefix+"backend", IndexCacheBackendDefault, fmt.Sprintf("The index cache backend type. "+ + "Multiple cache backend can be provided as a comma-separated ordered list to enable the implementation of a cache hierarchy. "+ "Supported values: %s.", - strings.Join(supportedIndexCacheBackends, ", "))) + strings.Join(supportedIndexCacheBackends, ", "))) cfg.InMemory.RegisterFlagsWithPrefix(f, prefix+"inmemory.") cfg.Memcached.RegisterFlagsWithPrefix(f, prefix+"memcached.") @@ -64,13 +65,19 @@ func (cfg *IndexCacheConfig) RegisterFlagsWithPrefix(f *flag.FlagSet, prefix str // Validate the config. func (cfg *IndexCacheConfig) Validate() error { - splitedBackends := strings.Split(cfg.Backend, ",") + splitBackends := strings.Split(cfg.Backend, ",") + configuredBackends := map[string]struct{}{} - for _, backend := range splitedBackends { + for _, backend := range splitBackends { if !util.StringsContain(supportedIndexCacheBackends, backend) { return errUnsupportedIndexCacheBackend } + if _, ok := configuredBackends[backend]; ok { + return errors.WithMessagef(errDuplicatedIndexCacheBackend, "duplicated backend: %v", backend) + } + + if backend == IndexCacheBackendMemcached { if err := cfg.Memcached.Validate(); err != nil { return err @@ -80,6 +87,8 @@ func (cfg *IndexCacheConfig) Validate() error { return err } } + + configuredBackends[backend] = struct{}{} } return nil diff --git a/pkg/storage/tsdb/multilevel_cache_test.go b/pkg/storage/tsdb/multilevel_cache_test.go index 82bd6ca2db8..c89b5794704 100644 --- a/pkg/storage/tsdb/multilevel_cache_test.go +++ b/pkg/storage/tsdb/multilevel_cache_test.go @@ -25,6 +25,7 @@ func Test_MultiIndexCacheInstantiation(t *testing.T) { testCases := map[string]struct { cfg IndexCacheConfig expectedType storecache.IndexCache + expectedValidationError error }{ "instantiate single backends": { cfg: IndexCacheConfig{ @@ -41,13 +42,25 @@ func Test_MultiIndexCacheInstantiation(t *testing.T) { }, expectedType: newMultiLevelCache(), }, + "should not allow duplicate backends": { + cfg: IndexCacheConfig{ + Backend: "inmemory,inmemory", + }, + expectedType: &storecache.InMemoryIndexCache{}, + expectedValidationError: errDuplicatedIndexCacheBackend, + }, } for name, tc := range testCases { t.Run(name, func(t *testing.T) { reg := prometheus.NewRegistry() - c, err := NewIndexCache(tc.cfg, log.NewNopLogger(), reg) - require.NoError(t, err) - require.IsType(t, tc.expectedType, c) + if tc.expectedValidationError == nil { + require.NoError(t, tc.cfg.Validate()) + c, err := NewIndexCache(tc.cfg, log.NewNopLogger(), reg) + require.NoError(t, err) + require.IsType(t, tc.expectedType, c) + } else { + require.ErrorIs(t, tc.cfg.Validate(), errDuplicatedIndexCacheBackend) + } }) } }