perf: add fast paths to KeyMatch2/3/4/5 for literals and "*"#1740
Open
akmalsyrf wants to merge 3 commits into
Open
perf: add fast paths to KeyMatch2/3/4/5 for literals and "*"#1740akmalsyrf wants to merge 3 commits into
akmalsyrf wants to merge 3 commits into
Conversation
Skip string transforms and RegexMatch when key2 is equal, a bare "*", or has no pattern characters. Preserves existing semantics while cutting BuildRoleLinks cost for RBAC domain graphs that are mostly concrete domains plus an admin "*" wildcard (see apache#1004). Co-authored-by: Cursor <cursoragent@cursor.com>
Only treat key2 as a pure literal when QuoteMeta leaves it unchanged
(plus KeyMatch2's ":" dialect). Preserves KeyMatch2("acmeXcom","acme.com")
and similar cases. Factor shared helper; document bare "*" as apache#330 fix.
Co-authored-by: Cursor <cursoragent@cursor.com>
A standalone key1 == key2 short-circuit is not behavior-preserving when key2 contains regexp metacharacters that do not match themselves, e.g. "^a+b$" does not match "a+b" and "^ab)$" panics. Move the equality check inside the pure-literal gate so only genuine literals return via equality; everything else falls through to the existing RegexMatch path unchanged. Also cover KeyMatch5 fast paths, KeyMatch2 vs KeyMatch3 colon asymmetry, and meta-equality regressions across KeyMatch3/4/5. Co-authored-by: Cursor <cursoragent@cursor.com>
akmalsyrf
force-pushed
the
perf/keymatch-literal-fast-path
branch
from
July 17, 2026 09:25
cae9372 to
422ddb9
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds cheap fast paths to
KeyMatch2,KeyMatch3,KeyMatch4, andKeyMatch5before the existingstrings.Replace+RegexMatchmachinery, via a sharedkeyMatchFastPathhelper. Two cases short-circuit:key2 == "*"→true(bare wildcard; avoids depending on compiling^*$— see #330)key2is a pure literal → returnkey1 == key2Anything else (real patterns, or
key2carrying stray regexp metacharacters) falls through to the unchanged regex path.Why: With
AddNamedDomainMatchingFunc("g", ..., KeyMatch2)(or KeyMatch3/4/5),DomainManagerevaluates the matcher O(N×D) times while building role links. Many real deployments use mostly concrete domains (team/123,org/456, …) plus a bare"*"admin/wildcard domain. After #1721,RegexMatchno longer recompiles on every call, but literal≠literal comparisons still pay forstrings.Replace, patternReplaceAllString, map lookup, andMatchString. That remains a dominant cost for large domain graphs and shows up as cold-start time when policies are loaded on boot.Related:
RegexMatch)strings.Replace)"*"explicit instead of relying on^*$(#330; on current Go that pattern already match-alls)Correctness
RegexMatchembedskey2unescaped into"^"+key2+"$", so the fast path must be careful:key2as a literal whenregexp.QuoteMeta(key2) == key2and it contains none of the matcher-specific extrasQuoteMetadoes not escape (":"for KeyMatch2). This keeps cases likeKeyMatch2("acmeXcom", "acme.com")on the regex path.key1 == key2 → trueis not equivalent:"^a+b$"does not match"a+b". Non-literalkey2falls through to the regex path.:asymmetry.":"is:paramdialect, not a Go regexp meta.KeyMatch2("team:1", "team:2")must staytrue(team[^/]+); KeyMatch3 treats":"as a literal so the same pair isfalse. Covered by tests.extraPatternCharsKeyMatch2::paramdialect;{/*already covered byQuoteMetaKeyMatch3{param}/*covered byQuoteMetaKeyMatch4KeyMatch5key1before fast pathTest plan
go test ./util/— KeyMatch2/3/4/5: bare"*", pure literals,.metas, meta-equality (a+b/a?b), KeyMatch2 vs KeyMatch3 colon asymmetry, KeyMatch5 query strip + fast pathsgo test ./...— full suite greengofmtclean; benchmarksBenchmarkKeyMatch2_LiteralDomains,BenchmarkKeyMatch2_RESTPatternsIllustrative local numbers (not a formal perf claim; use CI / longer
-benchtimeif citing):Pure concrete domains +
"*"short-circuit with 0 allocs (regexp.QuoteMetareturns the input unchanged when there is nothing to escape).Out of scope
DomainManagerto index pattern vs plain domains ([Bug] Performance issue in RBAC with pattern matching domains #1004 root cause)key2" behavior on the slow path (left unchanged)KeyMatch/GlobMatch, adapter, or enforcer API changes