From 517badc21d12b62a7e8d1b4d54d855205afd8878 Mon Sep 17 00:00:00 2001 From: Julius Volz Date: Thu, 23 Jul 2015 22:46:13 +0200 Subject: [PATCH] Only do regex lookups when there was no equality match. For the label matching index-based preselection phase, don't do an OR between equality and non-equality matchers. Execute only one of the two (with equality matchers preferred when present). Fixes https://github.com/prometheus/prometheus/issues/924 --- storage/local/storage.go | 53 ++++++++++++++++++----------------- storage/local/storage_test.go | 16 ++++++++++- 2 files changed, 42 insertions(+), 27 deletions(-) diff --git a/storage/local/storage.go b/storage/local/storage.go index fa2461275..7ff73107b 100644 --- a/storage/local/storage.go +++ b/storage/local/storage.go @@ -428,39 +428,40 @@ func (s *memorySeriesStorage) MetricsForLabelMatchers(matchers ...*metric.LabelM } var resFPs map[clientmodel.Fingerprint]struct{} - // If we cannot make a preselection based on equality matchers, expanding the other matchers to labels - // and intersecting their fingerprints is still likely to be the best choice. if len(equals) > 0 { resFPs = s.fingerprintsForLabelPairs(equals...) - } - var remaining metric.LabelMatchers - for _, matcher := range filters { - // Equal matches are all empty values. - if matcher.Match("") { - remaining = append(remaining, matcher) - continue - } - intersection := map[clientmodel.Fingerprint]struct{}{} + } else { + // If we cannot make a preselection based on equality matchers, expanding the other matchers to labels + // and intersecting their fingerprints is still likely to be the best choice. + var remaining metric.LabelMatchers + for _, matcher := range filters { + // Equal matches are all empty values. + if matcher.Match("") { + remaining = append(remaining, matcher) + continue + } + intersection := map[clientmodel.Fingerprint]struct{}{} - matches := matcher.Filter(s.LabelValuesForLabelName(matcher.Name)) - if len(matches) == 0 { - return nil - } - for _, v := range matches { - fps := s.fingerprintsForLabelPairs(metric.LabelPair{ - Name: matcher.Name, - Value: v, - }) - for fp := range fps { - if _, ok := resFPs[fp]; ok || resFPs == nil { - intersection[fp] = struct{}{} + matches := matcher.Filter(s.LabelValuesForLabelName(matcher.Name)) + if len(matches) == 0 { + return nil + } + for _, v := range matches { + fps := s.fingerprintsForLabelPairs(metric.LabelPair{ + Name: matcher.Name, + Value: v, + }) + for fp := range fps { + if _, ok := resFPs[fp]; ok || resFPs == nil { + intersection[fp] = struct{}{} + } } } + resFPs = intersection } - resFPs = intersection + // The intersected matchers no longer need to be compared against the actual metrics. + filters = remaining } - // The intersected matchers no longer need to be compared against the actual metrics. - filters = remaining result := make(map[clientmodel.Fingerprint]clientmodel.COWMetric, len(resFPs)) for fp := range resFPs { diff --git a/storage/local/storage_test.go b/storage/local/storage_test.go index 1ec404318..23fb47d48 100644 --- a/storage/local/storage_test.go +++ b/storage/local/storage_test.go @@ -70,7 +70,7 @@ func TestMatches(t *testing.T) { }{ { matchers: metric.LabelMatchers{newMatcher(metric.Equal, "label1", "x")}, - expected: fingerprints[:0], + expected: clientmodel.Fingerprints{}, }, { matchers: metric.LabelMatchers{newMatcher(metric.Equal, "label1", "test_0")}, @@ -161,6 +161,20 @@ func TestMatches(t *testing.T) { }, expected: append(append(clientmodel.Fingerprints{}, fingerprints[30:35]...), fingerprints[45:60]...), }, + { + matchers: metric.LabelMatchers{ + newMatcher(metric.Equal, "label1", `nonexistent`), + newMatcher(metric.RegexMatch, "label2", `test`), + }, + expected: clientmodel.Fingerprints{}, + }, + { + matchers: metric.LabelMatchers{ + newMatcher(metric.Equal, "label1", `test_0`), + newMatcher(metric.RegexMatch, "label2", `nonexistent`), + }, + expected: clientmodel.Fingerprints{}, + }, } for _, mt := range matcherTests {