fix(raft): state machine callback, start from main, remove asyncCheck, config
- applyCommand callback: committed entries applied to state machine - lastApplied incremented on commit via applyCommitted() - RaftNetwork.run() started from main() when raftEnabled=true - asyncCheck replaced with try/await in processMessage - bindAddr without hardcoded 127.0.0.1 - raft config: raftEnabled/Port/Peers/NodeId + env vars - 283 tests, 0 failures
This commit is contained in:
@@ -29,6 +29,10 @@ type
|
||||
jwtSecret*: string
|
||||
rateLimitGlobal*: int
|
||||
rateLimitPerClient*: int
|
||||
raftEnabled*: bool
|
||||
raftPort*: int
|
||||
raftPeers*: seq[string]
|
||||
raftNodeId*: string
|
||||
|
||||
CompactionStrategy* = enum
|
||||
csSizeTiered = "size_tiered"
|
||||
@@ -61,6 +65,10 @@ proc defaultConfig*(): BaraConfig =
|
||||
jwtSecret: "",
|
||||
rateLimitGlobal: 10_000,
|
||||
rateLimitPerClient: 1_000,
|
||||
raftEnabled: false,
|
||||
raftPort: 9473,
|
||||
raftPeers: @[],
|
||||
raftNodeId: "",
|
||||
)
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
@@ -152,6 +160,12 @@ proc loadConfigFromEnv*(cfg: var BaraConfig) =
|
||||
cfg.jwtSecret = getEnv("BARADB_JWT_SECRET", cfg.jwtSecret)
|
||||
cfg.rateLimitGlobal = parseEnvInt(getEnv("BARADB_RATE_LIMIT_GLOBAL", ""), cfg.rateLimitGlobal)
|
||||
cfg.rateLimitPerClient = parseEnvInt(getEnv("BARADB_RATE_LIMIT_PER_CLIENT", ""), cfg.rateLimitPerClient)
|
||||
cfg.raftEnabled = parseEnvBool(getEnv("BARADB_RAFT_ENABLED", ""), cfg.raftEnabled)
|
||||
cfg.raftPort = parseEnvInt(getEnv("BARADB_RAFT_PORT", ""), cfg.raftPort)
|
||||
let peersEnv = getEnv("BARADB_RAFT_PEERS", "")
|
||||
if peersEnv.len > 0:
|
||||
cfg.raftPeers = peersEnv.split(",")
|
||||
cfg.raftNodeId = getEnv("BARADB_RAFT_NODE_ID", cfg.raftNodeId)
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Master Loader
|
||||
|
||||
@@ -32,6 +32,8 @@ type
|
||||
log*: seq[LogEntry]
|
||||
commitIndex*: uint64
|
||||
lastApplied*: uint64
|
||||
# State machine callback
|
||||
applyCommand*: proc(cmd: string, data: seq[byte]) {.gcsafe.}
|
||||
# Leader state
|
||||
nextIndex*: Table[string, uint64]
|
||||
matchIndex*: Table[string, uint64]
|
||||
@@ -115,6 +117,15 @@ proc lastLogTerm*(node: RaftNode): uint64 =
|
||||
return 0
|
||||
return node.log[^1].term
|
||||
|
||||
proc applyCommitted(node: RaftNode) =
|
||||
while node.lastApplied < node.commitIndex:
|
||||
let idx = int(node.lastApplied)
|
||||
if idx < node.log.len:
|
||||
let entry = node.log[idx]
|
||||
if node.applyCommand != nil:
|
||||
node.applyCommand(entry.command, entry.data)
|
||||
inc node.lastApplied
|
||||
|
||||
proc becomeFollower*(node: RaftNode, term: uint64) =
|
||||
node.state = rsFollower
|
||||
node.currentTerm = term
|
||||
@@ -198,6 +209,7 @@ proc handleAppendEntries*(node: RaftNode, msg: RaftMessage): RaftMessage =
|
||||
# Update commit index
|
||||
if msg.leaderCommit > node.commitIndex:
|
||||
node.commitIndex = min(msg.leaderCommit, node.lastLogIndex)
|
||||
node.applyCommitted()
|
||||
|
||||
reply.success = true
|
||||
reply.matchIdx = node.lastLogIndex
|
||||
@@ -283,6 +295,7 @@ proc handleAppendReply*(node: RaftNode, peerId: string, reply: RaftMessage) =
|
||||
if medianIdx <= node.lastLogIndex and
|
||||
node.log[medianIdx - 1].term == node.currentTerm:
|
||||
node.commitIndex = medianIdx
|
||||
node.applyCommitted()
|
||||
else:
|
||||
if node.nextIndex[peerId] > 1:
|
||||
dec node.nextIndex[peerId]
|
||||
@@ -479,7 +492,10 @@ proc receiveLoop(net: RaftNetwork, client: AsyncSocket) {.async.} =
|
||||
for i in 0 ..< payloadLen:
|
||||
payload[i] = byte(payloadStr[i])
|
||||
let msg = deserializeRaftMessage(payload)
|
||||
asyncCheck net.processMessage(msg)
|
||||
try:
|
||||
await net.processMessage(msg)
|
||||
except:
|
||||
discard
|
||||
except:
|
||||
discard
|
||||
finally:
|
||||
@@ -496,7 +512,7 @@ proc heartbeatLoop(net: RaftNetwork) {.async.} =
|
||||
proc run*(net: RaftNetwork) {.async.} =
|
||||
net.socket = newAsyncSocket()
|
||||
net.socket.setSockOpt(OptReuseAddr, true)
|
||||
net.socket.bindAddr(Port(net.node.raftPort), "127.0.0.1")
|
||||
net.socket.bindAddr(Port(net.node.raftPort))
|
||||
net.socket.listen()
|
||||
net.running = true
|
||||
asyncCheck net.heartbeatLoop()
|
||||
|
||||
Reference in New Issue
Block a user