Skip to content

Commit

Permalink
Merge pull request #2938 from weaveworks/more-renderers
Browse files Browse the repository at this point in the history
Rewrite more Map-Reduces as Renderers to save garbage
  • Loading branch information
bboreham authored Nov 22, 2017
2 parents f56a44e + 1c206fb commit 3bc8f22
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 70 deletions.
4 changes: 2 additions & 2 deletions render/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func (c connectionJoin) Render(rpt report.Report) Nodes {
// Nodes without a hostid may be pseudo nodes - if so, pass through to result
if _, ok := m.Latest.Lookup(report.HostNodeID); !ok {
if id, ok := externalNodeID(m, addr, local); ok {
ret.addToResults(m, id, newPseudoNode)
ret.addChild(m, id, newPseudoNode)
continue
}
}
Expand All @@ -94,7 +94,7 @@ func (c connectionJoin) Render(rpt report.Report) Nodes {
id, found = ipNodes[report.MakeScopedEndpointNodeID(scope, addr, port)]
}
if found && id != "" { // not one we blanked out earlier
ret.addToResults(m, id, func(id string) report.Node {
ret.addChild(m, id, func(id string) report.Node {
return inputNodes.Nodes[id]
})
}
Expand Down
59 changes: 21 additions & 38 deletions render/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,14 @@ import (
// not memoised
var HostRenderer = MakeReduce(
endpoints2Hosts{},
MakeMap(
MapX2Host,
ColorConnectedProcessRenderer,
),
MakeMap(
MapX2Host,
ContainerRenderer,
),
MakeMap(
MapX2Host,
ContainerImageRenderer,
),
MakeMap(
MapX2Host,
PodRenderer,
),
CustomRenderer{RenderFunc: nodes2Hosts, Renderer: ColorConnectedProcessRenderer},
CustomRenderer{RenderFunc: nodes2Hosts, Renderer: ContainerRenderer},
CustomRenderer{RenderFunc: nodes2Hosts, Renderer: ContainerImageRenderer},
CustomRenderer{RenderFunc: nodes2Hosts, Renderer: PodRenderer},
SelectHost,
)

// MapX2Host maps any Nodes to host Nodes.
// nodes2Hosts maps any Nodes to host Nodes.
//
// If this function is given a node without a hostname
// (including other pseudo nodes), it will drop the node.
Expand All @@ -38,27 +26,22 @@ var HostRenderer = MakeReduce(
// format for a host, but without any Major or Minor labels. It does
// not have enough info to do that, and the resulting graph must be
// merged with a host graph to get that info.
func MapX2Host(n report.Node, _ report.Networks) report.Nodes {
// Don't propagate pseudo nodes - we do this in MapEndpoint2Host
if n.Topology == Pseudo {
return report.Nodes{}
}

hostIDs, ok := n.Parents.Lookup(report.Host)
if !ok {
return report.Nodes{}
}
func nodes2Hosts(nodes Nodes) Nodes {
ret := newJoinResults()

result := report.Nodes{}
children := report.MakeNodeSet(n)
for _, id := range hostIDs {
node := NewDerivedNode(id, n).WithTopology(report.Host)
node.Counters = node.Counters.Add(n.Topology, 1)
node.Children = children
result[id] = node
for _, n := range nodes.Nodes {
if n.Topology == Pseudo {
continue // Don't propagate pseudo nodes - we do this in endpoints2Hosts
}
hostIDs, _ := n.Parents.Lookup(report.Host)
for _, id := range hostIDs {
ret.addChild(n, id, func(id string) report.Node {
return report.MakeNode(id).WithTopology(report.Host)
})
}
}

return result
ret.fixupAdjacencies(nodes)
return ret.result()
}

// endpoints2Hosts takes nodes from the endpoint topology and produces
Expand All @@ -79,10 +62,10 @@ func (e endpoints2Hosts) Render(rpt report.Report) Nodes {
if !ok {
continue
}
ret.addToResults(n, id, newPseudoNode)
ret.addChild(n, id, newPseudoNode)
} else {
id := report.MakeHostNodeID(report.ExtractHostID(n))
ret.addToResults(n, id, func(id string) report.Node {
ret.addChild(n, id, func(id string) report.Node {
return report.MakeNode(id).WithTopology(report.Host).
WithLatest(report.HostNodeID, timestamp, hostNodeID)
})
Expand Down
45 changes: 20 additions & 25 deletions render/process.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,7 @@ var ProcessWithContainerNameRenderer = processWithContainerNameRenderer{ProcessR
// name graph by munging the progess graph.
//
// not memoised
var ProcessNameRenderer = ConditionalRenderer(renderProcesses,
MakeMap(
MapProcess2Name,
ProcessRenderer,
),
)
var ProcessNameRenderer = CustomRenderer{RenderFunc: processes2Names, Renderer: ProcessRenderer}

// endpoints2Processes joins the endpoint topology to the process
// topology, matching on hostID and pid.
Expand All @@ -99,7 +94,7 @@ func (e endpoints2Processes) Render(rpt report.Report) Nodes {
// Nodes without a hostid are treated as pseudo nodes
if hostNodeID, ok := n.Latest.Lookup(report.HostNodeID); !ok {
if id, ok := pseudoNodeID(n, local); ok {
ret.addToResults(n, id, newPseudoNode)
ret.addChild(n, id, newPseudoNode)
}
} else {
pid, timestamp, ok := n.Latest.LookupEntry(process.PID)
Expand All @@ -116,7 +111,7 @@ func (e endpoints2Processes) Render(rpt report.Report) Nodes {

hostID, _, _ := report.ParseNodeID(hostNodeID)
id := report.MakeProcessNodeID(hostID, pid)
ret.addToResults(n, id, func(id string) report.Node {
ret.addChild(n, id, func(id string) report.Node {
if processNode, found := processes.Nodes[id]; found {
return processNode
}
Expand All @@ -132,23 +127,23 @@ func (e endpoints2Processes) Render(rpt report.Report) Nodes {
return ret.result()
}

// MapProcess2Name maps process Nodes to Nodes
// for each process name.
//
// This mapper is unlike the other foo2bar mappers as the intention
// is not to join the information with another topology.
func MapProcess2Name(n report.Node, _ report.Networks) report.Nodes {
if n.Topology == Pseudo {
return report.Nodes{n.ID: n}
}
// processes2Names maps process Nodes to Nodes for each process name.
func processes2Names(processes Nodes) Nodes {
ret := newJoinResults()

name, timestamp, ok := n.Latest.LookupEntry(process.Name)
if !ok {
return report.Nodes{}
for _, n := range processes.Nodes {
if n.Topology == Pseudo {
ret.passThrough(n)
} else {
name, timestamp, ok := n.Latest.LookupEntry(process.Name)
if ok {
ret.addChildAndChildren(n, name, func(id string) report.Node {
return report.MakeNode(id).WithTopology(MakeGroupNodeTopology(n.Topology, process.Name)).
WithLatest(process.Name, timestamp, name)
})
}
}
}

node := NewDerivedNode(name, n).WithTopology(MakeGroupNodeTopology(n.Topology, process.Name))
node.Latest = node.Latest.Set(process.Name, timestamp, name)
node.Counters = node.Counters.Add(n.Topology, 1)
return report.Nodes{name: node}
ret.fixupAdjacencies(processes)
return ret.result()
}
32 changes: 27 additions & 5 deletions render/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,21 +158,43 @@ func newJoinResults() joinResults {
return joinResults{nodes: make(report.Nodes), mapped: map[string]string{}}
}

// Add Node M under id, creating a new result node if not already there
// and updating the mapping from old ID to new ID
// Note we do not update any counters for child topologies here, because addToResults
// is only ever called when m is an endpoint and we never look at endpoint counts
func (ret *joinResults) addToResults(m report.Node, id string, create func(string) report.Node) {
// Add m as a child of the node at id, creating a new result node if
// not already there, and updating the mapping from old ID to new ID.
func (ret *joinResults) addChild(m report.Node, id string, create func(string) report.Node) {
result, exists := ret.nodes[id]
if !exists {
result = create(id)
}
result.Children = result.Children.Add(m)
if m.Topology != report.Endpoint { // optimisation: we never look at endpoint counts
result.Counters = result.Counters.Add(m.Topology, 1)
}
ret.nodes[id] = result
ret.mapped[m.ID] = id
}

// Like addChild, but also add m's children.
func (ret *joinResults) addChildAndChildren(m report.Node, id string, create func(string) report.Node) {
result, exists := ret.nodes[id]
if !exists {
result = create(id)
}
result.Children = result.Children.Add(m)
result.Children = result.Children.Merge(m.Children)
if m.Topology != report.Endpoint { // optimisation: we never look at endpoint counts
result.Counters = result.Counters.Add(m.Topology, 1)
}
ret.nodes[id] = result
ret.mapped[m.ID] = id
}

// Add a copy of n straight into the results
func (ret *joinResults) passThrough(n report.Node) {
n.Adjacency = nil // fixupAdjacencies assumes all nodes start with blank lists
ret.nodes[n.ID] = n
ret.mapped[n.ID] = n.ID
}

// Rewrite Adjacency for new nodes in ret for original nodes in input
func (ret *joinResults) fixupAdjacencies(input Nodes) {
for _, n := range input.Nodes {
Expand Down

0 comments on commit 3bc8f22

Please sign in to comment.