From f731a90a7f33cf19ea8a63d889a1830a05c0236d Mon Sep 17 00:00:00 2001 From: Baskar Shanmugam <123750249+codebasky@users.noreply.github.com> Date: Fri, 19 May 2023 13:06:30 +0530 Subject: [PATCH] Fix LabelValueStats in posting stats (#12342) Problem: LabelValueStats - This will provide a list of the label names and memory used in bytes. It is calculated by adding the length of all values for a given label name. But internally Prometheus stores the name and the value independently for each series. Solution: MemPostings struct maintains the values to seriesRef map which is used to get the number of series which contains the label values. Using that LabelValueStats is calculated as: seriesCnt * len(value name) Signed-off-by: Baskar Shanmugam --- tsdb/index/postings.go | 5 +++-- tsdb/index/postings_test.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/tsdb/index/postings.go b/tsdb/index/postings.go index b93d3a202..200100239 100644 --- a/tsdb/index/postings.go +++ b/tsdb/index/postings.go @@ -184,8 +184,9 @@ func (p *MemPostings) Stats(label string) *PostingsStats { if n == label { metrics.push(Stat{Name: name, Count: uint64(len(values))}) } - labelValuePairs.push(Stat{Name: n + "=" + name, Count: uint64(len(values))}) - size += uint64(len(name)) + seriesCnt := uint64(len(values)) + labelValuePairs.push(Stat{Name: n + "=" + name, Count: seriesCnt}) + size += uint64(len(name)) * seriesCnt } labelValueLength.push(Stat{Name: n, Count: size}) } diff --git a/tsdb/index/postings_test.go b/tsdb/index/postings_test.go index a34f3c12d..9d8b5ebf3 100644 --- a/tsdb/index/postings_test.go +++ b/tsdb/index/postings_test.go @@ -916,6 +916,35 @@ func BenchmarkPostings_Stats(b *testing.B) { } } +func TestMemPostingsStats(t *testing.T) { + // create a new MemPostings + p := NewMemPostings() + + // add some postings to the MemPostings + p.Add(1, labels.FromStrings("label", "value1")) + p.Add(1, labels.FromStrings("label", "value2")) + p.Add(1, labels.FromStrings("label", "value3")) + p.Add(2, labels.FromStrings("label", "value1")) + + // call the Stats method to calculate the cardinality statistics + stats := p.Stats("label") + + // assert that the expected statistics were calculated + require.Equal(t, uint64(2), stats.CardinalityMetricsStats[0].Count) + require.Equal(t, "value1", stats.CardinalityMetricsStats[0].Name) + + require.Equal(t, uint64(3), stats.CardinalityLabelStats[0].Count) + require.Equal(t, "label", stats.CardinalityLabelStats[0].Name) + + require.Equal(t, uint64(24), stats.LabelValueStats[0].Count) + require.Equal(t, "label", stats.LabelValueStats[0].Name) + + require.Equal(t, uint64(2), stats.LabelValuePairsStats[0].Count) + require.Equal(t, "label=value1", stats.LabelValuePairsStats[0].Name) + + require.Equal(t, 3, stats.NumLabelPairs) +} + func TestMemPostings_Delete(t *testing.T) { p := NewMemPostings() p.Add(1, labels.FromStrings("lbl1", "a"))