You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ea...@apache.org on 2019/12/11 22:36:47 UTC
[qpid-dispatch] branch master updated: DISPATCH-1474 Ensure all
inter-router links are included in the console's traffic view
This is an automated email from the ASF dual-hosted git repository.
eallen pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/qpid-dispatch.git
The following commit(s) were added to refs/heads/master by this push:
new 9a6eda8 DISPATCH-1474 Ensure all inter-router links are included in the console's traffic view
9a6eda8 is described below
commit 9a6eda8fd2103afc7af225f08b5d81643c56c63e
Author: Ernest Allen <ea...@redhat.com>
AuthorDate: Wed Dec 11 17:36:31 2019 -0500
DISPATCH-1474 Ensure all inter-router links are included in the console's traffic view
---
console/react/src/topology/traffic.js | 631 ++++++++++++++++++++--------------
1 file changed, 379 insertions(+), 252 deletions(-)
diff --git a/console/react/src/topology/traffic.js b/console/react/src/topology/traffic.js
index 4b4caa8..14fc172 100644
--- a/console/react/src/topology/traffic.js
+++ b/console/react/src/topology/traffic.js
@@ -24,18 +24,16 @@ import { nextHop } from "./topoUtils.js";
import { utils } from "../common/amqp/utilities.js";
const transitionDuration = 1000;
-//const CHORDFILTERKEY = "chordFilter";
export class Traffic {
// eslint-disable-line no-unused-vars
- constructor($scope, QDRService, converter, radius, topology, types) {
+ constructor($scope, QDRService, converter, radius, topology, types, addressesChanged) {
this.QDRService = QDRService;
+ this.addressesChanged = addressesChanged;
this.types = [];
this.viss = [];
this.topology = topology; // contains the list of router nodes
this.$scope = $scope;
- this.addresses = $scope.state.legendOptions.traffic.addresses;
- this.addressColors = $scope.state.legendOptions.traffic.addressColors;
// internal variables
this.interval = null; // setInterval handle
types.forEach(
@@ -43,7 +41,7 @@ export class Traffic {
this.addAnimationType(t, converter, radius);
}.bind(this)
);
- // called by angular when mouse enters one of the address legends
+ // called when mouse enters one of the address legends
this.$scope.enterLegend = address => {
// fade all flows that aren't for this address
this.fadeOtherAddresses(address);
@@ -72,6 +70,7 @@ export class Traffic {
// start updating the traffic data
start() {
this.stop();
+ this.setup();
this.doUpdate();
this.interval = setInterval(this.doUpdate.bind(this), transitionDuration);
}
@@ -99,10 +98,44 @@ export class Traffic {
}
this.start();
}
+ // set the data needed for each animation
+ setup() {
+ this.viss.forEach(v => v.setup());
+ }
// called periodically to refresh the traffic flow
doUpdate() {
+ if (!this.interval) return;
this.viss.forEach(v => v.doUpdate());
}
+
+ setTopology(topology) {
+ this.topology = topology;
+ }
+
+ getAddressColors(service, converter) {
+ return Dots.getAddressColors(service, converter);
+ }
+
+ updateAddressColors(address, checked) {
+ if (addressColors[address]) {
+ addressColors[address].checked = checked;
+ }
+ this.updateDots();
+ }
+
+ updateDots() {
+ const dots = this.viss.find(v => v.type === "dots");
+ if (dots) {
+ const excludedAddresses = Object.keys(addressColors).filter(
+ address => !addressColors[address].checked
+ );
+ dots.updateAddresses(excludedAddresses);
+ }
+ }
+
+ addressColors() {
+ return addressColors;
+ }
}
/* Base class for congestion and dots visualizations */
@@ -129,6 +162,7 @@ class TrafficAnimation {
}
}
+const STEPS = 6;
/* Color the links between router to show how heavily used the links are. */
class Congestion extends TrafficAnimation {
constructor(traffic) {
@@ -136,6 +170,18 @@ class Congestion extends TrafficAnimation {
this.type = "congestion";
this.stopped = false;
}
+
+ setup() {
+ this.traffic.QDRService.management.topology.addUpdateEntities([
+ {
+ entity: "router.link"
+ },
+ {
+ entity: "connection"
+ }
+ ]);
+ }
+
findResult(node, entity, attribute, value) {
let attrIndex = node[entity].attributeNames.indexOf(attribute);
if (attrIndex >= 0) {
@@ -147,105 +193,106 @@ class Congestion extends TrafficAnimation {
}
return null;
}
+
doUpdate() {
this.stopped = false;
let self = this;
- this.traffic.QDRService.management.topology.ensureAllEntities(
- [
- {
- entity: "router.link",
- force: true
- },
- {
- entity: "connection"
- }
- ],
- function() {
- // animation was stopped between the ensureAllEntities request and the response
- if (self.stopped) return;
- let links = {};
- let nodeInfo = self.traffic.QDRService.management.topology.nodeInfo();
- const nodes = self.traffic.topology.nodes.nodes;
- const srv = self.traffic.QDRService;
- // accumulate all the inter-router links in an object
- // keyed by the svgs path id
- for (let nodeId in nodeInfo) {
- let node = nodeInfo[nodeId];
- let nodeLinks = node["router.link"];
- if (!nodeLinks) continue;
- for (let n = 0; n < nodeLinks.results.length; n++) {
- let link = srv.utilities.flatten(
- nodeLinks.attributeNames,
- nodeLinks.results[n]
- );
- if (link.linkType !== "router-control") {
- let f = self.nodeIndexFor(nodes, srv.utilities.nameFromId(nodeId));
- let connection = self.findResult(
- node,
- "connection",
- "identity",
- link.connectionId
+ // animation was stopped between the ensureAllEntities request and the response
+ if (self.stopped) return;
+ let links = {};
+ let nodeInfo = self.traffic.QDRService.management.topology.nodeInfo();
+ const nodes = self.traffic.topology.nodes.nodes;
+ const srv = self.traffic.QDRService;
+ // accumulate all the inter-router links in an object
+ // keyed by the svgs path id
+ for (let nodeId in nodeInfo) {
+ let node = nodeInfo[nodeId];
+ let nodeLinks = node["router.link"];
+ if (!nodeLinks) continue;
+ for (let n = 0; n < nodeLinks.results.length; n++) {
+ let link = srv.utilities.flatten(nodeLinks.attributeNames, nodeLinks.results[n]);
+ if (link.linkType !== "router-control") {
+ let f = self.nodeIndexFor(nodes, srv.utilities.nameFromId(nodeId));
+ let connection = self.findResult(
+ node,
+ "connection",
+ "identity",
+ link.connectionId
+ );
+ if (connection) {
+ let t = self.nodeIndexFor(nodes, connection.container);
+ let little = Math.min(f, t);
+ let big = Math.max(f, t);
+ if (little >= 0) {
+ let key = ["#hitpath", nodes[little].uid(srv), nodes[big].uid(srv)].join(
+ "-"
);
- if (connection) {
- let t = self.nodeIndexFor(nodes, connection.container);
- let little = Math.min(f, t);
- let big = Math.max(f, t);
- if (little >= 0) {
- let key = ["#path", nodes[little].uid(srv), nodes[big].uid(srv)].join(
- "-"
- );
- if (!links[key]) links[key] = [];
- links[key].push(link);
- }
- }
+ if (!links[key]) links[key] = [];
+ links[key].push(link);
}
}
}
- // accumulate the colors/directions to be used
- for (let key in links) {
- let congestion = self.congestion(links[key]);
- let pathId = key.replace(/\./g, "\\.").replace(/ /g, "\\ ");
- let path = d3.select(pathId);
- if (path && !path.empty()) {
- path
- .transition()
- .duration(1000)
- .style("stroke", congestion)
- .each("end", function(d) {
- if (self.stopped) {
- d3.select(this).style("stroke", "black");
- }
- });
- }
+ }
+ }
+ // accumulate the colors/directions to be used
+ for (let key in links) {
+ let congestion = self.congestion(links[key]);
+ let pathId = key.replace(/\./g, "\\.").replace(/ /g, "\\ ");
+ let path = d3.select(pathId);
+ if (path && !path.empty()) {
+ // start the path with transparent white
+ if (!path.attr("style")) {
+ path.style("stroke", "rgb(255, 255, 255)").style("opacity", 0);
}
+ // transition to next color
+ path
+ .transition()
+ .duration(1000)
+ .style("stroke", congestion)
+ .style("opacity", 0.2)
+ .each("end", function(d) {
+ if (self.stopped) {
+ // fade to transparent
+ const p = d3.select(this);
+ p.transition()
+ .duration(100)
+ .style("opacity", 0)
+ .each("end", function() {
+ // remove the style
+ p.style("stroke", null).style("opacity", null);
+ });
+ }
+ });
}
- );
+ }
}
congestion(links) {
+ const max = STEPS - 1;
let v = 0;
for (let l = 0; l < links.length; l++) {
let link = links[l];
v = Math.max(
v,
- (3 * (link.undeliveredCount + link.unsettledCount)) / link.capacity
+ (max * (link.undeliveredCount + link.unsettledCount)) / link.capacity
);
- if (link.deliveriesDelayed1Sec || link.deliveriesDelayed10Sec) v = 3;
- v = Math.min(3, v);
+ v = Math.min(max, v);
}
return this.fillColor(v);
}
fillColor(v) {
let color = d3.scale
.linear()
- .domain([0, 1, 2, 3])
+ .domain([...Array(STEPS).keys()])
.interpolate(d3.interpolateHcl)
.range([
d3.rgb("#999999"),
d3.rgb("#00FF00"),
+ d3.rgb("#66CC00"),
d3.rgb("#FFA500"),
+ d3.rgb("#FFCC00"),
d3.rgb("#FF0000")
]);
- return color(Math.max(0, Math.min(3, v)));
+ return color(Math.max(0, Math.min(STEPS - 1, v)));
}
remove() {
this.stopped = true;
@@ -253,15 +300,15 @@ class Congestion extends TrafficAnimation {
.selectAll("path.traffic")
.classed("traffic", false);
d3.select("#SVG_ID")
- .selectAll("path.link")
- .style("stroke", "black");
- d3.select("#SVG_ID")
.select("defs.custom-markers")
.selectAll("marker")
.remove();
}
}
+const colorGen = d3.scale.category10();
+const addressColors = {};
+
/* Create animated dots moving along the links between routers
to show message flow */
class Dots extends TrafficAnimation {
@@ -272,24 +319,34 @@ class Dots extends TrafficAnimation {
this.lastFlows = {}; // the number of dots animated between routers
this.stopped = false;
this.chordData = new ChordData(this.traffic.QDRService, true, converter); // gets ingressHistogram data
- // colors
- this.colorGen = d3.scale.category10();
- for (let i = 0; i < 10; i++) {
- this.colorGen(i);
+ if (Object.keys(addressColors).length === 0) {
+ // map address to {color, checked}
+ Dots.getAddressColors(this.traffic.QDRService, converter);
}
- this.chordData.getMatrix().then(() => {
- const addresses = this.chordData.getAddresses();
- const addressColors = {};
- for (let address in addresses) {
- this.fillColor(address, addressColors);
- }
- traffic.updateAddresses = this.updateAddresses;
- this.traffic.$scope.handleUpdatedAddresses(addresses);
- this.traffic.$scope.handleUpdateAddressColors(addressColors);
- // set excludedAddresses
- this.updateAddresses();
+ }
+
+ static getAddressColors(service, converter) {
+ return new Promise(resolve => {
+ const chordData = new ChordData(service, true, converter);
+ chordData.getMatrix().then(() => {
+ const addresses = chordData.getAddresses();
+ for (let address in addresses) {
+ addressColors[address] = { color: colorGen(address), checked: true };
+ }
+ resolve(addressColors);
+ });
});
}
+
+ setup() {
+ this.traffic.QDRService.management.topology.addUpdateEntities([
+ {
+ entity: "router.node",
+ attrs: ["id", "nextHop"]
+ }
+ ]);
+ }
+
remove() {
d3.select("#SVG_ID")
.selectAll("path.traffic")
@@ -300,15 +357,13 @@ class Dots extends TrafficAnimation {
this.lastFlows = {};
this.stopped = true;
}
- updateAddresses() {
- this.excludedAddresses = [];
- for (const address in this.traffic.addresses) {
- if (!this.traffic.addresses[address]) this.excludedAddresses.push(address);
- }
- if (this.chordData) {
- this.chordData.setFilter(this.excludedAddresses);
- }
+
+ updateAddresses(excludedAddresses) {
+ this.chordData.setFilter(excludedAddresses);
+ // make sure no excludedAddress have an animation
+ this.doUpdate();
}
+
fadeOtherAddresses(address) {
d3.selectAll("circle.flow").classed("fade", function(d) {
return d.address !== address;
@@ -317,173 +372,177 @@ class Dots extends TrafficAnimation {
unFadeAll() {
d3.selectAll("circle.flow").classed("fade", false);
}
+
doUpdate() {
- let self = this;
this.stopped = false;
- // we need the nextHop data to show traffic between routers that are connected by intermediaries
- this.traffic.QDRService.management.topology.ensureAllEntities(
- [
- {
- entity: "router.node",
- attrs: ["id", "nextHop"]
- }
- ],
- function() {
- // if we were stopped between the request and response, just exit
- if (self.stopped) return;
- // get the ingressHistogram data for all routers
- self.chordData.getMatrix().then(self.render.bind(self), function(e) {
- console.log("Could not get message histogram" + e);
- });
- }
- );
+ // get the ingressHistogram data for all routers
+ this.chordData.getMatrix().then(this.render);
}
- render(matrix) {
- if (this.stopped === false) {
- const addresses = this.chordData.getAddresses();
- this.traffic.$scope.handleUpdatedAddresses(addresses);
- const addressColors = {};
- for (let address in addresses) {
- this.fillColor(address, addressColors);
+
+ render = matrix => {
+ if (this.stopped) return;
+ const addresses = this.chordData.getAddresses();
+ let changed = false;
+ // make sure each address has a color
+ for (let address in addresses) {
+ if (!(address in addressColors)) {
+ addressColors[address] = { color: this.fillColor(address), checked: true };
+ changed = true;
}
- this.traffic.$scope.handleUpdateAddressColors(addressColors);
-
- // get the rate of message flow between routers
- let hops = {}; // every hop between routers that is involved in message flow
- let matrixMessages = matrix.matrixMessages();
- // the fastest traffic rate gets 3 times as many dots as the slowest
- let minmax = matrix.getMinMax();
- let flowScale = d3.scale
- .linear()
- .domain(minmax)
- .range([1, 1.1]);
- // row is ingress router, col is egress router. Value at [row][col] is the rate
- matrixMessages.forEach(
- function(row, r) {
- row.forEach(
- function(val, c) {
- if (val > MIN_CHORD_THRESHOLD) {
- // translate between matrix row/col and node index
- let f = this.nodeIndexFor(
- this.traffic.topology.nodes.nodes,
- matrix.rows[r].egress
- );
- let t = this.nodeIndexFor(
- this.traffic.topology.nodes.nodes,
- matrix.rows[r].ingress
- );
- let address = matrix.getAddress(r, c);
- if (r !== c) {
- // accumulate the hops between the ingress and egress routers
- nextHop(
- this.traffic.topology.nodes.nodes[f],
- this.traffic.topology.nodes.nodes[t],
- this.traffic.topology.nodes,
- this.traffic.topology.links,
- this.traffic.QDRService.management.topology.nodeInfo(),
- this.traffic.topology.nodes.nodes[f],
- function(link, fnode, tnode) {
- let key = "-" + link.uid;
- let back = fnode.index < tnode.index;
- if (!hops[key]) hops[key] = [];
- hops[key].push({
- val: val,
- back: back,
- address: address
- });
- }
- );
- }
- // Find the senders connected to nodes[f] and the receivers connected to nodes[t]
- // and add their links to the animation
- this.addClients(
- hops,
- this.traffic.topology.nodes.nodes,
- f,
- val,
- true,
- address
- );
- this.addClients(
- hops,
- this.traffic.topology.nodes.nodes,
- t,
- val,
- false,
- address
- );
- }
- }.bind(this)
+ }
+ // remove any address that no longer have traffic
+ for (let address in addressColors) {
+ if (!(address in addresses)) {
+ delete addressColors[address];
+ changed = true;
+ }
+ }
+ if (changed) {
+ this.traffic.addressesChanged();
+ }
+
+ // get the rate of message flow between routers
+ let hops = {}; // every hop between routers that is involved in message flow
+ let matrixMessages = matrix.matrixMessages();
+ // the fastest traffic rate gets more dots than the slowest
+ let minmax = matrix.getMinMax();
+ let flowScale = d3.scale
+ .linear()
+ .domain(minmax)
+ .range([1, 1.5]);
+ // row is ingress router, col is egress router. Value at [row][col] is the rate
+ matrixMessages.forEach((row, r) => {
+ row.forEach((val, c) => {
+ if (val > MIN_CHORD_THRESHOLD) {
+ // translate between matrix row/col and node index
+ let f = this.nodeIndexFor(
+ this.traffic.topology.nodes.nodes,
+ matrix.rows[r].egress
);
- }.bind(this)
- );
- // for each link between routers that has traffic, start an animation
- let keep = {};
- for (let id in hops) {
- let hop = hops[id];
- for (let h = 0; h < hop.length; h++) {
- let ahop = hop[h];
- let pathId = id.replace(/\./g, "\\.").replace(/ /g, "\\ ");
- let flowId =
- id.replace(/\./g, "").replace(/ /g, "") +
- "-" +
- this.addressIndex(this, ahop.address) +
- (ahop.back ? "b" : "");
- let path = d3.select("#path" + pathId);
- if (!path.empty()) {
- // start the animation. If the animation is already running, this will have no effect
- this.startAnimation(path, flowId, ahop, flowScale(ahop.val));
+ let t = this.nodeIndexFor(
+ this.traffic.topology.nodes.nodes,
+ matrix.rows[r].ingress
+ );
+ let address = matrix.getAddress(r, c);
+ if (r !== c) {
+ // accumulate the hops between the ingress and egress routers
+ nextHop(
+ this.traffic.topology.nodes.nodes[f],
+ this.traffic.topology.nodes.nodes[t],
+ this.traffic.topology.nodes,
+ this.traffic.topology.links,
+ this.traffic.QDRService.management.topology.nodeInfo(),
+ this.traffic.topology.nodes.nodes[f],
+ function(link, fnode, tnode) {
+ let key = "-" + link.uid();
+ let back = fnode.index < tnode.index;
+ if (!hops[key]) hops[key] = [];
+ hops[key].push({
+ val: val,
+ back: back,
+ address: address
+ });
+ }
+ );
}
- keep[flowId] = true;
+ // Find the senders connected to nodes[f] and the receivers connected to nodes[t]
+ // and add their links to the animation
+ this.addClients(hops, f, val, true, address);
+ this.addClients(hops, t, val, false, address);
+
+ const ftrue = this.addEdges(hops, f, val, true, address);
+ const ffalse = this.addEdges(hops, f, val, false, address);
+ const ttrue = this.addEdges(hops, t, val, true, address);
+ const tfalse = this.addEdges(hops, t, val, false, address);
+ [...ftrue, ...ffalse, ...ttrue, ...tfalse].forEach(eIndex => {
+ this.addClients(hops, eIndex, val, true, address);
+ this.addClients(hops, eIndex, val, false, address);
+ });
}
- }
- // remove any existing animations that we don't have data for anymore
- for (let id in this.lastFlows) {
- if (this.lastFlows[id] && !keep[id]) {
- this.lastFlows[id] = 0;
- d3.select("#SVG_ID")
- .selectAll("circle.flow" + id)
- .remove();
+ });
+ });
+ // for each link between routers that has traffic, start an animation
+ let keep = {};
+ let offset = 0; // index of the address going in the same driection
+ let total = 0; // number of addresses going in the same direction for this path
+
+ for (let id in hops) {
+ let hop = hops[id];
+ const backCount = hop.filter(h => h.back).length;
+ const foreCount = hop.length - backCount;
+ let backIndex = 0; // index of address going the back direction
+ let foreIndex = 0;
+ for (let h = 0; h < hop.length; h++) {
+ let ahop = hop[h];
+ let pathId = id.replace(/\./g, "\\.").replace(/ /g, "\\ ");
+ let flowId =
+ id.replace(/\./g, "").replace(/ /g, "") +
+ "-" +
+ this.addressIndex(ahop.address) +
+ (ahop.back ? "b" : "");
+ let path = d3.select("#path" + pathId);
+ if (!path.empty()) {
+ if (ahop.back) {
+ offset = backIndex++;
+ total = backCount;
+ } else {
+ offset = foreIndex++;
+ total = foreCount;
+ }
+ // start the animation. If the animation is already running, this will have no effect
+ this.animateDots(path, flowId, ahop, flowScale(ahop.val), offset, total);
}
+ keep[flowId] = true;
}
}
- }
- // animate the d3 selection (flow) along the given path
- animateFlow(flow, path, count, back, rate) {
+ // remove any existing animations that we don't have data for anymore
+ for (let id in this.lastFlows) {
+ if (this.lastFlows[id] && !keep[id]) {
+ this.lastFlows[id] = 0;
+ d3.select("#SVG_ID")
+ .selectAll("circle.flow" + id)
+ .remove();
+ }
+ }
+ };
+
+ // move the dots in the selection flow along the path
+ animateFlow(flow, path, back, rate, offset, total) {
let l = path.node().getTotalLength();
+ const count = flow.size();
+ const duration = (l * 10) / rate;
flow
.transition()
.ease("easeLinear")
- .duration((l * 10) / rate)
- .attrTween("transform", this.translateDots(this.radius, path, count, back))
+ .duration(duration)
+ .attrTween("transform", this.translateDots(path, count, back, offset, total))
.each("end", () => {
if (this.stopped === false) {
- this.animateFlow(flow, path, count, back, rate);
+ setTimeout(() => {
+ this.animateFlow(flow, path, back, rate, offset, total);
+ }, 1);
}
});
}
- // create dots along the path between routers
- startAnimation(selection, id, hop, rate) {
- if (selection.empty()) return;
- this.animateDots(selection, id, hop, rate);
- }
- animateDots(path, id, hop, rate) {
+
+ animateDots(path, id, hop, rate, offset, total) {
let back = hop.back,
address = hop.address;
// the density of dots is determined by the rate of this traffic relative to the other traffic
if (!path.node().getTotalLength) return;
let len = Math.max(Math.floor(path.node().getTotalLength() / 50), 1);
let dots = [];
- for (let i = 0, offset = this.addressIndex(this, address); i < len; ++i) {
+ for (let i = 0, offset = this.addressIndex(address); i < len; ++i) {
dots[i] = {
i: i + 10 * offset,
- address: address
+ address
};
}
// keep track of the number of dots for each link. If the length of the link is changed,
// re-create the animation
- if (!this.lastFlows[id]) this.lastFlows[id] = len;
- else {
+ if (!this.lastFlows[id]) {
+ this.lastFlows[id] = len;
+ } else {
if (this.lastFlows[id] !== len) {
this.lastFlows[id] = len;
d3.select("#SVG_ID")
@@ -502,27 +561,31 @@ class Dots extends TrafficAnimation {
.append("circle")
.attr("class", "flow flow" + id)
.attr("data-testid", (d, i) => `flow${id}-${i}`)
- .attr("fill", this.fillColor(address, this.traffic.addressColors))
+ .attr("fill", this.fillColor(address))
.attr("r", 4);
- this.animateFlow(circles, path, dots.length, back, rate);
+
+ // start the animation
+ if (circles.size() > 0) {
+ this.animateFlow(circles, path, back, rate, offset, total);
+ }
flow.exit().remove();
}
- fillColor(n, addressColors) {
- if (!(n in addressColors)) {
- let ci = Object.keys(addressColors).length;
- addressColors[n] = this.colorGen(ci);
- }
- return addressColors[n];
+
+ fillColor(address) {
+ return colorGen(address);
}
+
// find the link that carries traffic for this address
// going to nodes[f] if sender is true
// coming from nodes[f] if sender if false.
// Add the link's id to the hops array
- addClients(hops, nodes, f, val, sender, address) {
+ addClients(hops, f, val, sender, address) {
+ const nodes = this.traffic.topology.nodes.nodes;
if (!nodes[f]) return;
const cdir = sender ? "out" : "in";
const uuid = nodes[f].uid();
const key = nodes[f].key;
+ if (!this.traffic.QDRService.management.topology._nodeInfo[key]) return;
const links = this.traffic.QDRService.management.topology._nodeInfo[key][
"router.link"
];
@@ -538,7 +601,6 @@ class Dots extends TrafficAnimation {
l[ild] === cdir
);
}, this);
-
// we now have the links involved in traffic for this address that
// ingress/egress to/from this router (f).
// Now find the created node that each link is associated with
@@ -559,7 +621,7 @@ class Dots extends TrafficAnimation {
hops[key].push({
val: val,
back: !sender,
- address: address
+ address
});
return true;
}
@@ -568,19 +630,84 @@ class Dots extends TrafficAnimation {
}
}
}
- addressIndex(vis, address) {
- return Object.keys(vis.traffic.addresses).indexOf(address);
+
+ addEdges(hops, f, val, sender, address) {
+ const nodes = this.traffic.topology.nodes.nodes;
+ if (!nodes[f]) return;
+ const edges = [];
+ const cdir = sender ? "out" : "in";
+ const uuid = nodes[f].uid();
+ const key = nodes[f].key;
+ const links = this.traffic.QDRService.management.topology._nodeInfo[key][
+ "router.link"
+ ];
+ if (links) {
+ const ilt = links.attributeNames.indexOf("linkType");
+ const ioa = links.attributeNames.indexOf("owningAddr");
+ const ici = links.attributeNames.indexOf("connectionId");
+ const ild = links.attributeNames.indexOf("linkDir");
+ let foundLinks = links.results.filter(function(l) {
+ return (
+ (l[ilt] === "endpoint" || l[ilt] === "edge-downlink") &&
+ address === utils.addr_text(l[ioa]) &&
+ l[ild] === cdir
+ );
+ }, this);
+
+ // we now have the links involved in traffic for this address that
+ // ingress/egress to/from this router (f).
+ // Now find the edge router for the links
+ const connections = this.traffic.QDRService.management.topology._nodeInfo[key][
+ "connection"
+ ];
+ for (let linkIndex = 0; linkIndex < foundLinks.length; linkIndex++) {
+ const connectionId = foundLinks[linkIndex][ici];
+ const iconnid = connections.attributeNames.indexOf("identity");
+ const connection = connections.results.find(
+ result => result[iconnid] === connectionId
+ );
+ if (connection) {
+ const container = utils.valFor(
+ connections.attributeNames,
+ connection,
+ "container"
+ );
+ const edge = nodes.find(
+ node => node.nodeType === "_edge" && node.name === container
+ );
+ if (edge) {
+ const uuid2 = edge.uid();
+ const key = ["", uuid, uuid2].join("-");
+ if (!hops[key]) hops[key] = [];
+ hops[key].push({
+ val: val,
+ back: !sender,
+ address
+ });
+ edges.push(edge.index);
+ }
+ }
+ }
+ }
+ return edges;
+ }
+
+ addressIndex(address) {
+ return Object.keys(addressColors).indexOf(address);
}
+
// calculate the translation for each dot along the path
- translateDots(radius, path, count, back) {
+ translateDots(path, count, back, offset, total) {
let pnode = path.node();
// will be called for each element in the flow selection (for each dot)
return function(d) {
+ const off = offset / total / count;
// will be called with t going from 0 to 1 for each dot
return function(t) {
// start the points at different positions depending on their value (d)
- let tt = t * 1000;
- let f = ((tt + (d.i * 1000) / count) % 1000) / 1000;
+ let tt = t * 1000; // total time
+ let f = ((tt + (d.i * 1000) / count) % 1000) / 1000; // fraction
+ f = (f + off) % 1;
if (back) f = 1 - f;
// l needs to be calculated each tick because the path's length might be changed during the animation
let l = pnode.getTotalLength();
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org