wifi-densepose/vendor/ruvector/npm/packages/raft/src/state.js

158 lines
4.9 KiB
JavaScript

"use strict";
/**
* Raft State Management
* Manages persistent and volatile state for Raft consensus
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.RaftState = void 0;
const log_js_1 = require("./log.js");
/** State manager for a Raft node */
class RaftState {
constructor(nodeId, peers, options) {
this.nodeId = nodeId;
this.peers = peers;
this._currentTerm = 0;
this._votedFor = null;
this._commitIndex = 0;
this._lastApplied = 0;
this._leaderState = null;
this.log = new log_js_1.RaftLog({ onPersist: options?.onLogPersist });
this.persistCallback = options?.onPersist;
}
/** Get current term */
get currentTerm() {
return this._currentTerm;
}
/** Get voted for */
get votedFor() {
return this._votedFor;
}
/** Get commit index */
get commitIndex() {
return this._commitIndex;
}
/** Get last applied */
get lastApplied() {
return this._lastApplied;
}
/** Get leader state (null if not leader) */
get leaderState() {
return this._leaderState;
}
/** Update term (with persistence) */
async setTerm(term) {
if (term > this._currentTerm) {
this._currentTerm = term;
this._votedFor = null;
await this.persist();
}
}
/** Record vote (with persistence) */
async vote(term, candidateId) {
this._currentTerm = term;
this._votedFor = candidateId;
await this.persist();
}
/** Update commit index */
setCommitIndex(index) {
if (index > this._commitIndex) {
this._commitIndex = index;
}
}
/** Update last applied */
setLastApplied(index) {
if (index > this._lastApplied) {
this._lastApplied = index;
}
}
/** Initialize leader state */
initLeaderState() {
const nextIndex = new Map();
const matchIndex = new Map();
for (const peer of this.peers) {
// Initialize nextIndex to leader's last log index + 1
nextIndex.set(peer, this.log.lastIndex + 1);
// Initialize matchIndex to 0
matchIndex.set(peer, 0);
}
this._leaderState = { nextIndex, matchIndex };
}
/** Clear leader state */
clearLeaderState() {
this._leaderState = null;
}
/** Update nextIndex for a peer */
setNextIndex(peerId, index) {
if (this._leaderState) {
this._leaderState.nextIndex.set(peerId, Math.max(1, index));
}
}
/** Update matchIndex for a peer */
setMatchIndex(peerId, index) {
if (this._leaderState) {
this._leaderState.matchIndex.set(peerId, index);
}
}
/** Get nextIndex for a peer */
getNextIndex(peerId) {
return this._leaderState?.nextIndex.get(peerId) ?? this.log.lastIndex + 1;
}
/** Get matchIndex for a peer */
getMatchIndex(peerId) {
return this._leaderState?.matchIndex.get(peerId) ?? 0;
}
/** Update commit index based on match indices (for leader) */
updateCommitIndex() {
if (!this._leaderState)
return false;
// Find the highest index N such that a majority have matchIndex >= N
// and log[N].term == currentTerm
const matchIndices = Array.from(this._leaderState.matchIndex.values());
matchIndices.push(this.log.lastIndex); // Include self
matchIndices.sort((a, b) => b - a); // Sort descending
const majority = Math.floor((this.peers.length + 1) / 2) + 1;
for (const index of matchIndices) {
if (index <= this._commitIndex)
break;
const term = this.log.termAt(index);
if (term === this._currentTerm) {
// Count how many have this index or higher
const count = matchIndices.filter((m) => m >= index).length + 1; // +1 for self
if (count >= majority) {
this._commitIndex = index;
return true;
}
}
}
return false;
}
/** Get persistent state */
getPersistentState() {
return {
currentTerm: this._currentTerm,
votedFor: this._votedFor,
log: this.log.getAll(),
};
}
/** Get volatile state */
getVolatileState() {
return {
commitIndex: this._commitIndex,
lastApplied: this._lastApplied,
};
}
/** Load persistent state */
loadPersistentState(state) {
this._currentTerm = state.currentTerm;
this._votedFor = state.votedFor;
this.log.load(state.log);
}
/** Persist state */
async persist() {
if (this.persistCallback) {
await this.persistCallback(this.getPersistentState());
}
}
}
exports.RaftState = RaftState;
//# sourceMappingURL=state.js.map