Echo-cancel assertions, following syndicate/racket.
This commit is contained in:
parent
e9b431c50f
commit
935fb98a1f
|
@ -44,27 +44,43 @@ Mux.prototype.updateStream = function (pid, unclampedPatch) {
|
||||||
deltaAggregate: deltaAggregate };
|
deltaAggregate: deltaAggregate };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var atMetaEverything = Route.compilePattern(true, Patch.atMeta(Route.__));
|
||||||
|
var atMetaBranchKeys = Immutable.List([Route.SOA, Patch.$AtMeta]);
|
||||||
|
var onlyMeta = Immutable.Set.of("meta");
|
||||||
|
|
||||||
|
function echoCancelledTrie(t) {
|
||||||
|
return Route.subtract(t, atMetaEverything, function (v1, v2) {
|
||||||
|
return v1.has("meta") ? onlyMeta : null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function computeEvents(oldMux, newMux, updateStreamResult) {
|
function computeEvents(oldMux, newMux, updateStreamResult) {
|
||||||
var actingPid = updateStreamResult.pid;
|
var actingPid = updateStreamResult.pid;
|
||||||
var delta = updateStreamResult.delta;
|
var delta = updateStreamResult.delta;
|
||||||
var deltaAggregate = updateStreamResult.deltaAggregate;
|
var deltaAggregate = updateStreamResult.deltaAggregate;
|
||||||
|
var deltaAggregateNoEcho = (actingPid === "meta")
|
||||||
|
? delta // because echo-cancellation means that meta-SCNs are always new information
|
||||||
|
: new Patch.Patch(Route.triePruneBranch(deltaAggregate.added, atMetaBranchKeys),
|
||||||
|
Route.triePruneBranch(deltaAggregate.removed, atMetaBranchKeys));
|
||||||
var oldRoutingTable = oldMux.routingTable;
|
var oldRoutingTable = oldMux.routingTable;
|
||||||
var newRoutingTable = newMux.routingTable;
|
var newRoutingTable = newMux.routingTable;
|
||||||
var affectedPids = computeAffectedPids(oldRoutingTable, delta).add(actingPid).remove("meta");
|
var affectedPids =
|
||||||
|
computeAffectedPids(oldRoutingTable, deltaAggregateNoEcho).add(actingPid).remove("meta");
|
||||||
return {
|
return {
|
||||||
eventMap: Immutable.Map().withMutations(function (result) {
|
eventMap: Immutable.Map().withMutations(function (result) {
|
||||||
affectedPids.forEach(function (pid) {
|
affectedPids.forEach(function (pid) {
|
||||||
var patchForPid;
|
var patchForPid;
|
||||||
if (pid === actingPid) {
|
if (pid === actingPid) {
|
||||||
var part1 = new Patch.Patch(Patch.biasedIntersection(newRoutingTable, delta.added),
|
var part1 = new Patch.Patch(
|
||||||
Patch.biasedIntersection(oldRoutingTable, delta.removed));
|
echoCancelledTrie(Patch.biasedIntersection(newRoutingTable, delta.added)),
|
||||||
var part2 = new Patch.Patch(Patch.biasedIntersection(deltaAggregate.added,
|
echoCancelledTrie(Patch.biasedIntersection(oldRoutingTable, delta.removed)));
|
||||||
|
var part2 = new Patch.Patch(Patch.biasedIntersection(deltaAggregateNoEcho.added,
|
||||||
newMux.interestsOf(pid)),
|
newMux.interestsOf(pid)),
|
||||||
Patch.biasedIntersection(deltaAggregate.removed,
|
Patch.biasedIntersection(deltaAggregateNoEcho.removed,
|
||||||
oldMux.interestsOf(pid)));
|
oldMux.interestsOf(pid)));
|
||||||
patchForPid = part1.unsafeUnion(part2);
|
patchForPid = part1.unsafeUnion(part2);
|
||||||
} else {
|
} else {
|
||||||
patchForPid = updateStreamResult.deltaAggregate.viewFrom(oldMux.interestsOf(pid));
|
patchForPid = deltaAggregateNoEcho.viewFrom(oldMux.interestsOf(pid));
|
||||||
}
|
}
|
||||||
if (patchForPid.isNonEmpty()) {
|
if (patchForPid.isNonEmpty()) {
|
||||||
result.set(pid, patchForPid);
|
result.set(pid, patchForPid);
|
||||||
|
|
|
@ -1,83 +1,135 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var expect = require('expect.js');
|
var expect = require('expect.js');
|
||||||
|
var Immutable = require('immutable');
|
||||||
|
|
||||||
var Syndicate = require('../src/main.js');
|
var Syndicate = require('../src/main.js');
|
||||||
|
|
||||||
var Network = Syndicate.Network;
|
var Network = Syndicate.Network;
|
||||||
|
var Patch = Syndicate.Patch;
|
||||||
|
|
||||||
// var sub = Syndicate.sub;
|
var __ = Syndicate.__;
|
||||||
// var pub = Syndicate.pub;
|
var _$ = Syndicate._$;
|
||||||
// var __ = Syndicate.__;
|
|
||||||
// var _$ = Syndicate._$;
|
|
||||||
|
|
||||||
// function configurationTrace(bootConfiguration) {
|
function configurationTrace(bootConfiguration) {
|
||||||
// var eventLog = [];
|
var eventLog = [];
|
||||||
// function trace(item) {
|
function trace(item) {
|
||||||
// eventLog.push(item);
|
eventLog.push(item);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// var G = new Syndicate.Ground(function () {
|
var G = new Syndicate.Ground(function () {
|
||||||
// bootConfiguration(trace);
|
bootConfiguration(trace);
|
||||||
// });
|
});
|
||||||
|
|
||||||
// while (G.step()) {
|
while (G.step()) {
|
||||||
// // do nothing until G becomes inert
|
// do nothing until G becomes inert
|
||||||
// }
|
}
|
||||||
|
|
||||||
// return eventLog;
|
return eventLog;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// function checkTrace(bootConfiguration, expected) {
|
function traceEvent(trace) {
|
||||||
// expect(configurationTrace(bootConfiguration)).to.eql(expected);
|
return function(item) {
|
||||||
// }
|
trace((item.type === "stateChange") ? item.patch.pretty() : item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// describe("configurationTrace", function() {
|
function checkTrace(bootConfiguration, expected) {
|
||||||
// describe("with an inert configuration", function () {
|
expect(configurationTrace(bootConfiguration)).to.eql(expected);
|
||||||
// it("should yield an empty trace", function () {
|
}
|
||||||
// checkTrace(function (trace) {}, []);
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
|
|
||||||
// describe("with a single trace in an inert configuration", function () {
|
describe("configurationTrace", function() {
|
||||||
// it("should yield that trace", function () {
|
describe("with an inert configuration", function () {
|
||||||
// checkTrace(function (trace) { trace(1) }, [1]);
|
it("should yield an empty trace", function () {
|
||||||
// });
|
checkTrace(function (trace) {}, []);
|
||||||
// });
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// describe("with some traced communication", function () {
|
describe("with a single trace in an inert configuration", function () {
|
||||||
// it("should yield an appropriate trace", function () {
|
it("should yield that trace", function () {
|
||||||
// checkTrace(function (trace) {
|
checkTrace(function (trace) { trace(1) }, [1]);
|
||||||
// Network.spawn({
|
});
|
||||||
// boot: function () { return [sub(__)] },
|
});
|
||||||
// handleEvent: function (e) {
|
|
||||||
// trace(e);
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// Network.send(123);
|
|
||||||
// Network.send(234);
|
|
||||||
// }, [Syndicate.updateRoutes([]),
|
|
||||||
// Syndicate.sendMessage(123),
|
|
||||||
// Syndicate.sendMessage(234)]);
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
|
|
||||||
// describe("nonempty initial routes", function () {
|
describe("with some traced communication", function () {
|
||||||
// it("should be immediately signalled to the process", function () {
|
it("should yield an appropriate trace", function () {
|
||||||
// // Specifically, no Syndicate.updateRoutes([]) first.
|
checkTrace(function (trace) {
|
||||||
// checkTrace(function (trace) {
|
Network.spawn({
|
||||||
// Network.spawn({
|
boot: function () { return Syndicate.sub(__); },
|
||||||
// boot: function () { return [pub(["A", __])] },
|
handleEvent: traceEvent(trace)
|
||||||
// handleEvent: function (e) {
|
});
|
||||||
// Network.spawn({
|
Network.send(123);
|
||||||
// boot: function () { return [sub(["A", __], 0, 1)] },
|
Network.send(234);
|
||||||
// handleEvent: trace
|
}, ['<<<<<<<< Removed:\n'+
|
||||||
// });
|
'::: nothing\n'+
|
||||||
// }
|
'======== Added:\n'+
|
||||||
// });
|
' < $Observe ★ > >{[0]}\n'
|
||||||
// }, [Syndicate.updateRoutes([pub(["A", __]).label(1)])]);
|
+' >::: nothing\n'+
|
||||||
// });
|
'>>>>>>>>',
|
||||||
// });
|
Syndicate.message(123),
|
||||||
|
Syndicate.message(234)]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("nonempty initial routes", function () {
|
||||||
|
it("should be immediately signalled to the process", function () {
|
||||||
|
// Specifically, no Syndicate.updateRoutes([]) first.
|
||||||
|
checkTrace(function (trace) {
|
||||||
|
Network.spawn({
|
||||||
|
boot: function () { return Patch.assert(["A", __]); },
|
||||||
|
handleEvent: function (e) {}
|
||||||
|
});
|
||||||
|
Network.spawn({
|
||||||
|
boot: function () { return Patch.sub(["A", __]); },
|
||||||
|
handleEvent: traceEvent(trace)
|
||||||
|
});
|
||||||
|
}, ['<<<<<<<< Removed:\n'+
|
||||||
|
'::: nothing\n'+
|
||||||
|
'======== Added:\n'+
|
||||||
|
' < "A" ★ > >{[1]}\n'+
|
||||||
|
'>>>>>>>>']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("nested actor with an echoey protocol", function () {
|
||||||
|
it("shouldn't see an echoed assertion", function () {
|
||||||
|
checkTrace(function (trace) {
|
||||||
|
Network.spawn(new Network(function () {
|
||||||
|
Network.spawn({
|
||||||
|
boot: function () {
|
||||||
|
Network.stateChange(Patch.retract("X", 1)); // happens after subs on next line!
|
||||||
|
return Patch.sub("X", 1).andThen(Patch.assert("X", 1));
|
||||||
|
},
|
||||||
|
handleEvent: traceEvent(trace)
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
}, ['<<<<<<<< Removed:\n'+
|
||||||
|
'::: nothing\n'+
|
||||||
|
'======== Added:\n'+
|
||||||
|
' < $AtMeta "X" > >{[0]}\n'+
|
||||||
|
'>>>>>>>>',
|
||||||
|
'<<<<<<<< Removed:\n'+
|
||||||
|
' < $AtMeta "X" > >{[0]}\n'+
|
||||||
|
'======== Added:\n'+
|
||||||
|
'::: nothing\n'+
|
||||||
|
'>>>>>>>>']);
|
||||||
|
})
|
||||||
|
it("shouldn't see an echoed message", function () {
|
||||||
|
checkTrace(function (trace) {
|
||||||
|
Network.spawn(new Network(function () {
|
||||||
|
Network.spawn({
|
||||||
|
boot: function () {
|
||||||
|
Network.send("X", 1); // happens after subs on next line!
|
||||||
|
return Patch.sub("X", 1);
|
||||||
|
},
|
||||||
|
handleEvent: traceEvent(trace)
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
}, [Syndicate.message(Patch.atMeta("X"))]);
|
||||||
|
});
|
||||||
|
it("shouldn't see an echoed assertion", function () {
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// describe("actor with nonempty initial routes", function () {
|
// describe("actor with nonempty initial routes", function () {
|
||||||
// it("shouldn't see initial empty conversational context", function () {
|
// it("shouldn't see initial empty conversational context", function () {
|
||||||
|
|
Loading…
Reference in New Issue