From 25eeec0227db6615a0f3ab7910cd867694db7f86 Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Mon, 18 Dec 2017 21:13:15 +0000 Subject: [PATCH 1/2] enhance joinResult to handle mapping one node to multiple nodes --- render/render.go | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/render/render.go b/render/render.go index c67fbdf7c9..6a77b0f0b3 100644 --- a/render/render.go +++ b/render/render.go @@ -163,7 +163,7 @@ func (cr conditionalRenderer) Render(rpt report.Report) Nodes { // joinResults is used by Renderers that join sets of nodes type joinResults struct { nodes report.Nodes - mapped map[string]string // input node ID -> output node ID + mapped map[string][]string // input node ID -> output node IDs } func newJoinResults(inputNodes report.Nodes) joinResults { @@ -172,12 +172,12 @@ func newJoinResults(inputNodes report.Nodes) joinResults { n.Adjacency = nil // result() assumes all nodes start with no adjacencies nodes[id] = n } - return joinResults{nodes: nodes, mapped: map[string]string{}} + return joinResults{nodes: nodes, mapped: map[string][]string{}} } func (ret *joinResults) add(m report.Node, n report.Node) { ret.nodes[n.ID] = n - ret.mapped[m.ID] = n.ID + ret.mapped[m.ID] = append(ret.mapped[m.ID], n.ID) } // Add m as a child of the node at id, creating a new result node if @@ -218,19 +218,15 @@ func (ret *joinResults) passThrough(n report.Node) { // input, and return the result. func (ret *joinResults) result(input Nodes) Nodes { for _, n := range input.Nodes { - outID, ok := ret.mapped[n.ID] - if !ok { - continue - } - out := ret.nodes[outID] - // for each adjacency in the original node, find out what it maps to (if any), - // and add that to the new node - for _, a := range n.Adjacency { - if mappedDest, found := ret.mapped[a]; found { - out.Adjacency = out.Adjacency.Add(mappedDest) + for _, outID := range ret.mapped[n.ID] { + out := ret.nodes[outID] + // for each adjacency in the original node, find out what it maps to (if any), + // and add that to the new node + for _, a := range n.Adjacency { + out.Adjacency = out.Adjacency.Add(ret.mapped[a]...) } + ret.nodes[outID] = out } - ret.nodes[outID] = out } return Nodes{Nodes: ret.nodes} } From ee4a56e8ad0d8bd663a9581adae469f932b05915 Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Tue, 19 Dec 2017 18:52:26 +0000 Subject: [PATCH 2/2] optimse common one->one mapping case one->many is much rarer --- render/render.go | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/render/render.go b/render/render.go index 6a77b0f0b3..48bd250d7e 100644 --- a/render/render.go +++ b/render/render.go @@ -163,7 +163,8 @@ func (cr conditionalRenderer) Render(rpt report.Report) Nodes { // joinResults is used by Renderers that join sets of nodes type joinResults struct { nodes report.Nodes - mapped map[string][]string // input node ID -> output node IDs + mapped map[string]string // input node ID -> output node ID - common case + multi map[string][]string // input node ID -> output node IDs - exceptional case } func newJoinResults(inputNodes report.Nodes) joinResults { @@ -172,12 +173,16 @@ func newJoinResults(inputNodes report.Nodes) joinResults { n.Adjacency = nil // result() assumes all nodes start with no adjacencies nodes[id] = n } - return joinResults{nodes: nodes, mapped: map[string][]string{}} + return joinResults{nodes: nodes, mapped: map[string]string{}, multi: map[string][]string{}} } func (ret *joinResults) add(m report.Node, n report.Node) { ret.nodes[n.ID] = n - ret.mapped[m.ID] = append(ret.mapped[m.ID], n.ID) + if _, ok := ret.mapped[m.ID]; !ok { + ret.mapped[m.ID] = n.ID + } else { + ret.multi[m.ID] = append(ret.multi[m.ID], n.ID) + } } // Add m as a child of the node at id, creating a new result node if @@ -218,19 +223,31 @@ func (ret *joinResults) passThrough(n report.Node) { // input, and return the result. func (ret *joinResults) result(input Nodes) Nodes { for _, n := range input.Nodes { - for _, outID := range ret.mapped[n.ID] { - out := ret.nodes[outID] - // for each adjacency in the original node, find out what it maps to (if any), - // and add that to the new node - for _, a := range n.Adjacency { - out.Adjacency = out.Adjacency.Add(ret.mapped[a]...) - } - ret.nodes[outID] = out + outID, ok := ret.mapped[n.ID] + if !ok { + continue + } + ret.rewriteAdjacency(outID, n.Adjacency) + for _, outID := range ret.multi[n.ID] { + ret.rewriteAdjacency(outID, n.Adjacency) } } return Nodes{Nodes: ret.nodes} } +func (ret *joinResults) rewriteAdjacency(outID string, adjacency report.IDList) { + out := ret.nodes[outID] + // for each adjacency in the original node, find out what it maps + // to (if any), and add that to the new node + for _, a := range adjacency { + if mappedDest, found := ret.mapped[a]; found { + out.Adjacency = out.Adjacency.Add(mappedDest) + out.Adjacency = out.Adjacency.Add(ret.multi[a]...) + } + } + ret.nodes[outID] = out +} + // ResetCache blows away the rendered node cache, and known service // cache. func ResetCache() {