diff --git a/promql/info.go b/promql/info.go index 318dae399a..0067fce845 100644 --- a/promql/info.go +++ b/promql/info.go @@ -55,13 +55,13 @@ func (ev *evaluator) evalInfo(ctx context.Context, args parser.Expressions) (par } // Don't try to enrich info series. - ignoreSeries := map[int]struct{}{} + ignoreSeries := map[uint64]struct{}{} loop: - for i, s := range mat { + for _, s := range mat { name := s.Metric.Get(labels.MetricName) for _, m := range infoNameMatchers { if m.Matches(name) { - ignoreSeries[i] = struct{}{} + ignoreSeries[s.Metric.Hash()] = struct{}{} continue loop } } @@ -121,11 +121,11 @@ func (ev *evaluator) infoSelectHints(expr parser.Expr) storage.SelectHints { // fetchInfoSeries fetches info series given matching identifying labels in mat. // Series in ignoreSeries are not fetched. // dataLabelMatchers may be mutated. -func (ev *evaluator) fetchInfoSeries(ctx context.Context, mat Matrix, ignoreSeries map[int]struct{}, dataLabelMatchers map[string][]*labels.Matcher, selectHints storage.SelectHints) (Matrix, annotations.Annotations, error) { +func (ev *evaluator) fetchInfoSeries(ctx context.Context, mat Matrix, ignoreSeries map[uint64]struct{}, dataLabelMatchers map[string][]*labels.Matcher, selectHints storage.SelectHints) (Matrix, annotations.Annotations, error) { // A map of values for all identifying labels we are interested in. idLblValues := map[string]map[string]struct{}{} - for i, s := range mat { - if _, exists := ignoreSeries[i]; exists { + for _, s := range mat { + if _, exists := ignoreSeries[s.Metric.Hash()]; exists { continue } @@ -197,7 +197,7 @@ func (ev *evaluator) fetchInfoSeries(ctx context.Context, mat Matrix, ignoreSeri } // combineWithInfoSeries combines mat with select data labels from infoMat. -func (ev *evaluator) combineWithInfoSeries(ctx context.Context, mat, infoMat Matrix, ignoreSeries map[int]struct{}, dataLabelMatchers map[string][]*labels.Matcher) (Matrix, annotations.Annotations) { +func (ev *evaluator) combineWithInfoSeries(ctx context.Context, mat, infoMat Matrix, ignoreSeries map[uint64]struct{}, dataLabelMatchers map[string][]*labels.Matcher) (Matrix, annotations.Annotations) { buf := make([]byte, 0, 1024) lb := labels.NewScratchBuilder(0) sigFunction := func(name string) func(labels.Labels) string { @@ -249,13 +249,13 @@ func (ev *evaluator) combineWithInfoSeries(ctx context.Context, mat, infoMat Mat tempNumSamples := ev.currentSamples // For every base series, compute signature per info metric. - baseSigs := make([]map[string]string, 0, len(mat)) + baseSigs := make(map[uint64]map[string]string, len(mat)) for _, s := range mat { sigs := make(map[string]string, len(infoMetrics)) for infoName := range infoMetrics { sigs[infoName] = sigfs[infoName](s.Metric) } - baseSigs = append(baseSigs, sigs) + baseSigs[s.Metric.Hash()] = sigs } infoSigs := make(map[uint64]string, len(infoMat)) @@ -331,7 +331,7 @@ func (ev *evaluator) combineWithInfoSeries(ctx context.Context, mat, infoMat Mat // combineWithInfoVector combines base and info Vectors. // Base series in ignoreSeries are not combined. -func (ev *evaluator) combineWithInfoVector(base, info Vector, ignoreSeries map[int]struct{}, baseSigs []map[string]string, infoSigs map[uint64]string, enh *EvalNodeHelper, dataLabelMatchers map[string][]*labels.Matcher) (Vector, error) { +func (ev *evaluator) combineWithInfoVector(base, info Vector, ignoreSeries map[uint64]struct{}, baseSigs map[uint64]map[string]string, infoSigs map[uint64]string, enh *EvalNodeHelper, dataLabelMatchers map[string][]*labels.Matcher) (Vector, error) { if len(base) == 0 { return nil, nil // Short-circuit: nothing is going to match. } @@ -370,8 +370,10 @@ func (ev *evaluator) combineWithInfoVector(base, info Vector, ignoreSeries map[i } } - for i, bs := range base { - if _, exists := ignoreSeries[i]; exists { + for _, bs := range base { + hash := bs.Metric.Hash() + + if _, exists := ignoreSeries[hash]; exists { // This series should not be enriched with info metric data labels. enh.Out = append(enh.Out, Sample{ Metric: bs.Metric, @@ -386,7 +388,7 @@ func (ev *evaluator) combineWithInfoVector(base, info Vector, ignoreSeries map[i // For every info metric name, try to find an info series with the same signature. seenInfoMetrics := map[string]struct{}{} - for infoName, sig := range baseSigs[i] { + for infoName, sig := range baseSigs[hash] { is, exists := enh.rightSigs[sig] if !exists { continue diff --git a/promql/promqltest/testdata/info.test b/promql/promqltest/testdata/info.test index 660454a3b7..891e0eaa53 100644 --- a/promql/promqltest/testdata/info.test +++ b/promql/promqltest/testdata/info.test @@ -114,6 +114,8 @@ eval range from 1m to 4m step 1m info(metric offset 1m) clear +# info_metric churn: + load 1m data_metric{instance="a", job="work"} 10 20 30 data_metric{instance="b", job="work"} 11 21 31 @@ -125,3 +127,26 @@ eval range from 0 to 2m step 1m info(data_metric, {__name__="info_metric"}) data_metric{instance="a", job="work", state="running"} 10 20 30 data_metric{instance="b", job="work", state="stopped"} 11 21 _ data_metric{instance="b", job="work", state="running"} _ _ 31 + +clear + +# data_metric churn: + +load 1m + data_metric{instance="a", job="work"} 10 20 stale + data_metric{instance="b", job="work"} 11 21 31 + data_metric{instance="a", job="work", label="new"} _ _ 30 + info_metric{instance="b", job="work", state="stopped"} 1 1 1 + info_metric{instance="a", job="work", state="running"} 1 1 1 + +eval range from 0 to 2m step 1m info(data_metric, {__name__="info_metric"}) + data_metric{instance="a", job="work", state="running"} 10 20 _ + data_metric{instance="b", job="work", state="stopped"} 11 21 31 + data_metric{instance="a", job="work", state="running", label="new"} _ _ 30 + +eval range from 0 to 2m step 1m info({job="work"}, {__name__="info_metric"}) + data_metric{instance="a", job="work", state="running"} 10 20 _ + data_metric{instance="b", job="work", state="stopped"} 11 21 31 + data_metric{instance="a", job="work", state="running", label="new"} _ _ 30 + info_metric{instance="b", job="work", state="stopped"} 1 1 1 + info_metric{instance="a", job="work", state="running"} 1 1 1