From eaa0612e0260a6ec16aa3be1f6ced21f059dd794 Mon Sep 17 00:00:00 2001 From: qupeng Date: Fri, 20 Dec 2019 12:07:52 +0800 Subject: [PATCH] raft: abort leader transferring if the target is demoted (#11417) Signed-off-by: qupeng --- raft/raft.go | 4 ++-- raft/raft_test.go | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/raft/raft.go b/raft/raft.go index cdcb43d3f..8f570a75a 100644 --- a/raft/raft.go +++ b/raft/raft.go @@ -1566,8 +1566,8 @@ func (r *raft) switchToConfig(cfg tracker.Config, prs tracker.ProgressMap) pb.Co r.maybeSendAppend(id, false /* sendIfEmpty */) }) } - // If the the leadTransferee was removed, abort the leadership transfer. - if _, tOK := r.prs.Progress[r.leadTransferee]; !tOK && r.leadTransferee != 0 { + // If the the leadTransferee was removed or demoted, abort the leadership transfer. + if _, tOK := r.prs.Config.Voters.IDs()[r.leadTransferee]; !tOK && r.leadTransferee != 0 { r.abortLeaderTransfer() } diff --git a/raft/raft_test.go b/raft/raft_test.go index b4e935edf..87ceb99ca 100644 --- a/raft/raft_test.go +++ b/raft/raft_test.go @@ -3601,6 +3601,38 @@ func TestLeaderTransferRemoveNode(t *testing.T) { checkLeaderTransferState(t, lead, StateLeader, 1) } +func TestLeaderTransferDemoteNode(t *testing.T) { + nt := newNetwork(nil, nil, nil) + nt.send(pb.Message{From: 1, To: 1, Type: pb.MsgHup}) + + nt.ignore(pb.MsgTimeoutNow) + + lead := nt.peers[1].(*raft) + + // The leadTransferee is demoted when leadship transferring. + nt.send(pb.Message{From: 3, To: 1, Type: pb.MsgTransferLeader}) + if lead.leadTransferee != 3 { + t.Fatalf("wait transferring, leadTransferee = %v, want %v", lead.leadTransferee, 3) + } + + lead.applyConfChange(pb.ConfChangeV2{ + Changes: []pb.ConfChangeSingle{ + { + Type: pb.ConfChangeRemoveNode, + NodeID: 3, + }, + { + Type: pb.ConfChangeAddLearnerNode, + NodeID: 3, + }, + }, + }) + + // Make the Raft group commit the LeaveJoint entry. + lead.applyConfChange(pb.ConfChangeV2{}) + checkLeaderTransferState(t, lead, StateLeader, 1) +} + // TestLeaderTransferBack verifies leadership can transfer back to self when last transfer is pending. func TestLeaderTransferBack(t *testing.T) { nt := newNetwork(nil, nil, nil)