Skip to content

Commit b60d3b6

Browse files
committed
perf(database): 优化字段缓存管理器性能
1 parent e80897d commit b60d3b6

File tree

2 files changed

+75
-75
lines changed

2 files changed

+75
-75
lines changed

database/gdb/gdb_type_result_scanlist.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -478,9 +478,8 @@ func doScanListAssignmentLoop(
478478
relationBindToFieldNameChecked bool
479479
)
480480

481-
// Phase 1 优化:使用缓存管理器获取字段索引缓存
482-
// 这里缓存了确定性的字段访问信息,避免循环内重复反射
483-
cache, err := fieldCacheMgr.getOrBuild(
481+
// 使用缓存管理器获取字段索引缓存,这里缓存了确定性的字段访问信息,避免循环内重复反射
482+
cache, err := fieldCacheInstance.getOrSet(
484483
arrayItemType,
485484
in.BindToAttrName,
486485
in.RelationAttrName,

database/gdb/gdb_type_result_scanlist_cache.go

Lines changed: 73 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -9,163 +9,164 @@ package gdb
99
import (
1010
"fmt"
1111
"reflect"
12+
"strings"
1213
"sync"
13-
14-
"github.com/gogf/gf/v2/text/gstr"
1514
)
1615

17-
// ==================== 字段元数据缓存管理器 ====================
18-
// 设计原则:
19-
// 1. 仅缓存确定性信息(字段索引、类型判断)
20-
// 2. 保留动态查找能力(嵌入字段、大小写不敏感)
21-
// 3. 使用 sync.Map 保证高性能并发读取
16+
// Field metadata cache manager
17+
// Design principle:
18+
// 1. Cache deterministic information only (field index, type judgment)
19+
// 2. Retain dynamic lookup capability (embedded fields, case insensitive)
20+
// 3. Use sync.Map to ensure high performance concurrent access
2221

23-
// fieldCacheManager 字段缓存管理器
22+
// fieldCacheManager field cache manager
2423
type fieldCacheManager struct {
2524
cache sync.Map // map[string]*fieldCache
2625
}
2726

28-
// newFieldCacheManager 创建字段缓存管理器
27+
// newFieldCacheManager creates field cache manager
2928
func newFieldCacheManager() *fieldCacheManager {
3029
return &fieldCacheManager{}
3130
}
3231

33-
// fieldCacheMgr 全局字段缓存管理器实例
34-
var fieldCacheMgr = newFieldCacheManager()
32+
// fieldCacheInstance global field cache manager instance
33+
var fieldCacheInstance = newFieldCacheManager()
3534

36-
// fieldCache 字段缓存
37-
// 存储可以安全缓存的确定性字段信息,避免在循环内重复反射
35+
// fieldCache field cache
36+
// Stores deterministic field information that can be safely cached to avoid repeated reflection in loops
3837
type fieldCache struct {
39-
// 确定性字段索引(可安全缓存)
40-
bindToAttrIndex int // 绑定属性的字段索引(如 UserDetail
41-
relationAttrIndex int // 关系属性的字段索引(如 User,-1表示无)
42-
isPointerElem bool // 数组元素是否为指针类型
43-
bindToAttrKind reflect.Kind // 绑定属性的类型
38+
// Deterministic field index (can be safely cached)
39+
bindToAttrIndex int // Field index of bound attribute (e.g. UserDetail)
40+
relationAttrIndex int // Field index of relation attribute (e.g. User, -1 means none)
41+
isPointerElem bool // Whether array element is pointer type
42+
bindToAttrKind reflect.Kind // Type of bound attribute
4443

45-
// 字段名映射(支持大小写不敏感查找)
44+
// Field name mapping (supports case-insensitive lookup)
4645
fieldNameMap map[string]string // lowercase -> OriginalName
4746
fieldIndexMap map[string]int // FieldName -> Index
4847
}
4948

50-
// getOrBuild 获取或构建缓存(线程安全)
51-
func (m *fieldCacheManager) getOrBuild(
49+
// getOrSet gets or sets cache (thread-safe)
50+
func (m *fieldCacheManager) getOrSet(
5251
arrayItemType reflect.Type,
5352
bindToAttrName string,
5453
relationAttrName string,
5554
) (*fieldCache, error) {
56-
// 构建缓存键
55+
// Build cache key
5756
cacheKey := m.buildCacheKey(arrayItemType, bindToAttrName, relationAttrName)
5857

59-
// 快速路径:缓存命中
58+
// Fast path: cache hit
6059
if cached, ok := m.cache.Load(cacheKey); ok {
6160
return cached.(*fieldCache), nil
6261
}
6362

64-
// 慢速路径:构建缓存
63+
// Slow path: build cache
6564
cache, err := m.buildCache(arrayItemType, bindToAttrName, relationAttrName)
6665
if err != nil {
6766
return nil, err
6867
}
6968

70-
// 存储到缓存(如果并发构建,只有一个会被保存)
69+
// Store to cache (if built concurrently, only one will be saved)
7170
actual, _ := m.cache.LoadOrStore(cacheKey, cache)
7271
return actual.(*fieldCache), nil
7372
}
7473

75-
// buildCacheKey 构建缓存键
74+
// buildCacheKey builds the cache key
7675
func (m *fieldCacheManager) buildCacheKey(
7776
typ reflect.Type,
7877
bindToAttrName string,
7978
relationAttrName string,
8079
) string {
81-
// 使用类型的唯一标识 + 字段名组合
82-
return fmt.Sprintf("%s|%s|%s", typ.String(), bindToAttrName, relationAttrName)
80+
// Estimate capacity: type name + two field names + 2 separators
81+
var builder strings.Builder
82+
typeName := typ.String()
83+
builder.Grow(len(typeName) + len(bindToAttrName) + len(relationAttrName) + 2)
84+
85+
builder.WriteString(typeName)
86+
builder.WriteByte('|')
87+
builder.WriteString(bindToAttrName)
88+
builder.WriteByte('|')
89+
builder.WriteString(relationAttrName)
90+
91+
return builder.String()
8392
}
8493

85-
// buildCache 构建字段访问缓存
94+
// buildCache builds field access cache
8695
func (m *fieldCacheManager) buildCache(
8796
arrayItemType reflect.Type,
8897
bindToAttrName string,
8998
relationAttrName string,
9099
) (*fieldCache, error) {
91-
cache := &fieldCache{
92-
relationAttrIndex: -1, // 默认值
93-
fieldNameMap: make(map[string]string),
94-
fieldIndexMap: make(map[string]int),
95-
}
96-
97-
// 获取实际的结构体类型
100+
// Get the actual struct type
98101
structType := arrayItemType
102+
isPointerElem := false
99103
if structType.Kind() == reflect.Pointer {
100104
structType = structType.Elem()
101-
cache.isPointerElem = true
105+
isPointerElem = true
102106
}
103107

104108
if structType.Kind() != reflect.Struct {
105109
return nil, fmt.Errorf("arrayItemType must be struct or pointer to struct, got: %s", arrayItemType.Kind())
106110
}
107111

108-
// 遍历所有字段,构建字段映射
109112
numField := structType.NumField()
113+
cache := &fieldCache{
114+
relationAttrIndex: -1,
115+
isPointerElem: isPointerElem,
116+
fieldNameMap: make(map[string]string, numField), // Pre-allocate capacity
117+
fieldIndexMap: make(map[string]int, numField), // Pre-allocate capacity
118+
}
119+
120+
// Iterate all fields, build field mapping
110121
for i := 0; i < numField; i++ {
111122
field := structType.Field(i)
112123
fieldName := field.Name
113124

114125
cache.fieldIndexMap[fieldName] = i
115-
cache.fieldNameMap[gstr.ToLower(fieldName)] = fieldName
126+
cache.fieldNameMap[strings.ToLower(fieldName)] = fieldName
116127
}
117128

118-
// 查找 bindToAttrName 字段索引
129+
// Find bindToAttrName field index
119130
if idx, ok := cache.fieldIndexMap[bindToAttrName]; ok {
120131
cache.bindToAttrIndex = idx
121132
field := structType.Field(idx)
122133
cache.bindToAttrKind = field.Type.Kind()
123-
} else if originalName, ok := cache.fieldNameMap[gstr.ToLower(bindToAttrName)]; ok {
124-
// 大小写不敏感查找
125-
cache.bindToAttrIndex = cache.fieldIndexMap[originalName]
126-
field := structType.Field(cache.bindToAttrIndex)
127-
cache.bindToAttrKind = field.Type.Kind()
128134
} else {
129-
return nil, fmt.Errorf(`field "%s" not found in type %s`, bindToAttrName, arrayItemType.String())
135+
// Case-insensitive lookup
136+
lowerBindName := strings.ToLower(bindToAttrName)
137+
if originalName, ok := cache.fieldNameMap[lowerBindName]; ok {
138+
cache.bindToAttrIndex = cache.fieldIndexMap[originalName]
139+
field := structType.Field(cache.bindToAttrIndex)
140+
cache.bindToAttrKind = field.Type.Kind()
141+
} else {
142+
return nil, fmt.Errorf(`field "%s" not found in type %s`, bindToAttrName, arrayItemType.String())
143+
}
130144
}
131145

132-
// 查找 relationAttrName 字段索引(可选)
146+
// Find relationAttrName field index (optional)
133147
if relationAttrName != "" {
134148
if idx, ok := cache.fieldIndexMap[relationAttrName]; ok {
135149
cache.relationAttrIndex = idx
136-
} else if originalName, ok := cache.fieldNameMap[gstr.ToLower(relationAttrName)]; ok {
137-
cache.relationAttrIndex = cache.fieldIndexMap[originalName]
150+
} else {
151+
// Case-insensitive lookup
152+
lowerRelName := strings.ToLower(relationAttrName)
153+
if originalName, ok := cache.fieldNameMap[lowerRelName]; ok {
154+
cache.relationAttrIndex = cache.fieldIndexMap[originalName]
155+
}
138156
}
139-
// 注意:如果找不到,保持 -1,表示需要使用 arrayElemValue 本身
157+
// Note: if not found, keep -1, indicating that arrayElemValue itself should be used
140158
}
141159

142160
return cache, nil
143161
}
144162

145-
// clear 清空所有缓存(测试或热更新时使用)
163+
// clear clears all cache (used for testing or hot updates)
146164
func (m *fieldCacheManager) clear() {
147-
m.cache.Range(func(key, value any) bool {
148-
m.cache.Delete(key)
149-
return true
150-
})
151-
}
152-
153-
// stats 获取缓存统计信息
154-
func (m *fieldCacheManager) stats() (count int) {
155-
m.cache.Range(func(key, value any) bool {
156-
count++
157-
return true
158-
})
159-
return count
165+
m.cache.Clear()
160166
}
161167

162-
// ClearFieldCache 清空字段缓存(供外部调用)
163-
// 用于测试或应用热更新场景
168+
// ClearFieldCache clears field cache (for external calls)
169+
// Used for testing or application hot update scenarios
164170
func ClearFieldCache() {
165-
fieldCacheMgr.clear()
166-
}
167-
168-
// GetFieldCacheStats 获取字段缓存统计信息(供监控使用)
169-
func GetFieldCacheStats() int {
170-
return fieldCacheMgr.stats()
171+
fieldCacheInstance.clear()
171172
}

0 commit comments

Comments
 (0)