From b698d1bdc0266d9cdc121c97d52bf4986a5cf6a5 Mon Sep 17 00:00:00 2001 From: Ben Vincent Date: Thu, 2 Jul 2026 00:33:46 +1000 Subject: [PATCH] perf: memoise regex compilation in the classifier Classify runs on every proxied request and recompiled each remote's pattern lists every time. Cache compiled regexes keyed by pattern text so each distinct pattern compiles once and is reused thereafter. Refs #73 --- internal/proxy/classifier.go | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/internal/proxy/classifier.go b/internal/proxy/classifier.go index b8bc686..82b889c 100644 --- a/internal/proxy/classifier.go +++ b/internal/proxy/classifier.go @@ -2,6 +2,7 @@ package proxy import ( "regexp" + "sync" "git.unkin.net/unkin/artifactapi/internal/provider" "git.unkin.net/unkin/artifactapi/pkg/models" @@ -60,10 +61,29 @@ func (c *Classifier) Classify(remote models.Remote, path string) Classification return ClassImmutable } +// patternCache memoises regex compilation. Classify runs on every proxied +// request and previously recompiled each remote's pattern lists every time; +// keying by the pattern string lets each distinct pattern compile once and +// then be reused, with no invalidation needed (the pattern text is the key). +// A pattern that fails to compile is cached as a typed nil so we don't retry. +var patternCache sync.Map // map[string]*regexp.Regexp + +func compileCached(pattern string) *regexp.Regexp { + if v, ok := patternCache.Load(pattern); ok { + return v.(*regexp.Regexp) + } + re, err := regexp.Compile(pattern) + if err != nil { + re = nil + } + patternCache.Store(pattern, re) + return re +} + func compilePatterns(patterns []string) []*regexp.Regexp { compiled := make([]*regexp.Regexp, 0, len(patterns)) for _, p := range patterns { - if re, err := regexp.Compile(p); err == nil { + if re := compileCached(p); re != nil { compiled = append(compiled, re) } }