perf(decode): cache struct schemas per type

Assisted-by: GLM 5.3
This commit is contained in:
2026-09-17 23:08:14 +02:00
parent a8d69d90d5
commit aaea68efc9
3 changed files with 29 additions and 3 deletions
+17 -1
View File
@@ -8,6 +8,7 @@ import (
"math"
"reflect"
"strings"
"sync"
"time"
)
@@ -105,7 +106,7 @@ func (d *decoder) assignTable(tbl map[string]any, dst reflect.Value) error {
}
func (d *decoder) assignStruct(tbl map[string]any, dst reflect.Value) error {
schema := newStructSchema(dst.Type())
schema := cachedStructSchema(dst.Type())
for key, val := range tbl {
field, ok := schema.byName[strings.ToLower(key)]
if !ok {
@@ -253,6 +254,21 @@ type structSchema struct {
embedMaps [][]int
}
// structSchemaCache holds one schema per struct type. A schema is immutable
// once published, so concurrent callers only race to build an identical value,
// the same trade-off encoding/json's field cache makes. The cache grows with
// the number of distinct types decoded or encoded, never per document.
var structSchemaCache sync.Map // reflect.Type -> structSchema
func cachedStructSchema(t reflect.Type) structSchema {
if s, ok := structSchemaCache.Load(t); ok {
return s.(structSchema)
}
s := newStructSchema(t)
actual, _ := structSchemaCache.LoadOrStore(t, s)
return actual.(structSchema)
}
func newStructSchema(t reflect.Type) structSchema {
s := structSchema{byName: make(map[string]structFieldLoc, t.NumField())}
// A struct may embed a pointer to itself, which is legal Go, so the walk