diff --git a/storage/metric/tiered/memory.go b/storage/metric/tiered/memory.go index 896c1f8e7..76b2ff1ad 100644 --- a/storage/metric/tiered/memory.go +++ b/storage/metric/tiered/memory.go @@ -367,7 +367,7 @@ func (s *memorySeriesStorage) GetFingerprintsForLabelMatchers(labelMatchers metr } sets = append(sets, set) default: - values, err := s.GetLabelValuesForLabelName(matcher.Name) + values, err := s.getLabelValuesForLabelName(matcher.Name) if err != nil { return nil, err } @@ -414,6 +414,10 @@ func (s *memorySeriesStorage) GetLabelValuesForLabelName(labelName clientmodel.L s.RLock() defer s.RUnlock() + return s.getLabelValuesForLabelName(labelName) +} + +func (s *memorySeriesStorage) getLabelValuesForLabelName(labelName clientmodel.LabelName) (clientmodel.LabelValues, error) { set, ok := s.labelNameToLabelValues[labelName] if !ok { return nil, nil diff --git a/storage/metric/tiered/memory_test.go b/storage/metric/tiered/memory_test.go index e948d1267..19a157880 100644 --- a/storage/metric/tiered/memory_test.go +++ b/storage/metric/tiered/memory_test.go @@ -16,6 +16,7 @@ package tiered import ( "fmt" "runtime" + "sync" "testing" "time" @@ -154,3 +155,65 @@ func TestDroppedSeriesIndexRegression(t *testing.T) { t.Fatalf("Got %d fingerprints, expected 1", len(fps)) } } + +func TestReaderWriterDeadlockRegression(t *testing.T) { + mp := runtime.GOMAXPROCS(2) + defer func(mp int) { + runtime.GOMAXPROCS(mp) + }(mp) + + s := NewMemorySeriesStorage(MemorySeriesOptions{}) + lms := metric.LabelMatchers{} + + for i := 0; i < 100; i++ { + lm, err := metric.NewLabelMatcher(metric.NotEqual, clientmodel.MetricNameLabel, "testmetric") + if err != nil { + t.Fatal(err) + } + lms = append(lms, lm) + } + + wg := sync.WaitGroup{} + wg.Add(2) + + start := time.Now() + runDuration := 250 * time.Millisecond + + writer := func() { + for time.Since(start) < runDuration { + s.AppendSamples(clientmodel.Samples{ + &clientmodel.Sample{ + Metric: clientmodel.Metric{ + clientmodel.MetricNameLabel: "testmetric", + }, + Value: 1, + Timestamp: 0, + }, + }) + } + wg.Done() + } + + reader := func() { + for time.Since(start) < runDuration { + s.GetFingerprintsForLabelMatchers(lms) + } + wg.Done() + } + + go reader() + go writer() + + allDone := make(chan struct{}) + go func() { + wg.Wait() + allDone <- struct{}{} + }() + + select { + case <-allDone: + break + case <-time.NewTimer(5 * time.Second).C: + t.Fatalf("Deadlock timeout") + } +}