Skip to content

Commit a753c37

Browse files
committed
internal/core/topsort: prevent duplicates in nodeToStructMeta
Use a map of maps rather than a map of slices so we can insert structMeta pointers on a per-node basis while avoiding duplicates. With the code from https://cuelang.org/discussion/3879, available at https://github.com/joelMuehlena/cue-netbox-example, we can see a significant improvement. Note that we skip closedness as it causes a massive slow-down due to https://cuelang.org/issue/3881. $ time CUE_DEBUG=opendef cue export | wc -l 81692 real 0m9.145s user 0m10.564s sys 0m0.174s And with the change here: $ time CUE_DEBUG=opendef cue export | wc -l 81692 real 0m1.564s user 0m3.326s sys 0m0.171s See #3879. Signed-off-by: Daniel Martí <[email protected]> Change-Id: I6118e66b8f74e085e9ef130dcbc1f1eec91633ad Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1213537 Reviewed-by: Matthew Sackman <[email protected]> Unity-Result: CUE porcuepine <[email protected]> TryBot-Result: CUEcueckoo <[email protected]>
1 parent b12e201 commit a753c37

File tree

1 file changed

+20
-8
lines changed

1 file changed

+20
-8
lines changed

Diff for: internal/core/toposort/vertex.go

+20-8
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ package toposort
137137

138138
import (
139139
"fmt"
140+
"maps"
140141
"slices"
141142

142143
"cuelang.org/go/cue/token"
@@ -218,7 +219,18 @@ func (sm *structMeta) hasDynamic(dynFieldsMap map[*adt.DynamicField][]adt.Featur
218219
// the binary expression, and mark them as explicit unification.
219220
func analyseStructs(v *adt.Vertex, builder *GraphBuilder) []*structMeta {
220221
structInfos := v.Structs
221-
nodeToStructMeta := make(map[adt.Node][]*structMeta)
222+
// Note that it's important that nodeToStructMetas avoids duplicate entries,
223+
// which cause significant slowness for some large configs.
224+
nodeToStructMetas := make(map[adt.Node]map[*structMeta]bool)
225+
// structMetaMap is heplful as we can't insert into a map unless we make it.
226+
structMetaMap := func(node adt.Node) map[*structMeta]bool {
227+
if m := nodeToStructMetas[node]; m != nil {
228+
return m
229+
}
230+
m := make(map[*structMeta]bool)
231+
nodeToStructMetas[node] = m
232+
return m
233+
}
222234
structMetas := make([]*structMeta, 0, len(structInfos))
223235

224236
// Create all the structMetas and map to them from a StructInfo's
@@ -235,9 +247,9 @@ func analyseStructs(v *adt.Vertex, builder *GraphBuilder) []*structMeta {
235247
if src := sl.Source(); src != nil {
236248
sMeta.pos = src.Pos()
237249
}
238-
nodeToStructMeta[sl] = append(nodeToStructMeta[sl], sMeta)
250+
structMetaMap(sl)[sMeta] = true
239251
for _, decl := range sl.Decls {
240-
nodeToStructMeta[decl] = append(nodeToStructMeta[decl], sMeta)
252+
structMetaMap(decl)[sMeta] = true
241253
}
242254
}
243255

@@ -250,12 +262,12 @@ func analyseStructs(v *adt.Vertex, builder *GraphBuilder) []*structMeta {
250262
field := c.Field()
251263
debug("self arc conjunct field %p :: %T, expr %p :: %T (%v)\n",
252264
field, field, c.Expr(), c.Expr(), c.Expr().Source())
253-
sMetas, found := nodeToStructMeta[field]
265+
sMetas, found := nodeToStructMetas[field]
254266
if !found {
255267
return true
256268
}
257269
if src := field.Source(); src != nil {
258-
for _, sMeta := range sMetas {
270+
for sMeta := range sMetas {
259271
sMeta.pos = src.Pos()
260272
}
261273
}
@@ -270,9 +282,9 @@ func analyseStructs(v *adt.Vertex, builder *GraphBuilder) []*structMeta {
270282
debug(" ref %p :: %T (%v)\n",
271283
refs.Ref, refs.Ref, refs.Ref.Source().Pos())
272284
}
273-
nodeToStructMeta[refs.Ref] = append(nodeToStructMeta[refs.Ref], sMetas...)
285+
maps.Insert(structMetaMap(refs.Ref), maps.All(sMetas))
274286
if pos := refs.Ref.Source().Pos(); pos != token.NoPos {
275-
for _, sMeta := range nodeToStructMeta[refs.Ref] {
287+
for sMeta := range nodeToStructMetas[refs.Ref] {
276288
sMeta.pos = pos
277289
}
278290
}
@@ -307,7 +319,7 @@ func analyseStructs(v *adt.Vertex, builder *GraphBuilder) []*structMeta {
307319
continue
308320
}
309321
for _, expr := range []adt.Expr{binExpr.X, binExpr.Y} {
310-
for _, sMeta := range nodeToStructMeta[expr] {
322+
for sMeta := range nodeToStructMetas[expr] {
311323
sMeta.isExplicit = true
312324
debug(" now explicit: %v\n", sMeta)
313325
}

0 commit comments

Comments
 (0)