nodeway-raft
Version:
It is an implementation of the Raft consensus algorithm in Nodeway.
77 lines (71 loc) • 2.64 kB
JavaScript
'use strict';
class Leader {
constructor(node, currentTerm, log) {
this.node = node;
this.currentTerm = currentTerm;
this.log = log;
this.nextIndex = {};
this.matchIndex = {};
this.requestAppend();
}
setHeartbeatInterval(heartbeatInterval) {
this.heartbeatInterval = setInterval(
this.requestAppend.bind(this),
heartbeatInterval
);
}
clearHeartbeatInterval() {
clearInterval(this.heartbeatInterval);
}
requestAppend(_id) {
function replicate(id) {
if (typeof this.nextIndex[id]==='undefined')
this.nextIndex[id] = this.log.size()+1;
if (typeof this.matchIndex[id]==='undefined')
this.matchIndex[id] = 0;
let prevLogIndex = this.nextIndex[id]-1,
prevLogTerm = this.log.termAt(prevLogIndex),
entry = this.log.entryAt(this.nextIndex[id]);
return {
term: this.currentTerm,
prevLogIndex,
prevLogTerm,
entries: entry ? [entry] : [],
commitIndex: this.log.commitIndex
}
}
_id ? this.node.emit(_id, 'AppendEntries', replicate.bind(this))
: this.node.broadcast('AppendEntries', replicate.bind(this));
}
onAppendEntries(id, args) {
if (args.success) {
this.nextIndex[id] = args.matchIndex+1;
this.matchIndex[id] = args.matchIndex;
let index = Object.keys(this.matchIndex)
.map(id => this.matchIndex[id])
.concat(this.log.size())
.sort((a, b) => b-a),
agree = this.node.majority();
if (agree < index.length && this.log.termAt(index[agree])===this.currentTerm) {
let prevCommitIndex = this.log.commitIndex;
this.log.commitIndex = index[agree];
if (this.log.commitIndex > prevCommitIndex) {
setImmediate(this.requestAppend.bind(this));
return;
}
}
}
else {
this.nextIndex[id] = Math.max(this.nextIndex[id]-1, 1);
}
this.nextIndex[id]<=this.log.size() && this.requestAppend(id);
}
appendEntry(entry, nocb) {
entry.state = 'leader';
entry.term = this.currentTerm;
entry.nocb = nocb;
this.log.push(entry);
this.node.majority() ? this.requestAppend() : this.log.commitIndex++;
}
}
module.exports = Leader;