mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00
raft: pull checkQuorumActive into prs
It's looking at each voter's Progress and needs to know how quorums work, so this is the ideal new home for it.
This commit is contained in:
parent
a6f222e62d
commit
bc828e939a
@ -381,6 +381,20 @@ func (p *prs) visit(f func(id uint64, pr *Progress)) {
|
||||
}
|
||||
}
|
||||
|
||||
// checkQuorumActive returns true if the quorum is active from
|
||||
// the view of the local raft state machine. Otherwise, it returns
|
||||
// false.
|
||||
func (p *prs) quorumActive() bool {
|
||||
var act int
|
||||
p.visit(func(id uint64, pr *Progress) {
|
||||
if pr.RecentActive && !pr.IsLearner {
|
||||
act++
|
||||
}
|
||||
})
|
||||
|
||||
return act >= p.quorum()
|
||||
}
|
||||
|
||||
func (p *prs) voterNodes() []uint64 {
|
||||
nodes := make([]uint64, 0, len(p.nodes))
|
||||
for id := range p.nodes {
|
||||
|
44
raft/raft.go
44
raft/raft.go
@ -933,10 +933,26 @@ func stepLeader(r *raft, m pb.Message) error {
|
||||
r.bcastHeartbeat()
|
||||
return nil
|
||||
case pb.MsgCheckQuorum:
|
||||
if !r.checkQuorumActive() {
|
||||
// The leader should always see itself as active. As a precaution, handle
|
||||
// the case in which the leader isn't in the configuration any more (for
|
||||
// example if it just removed itself).
|
||||
//
|
||||
// TODO(tbg): I added a TODO in removeNode, it doesn't seem that the
|
||||
// leader steps down when removing itself. I might be missing something.
|
||||
if pr := r.prs.getProgress(r.id); pr != nil {
|
||||
pr.RecentActive = true
|
||||
}
|
||||
if !r.prs.quorumActive() {
|
||||
r.logger.Warningf("%x stepped down to follower since quorum is not active", r.id)
|
||||
r.becomeFollower(r.Term, None)
|
||||
}
|
||||
// Mark everyone (but ourselves) as inactive in preparation for the next
|
||||
// CheckQuorum.
|
||||
r.prs.visit(func(id uint64, pr *Progress) {
|
||||
if id != r.id {
|
||||
pr.RecentActive = false
|
||||
}
|
||||
})
|
||||
return nil
|
||||
case pb.MsgProp:
|
||||
if len(m.Entries) == 0 {
|
||||
@ -1393,6 +1409,9 @@ func (r *raft) removeNode(id uint64) {
|
||||
return
|
||||
}
|
||||
|
||||
// TODO(tbg): won't bad (or at least unfortunate) things happen if the
|
||||
// leader just removed itself?
|
||||
|
||||
// The quorum size is now smaller, so see if any pending entries can
|
||||
// be committed.
|
||||
if r.maybeCommit() {
|
||||
@ -1424,29 +1443,6 @@ func (r *raft) resetRandomizedElectionTimeout() {
|
||||
r.randomizedElectionTimeout = r.electionTimeout + globalRand.Intn(r.electionTimeout)
|
||||
}
|
||||
|
||||
// checkQuorumActive returns true if the quorum is active from
|
||||
// the view of the local raft state machine. Otherwise, it returns
|
||||
// false.
|
||||
// checkQuorumActive also resets all RecentActive to false.
|
||||
func (r *raft) checkQuorumActive() bool {
|
||||
var act int
|
||||
|
||||
r.prs.visit(func(id uint64, pr *Progress) {
|
||||
if id == r.id { // self is always active
|
||||
act++
|
||||
return
|
||||
}
|
||||
|
||||
if pr.RecentActive && !pr.IsLearner {
|
||||
act++
|
||||
}
|
||||
|
||||
pr.RecentActive = false
|
||||
})
|
||||
|
||||
return act >= r.prs.quorum()
|
||||
}
|
||||
|
||||
func (r *raft) sendTimeoutNow(to uint64) {
|
||||
r.send(pb.Message{To: to, Type: pb.MsgTimeoutNow})
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user