diff --git a/schemaLoader.go b/schemaLoader.go index 20db0c1f..b8202acb 100644 --- a/schemaLoader.go +++ b/schemaLoader.go @@ -34,7 +34,7 @@ func NewSchemaLoader() *SchemaLoader { ps := &SchemaLoader{ pool: &schemaPool{ - schemaPoolDocuments: make(map[string]*schemaPoolDocument), + schemaPoolDocuments: new(schemaPoolDocuments), }, AutoDetect: true, Validate: false, diff --git a/schemaPool.go b/schemaPool.go index 35b1cc63..870a1772 100644 --- a/schemaPool.go +++ b/schemaPool.go @@ -40,7 +40,7 @@ type schemaPoolDocument struct { } type schemaPool struct { - schemaPoolDocuments map[string]*schemaPoolDocument + schemaPoolDocuments *schemaPoolDocuments jsonLoaderFactory JSONLoaderFactory autoDetect *bool } @@ -53,7 +53,7 @@ func (p *schemaPool) parseReferences(document interface{}, ref gojsonreference.J reference = ref.String() ) // Only the root document should be added to the schema pool if pooled is true - if _, ok := p.schemaPoolDocuments[reference]; pooled && ok { + if _, ok := p.schemaPoolDocuments.Load(reference); pooled && ok { return fmt.Errorf("Reference already exists: \"%s\"", reference) } @@ -67,7 +67,7 @@ func (p *schemaPool) parseReferences(document interface{}, ref gojsonreference.J err = p.parseReferencesRecursive(document, ref, draft) if pooled { - p.schemaPoolDocuments[reference] = &schemaPoolDocument{Document: document, Draft: draft} + p.schemaPoolDocuments.Store(reference, &schemaPoolDocument{Document: document, Draft: draft}) } return err @@ -97,10 +97,10 @@ func (p *schemaPool) parseReferencesRecursive(document interface{}, ref gojsonre if err == nil { localRef, err = ref.Inherits(jsonReference) if err == nil { - if _, ok := p.schemaPoolDocuments[localRef.String()]; ok { + if _, ok := p.schemaPoolDocuments.Load(localRef.String()); ok { return fmt.Errorf("Reference already exists: \"%s\"", localRef.String()) } - p.schemaPoolDocuments[localRef.String()] = &schemaPoolDocument{Document: document, Draft: draft} + p.schemaPoolDocuments.Store(localRef.String(), &schemaPoolDocument{Document: document, Draft: draft}) } } } @@ -155,7 +155,7 @@ func (p *schemaPool) GetDocument(reference gojsonreference.JsonReference) (*sche // First check if the given fragment is a location independent identifier // http://json-schema.org/latest/json-schema-core.html#rfc.section.8.2.3 - if spd, ok = p.schemaPoolDocuments[refToURL.String()]; ok { + if spd, ok = p.schemaPoolDocuments.Load(refToURL.String()); ok { if internalLogEnabled { internalLog(" From pool") } @@ -167,7 +167,7 @@ func (p *schemaPool) GetDocument(reference gojsonreference.JsonReference) (*sche refToURL.GetUrl().Fragment = "" - if cachedSpd, ok := p.schemaPoolDocuments[refToURL.String()]; ok { + if cachedSpd, ok := p.schemaPoolDocuments.Load(refToURL.String()); ok { document, _, err := reference.GetPointer().Get(cachedSpd.Document) if err != nil { @@ -179,7 +179,7 @@ func (p *schemaPool) GetDocument(reference gojsonreference.JsonReference) (*sche } spd = &schemaPoolDocument{Document: document, Draft: cachedSpd.Draft} - p.schemaPoolDocuments[reference.String()] = spd + p.schemaPoolDocuments.Store(reference.String(), spd) return spd, nil } diff --git a/schemaPoolDocuments.go b/schemaPoolDocuments.go new file mode 100644 index 00000000..b54b6deb --- /dev/null +++ b/schemaPoolDocuments.go @@ -0,0 +1,48 @@ +package gojsonschema + +import "sync" + +type schemaPoolDocuments struct { + mp sync.Map +} + +func (spd *schemaPoolDocuments) Load(key string) (*schemaPoolDocument, bool) { + val, ok := spd.mp.Load(key) + if !ok { + return nil, false + } + return val.(*schemaPoolDocument), true +} + +func (spd *schemaPoolDocuments) Delete(key string) { + spd.mp.Delete(key) + +} + +func (spd *schemaPoolDocuments) LoadAndDelete(key string) (*schemaPoolDocument, bool) { + val, ok := spd.mp.LoadAndDelete(key) + if !ok { + return nil, false + } + return val.(*schemaPoolDocument), true +} + +func (spd *schemaPoolDocuments) LoadOrStore(key string, value *schemaPoolDocument) (*schemaPoolDocument, bool) { + actual, ok := spd.mp.LoadOrStore(key, value) + if !ok { + return nil, false + } + return actual.(*schemaPoolDocument), true +} + +func (spd *schemaPoolDocuments) Range(f func(key string, value *schemaPoolDocument) bool) { + spd.mp.Range(func(key, value interface{}) bool { + typedKey := key.(string) + typedVal := value.(*schemaPoolDocument) + return f(typedKey, typedVal) + }) +} + +func (spd *schemaPoolDocuments) Store(key string, value *schemaPoolDocument) { + spd.mp.Store(key, value) +}