From 406fd1ed84a2d5ba4d7c6ff93079c1f30a266503 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=90=8D=E9=94=90?= <1565842059@qq.com> Date: Fri, 28 Aug 2026 19:39:13 +0800 Subject: [PATCH] perf(util): replace global RWMutex with lock-free sync.Map in reCache to eliminate contention (fix #1690) --- util/builtin_operators.go | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/util/builtin_operators.go b/util/builtin_operators.go index cb0361ef..6f26211f 100644 --- a/util/builtin_operators.go +++ b/util/builtin_operators.go @@ -40,8 +40,7 @@ var ( keyMatch5Re = regexp.MustCompile(`\{[^/]+\}`) keyGet2Re1 = regexp.MustCompile(`:[^/]+`) keyGet3Re1 = regexp.MustCompile(`\{[^/]+?\}`) // non-greedy match of `{...}` to support multiple {} in `/.../` - reCache = map[string]*regexp.Regexp{} - reCacheMu = sync.RWMutex{} + reCache sync.Map // string -> *regexp.Regexp ) // regexpMetaChars is exactly the set of characters that regexp.QuoteMeta escapes. @@ -128,18 +127,13 @@ var ( ) func mustCompileOrGet(key string) *regexp.Regexp { - reCacheMu.RLock() - re, ok := reCache[key] - reCacheMu.RUnlock() - - if !ok { - re = regexp.MustCompile(key) - reCacheMu.Lock() - reCache[key] = re - reCacheMu.Unlock() + if v, ok := reCache.Load(key); ok { + return v.(*regexp.Regexp) } - return re + re := regexp.MustCompile(key) + actual, _ := reCache.LoadOrStore(key, re) + return actual.(*regexp.Regexp) } // validate the variadic parameter size and type as string.