From ecf132933e52f4ecc25be9b5c6d61b8a0eb7458d Mon Sep 17 00:00:00 2001 From: Aliaksandr Valialkin Date: Mon, 15 Feb 2021 16:24:08 +0200 Subject: [PATCH] lib/storage: increase match cost for negative tag filters, since they need to scan all the label pairs --- lib/storage/index_db.go | 2 +- lib/storage/tag_filters.go | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/storage/index_db.go b/lib/storage/index_db.go index 49aa87814..d7f29d73a 100644 --- a/lib/storage/index_db.go +++ b/lib/storage/index_db.go @@ -2804,7 +2804,7 @@ func (is *indexSearch) getMetricIDsForDateAndFilters(date uint64, tfs *TagFilter if a.seconds != b.seconds { return a.seconds < b.seconds } - return a.tf.matchCost < b.tf.matchCost + return a.tf.Less(b.tf) }) // Populate metricIDs for the first non-negative filter. diff --git a/lib/storage/tag_filters.go b/lib/storage/tag_filters.go index 60b340d9e..eae02771f 100644 --- a/lib/storage/tag_filters.go +++ b/lib/storage/tag_filters.go @@ -240,6 +240,9 @@ type tagFilter struct { func (tf *tagFilter) Less(other *tagFilter) bool { // Move regexp and negative filters to the end, since they require scanning // all the entries for the given label. + if tf.matchCost != other.matchCost { + return tf.matchCost < other.matchCost + } if tf.isRegexp != other.isRegexp { return !tf.isRegexp } @@ -312,6 +315,9 @@ func (tf *tagFilter) InitFromGraphiteQuery(commonPrefix, query []byte, paths []s tf.prefix = marshalTagValueNoTrailingTagSeparator(tf.prefix, []byte(prefix)) tf.orSuffixes = append(tf.orSuffixes[:0], orSuffixes...) tf.reSuffixMatch, tf.matchCost = newMatchFuncForOrSuffixes(orSuffixes) + if isNegative { + tf.matchCost *= negativeMatchCostMultiplier + } } func getCommonPrefix(ss []string) (string, []string) { @@ -379,6 +385,9 @@ func (tf *tagFilter) Init(commonPrefix, key, value []byte, isNegative, isRegexp tf.orSuffixes = append(tf.orSuffixes[:0], "") tf.isEmptyMatch = len(prefix) == 0 tf.matchCost = fullMatchCost + if isNegative { + tf.matchCost *= negativeMatchCostMultiplier + } return nil } rcv, err := getRegexpFromCache(expr) @@ -388,6 +397,9 @@ func (tf *tagFilter) Init(commonPrefix, key, value []byte, isNegative, isRegexp tf.orSuffixes = append(tf.orSuffixes[:0], rcv.orValues...) tf.reSuffixMatch = rcv.reMatch tf.matchCost = rcv.reCost + if isNegative { + tf.matchCost *= negativeMatchCostMultiplier + } tf.isEmptyMatch = len(prefix) == 0 && tf.reSuffixMatch(nil) if !tf.isNegative && len(key) == 0 && strings.IndexByte(rcv.literalSuffix, '.') >= 0 { // Reverse suffix is needed only for non-negative regexp filters on __name__ that contains dots. @@ -559,6 +571,8 @@ const ( reMatchCost = 100 ) +const negativeMatchCostMultiplier = 1000 + func getOptimizedReMatchFuncExt(reMatch func(b []byte) bool, sre *syntax.Regexp) (func(b []byte) bool, string, uint64) { if isDotStar(sre) { // '.*'