Remove partially merged nodes from deltas

Scope probes send full reports and deltas. If a node is eliminated
between two full reports, then the app might only have a delta of its
last state. Remove all such nodes before rendering.
This commit is contained in:
Bryan Boreham
2021-04-23 09:38:45 +00:00
parent 4e2f364381
commit 4dbf908cde
6 changed files with 28 additions and 2 deletions

View File

@@ -479,6 +479,7 @@ func (r *Registry) makeTopologyList(rep Reporter) CtxHandlerFunc {
respondWith(ctx, w, http.StatusInternalServerError, err)
return
}
report.UnsafeRemovePartMergedNodes()
respondWith(ctx, w, http.StatusOK, r.renderTopologies(ctx, report, req))
}
}
@@ -579,6 +580,7 @@ func (r *Registry) captureRenderer(rep Reporter, f rendererHandler) CtxHandlerFu
respondWith(ctx, w, http.StatusInternalServerError, err)
return
}
rpt.UnsafeRemovePartMergedNodes()
req.ParseForm()
renderer, filter, err := r.RendererForTopology(topologyID, req.Form, rpt)
if err != nil {

View File

@@ -182,6 +182,7 @@ func (wc *websocketState) update(ctx context.Context) error {
if err != nil {
return errors.Wrap(err, "Error generating report")
}
re.UnsafeRemovePartMergedNodes()
renderer, filter, err := topologyRegistry.RendererForTopology(wc.topologyID, wc.values, re)
if err != nil {
return errors.Wrap(err, "Error generating report")

View File

@@ -87,6 +87,7 @@ func getReport(b *testing.B) report.Report {
func benchmarkRender(b *testing.B, f func(report.Report)) {
r := getReport(b)
r.UnsafeRemovePartMergedNodes()
b.ResetTimer()
for i := 0; i < b.N; i++ {
b.StopTimer()

View File

@@ -23,10 +23,10 @@ func TestCollector(t *testing.T) {
defer mtime.NowReset()
r1 := report.MakeReport()
r1.Endpoint.AddNode(report.MakeNode("foo"))
r1.Endpoint.AddNode(report.MakeNode("foo").WithTopology("bar"))
r2 := report.MakeReport()
r2.Endpoint.AddNode(report.MakeNode("foo"))
r2.Endpoint.AddNode(report.MakeNode("foo").WithTopology("bar"))
have, err := c.Report(ctx, mtime.Now())
if err != nil {
@@ -52,6 +52,7 @@ func TestCollector(t *testing.T) {
merged := report.MakeReport()
merged.UnsafeMerge(r1)
merged.UnsafeMerge(r2)
merged.UnsafeRemovePartMergedNodes()
have, err = c.Report(ctx, mtime.Now())
if err != nil {
t.Error(err)

View File

@@ -236,3 +236,10 @@ func (n *Node) UnsafeUnMerge(other Node) bool {
// metrics don't overlap so just check if we have any
return remove && len(n.Metrics) == 0
}
// If a node is removed from source between two full reports, then we
// might only have a delta of its last state. Detect that from a blank topology,
// which cannot arise in a properly-formed Node.
func (n *Node) isPartMerged() bool {
return n.Topology == ""
}

View File

@@ -363,6 +363,20 @@ func (r *Report) UnsafeUnMerge(other Report) {
})
}
// UnsafeRemovePartMergedNodes removes nodes that have not fully re-merged.
// E.g. if a node is removed from source between two full reports, then we
// might only have a delta of its last state. Remove that from the set.
// The original is modified.
func (r *Report) UnsafeRemovePartMergedNodes() {
r.WalkTopologies(func(t *Topology) {
for k, v := range t.Nodes {
if v.isPartMerged() {
delete(t.Nodes, k)
}
}
})
}
// WalkTopologies iterates through the Topologies of the report,
// potentially modifying them
func (r *Report) WalkTopologies(f func(*Topology)) {