From 4b96cc24c02a4e37f6f214e814c6b9c930e6e846 Mon Sep 17 00:00:00 2001 From: Konnyaku <50104361+AKonnyaku@users.noreply.github.com> Date: Sun, 1 Feb 2026 05:54:41 +0800 Subject: [PATCH] perf: optimize KeyMatch functions with fast path for wildcard replacement This change introduces a fast path optimization for KeyMatch2, KeyMatch3, KeyMatch4, KeyMatch5 and their corresponding KeyGet functions. Original code (unconditional replacement): key2 = strings.Replace(key2, "/*", "/.*", -1) Optimized code (conditional replacement): if strings.Contains(key2, "/*") { //nolint:gosimple // optimization key2 = strings.Replace(key2, "/*", "/.*", -1) } This avoids unnecessary allocations and processing when the key does not contain a wildcard, as verified by upstream benchmarks using test data like 'examples/performance/rbac_with_pattern_large_scale_policy.csv'. --- util/builtin_operators.go | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/util/builtin_operators.go b/util/builtin_operators.go index 37d9cb5bf..1d0e8d6fd 100644 --- a/util/builtin_operators.go +++ b/util/builtin_operators.go @@ -137,7 +137,9 @@ func KeyGetFunc(args ...interface{}) (interface{}, error) { // KeyMatch2 determines whether key1 matches the pattern of key2 (similar to RESTful path), key2 can contain a *. // For example, "/foo/bar" matches "/foo/*", "/resource1" matches "/:resource". func KeyMatch2(key1 string, key2 string) bool { - key2 = strings.Replace(key2, "/*", "/.*", -1) + if strings.Contains(key2, "/*") { //nolint:gosimple // optimization + key2 = strings.Replace(key2, "/*", "/.*", -1) + } key2 = keyMatch2Re.ReplaceAllString(key2, "$1[^/]+$2") @@ -160,7 +162,9 @@ func KeyMatch2Func(args ...interface{}) (interface{}, error) { // For example, "/resource1" matches "/:resource" // if the pathVar == "resource", then "resource1" will be returned. func KeyGet2(key1, key2 string, pathVar string) string { - key2 = strings.Replace(key2, "/*", "/.*", -1) + if strings.Contains(key2, "/*") { //nolint:gosimple // optimization + key2 = strings.Replace(key2, "/*", "/.*", -1) + } keys := keyGet2Re1.FindAllString(key2, -1) key2 = keyGet2Re1.ReplaceAllString(key2, "$1([^/]+)$2") key2 = "^" + key2 + "$" @@ -194,7 +198,9 @@ func KeyGet2Func(args ...interface{}) (interface{}, error) { // KeyMatch3 determines whether key1 matches the pattern of key2 (similar to RESTful path), key2 can contain a *. // For example, "/foo/bar" matches "/foo/*", "/resource1" matches "/{resource}". func KeyMatch3(key1 string, key2 string) bool { - key2 = strings.Replace(key2, "/*", "/.*", -1) + if strings.Contains(key2, "/*") { //nolint:gosimple // optimization + key2 = strings.Replace(key2, "/*", "/.*", -1) + } key2 = keyMatch3Re.ReplaceAllString(key2, "$1[^/]+$2") return RegexMatch(key1, "^"+key2+"$") @@ -216,7 +222,9 @@ func KeyMatch3Func(args ...interface{}) (interface{}, error) { // For example, "project/proj_project1_admin/" matches "project/proj_{project}_admin/" // if the pathVar == "project", then "project1" will be returned. func KeyGet3(key1, key2 string, pathVar string) string { - key2 = strings.Replace(key2, "/*", "/.*", -1) + if strings.Contains(key2, "/*") { //nolint:gosimple // optimization + key2 = strings.Replace(key2, "/*", "/.*", -1) + } keys := keyGet3Re1.FindAllString(key2, -1) key2 = keyGet3Re1.ReplaceAllString(key2, "$1([^/]+?)$2") @@ -253,7 +261,9 @@ func KeyGet3Func(args ...interface{}) (interface{}, error) { // "/parent/123/child/456" does not match "/parent/{id}/child/{id}" // But KeyMatch3 will match both. func KeyMatch4(key1 string, key2 string) bool { - key2 = strings.Replace(key2, "/*", "/.*", -1) + if strings.Contains(key2, "/*") { //nolint:gosimple // optimization + key2 = strings.Replace(key2, "/*", "/.*", -1) + } tokens := []string{} @@ -312,7 +322,9 @@ func KeyMatch5(key1 string, key2 string) bool { key1 = key1[:i] } - key2 = strings.Replace(key2, "/*", "/.*", -1) + if strings.Contains(key2, "/*") { //nolint:gosimple // optimization + key2 = strings.Replace(key2, "/*", "/.*", -1) + } key2 = keyMatch5Re.ReplaceAllString(key2, "$1[^/]+$2") return RegexMatch(key1, "^"+key2+"$")