From a2cd79576f9e672e080a01a2ef7fe44d06f85820 Mon Sep 17 00:00:00 2001 From: Aliaksandr Valialkin Date: Fri, 26 Aug 2022 21:47:20 +0300 Subject: [PATCH] lib/promrelabel: call PromRegex.MatchString() on a slow path only if it contains non-empty literal prefix This should improve slow path speed for regexps without literal prefixes --- lib/promrelabel/relabel.go | 23 +++++++++++------------ lib/regexutil/promregex.go | 8 ++++++++ 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/lib/promrelabel/relabel.go b/lib/promrelabel/relabel.go index c60c3ff894..f03f29ba2e 100644 --- a/lib/promrelabel/relabel.go +++ b/lib/promrelabel/relabel.go @@ -203,7 +203,7 @@ func (prc *parsedRelabelConfig) apply(labels []prompbmarshal.Label, labelsOffset return labels } } - if !prc.regex.MatchString(bytesutil.ToUnsafeString(bb.B)) { + if re := prc.regex; re.HasPrefix() && !re.MatchString(bytesutil.ToUnsafeString(bb.B)) { // Fast path - regexp mismatch. relabelBufPool.Put(bb) return labels @@ -304,8 +304,7 @@ func (prc *parsedRelabelConfig) apply(labels []prompbmarshal.Label, labelsOffset return setLabelValue(labels, labelsOffset, prc.TargetLabel, value) case "labelmap": // Replace label names with the `replacement` if they match `regex` - for i := range src { - label := &src[i] + for _, label := range src { labelName, ok := prc.replaceFullString(label.Name, prc.Replacement, prc.hasCaptureGroupInReplacement) if ok { labels = setLabelValue(labels, labelsOffset, labelName, label.Value) @@ -322,20 +321,20 @@ func (prc *parsedRelabelConfig) apply(labels []prompbmarshal.Label, labelsOffset case "labeldrop": // Drop labels with names matching the `regex` dst := labels[:labelsOffset] - for i := range src { - label := &src[i] - if !prc.regex.MatchString(label.Name) { - dst = append(dst, *label) + re := prc.regex + for _, label := range src { + if !re.MatchString(label.Name) { + dst = append(dst, label) } } return dst case "labelkeep": // Keep labels with names matching the `regex` dst := labels[:labelsOffset] - for i := range src { - label := &src[i] - if prc.regex.MatchString(label.Name) { - dst = append(dst, *label) + re := prc.regex + for _, label := range src { + if re.MatchString(label.Name) { + dst = append(dst, label) } } return dst @@ -393,7 +392,7 @@ func (prc *parsedRelabelConfig) replaceFullString(s, replacement string, hasCapt } } } - if !prc.regex.MatchString(s) { + if re := prc.regex; re.HasPrefix() && !re.MatchString(s) { // Fast path - regex mismatch return s, false } diff --git a/lib/regexutil/promregex.go b/lib/regexutil/promregex.go index e1d82806fc..96e39ec96f 100644 --- a/lib/regexutil/promregex.go +++ b/lib/regexutil/promregex.go @@ -61,6 +61,14 @@ func NewPromRegex(expr string) (*PromRegex, error) { return pr, nil } +// HasPrefix returns true if pr contains non-empty literal prefix. +// +// For example, if pr is "foo(bar|baz)", then the prefix is "foo", +// so HasPrefix() returns true. +func (pr *PromRegex) HasPrefix() bool { + return len(pr.prefix) > 0 +} + // MatchString retruns true if s matches pr. // // The pr is automatically anchored to the beginning and to the end