Skip to content

perf: add fast paths to KeyMatch2/3/4/5 for literals and "*"#1740

Open
akmalsyrf wants to merge 3 commits into
apache:masterfrom
akmalsyrf:perf/keymatch-literal-fast-path
Open

perf: add fast paths to KeyMatch2/3/4/5 for literals and "*"#1740
akmalsyrf wants to merge 3 commits into
apache:masterfrom
akmalsyrf:perf/keymatch-literal-fast-path

Conversation

@akmalsyrf

@akmalsyrf akmalsyrf commented Jul 17, 2026

Copy link
Copy Markdown

Summary

Adds cheap fast paths to KeyMatch2, KeyMatch3, KeyMatch4, and KeyMatch5 before the existing strings.Replace + RegexMatch machinery, via a shared keyMatchFastPath helper. Two cases short-circuit:

  1. key2 == "*"true (bare wildcard; avoids depending on compiling ^*$ — see #330)
  2. key2 is a pure literal → return key1 == key2

Anything else (real patterns, or key2 carrying stray regexp metacharacters) falls through to the unchanged regex path.

Why: With AddNamedDomainMatchingFunc("g", ..., KeyMatch2) (or KeyMatch3/4/5), DomainManager evaluates 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, RegexMatch no longer recompiles on every call, but literal≠literal comparisons still pay for strings.Replace, pattern ReplaceAllString, map lookup, and MatchString. That remains a dominant cost for large domain graphs and shows up as cold-start time when policies are loaded on boot.

Related:

Correctness

RegexMatch embeds key2 unescaped into "^"+key2+"$", so the fast path must be careful:

  1. Literal detection. Only treat key2 as a literal when regexp.QuoteMeta(key2) == key2 and it contains none of the matcher-specific extras QuoteMeta does not escape (":" for KeyMatch2). This keeps cases like KeyMatch2("acmeXcom", "acme.com") on the regex path.
  2. Equality is gated by literal detection. A naive key1 == key2 → true is not equivalent: "^a+b$" does not match "a+b". Non-literal key2 falls through to the regex path.
  3. KeyMatch2 : asymmetry. ":" is :param dialect, not a Go regexp meta. KeyMatch2("team:1", "team:2") must stay true (team[^/]+); KeyMatch3 treats ":" as a literal so the same pair is false. Covered by tests.
Matcher extraPatternChars Notes
KeyMatch2 : :param dialect; {/* already covered by QuoteMeta
KeyMatch3 (empty) {param} / * covered by QuoteMeta
KeyMatch4 (empty) same; repeated-token logic unchanged
KeyMatch5 (empty) query string stripped from key1 before fast path

Test 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 paths
  • go test ./... — full suite green
  • gofmt clean; benchmarks BenchmarkKeyMatch2_LiteralDomains, BenchmarkKeyMatch2_RESTPatterns

Illustrative local numbers (not a formal perf claim; use CI / longer -benchtime if citing):

BenchmarkKeyMatch2_LiteralDomains    ~30ms/op    0 B/op    0 allocs/op

Pure concrete domains + "*" short-circuit with 0 allocs (regexp.QuoteMeta returns the input unchanged when there is nothing to escape).

Out of scope

akmalsyrf and others added 3 commits July 17, 2026 15:54
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
akmalsyrf force-pushed the perf/keymatch-literal-fast-path branch from cae9372 to 422ddb9 Compare July 17, 2026 09:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant