fix promise-sending.

This commit is contained in:
Howard Stearns 2016-02-02 15:37:22 -08:00
parent fbcacbe14a
commit 03244fbeb5
2 changed files with 15 additions and 14 deletions

View file

@ -40,7 +40,7 @@ virtualBaton = function virtualBaton(options) {
electionWatchdog, electionWatchdog,
// paxos acceptor state // paxos acceptor state
bestProposal = {number: 0}, bestProposal = {number: 0},
accepted = null; accepted = {};
if (!key) { if (!key) {
throw new Error("A VirtualBaton must specify a key."); throw new Error("A VirtualBaton must specify a key.");
} }
@ -54,7 +54,8 @@ virtualBaton = function virtualBaton(options) {
} }
function doRelease() { function doRelease() {
var callback = releaseCallback, oldAccepted = accepted; var callback = releaseCallback, oldAccepted = accepted;
accepted = releaseCallback = undefined; releaseCallback = undefined;
accepted = {number: oldAccepted.number, proposerId: oldAccepted.proposerId};
debug('baton: doRelease', key, callback); debug('baton: doRelease', key, callback);
if (!callback) { return; } // Already released, but we might still receive a stale message. That's ok. if (!callback) { return; } // Already released, but we might still receive a stale message. That's ok.
Messages.messageReceived.disconnect(messageHandler); Messages.messageReceived.disconnect(messageHandler);
@ -68,7 +69,7 @@ virtualBaton = function virtualBaton(options) {
// still have to deal with the same issues of verification in the presence of lost/delayed/reordered messages. // still have to deal with the same issues of verification in the presence of lost/delayed/reordered messages.
// Paxos is known to be optimal under these circumstances, except that its best to have a dedicated proposer // Paxos is known to be optimal under these circumstances, except that its best to have a dedicated proposer
// (such as the server). // (such as the server).
function acceptedId() { return accepted && accepted.winner; } function acceptedId() { return accepted && accepted.winner; } // fixme doesn't need to be so fancy any more?
// Paxos makes several tests of one "proposal number" versus another, assuming // Paxos makes several tests of one "proposal number" versus another, assuming
// that better proposals from the same proposer have a higher number, // that better proposals from the same proposer have a higher number,
// and different proposers use a different set of numbers. We achieve that // and different proposers use a different set of numbers. We achieve that
@ -84,14 +85,13 @@ virtualBaton = function virtualBaton(options) {
if (electionWatchdog) { Script.clearTimeout(electionWatchdog); } if (electionWatchdog) { Script.clearTimeout(electionWatchdog); }
if (!claimCallback) { return; } // We're not participating. if (!claimCallback) { return; } // We're not participating.
nPromises = 0; nPromises = 0;
nQuorum = Math.floor(AvatarList.getAvatarIdentifiers().length / 2) + 1; nQuorum = Math.floor(AvatarList.getAvatarIdentifiers().length / 2) + 1; // N.B.: ASSUMES EVERY USER IS RUNNING THE SCRIPT!
bestPromise.proposerId = MyAvatar.sessionUUID; bestPromise.proposerId = MyAvatar.sessionUUID;
bestPromise.number++; bestPromise.number++;
bestPromise.winner = claim; bestPromise.winner = claim;
send('prepare!', bestPromise); send('prepare!', bestPromise);
electionWatchdog = Script.setTimeout(function () { function reclaim() { propose(claim); }
propose(claim); electionWatchdog = Script.setTimeout(reclaim, electionTimeout);
}, electionTimeout);
} }
function messageHandler(messageChannel, messageString, senderID) { function messageHandler(messageChannel, messageString, senderID) {
if (messageChannel !== channel) { return; } if (messageChannel !== channel) { return; }
@ -105,14 +105,15 @@ virtualBaton = function virtualBaton(options) {
//FIXME bestPromise.number = Math.max(bestPromise.number, data.number); //FIXME bestPromise.number = Math.max(bestPromise.number, data.number);
if (betterNumber(data, bestProposal)) { if (betterNumber(data, bestProposal)) {
var response = accepted || data; bestProposal = data;
if (!response.winner && claimCallback) { if (claimCallback) {
// Optimization: Let the proposer know we're interested in the job if the proposer doesn't // Optimization: Let the proposer know we're interested in the job if the proposer doesn't
// know who else to pick. Avoids needing to start multiple simultaneous proposals. // know who else to pick. Avoids needing to start multiple simultaneous proposals.
response.interested = MyAvatar.sessionUUID; accepted.interested = MyAvatar.sessionUUID;
} }
bestProposal = data; send('promise', accepted.winner ? // data must include proposerId so that proposer catalogs results.
send('promise', response); {number: accepted.number, proposerId: data.proposerId, winner: accepted.winner} :
{proposerId: data.proposerId});
} // FIXME nack? } // FIXME nack?
break; break;
case 'promise': case 'promise':
@ -137,7 +138,7 @@ virtualBaton = function virtualBaton(options) {
break; break;
case 'accepted': case 'accepted':
accepted = data; accepted = data;
if (acceptedId() === MyAvatar.sessionUUID) { // Note that we might not been the proposer. if (acceptedId() === MyAvatar.sessionUUID) { // Note that we might not have been the proposer.
if (electionWatchdog) { if (electionWatchdog) {
Script.clearTimeout(electionWatchdog); Script.clearTimeout(electionWatchdog);
electionWatchdog = null; electionWatchdog = null;

View file

@ -12,7 +12,7 @@ var Vec3, Quat, MyAvatar, Entities, Camera, Script, print;
// All participants should run the test script. // All participants should run the test script.
Script.include("../libraries/virtualBaton.21.js"); Script.include("../libraries/virtualBaton.25.js");
var TICKER_INTERVAL = 1000; // ms var TICKER_INTERVAL = 1000; // ms
var baton = virtualBaton({key: 'io.highfidelity.testBaton'}); var baton = virtualBaton({key: 'io.highfidelity.testBaton'});
var ticker, countDown; var ticker, countDown;