diff --git a/node.js b/node.js index 9a1646e..9328d0d 100644 --- a/node.js +++ b/node.js @@ -13,6 +13,7 @@ function Node() { }; this._routes = {}; this._lastTimestampGenerated = 0; + this._cycleFound = false; } Node.prototype._getTimestamp = function() { @@ -85,7 +86,12 @@ Node.prototype._probeIsKnown = function(treeToken) { Node.prototype.handleProbeMessage = function(neighborId, direction, msgObj) { if (direction === 'in') { if (this._probeIsKnown(msgObj.treeToken)) { - this._cycleFound = true; + if (this._routes[msgObj.treeToken].wasBacktracked()) { + //cross-edge, backtrack again + this._neighbors['in'][neighborId].sendProbeMessage(msgObj); + } else { + this._cycleFound = true; + } return; } this._routes[msgObj.treeToken] = new Route(neighborId, msgObj.treeToken, msgObj.pathToken); @@ -93,6 +99,7 @@ Node.prototype.handleProbeMessage = function(neighborId, direction, msgObj) { if (firstOutNeighborId) { this._neighbors.out[firstOutNeighborId].sendProbeMessage(msgObj); } else { // backtrack + this._routes[msgObj.treeToken].markBacktracked(); this._neighbors['in'][neighborId].sendProbeMessage(msgObj); } } else { @@ -101,6 +108,7 @@ Node.prototype.handleProbeMessage = function(neighborId, direction, msgObj) { msgObj.pathToken = this._routes[msgObj.treeToken].getPathToken(); this._neighbors.out[nextOutNeighborId].sendProbeMessage(msgObj); } else { // backtrack + this._routes[msgObj.treeToken].markBacktracked(); this._neighbors['in'][neighborId].sendProbeMessage(msgObj); } } diff --git a/route.js b/route.js index 683cb42..2147ea6 100644 --- a/route.js +++ b/route.js @@ -9,6 +9,7 @@ function Route(inNeighbor, treeToken) { this._treeToken = treeToken; this._outNeighbors = { }; + this._backtracked = false; } Route.prototype.getNextSiblingToTry = function(outNeighborIds) { @@ -28,4 +29,12 @@ Route.prototype.getOutNeighborNick = function(pathToken) { } }; +Route.prototype.markBacktracked = function() { + this._backtracked = true; +}; + +Route.prototype.wasBacktracked = function() { + return this._backtracked; +}; + module.exports = Route; diff --git a/test/cross-edge.js b/test/cross-edge.js new file mode 100644 index 0000000..69d74aa --- /dev/null +++ b/test/cross-edge.js @@ -0,0 +1,58 @@ +var Node = require('../index.js'); +var Graph = require('./helpers/graph.js'); +var assert = require('assert'); + +describe('Cross-edge', function() { + var graph; + beforeEach(function() { + graph = new Graph({ + a: new Node(), + b: new Node(), + c: new Node(), + }); + + // -------- + // v \ + // a -> b -> c + // \ ^ + // -------- + + graph.connect('a', 'b'); + graph.connect('b', 'c'); + graph.connect('a', 'c'); + graph.connect('c', 'a'); + return graph.propagate(); + }); + + it('should find both cycles', function() { + assert.deepEqual(graph.nodes.a.getActiveNeighbors(), { + 'in': ['c'], + out: ['b', 'c'], + }); + assert.deepEqual(graph.nodes.b.getActiveNeighbors(), { + 'in': ['a'], + out: ['c'], + }); + assert.deepEqual(graph.nodes.c.getActiveNeighbors(), { + 'in': ['b', 'a'], + out: ['a'], + }); + }); + describe('incoming probe message for a', function() { + beforeEach(function() { + graph.nodes.a.handleProbeMessage('c', 'in', { + treeToken: 'asdf', + }); + return graph.propagate(); + }); + it('a should not find a route', function() { + assert.equal(graph.nodes.a._cycleFound, true); + }); + it('b should not find a route', function() { + assert.equal(graph.nodes.b._cycleFound, false); + }); + it('c should not find a route', function() { + assert.equal(graph.nodes.c._cycleFound, false); + }); + }); +}); diff --git a/test/square.js b/test/square.js index d6047b9..3923c8c 100644 --- a/test/square.js +++ b/test/square.js @@ -43,8 +43,17 @@ describe('Four nodes', function() { }); return graph.propagate(); }); - it('should find a route', function() { + it('a should find a route', function() { assert.equal(graph.nodes.a._cycleFound, true); }); + it('b should not find a route', function() { + assert.equal(graph.nodes.b._cycleFound, false); + }); + it('c should not find a route', function() { + assert.equal(graph.nodes.c._cycleFound, false); + }); + it('d should not find a route', function() { + assert.equal(graph.nodes.d._cycleFound, false); + }); }); }); diff --git a/test/triangle.js b/test/triangle.js index dce878b..4ade7ed 100644 --- a/test/triangle.js +++ b/test/triangle.js @@ -41,8 +41,14 @@ describe('Three nodes', function() { }); return graph.propagate(); }); - it('should find a route', function() { + it('a should find a route', function() { assert.equal(graph.nodes.a._cycleFound, true); }); + it('b should not find a route', function() { + assert.equal(graph.nodes.b._cycleFound, false); + }); + it('c should not find a route', function() { + assert.equal(graph.nodes.c._cycleFound, false); + }); }); });