From 03c26eca02fb07a2bf9ed735f062b4a6b509a191 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Tue, 10 Mar 2026 19:07:32 +0100 Subject: [PATCH] refactor: hoist LoaderFunc to package-level var in phpheaders (#2053) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Hoists the `otter.LoaderFunc` closure in `GetUnCommonHeader` to a package-level `loader` var, so it is allocated once at init time instead of being re-created on every call. This is a minor cleanup — the previous code created a new `LoaderFunc` closure each time `GetUnCommonHeader` was called. While otter's cache-hit path is fast enough that this doesn't show a measurable difference in end-to-end benchmarks, avoiding the repeated allocation is strictly better. ## What changed **Before** (closure created per call): ```go func GetUnCommonHeader(ctx context.Context, key string) string { phpHeaderKey, err := headerKeyCache.Get( ctx, key, otter.LoaderFunc[string, string](func(_ context.Context, key string) (string, error) { return "HTTP_" + headerNameReplacer.Replace(strings.ToUpper(key)) + "\x00", nil }), ) ... } ``` **After** (closure allocated once): ```go var loader = otter.LoaderFunc[string, string](func(_ context.Context, key string) (string, error) { return "HTTP_" + headerNameReplacer.Replace(strings.ToUpper(key)) + "\x00", nil }) func GetUnCommonHeader(ctx context.Context, key string) string { phpHeaderKey, err := headerKeyCache.Get(ctx, key, loader) ... } ``` ## Benchmarks Apple M1 Pro, 8 runs, `benchstat` comparison — no regressions, no extra allocations: | Benchmark | main | PR | vs base | |---|---|---|---| | HelloWorld | 41.81µ ± 2% | 42.75µ ± 5% | ~ (p=0.065) | | ServerSuperGlobal | 73.36µ ± 2% | 74.20µ ± 3% | ~ (p=0.105) | | UncommonHeaders | 69.03µ ± 3% | 68.71µ ± 1% | ~ (p=0.382) | All results within noise. Zero change in allocations. --- internal/phpheaders/phpheaders.go | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/internal/phpheaders/phpheaders.go b/internal/phpheaders/phpheaders.go index 71f23e7d..d126ec4c 100644 --- a/internal/phpheaders/phpheaders.go +++ b/internal/phpheaders/phpheaders.go @@ -119,18 +119,16 @@ var CommonRequestHeaders = map[string]string{ // Cache up to 256 uncommon headers // This is ~2.5x faster than converting the header each time -var headerKeyCache = otter.Must[string, string](&otter.Options[string, string]{MaximumSize: 256}) - -var headerNameReplacer = strings.NewReplacer(" ", "_", "-", "_") +var ( + headerKeyCache = otter.Must[string, string](&otter.Options[string, string]{MaximumSize: 256}) + headerNameReplacer = strings.NewReplacer(" ", "_", "-", "_") + loader = otter.LoaderFunc[string, string](func(_ context.Context, key string) (string, error) { + return "HTTP_" + headerNameReplacer.Replace(strings.ToUpper(key)) + "\x00", nil + }) +) func GetUnCommonHeader(ctx context.Context, key string) string { - phpHeaderKey, err := headerKeyCache.Get( - ctx, - key, - otter.LoaderFunc[string, string](func(_ context.Context, key string) (string, error) { - return "HTTP_" + headerNameReplacer.Replace(strings.ToUpper(key)) + "\x00", nil - }), - ) + phpHeaderKey, err := headerKeyCache.Get(ctx, key, loader) if err != nil { panic(err) }