Skip to content

Commit

Permalink
Add caching to various schema reading functions
Browse files Browse the repository at this point in the history
  • Loading branch information
dshafik committed Jul 27, 2017
1 parent 870617d commit 8a07146
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 20 deletions.
15 changes: 14 additions & 1 deletion helper/schema/field_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ package schema
import (
"fmt"
"strconv"
"strings"
)

var (
schemaCache map[string][]*Schema = make(map[string][]*Schema)
)

// FieldReaders are responsible for decoding fields out of data into
Expand Down Expand Up @@ -45,6 +50,11 @@ func (r *FieldReadResult) ValueOrZero(s *Schema) interface{} {
// and the given schema. It returns all the schemas that led to the final
// schema. These are in order of the address (out to in).
func addrToSchema(addr []string, schemaMap map[string]*Schema) []*Schema {
cacheKey := strings.Join(addr, ".")
if r, ok := schemaCache[cacheKey]; ok {
return r
}

current := &Schema{
Type: typeObject,
Elem: schemaMap,
Expand All @@ -53,7 +63,8 @@ func addrToSchema(addr []string, schemaMap map[string]*Schema) []*Schema {
// If we aren't given an address, then the user is requesting the
// full object, so we return the special value which is the full object.
if len(addr) == 0 {
return []*Schema{current}
schemaCache[cacheKey] = []*Schema{current}
return schemaCache[cacheKey]
}

result := make([]*Schema, 0, len(addr))
Expand Down Expand Up @@ -161,6 +172,8 @@ func addrToSchema(addr []string, schemaMap map[string]*Schema) []*Schema {
}
}

schemaCache[cacheKey] = result

return result
}

Expand Down
31 changes: 23 additions & 8 deletions helper/schema/field_reader_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,21 @@ type ConfigFieldReader struct {
once sync.Once
}

var (
configReadFieldCache map[string]readFieldCacheObject = make(map[string]readFieldCacheObject)
)

func (r *ConfigFieldReader) ReadField(address []string) (FieldReadResult, error) {
r.once.Do(func() { r.indexMaps = make(map[string]map[string]int) })
return r.readField(address, false)
}

func (r *ConfigFieldReader) readField(
address []string, nested bool) (FieldReadResult, error) {
func (r *ConfigFieldReader) readField(address []string, nested bool) (FieldReadResult, error) {
cacheKey := strings.Join(address, ".")
if v, ok := configReadFieldCache[cacheKey]; ok {
return v.result, v.err
}

schemaList := addrToSchema(address, r.Schema)
if len(schemaList) == 0 {
return FieldReadResult{}, nil
Expand Down Expand Up @@ -79,6 +87,10 @@ func (r *ConfigFieldReader) readField(

k := strings.Join(address, ".")
schema := schemaList[len(schemaList)-1]
var (
result FieldReadResult
err error
)

// If we're getting the single element of a promoted list, then
// check to see if we have a single element we need to promote.
Expand All @@ -95,7 +107,7 @@ func (r *ConfigFieldReader) readField(

switch schema.Type {
case TypeBool, TypeFloat, TypeInt, TypeString:
return r.readPrimitive(k, schema)
result, err = r.readPrimitive(k, schema)
case TypeList:
// If we support promotion then we first check if we have a lone
// value that we must promote.
Expand All @@ -104,22 +116,25 @@ func (r *ConfigFieldReader) readField(
result, err := r.readPrimitive(k, schema.Elem.(*Schema))
if err == nil && result.Exists {
result.Value = []interface{}{result.Value}
return result, nil
result, err = result, nil
}
}

return readListField(&nestedConfigFieldReader{r}, address, schema)
result, err = readListField(&nestedConfigFieldReader{r}, address, schema)
case TypeMap:
return r.readMap(k, schema)
result, err = r.readMap(k, schema)
case TypeSet:
return r.readSet(address, schema)
result, err = r.readSet(address, schema)
case typeObject:
return readObjectField(
result, err = readObjectField(
&nestedConfigFieldReader{r},
address, schema.Elem.(map[string]*Schema))
default:
panic(fmt.Sprintf("Unknown type: %s", schema.Type))
}

configReadFieldCache[cacheKey] = readFieldCacheObject{result: result, err: err}
return configReadFieldCache[cacheKey].result, configReadFieldCache[cacheKey].err
}

func (r *ConfigFieldReader) readMap(k string, schema *Schema) (FieldReadResult, error) {
Expand Down
31 changes: 26 additions & 5 deletions helper/schema/field_reader_diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,27 +31,48 @@ type DiffFieldReader struct {
Schema map[string]*Schema
}

type readFieldCacheObject struct {
result FieldReadResult
err error
}

var (
diffReadFieldCache map[string]readFieldCacheObject = make(map[string]readFieldCacheObject)
)

func (r *DiffFieldReader) ReadField(address []string) (FieldReadResult, error) {
cacheKey := strings.Join(address, ".")
if v, ok := diffReadFieldCache[cacheKey]; ok {
return v.result, v.err
}

schemaList := addrToSchema(address, r.Schema)
if len(schemaList) == 0 {
return FieldReadResult{}, nil
}

schema := schemaList[len(schemaList)-1]
var (
result FieldReadResult
err error
)
switch schema.Type {
case TypeBool, TypeInt, TypeFloat, TypeString:
return r.readPrimitive(address, schema)
result, err = r.readPrimitive(address, schema)
case TypeList:
return readListField(r, address, schema)
result, err = readListField(r, address, schema)
case TypeMap:
return r.readMap(address, schema)
result, err = r.readMap(address, schema)
case TypeSet:
return r.readSet(address, schema)
result, err = r.readSet(address, schema)
case typeObject:
return readObjectField(r, address, schema.Elem.(map[string]*Schema))
result, err = readObjectField(r, address, schema.Elem.(map[string]*Schema))
default:
panic(fmt.Sprintf("Unknown type: %#v", schema.Type))
}

diffReadFieldCache[cacheKey] = readFieldCacheObject{result: result, err: err}
return diffReadFieldCache[cacheKey].result, diffReadFieldCache[cacheKey].err
}

func (r *DiffFieldReader) readMap(
Expand Down
28 changes: 22 additions & 6 deletions helper/schema/field_reader_map.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,44 @@ type MapFieldReader struct {
Schema map[string]*Schema
}

var (
mapReadFieldCache map[string]readFieldCacheObject = make(map[string]readFieldCacheObject)
)

func (r *MapFieldReader) ReadField(address []string) (FieldReadResult, error) {
cacheKey := strings.Join(address, ".")
if v, ok := mapReadFieldCache[cacheKey]; ok {
return v.result, v.err
}

k := strings.Join(address, ".")
schemaList := addrToSchema(address, r.Schema)
if len(schemaList) == 0 {
return FieldReadResult{}, nil
}

schema := schemaList[len(schemaList)-1]
var (
result FieldReadResult
err error
)
switch schema.Type {
case TypeBool, TypeInt, TypeFloat, TypeString:
return r.readPrimitive(address, schema)
result, err = r.readPrimitive(address, schema)
case TypeList:
return readListField(r, address, schema)
result, err = readListField(r, address, schema)
case TypeMap:
return r.readMap(k, schema)
result, err = r.readMap(k, schema)
case TypeSet:
return r.readSet(address, schema)
result, err = r.readSet(address, schema)
case typeObject:
return readObjectField(r, address, schema.Elem.(map[string]*Schema))
result, err = readObjectField(r, address, schema.Elem.(map[string]*Schema))
default:
panic(fmt.Sprintf("Unknown type: %s", schema.Type))
panic(fmt.Sprintf("Unknown type: %#v", schema.Type))
}

mapReadFieldCache[cacheKey] = readFieldCacheObject{result: result, err: err}
return mapReadFieldCache[cacheKey].result, mapReadFieldCache[cacheKey].err
}

func (r *MapFieldReader) readMap(k string, schema *Schema) (FieldReadResult, error) {
Expand Down

0 comments on commit 8a07146

Please sign in to comment.