Skip to content

Commit e8a9669

Browse files
committed
raft: ignore setting the lead field from a MsgDeFortify at current term
When receiving a MsgDeFortifyLeader at the same term as we are, we should not set the lead field to the sender. Mainly for two reasons: 1) By definition, a MsgDeFortifyLeader is sent by an ex-leader until it hears of a new committed term. If we forgot the leader at the current term, we shouldn't remember it since we are using the fact that lead==None to indicate that this replica has been leaderless for some time. Read the leaderlessWatcher for more details. 2) This could lead to a situation where no replica can win an election as it could require votes from some replicas that still know who know the leader is (due to MsgDefortifyLeader), and that have recently campaigned and lost due to not having the most up-to-date log, which reset the electionElapsed to 0. Meaning that this replica is in a heartbeat lease, and will reject MsgVotes. Fixes: #142994 Release note: None
1 parent 9a72322 commit e8a9669

File tree

2 files changed

+100
-14
lines changed

2 files changed

+100
-14
lines changed

pkg/raft/raft.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2258,11 +2258,11 @@ func stepCandidate(r *raft, m pb.Message) error {
22582258

22592259
func stepFollower(r *raft, m pb.Message) error {
22602260
if IsMsgFromLeader(m.Type) {
2261-
r.setLead(m.From)
22622261
if m.Type != pb.MsgDeFortifyLeader {
22632262
// If we receive any message from the leader except a MsgDeFortifyLeader,
22642263
// we know that the leader is still alive and still acting as the leader,
22652264
// so reset the election timer.
2265+
r.setLead(m.From)
22662266
r.electionElapsed = 0
22672267
}
22682268
}

pkg/raft/testdata/liveness_impacted_after_temporary_loss_of_quorum.txt renamed to pkg/raft/testdata/liveness_recovered_after_temporary_loss_of_quorum.txt

Lines changed: 99 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
# This test ensures that if there is a temporary blip that causes loss of
22
# quorum, the liveness of the raft group is restored once the blip is fixed.
3-
# Right now, there is a bug where no peer will be able to become a leader, and
4-
# liveness could be stalled indefinitely.
53

64
log-level none
75
----
@@ -144,9 +142,6 @@ stabilize
144142
1->2 MsgDeFortifyLeader Term:1 Log:0/0
145143
> 2 receiving messages
146144
1->2 MsgDeFortifyLeader Term:1 Log:0/0
147-
> 2 handling Ready
148-
Ready MustSync=true:
149-
HardState Term:1 Vote:1 Commit:11 Lead:1 LeadEpoch:0
150145

151146
# Fix the randomized election timeout to be one tick-election.
152147
set-randomized-election-timeout 1 timeout=3
@@ -170,13 +165,104 @@ stabilize
170165
INFO 1 has received 1 MsgPreVoteResp votes and 0 vote rejections
171166
> 2 receiving messages
172167
1->2 MsgPreVote Term:2 Log:1/12
173-
INFO 2 [logterm: 1, index: 11, vote: 1] ignored MsgPreVote from 1 [logterm: 1, index: 12] at term 1: recently received communication from leader (remaining ticks: 3)
174-
175-
# At this point we saw that both peers attempted to campaign, but non of them
176-
# succeeded. Peer 1's request got rejected because 2 recently heard from 1
177-
# when receiving the MsgDefortifyLeader request.
178-
# Note that now 2 thinks that 1 is the leader for term 1, even though it isn't.
168+
INFO 2 [logterm: 1, index: 11, vote: 1] cast MsgPreVote for 1 [logterm: 1, index: 12] at term 1
169+
> 2 handling Ready
170+
Ready MustSync=false:
171+
Messages:
172+
2->1 MsgPreVoteResp Term:2 Log:0/0
173+
> 1 receiving messages
174+
2->1 MsgPreVoteResp Term:2 Log:0/0
175+
INFO 1 received MsgPreVoteResp from 2 at term 1
176+
INFO 1 has received 2 MsgPreVoteResp votes and 0 vote rejections
177+
INFO 1 became candidate at term 2
178+
INFO 1 [logterm: 1, index: 12] sent MsgVote request to 2 at term 2
179+
> 1 handling Ready
180+
Ready MustSync=true:
181+
State:StateCandidate
182+
HardState Term:2 Vote:1 Commit:11 Lead:0 LeadEpoch:0
183+
Messages:
184+
1->2 MsgVote Term:2 Log:1/12
185+
INFO 1 received MsgVoteResp from 1 at term 2
186+
INFO 1 has received 1 MsgVoteResp votes and 0 vote rejections
187+
> 2 receiving messages
188+
1->2 MsgVote Term:2 Log:1/12
189+
INFO 2 [term: 1] received a MsgVote message with higher term from 1 [term: 2], advancing term
190+
INFO 2 became follower at term 2
191+
INFO 2 [logterm: 1, index: 11, vote: 0] cast MsgVote for 1 [logterm: 1, index: 12] at term 2
192+
> 2 handling Ready
193+
Ready MustSync=true:
194+
HardState Term:2 Vote:1 Commit:11 Lead:0 LeadEpoch:0
195+
Messages:
196+
2->1 MsgVoteResp Term:2 Log:0/0
197+
> 1 receiving messages
198+
2->1 MsgVoteResp Term:2 Log:0/0
199+
INFO 1 received MsgVoteResp from 2 at term 2
200+
INFO 1 has received 2 MsgVoteResp votes and 0 vote rejections
201+
INFO 1 became leader at term 2
202+
> 1 handling Ready
203+
Ready MustSync=true:
204+
State:StateLeader
205+
HardState Term:2 Vote:1 Commit:11 Lead:1 LeadEpoch:1
206+
Entries:
207+
2/13 EntryNormal ""
208+
Messages:
209+
1->2 MsgFortifyLeader Term:2 Log:0/0
210+
1->2 MsgApp Term:2 Log:1/12 Commit:11 Entries:[2/13 EntryNormal ""]
211+
> 2 receiving messages
212+
1->2 MsgFortifyLeader Term:2 Log:0/0
213+
1->2 MsgApp Term:2 Log:1/12 Commit:11 Entries:[2/13 EntryNormal ""]
214+
> 2 handling Ready
215+
Ready MustSync=true:
216+
HardState Term:2 Vote:1 Commit:11 Lead:1 LeadEpoch:1
217+
Messages:
218+
2->1 MsgFortifyLeaderResp Term:2 Log:0/0 LeadEpoch:1
219+
2->1 MsgAppResp Term:2 Log:1/12 Rejected (Hint: 11) Commit:11
220+
> 1 receiving messages
221+
2->1 MsgFortifyLeaderResp Term:2 Log:0/0 LeadEpoch:1
222+
2->1 MsgAppResp Term:2 Log:1/12 Rejected (Hint: 11) Commit:11
223+
> 1 handling Ready
224+
Ready MustSync=false:
225+
Messages:
226+
1->2 MsgApp Term:2 Log:1/11 Commit:11 Entries:[
227+
1/12 EntryNormal "data1"
228+
2/13 EntryNormal ""
229+
]
230+
> 2 receiving messages
231+
1->2 MsgApp Term:2 Log:1/11 Commit:11 Entries:[
232+
1/12 EntryNormal "data1"
233+
2/13 EntryNormal ""
234+
]
235+
> 2 handling Ready
236+
Ready MustSync=true:
237+
Entries:
238+
1/12 EntryNormal "data1"
239+
2/13 EntryNormal ""
240+
Messages:
241+
2->1 MsgAppResp Term:2 Log:0/13 Commit:11
242+
> 1 receiving messages
243+
2->1 MsgAppResp Term:2 Log:0/13 Commit:11
244+
> 1 handling Ready
245+
Ready MustSync=true:
246+
HardState Term:2 Vote:1 Commit:13 Lead:1 LeadEpoch:1
247+
CommittedEntries:
248+
1/12 EntryNormal "data1"
249+
2/13 EntryNormal ""
250+
Messages:
251+
1->2 MsgApp Term:2 Log:2/13 Commit:13
252+
> 2 receiving messages
253+
1->2 MsgApp Term:2 Log:2/13 Commit:13
254+
> 2 handling Ready
255+
Ready MustSync=true:
256+
HardState Term:2 Vote:1 Commit:13 Lead:1 LeadEpoch:1
257+
CommittedEntries:
258+
1/12 EntryNormal "data1"
259+
2/13 EntryNormal ""
260+
Messages:
261+
2->1 MsgAppResp Term:2 Log:0/13 Commit:13
262+
> 1 receiving messages
263+
2->1 MsgAppResp Term:2 Log:0/13 Commit:13
264+
179265
raft-state
180266
----
181-
1: StatePreCandidate (Voter) Term:1 Lead:0 LeadEpoch:0
182-
2: StateFollower (Voter) Term:1 Lead:1 LeadEpoch:0
267+
1: StateLeader (Voter) Term:2 Lead:1 LeadEpoch:1
268+
2: StateFollower (Voter) Term:2 Lead:1 LeadEpoch:1

0 commit comments

Comments
 (0)