Skip to content

Commit 8c2248a

Browse files
joeybloggsjoeybloggs
authored andcommitted
add map thread safety
1 parent 0c5fbee commit 8c2248a

File tree

1 file changed

+44
-6
lines changed

1 file changed

+44
-6
lines changed

validator.go

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"fmt"
1515
"reflect"
1616
"strings"
17+
"sync"
1718
"time"
1819
"unicode"
1920
)
@@ -51,8 +52,45 @@ type cachedStruct struct {
5152
fields []*cachedField
5253
}
5354

54-
var structCache = map[reflect.Type]*cachedStruct{}
55-
var fieldsCache = map[string][]*cachedTags{}
55+
type structsCacheMap struct {
56+
lock sync.RWMutex
57+
m map[reflect.Type]*cachedStruct
58+
}
59+
60+
func (s *structsCacheMap) Get(key reflect.Type) (*cachedStruct, bool) {
61+
s.lock.RLock()
62+
defer s.lock.RUnlock()
63+
value, ok := s.m[key]
64+
return value, ok
65+
}
66+
67+
func (s *structsCacheMap) Set(key reflect.Type, value *cachedStruct) {
68+
s.lock.Lock()
69+
defer s.lock.Unlock()
70+
s.m[key] = value
71+
}
72+
73+
var structCache = &structsCacheMap{m: map[reflect.Type]*cachedStruct{}}
74+
75+
type fieldsCacheMap struct {
76+
lock sync.RWMutex
77+
m map[string][]*cachedTags
78+
}
79+
80+
func (s *fieldsCacheMap) Get(key string) ([]*cachedTags, bool) {
81+
s.lock.RLock()
82+
defer s.lock.RUnlock()
83+
value, ok := s.m[key]
84+
return value, ok
85+
}
86+
87+
func (s *fieldsCacheMap) Set(key string, value []*cachedTags) {
88+
s.lock.Lock()
89+
defer s.lock.Unlock()
90+
s.m[key] = value
91+
}
92+
93+
var fieldsCache = &fieldsCacheMap{m: map[string][]*cachedTags{}}
5694

5795
// FieldError contains a single field's validation error along
5896
// with other properties that may be needed for error message creation
@@ -205,7 +243,7 @@ func (v *Validate) structRecursive(top interface{}, current interface{}, s inter
205243
var structName string
206244
var numFields int
207245

208-
cs, isCached := structCache[structType]
246+
cs, isCached := structCache.Get(structType)
209247

210248
if isCached {
211249
structName = cs.name
@@ -214,7 +252,7 @@ func (v *Validate) structRecursive(top interface{}, current interface{}, s inter
214252
structName = structType.Name()
215253
numFields = structValue.NumField()
216254
cs = &cachedStruct{name: structName, children: numFields}
217-
structCache[structType] = cs
255+
structCache.Set(structType, cs)
218256
}
219257

220258
validationErrors := &StructErrors{
@@ -374,7 +412,7 @@ func (v *Validate) fieldWithNameAndValue(val interface{}, current interface{}, f
374412
if len(cField.tags) == 0 {
375413

376414
if isSingleField {
377-
cField.tags, isCached = fieldsCache[tag]
415+
cField.tags, isCached = fieldsCache.Get(tag)
378416
}
379417

380418
if !isCached {
@@ -404,7 +442,7 @@ func (v *Validate) fieldWithNameAndValue(val interface{}, current interface{}, f
404442
}
405443

406444
if isSingleField {
407-
fieldsCache[cField.tag] = cField.tags
445+
fieldsCache.Set(cField.tag, cField.tags)
408446
}
409447
}
410448
}

0 commit comments

Comments
 (0)