From 8c2248a5cee46f54ec089f7890f6fe885b305225 Mon Sep 17 00:00:00 2001 From: joeybloggs Date: Sun, 7 Jun 2015 23:22:13 -0400 Subject: [PATCH] add map thread safety --- validator.go | 50 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/validator.go b/validator.go index 2471e2a..8a85c69 100644 --- a/validator.go +++ b/validator.go @@ -14,6 +14,7 @@ import ( "fmt" "reflect" "strings" + "sync" "time" "unicode" ) @@ -51,8 +52,45 @@ type cachedStruct struct { fields []*cachedField } -var structCache = map[reflect.Type]*cachedStruct{} -var fieldsCache = map[string][]*cachedTags{} +type structsCacheMap struct { + lock sync.RWMutex + m map[reflect.Type]*cachedStruct +} + +func (s *structsCacheMap) Get(key reflect.Type) (*cachedStruct, bool) { + s.lock.RLock() + defer s.lock.RUnlock() + value, ok := s.m[key] + return value, ok +} + +func (s *structsCacheMap) Set(key reflect.Type, value *cachedStruct) { + s.lock.Lock() + defer s.lock.Unlock() + s.m[key] = value +} + +var structCache = &structsCacheMap{m: map[reflect.Type]*cachedStruct{}} + +type fieldsCacheMap struct { + lock sync.RWMutex + m map[string][]*cachedTags +} + +func (s *fieldsCacheMap) Get(key string) ([]*cachedTags, bool) { + s.lock.RLock() + defer s.lock.RUnlock() + value, ok := s.m[key] + return value, ok +} + +func (s *fieldsCacheMap) Set(key string, value []*cachedTags) { + s.lock.Lock() + defer s.lock.Unlock() + s.m[key] = value +} + +var fieldsCache = &fieldsCacheMap{m: map[string][]*cachedTags{}} // FieldError contains a single field's validation error along // 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 var structName string var numFields int - cs, isCached := structCache[structType] + cs, isCached := structCache.Get(structType) if isCached { structName = cs.name @@ -214,7 +252,7 @@ func (v *Validate) structRecursive(top interface{}, current interface{}, s inter structName = structType.Name() numFields = structValue.NumField() cs = &cachedStruct{name: structName, children: numFields} - structCache[structType] = cs + structCache.Set(structType, cs) } validationErrors := &StructErrors{ @@ -374,7 +412,7 @@ func (v *Validate) fieldWithNameAndValue(val interface{}, current interface{}, f if len(cField.tags) == 0 { if isSingleField { - cField.tags, isCached = fieldsCache[tag] + cField.tags, isCached = fieldsCache.Get(tag) } if !isCached { @@ -404,7 +442,7 @@ func (v *Validate) fieldWithNameAndValue(val interface{}, current interface{}, f } if isSingleField { - fieldsCache[cField.tag] = cField.tags + fieldsCache.Set(cField.tag, cField.tags) } } }