| Index: service/datastore/pls_impl.go
 | 
| diff --git a/service/datastore/pls_impl.go b/service/datastore/pls_impl.go
 | 
| index 9fab74f59e6a18364acbca48238867a03d0ff12c..5f7fe4740d06b5dd585f3444435340cdec8841bd 100644
 | 
| --- a/service/datastore/pls_impl.go
 | 
| +++ b/service/datastore/pls_impl.go
 | 
| @@ -27,12 +27,15 @@ type structTag struct {
 | 
|  	substructCodec *structCodec
 | 
|  	convert        bool
 | 
|  	metaVal        interface{}
 | 
| +	isExtra        bool
 | 
|  	canSet         bool
 | 
|  }
 | 
|  
 | 
|  type structCodec struct {
 | 
| -	byMeta   map[string]int
 | 
| -	byName   map[string]int
 | 
| +	byMeta    map[string]int
 | 
| +	byName    map[string]int
 | 
| +	bySpecial map[string]int
 | 
| +
 | 
|  	byIndex  []structTag
 | 
|  	hasSlice bool
 | 
|  	problem  error
 | 
| @@ -55,19 +58,38 @@ func typeMismatchReason(val interface{}, v reflect.Value) string {
 | 
|  func (p *structPLS) Load(propMap PropertyMap) error {
 | 
|  	convFailures := errors.MultiError(nil)
 | 
|  
 | 
| +	useExtra := false
 | 
| +	extra := (*PropertyMap)(nil)
 | 
| +	if i, ok := p.c.bySpecial["extra"]; ok {
 | 
| +		useExtra = true
 | 
| +		f := p.c.byIndex[i]
 | 
| +		if f.canSet {
 | 
| +			extra = p.o.Field(i).Addr().Interface().(*PropertyMap)
 | 
| +		}
 | 
| +	}
 | 
|  	t := reflect.Type(nil)
 | 
|  	for name, props := range propMap {
 | 
|  		multiple := len(props) > 1
 | 
|  		for i, prop := range props {
 | 
|  			if reason := loadInner(p.c, p.o, i, name, prop, multiple); reason != "" {
 | 
| -				if t == nil {
 | 
| -					t = p.o.Type()
 | 
| +				if useExtra {
 | 
| +					if extra != nil {
 | 
| +						if *extra == nil {
 | 
| +							*extra = make(PropertyMap, 1)
 | 
| +						}
 | 
| +						(*extra)[name] = props
 | 
| +					}
 | 
| +					break // go to the next property in propMap
 | 
| +				} else {
 | 
| +					if t == nil {
 | 
| +						t = p.o.Type()
 | 
| +					}
 | 
| +					convFailures = append(convFailures, &ErrFieldMismatch{
 | 
| +						StructType: t,
 | 
| +						FieldName:  name,
 | 
| +						Reason:     reason,
 | 
| +					})
 | 
|  				}
 | 
| -				convFailures = append(convFailures, &ErrFieldMismatch{
 | 
| -					StructType: t,
 | 
| -					FieldName:  name,
 | 
| -					Reason:     reason,
 | 
| -				})
 | 
|  			}
 | 
|  		}
 | 
|  	}
 | 
| @@ -253,7 +275,7 @@ func (p *structPLS) save(propMap PropertyMap, prefix string, is IndexSetting) (i
 | 
|  	}
 | 
|  
 | 
|  	for i, st := range p.c.byIndex {
 | 
| -		if st.name == "-" {
 | 
| +		if st.name == "-" || st.isExtra {
 | 
|  			continue
 | 
|  		}
 | 
|  		name := st.name
 | 
| @@ -277,6 +299,17 @@ func (p *structPLS) save(propMap PropertyMap, prefix string, is IndexSetting) (i
 | 
|  			}
 | 
|  		}
 | 
|  	}
 | 
| +
 | 
| +	if i, ok := p.c.bySpecial["extra"]; ok {
 | 
| +		if p.c.byIndex[i].name != "-" {
 | 
| +			for fullName, vals := range p.o.Field(i).Interface().(PropertyMap) {
 | 
| +				if _, ok := propMap[fullName]; !ok {
 | 
| +					propMap[fullName] = vals
 | 
| +				}
 | 
| +			}
 | 
| +		}
 | 
| +	}
 | 
| +
 | 
|  	return
 | 
|  }
 | 
|  
 | 
| @@ -419,9 +452,10 @@ func getStructCodecLocked(t reflect.Type) (c *structCodec) {
 | 
|  	}
 | 
|  
 | 
|  	c = &structCodec{
 | 
| -		byIndex: make([]structTag, t.NumField()),
 | 
| -		byName:  make(map[string]int, t.NumField()),
 | 
| -		byMeta:  make(map[string]int, t.NumField()),
 | 
| +		byIndex:   make([]structTag, t.NumField()),
 | 
| +		byName:    make(map[string]int, t.NumField()),
 | 
| +		byMeta:    make(map[string]int, t.NumField()),
 | 
| +		bySpecial: make(map[string]int, 1),
 | 
|  
 | 
|  		problem: errRecursiveStruct, // we'll clear this later if it's not recursive
 | 
|  	}
 | 
| @@ -446,6 +480,24 @@ func getStructCodecLocked(t reflect.Type) (c *structCodec) {
 | 
|  			name, opts = name[:i], name[i+1:]
 | 
|  		}
 | 
|  		st.canSet = f.PkgPath == "" // blank == exported
 | 
| +		if opts == "extra" {
 | 
| +			if _, ok := c.bySpecial["extra"]; ok {
 | 
| +				c.problem = me("struct has multiple fields tagged as 'extra'")
 | 
| +				return
 | 
| +			}
 | 
| +			if name != "" && name != "-" {
 | 
| +				c.problem = me("struct 'extra' field has invalid name %s, expecing `` or `-`", name)
 | 
| +				return
 | 
| +			}
 | 
| +			if ft != typeOfPropertyMap {
 | 
| +				c.problem = me("struct 'extra' field has invalid type %s, expecing PropertyMap", ft)
 | 
| +				return
 | 
| +			}
 | 
| +			st.isExtra = true
 | 
| +			st.name = name
 | 
| +			c.bySpecial["extra"] = i
 | 
| +			continue
 | 
| +		}
 | 
|  		st.convert = reflect.PtrTo(ft).Implements(typeOfPropertyConverter)
 | 
|  		switch {
 | 
|  		case name == "":
 | 
| 
 |