The node ID of group nodes is in fact the same value as we get from
looking up the metadata key contained in the group topology id. So
just use that since a) we always have it, and b) we save a LatestMap
lookup.
We fall back to image id when we cannot find a name. We extract the
image id from the node id rather than the docker.ImageID latest map
entry since that way we are guaranteed to get it.
The main change here is to to label the node with its pseudoID as the
last resort.
We also set the rank to the pseudoID instead of the full node id,
since including the "pseudo:" prefix is not conducive to good ranking.
The rest is just moving from 'if' to 'switch'.
We fall back to the truncated container id when we cannot find a
name. NB: this also happens when rendering a container as a parent.
We cope with the absence of an image name and/or host name.
We cope with the absence of the process name and/or container name,
and extract the hostID and pid from the node id rather than metadata
since that way we are guaranteed to get values for them.
This doesn't make any difference to the outcome - we were simply
setting the shape in the NodeSummary to "", which is what it starts
out as - but looks less weird in the code.
It's a dynamic type check of sorts.
In the process we stop abusing ParseNodeID for extracting the host,
which in turn allows us to clarify its purpose.
We consistently
- pre-allocate in Copy()
- merge the smaller into a copy of the larger in Merge()
This doesn't make much of a difference overall, since there are
comparatively few instances of these structures. But it costs little
in the code, and the consistency alone is worth it.
Pre-allocating slices really pays dividends when we create loads of
them and they don't grow very large.
We take special care to return nil rather than 0-length slices. This
a) saves further on allocation, and b) is required for some crude
tests to pass that match on nil rather than length.
Also, a bunch of code in templates/tables used slices as Maybe's,
i.e. returning nil or a single-element slice, which is horrendously
inefficient. Eliminating these saves a lot of allocations.
Having 6 lists of topolgies in the same file is a bit much:
1. consts for topology names
2. Report type definition
3. MakeReport() Report initialisation
4. Report.Topology(name) lookup
5. Report.TopologyMap() mapping of names to topology references
6. Report.WalkPairedTopologies() iterator over topology references
We get rid of 5 and 6 by introducing a topologyNames slice. So we
are down to 5.
We replace Report.TopologyMap() with a new function,
WalkNamedTopologies, that uses topologyNames. WalkPairedTopologies()
is updated to operate in a similar fashion. Likewise for
WalkTopologies() and Topologies() - these were previously calling
Walk[Paired]Topologies, but it is clearer to simply implement them
directly.
Previously this was buidling a fresh map of all topologies, just so it
could look up the one given as an argument.
Node summarisation (via detailed.Summaries) in particular was badly
affected by that.
This doesn't make any difference to the outcome - we were simply
setting the shape in the NodeSummary to "", which is what it starts
out as - but looks less weird in the code.
Report.Copy() shallow-copies the nodes in Report.Nodes. Hence
Node.Metrics is shared between the original and the copy. Hence bad
things happen when modifying it.
This bug has laid dormant because by luck other tests in detailed_test
involving metrics are executed first.