From 9ac758545dd6d239eada80b7c14284969a45e91c Mon Sep 17 00:00:00 2001 From: Andrew Werner Date: Mon, 14 Mar 2022 20:37:49 -0400 Subject: [PATCH] sql/schemachanger/screl: optimize walk a tad Before this change, walk would allocate once per struct field. Now it does not. Release justification: bug fixes and low-risk updates to new functionality Release note: None --- pkg/sql/schemachanger/screl/walk.go | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/pkg/sql/schemachanger/screl/walk.go b/pkg/sql/schemachanger/screl/walk.go index f9618a2a9bc2..315487ceae87 100644 --- a/pkg/sql/schemachanger/screl/walk.go +++ b/pkg/sql/schemachanger/screl/walk.go @@ -102,9 +102,11 @@ func walk(wantType reflect.Type, toWalk interface{}, f func(interface{}) error) } case reflect.Struct: for i := 0; i < value.NumField(); i++ { - if f := value.Field(i); f.CanAddr() && value.Type().Field(i).IsExported() { - walk(f.Addr().Elem()) + f := value.Field(i) + if !f.CanAddr() || !fieldIsExported(value.Type(), i) { + continue } + walk(value.Field(i).Addr().Elem()) } case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, @@ -123,3 +125,22 @@ func walk(wantType reflect.Type, toWalk interface{}, f func(interface{}) error) walk(v.Elem()) return nil } + +// fieldIsExported caches whether a field is exported as an optimization to avoid +// allocations due to (*reflect.Type).Field() calls. +func fieldIsExported(typ reflect.Type, field int) bool { + k := fieldExportedCacheKey{typ: typ, field: field} + if exported, ok := fieldExportedCache[k]; ok { + return exported + } + exported := typ.Field(field).IsExported() + fieldExportedCache[k] = exported + return exported +} + +type fieldExportedCacheKey struct { + typ reflect.Type + field int +} + +var fieldExportedCache = map[fieldExportedCacheKey]bool{}