Compare commits
No commits in common. "c4cc30027ab0247eda9a647c406c47a275c9cc80" and "b8701b4aa7c06086c1e91cd8887bee9f5d487534" have entirely different histories.
c4cc30027a
...
b8701b4aa7
31
tinyraft.js
31
tinyraft.js
|
@ -188,41 +188,36 @@ class TinyRaft extends EventEmitter
|
||||||
{
|
{
|
||||||
this.leader = msg.leader;
|
this.leader = msg.leader;
|
||||||
this.term = msg.term;
|
this.term = msg.term;
|
||||||
this.state = FOLLOWER;
|
this.state = CANDIDATE;
|
||||||
this.followers = null;
|
|
||||||
this._nextTerm(this.heartbeatTimeout*2 + this.electionTimeout);
|
this._nextTerm(this.heartbeatTimeout*2 + this.electionTimeout);
|
||||||
this.emit('change', { state: this.state, term: this.term, leader: this.leader });
|
this.emit('change', { state: this.state, term: this.term, leader: this.leader });
|
||||||
}
|
}
|
||||||
this.send(from, { type: VOTE, term: this.term, leader: this.leader });
|
this.send(from, { type: VOTE, term: this.term, leader: this.leader });
|
||||||
}
|
}
|
||||||
else if (msg.type == VOTE)
|
else if (msg.type == VOTE && msg.term == this.term)
|
||||||
{
|
|
||||||
if (msg.term == this.term)
|
|
||||||
{
|
{
|
||||||
this.voted++;
|
this.voted++;
|
||||||
this.votes[msg.leader] = this.votes[msg.leader] || [];
|
this.votes[msg.leader] = this.votes[msg.leader] || [];
|
||||||
this.votes[msg.leader].push(from);
|
this.votes[msg.leader].push(from);
|
||||||
const n = this.votes[msg.leader].length;
|
const n = this.votes[msg.leader].length;
|
||||||
if (n > this.nodes.length/2 && n-1 <= this.nodes.length/2)
|
if (n == 1 + (0 | this.nodes.length/2) && msg.leader == this.nodeId)
|
||||||
{
|
{
|
||||||
this.leader = msg.leader;
|
this.leader = msg.leader;
|
||||||
this.state = (this.leader == this.nodeId ? LEADER : FOLLOWER);
|
this.state = LEADER;
|
||||||
if (this.state == LEADER)
|
|
||||||
{
|
|
||||||
this._nextTerm(this.leadershipTimeout > 0 ? this.leadershipTimeout : -1);
|
this._nextTerm(this.leadershipTimeout > 0 ? this.leadershipTimeout : -1);
|
||||||
this.followers = this.votes[this.nodeId];
|
this.followers = this.votes[this.nodeId];
|
||||||
this.emit('change', { state: this.state, term: this.term, leader: this.nodeId, followers: this.votes[this.nodeId] });
|
for (const follower of this.followers)
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
this.followers = null;
|
// Send a heartbeat to confirm leadership
|
||||||
this._nextTerm(this.heartbeatTimeout*2 + this.electionTimeout);
|
this.send(follower, { type: PING, term: this.term });
|
||||||
this.emit('change', { state: this.state, term: this.term, leader: this.leader });
|
|
||||||
}
|
}
|
||||||
|
this.emit('change', { state: this.state, term: this.term, leader: this.nodeId, followers: this.votes[this.nodeId] });
|
||||||
}
|
}
|
||||||
else if (n > this.nodes.length/2 && this.state == LEADER && msg.leader == this.nodeId)
|
else if (n > this.nodes.length/2 && this.state == LEADER && msg.leader == this.nodeId)
|
||||||
{
|
{
|
||||||
this.followers = this.votes[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] });
|
this.emit('change', { state: this.state, term: this.term, leader: this.nodeId, followers: this.votes[this.nodeId] });
|
||||||
}
|
}
|
||||||
else if (this._isVotingFailed())
|
else if (this._isVotingFailed())
|
||||||
|
@ -230,9 +225,13 @@ class TinyRaft extends EventEmitter
|
||||||
this._nextTerm(0);
|
this._nextTerm(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if (msg.type == PING)
|
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)
|
if (this.state == FOLLOWER && from == this.leader)
|
||||||
{
|
{
|
||||||
this.markAlive();
|
this.markAlive();
|
||||||
|
|
|
@ -67,12 +67,12 @@ function checkQuorum(nodes, count)
|
||||||
|
|
||||||
function checkNoQuorum(nodes)
|
function checkNoQuorum(nodes)
|
||||||
{
|
{
|
||||||
const leaders = Object.values(nodes).filter(n => n.state == TinyRaft.LEADER);
|
const nc = Object.values(nodes).filter(n => n.state != TinyRaft.CANDIDATE);
|
||||||
if (leaders.length > 0)
|
if (nc.length > 0)
|
||||||
{
|
{
|
||||||
throw new Error('we have a leader ('+leaders.map(n => n.nodeId).join(', ')+'), but we should not');
|
throw new Error('we have non-candidates ('+nc.map(n => n.nodeId).join(', ')+'), but we should not');
|
||||||
}
|
}
|
||||||
console.log('OK: '+Object.keys(nodes).length+' nodes, no quorum');
|
console.log('OK: '+Object.keys(nodes).length+' candidates, no quorum');
|
||||||
}
|
}
|
||||||
|
|
||||||
async function testStartThenRemoveNode()
|
async function testStartThenRemoveNode()
|
||||||
|
|
Loading…
Reference in New Issue