feat: dont compile regex matcher if we know its a literal (#12434)

labels: dont compile regex matcher if we know its a literal

Signed-off-by: Michael Hoffmann <mhoffm@posteo.de>

Co-authored-by: Sharad <sharadgaur@gmail.com>
This commit is contained in:
Michael Hoffmann 2023-06-07 22:54:30 +02:00 committed by GitHub
parent 4268feb9d7
commit 344c8ff97c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 31 additions and 4 deletions

View File

@ -102,12 +102,12 @@ func TestInverse(t *testing.T) {
expected: &Matcher{Type: MatchEqual, Name: "name2", Value: "value2"}, expected: &Matcher{Type: MatchEqual, Name: "name2", Value: "value2"},
}, },
{ {
matcher: &Matcher{Type: MatchRegexp, Name: "name3", Value: "value3"}, matcher: &Matcher{Type: MatchRegexp, Name: "name3", Value: "value3.*"},
expected: &Matcher{Type: MatchNotRegexp, Name: "name3", Value: "value3"}, expected: &Matcher{Type: MatchNotRegexp, Name: "name3", Value: "value3.*"},
}, },
{ {
matcher: &Matcher{Type: MatchNotRegexp, Name: "name4", Value: "value4"}, matcher: &Matcher{Type: MatchNotRegexp, Name: "name4", Value: "value4.*"},
expected: &Matcher{Type: MatchRegexp, Name: "name4", Value: "value4"}, expected: &Matcher{Type: MatchRegexp, Name: "name4", Value: "value4.*"},
}, },
} }
@ -123,3 +123,13 @@ func BenchmarkMatchType_String(b *testing.B) {
_ = MatchType(i % int(MatchNotRegexp+1)).String() _ = MatchType(i % int(MatchNotRegexp+1)).String()
} }
} }
func BenchmarkNewMatcher(b *testing.B) {
b.Run("regex matcher with literal", func(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
for i := 0; i <= b.N; i++ {
NewMatcher(MatchRegexp, "foo", "bar")
}
})
}

View File

@ -25,9 +25,16 @@ type FastRegexMatcher struct {
prefix string prefix string
suffix string suffix string
contains string contains string
// shortcut for literals
literal bool
value string
} }
func NewFastRegexMatcher(v string) (*FastRegexMatcher, error) { func NewFastRegexMatcher(v string) (*FastRegexMatcher, error) {
if isLiteral(v) {
return &FastRegexMatcher{literal: true, value: v}, nil
}
re, err := regexp.Compile("^(?:" + v + ")$") re, err := regexp.Compile("^(?:" + v + ")$")
if err != nil { if err != nil {
return nil, err return nil, err
@ -50,6 +57,9 @@ func NewFastRegexMatcher(v string) (*FastRegexMatcher, error) {
} }
func (m *FastRegexMatcher) MatchString(s string) bool { func (m *FastRegexMatcher) MatchString(s string) bool {
if m.literal {
return s == m.value
}
if m.prefix != "" && !strings.HasPrefix(s, m.prefix) { if m.prefix != "" && !strings.HasPrefix(s, m.prefix) {
return false return false
} }
@ -63,9 +73,16 @@ func (m *FastRegexMatcher) MatchString(s string) bool {
} }
func (m *FastRegexMatcher) GetRegexString() string { func (m *FastRegexMatcher) GetRegexString() string {
if m.literal {
return m.value
}
return m.re.String() return m.re.String()
} }
func isLiteral(re string) bool {
return regexp.QuoteMeta(re) == re
}
// optimizeConcatRegex returns literal prefix/suffix text that can be safely // optimizeConcatRegex returns literal prefix/suffix text that can be safely
// checked against the label value before running the regexp matcher. // checked against the label value before running the regexp matcher.
func optimizeConcatRegex(r *syntax.Regexp) (prefix, suffix, contains string) { func optimizeConcatRegex(r *syntax.Regexp) (prefix, suffix, contains string) {