Skip to content

Commit b933a62

Browse files
committed
various memory management improvements
1 parent cb9c039 commit b933a62

File tree

2 files changed

+44
-12
lines changed

2 files changed

+44
-12
lines changed

typed/helpers.go

+8
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,14 @@ func (ef *errorFormatter) descend(pe fieldpath.PathElement) {
6767
ef.path = append(ef.path, pe)
6868
}
6969

70+
// parent returns the parent, for the purpose of buffer reuse. It's an error to
71+
// call this if there is no parent.
72+
func (ef *errorFormatter) parent() errorFormatter {
73+
return errorFormatter{
74+
path: ef.path[:len(ef.path)-1],
75+
}
76+
}
77+
7078
func (ef errorFormatter) errorf(format string, args ...interface{}) ValidationErrors {
7179
return ValidationErrors{{
7280
Path: append(fieldpath.Path{}, ef.path...),

typed/merge.go

+36-12
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ type mergingWalker struct {
4343

4444
// internal housekeeping--don't set when constructing.
4545
inLeaf bool // Set to true if we're in a "big leaf"--atomic map/list
46+
47+
// Allocate only as many walkers as needed for the depth by storing them here.
48+
spareWalkers *[]*mergingWalker
4649
}
4750

4851
// merge rules examine w.lhs and w.rhs (up to one of which may be nil) and
@@ -117,13 +120,30 @@ func (w *mergingWalker) doScalar(t schema.Scalar) (errs ValidationErrors) {
117120
}
118121

119122
func (w *mergingWalker) prepareDescent(pe fieldpath.PathElement, tr schema.TypeRef) *mergingWalker {
120-
w2 := *w
123+
if w.spareWalkers == nil {
124+
// first descent.
125+
w.spareWalkers = &[]*mergingWalker{}
126+
}
127+
var w2 *mergingWalker
128+
if n := len(*w.spareWalkers); n > 0 {
129+
w2, *w.spareWalkers = (*w.spareWalkers)[n-1], (*w.spareWalkers)[:n-1]
130+
} else {
131+
w2 = &mergingWalker{}
132+
}
133+
*w2 = *w
121134
w2.typeRef = tr
122135
w2.errorFormatter.descend(pe)
123136
w2.lhs = nil
124137
w2.rhs = nil
125138
w2.out = nil
126-
return &w2
139+
return w2
140+
}
141+
142+
func (w *mergingWalker) finishDescent(w2 *mergingWalker) {
143+
// if the descent caused a realloc, ensure that we reuse the buffer
144+
// for the next sibling.
145+
w.errorFormatter = w2.errorFormatter.parent()
146+
*w.spareWalkers = append(*w.spareWalkers, w2)
127147
}
128148

129149
func (w *mergingWalker) derefMap(prefix string, v *value.Value, dest **value.Map) (errs ValidationErrors) {
@@ -198,6 +218,7 @@ func (w *mergingWalker) visitListItems(t schema.List, lhs, rhs *value.List) (err
198218
} else if w2.out != nil {
199219
out.Items = append(out.Items, *w2.out)
200220
}
221+
w.finishDescent(w2)
201222
// Keep track of children that have been handled
202223
delete(observedRHS, keyStr)
203224
}
@@ -212,6 +233,7 @@ func (w *mergingWalker) visitListItems(t schema.List, lhs, rhs *value.List) (err
212233
} else if w2.out != nil {
213234
out.Items = append(out.Items, *w2.out)
214235
}
236+
w.finishDescent(w2)
215237
}
216238
}
217239

@@ -272,13 +294,13 @@ func (w *mergingWalker) visitMapItems(t schema.Map, lhs, rhs *value.Map) (errs V
272294
}
273295

274296
if lhs != nil {
275-
for _, litem := range lhs.Items {
276-
name := litem.Name
297+
for i := range lhs.Items {
298+
litem := &lhs.Items[i]
277299
fieldType := t.ElementType
278-
if ft, ok := fieldTypes[name]; ok {
300+
if ft, ok := fieldTypes[litem.Name]; ok {
279301
fieldType = ft
280302
}
281-
w2 := w.prepareDescent(fieldpath.PathElement{FieldName: &name}, fieldType)
303+
w2 := w.prepareDescent(fieldpath.PathElement{FieldName: &litem.Name}, fieldType)
282304
w2.lhs = &litem.Value
283305
if rhs != nil {
284306
if ritem, ok := rhs.Get(litem.Name); ok {
@@ -288,31 +310,33 @@ func (w *mergingWalker) visitMapItems(t schema.Map, lhs, rhs *value.Map) (errs V
288310
if newErrs := w2.merge(); len(newErrs) > 0 {
289311
errs = append(errs, newErrs...)
290312
} else if w2.out != nil {
291-
out.Set(name, *w2.out)
313+
out.Items = append(out.Items, value.Field{litem.Name, *w2.out})
292314
}
315+
w.finishDescent(w2)
293316
}
294317
}
295318

296319
if rhs != nil {
297-
for _, ritem := range rhs.Items {
320+
for j := range rhs.Items {
321+
ritem := &rhs.Items[j]
298322
if lhs != nil {
299323
if _, ok := lhs.Get(ritem.Name); ok {
300324
continue
301325
}
302326
}
303327

304-
name := ritem.Name
305328
fieldType := t.ElementType
306-
if ft, ok := fieldTypes[name]; ok {
329+
if ft, ok := fieldTypes[ritem.Name]; ok {
307330
fieldType = ft
308331
}
309-
w2 := w.prepareDescent(fieldpath.PathElement{FieldName: &name}, fieldType)
332+
w2 := w.prepareDescent(fieldpath.PathElement{FieldName: &ritem.Name}, fieldType)
310333
w2.rhs = &ritem.Value
311334
if newErrs := w2.merge(); len(newErrs) > 0 {
312335
errs = append(errs, newErrs...)
313336
} else if w2.out != nil {
314-
out.Set(name, *w2.out)
337+
out.Items = append(out.Items, value.Field{ritem.Name, *w2.out})
315338
}
339+
w.finishDescent(w2)
316340
}
317341
}
318342

0 commit comments

Comments
 (0)