Compare commits

..

No commits in common. "b8701b4aa7c06086c1e91cd8887bee9f5d487534" and "c4cc30027ab0247eda9a647c406c47a275c9cc80" have entirely different histories.

2 changed files with 36 additions and 35 deletions

View File

@ -188,36 +188,41 @@ class TinyRaft extends EventEmitter
{
this.leader = msg.leader;
this.term = msg.term;
this.state = CANDIDATE;
this.state = FOLLOWER;
this.followers = null;
this._nextTerm(this.heartbeatTimeout*2 + this.electionTimeout);
this.emit('change', { state: this.state, term: this.term, leader: this.leader });
}
this.send(from, { type: VOTE, term: this.term, leader: this.leader });
}
else if (msg.type == VOTE && msg.term == this.term)
else if (msg.type == VOTE)
{
if (msg.term == this.term)
{
this.voted++;
this.votes[msg.leader] = this.votes[msg.leader] || [];
this.votes[msg.leader].push(from);
const n = this.votes[msg.leader].length;
if (n == 1 + (0 | this.nodes.length/2) && msg.leader == this.nodeId)
if (n > this.nodes.length/2 && n-1 <= this.nodes.length/2)
{
this.leader = msg.leader;
this.state = LEADER;
this.state = (this.leader == this.nodeId ? LEADER : FOLLOWER);
if (this.state == LEADER)
{
this._nextTerm(this.leadershipTimeout > 0 ? this.leadershipTimeout : -1);
this.followers = this.votes[this.nodeId];
for (const follower of this.followers)
{
// Send a heartbeat to confirm leadership
this.send(follower, { type: PING, term: this.term });
}
this.emit('change', { state: this.state, term: this.term, leader: this.nodeId, followers: this.votes[this.nodeId] });
}
else
{
this.followers = null;
this._nextTerm(this.heartbeatTimeout*2 + this.electionTimeout);
this.emit('change', { state: this.state, term: this.term, leader: this.leader });
}
}
else if (n > this.nodes.length/2 && this.state == LEADER && msg.leader == this.nodeId)
{
this.followers = this.votes[this.nodeId];
// Send a heartbeat to confirm leadership
this.send(from, { type: PING, term: this.term });
this.emit('change', { state: this.state, term: this.term, leader: this.nodeId, followers: this.votes[this.nodeId] });
}
else if (this._isVotingFailed())
@ -225,13 +230,9 @@ class TinyRaft extends EventEmitter
this._nextTerm(0);
}
}
}
else if (msg.type == PING)
{
if (this.state == CANDIDATE && this.term == msg.term && from == this.leader)
{
this.state = FOLLOWER;
this.emit('change', { state: this.state, term: this.term, leader: this.nodeId });
}
if (this.state == FOLLOWER && from == this.leader)
{
this.markAlive();

View File

@ -67,12 +67,12 @@ function checkQuorum(nodes, count)
function checkNoQuorum(nodes)
{
const nc = Object.values(nodes).filter(n => n.state != TinyRaft.CANDIDATE);
if (nc.length > 0)
const leaders = Object.values(nodes).filter(n => n.state == TinyRaft.LEADER);
if (leaders.length > 0)
{
throw new Error('we have non-candidates ('+nc.map(n => n.nodeId).join(', ')+'), but we should not');
throw new Error('we have a leader ('+leaders.map(n => n.nodeId).join(', ')+'), but we should not');
}
console.log('OK: '+Object.keys(nodes).length+' candidates, no quorum');
console.log('OK: '+Object.keys(nodes).length+' nodes, no quorum');
}
async function testStartThenRemoveNode()