Skip to content

Commit 2fbeee5

Browse files
authored
raft: next index shall be larger than match index (#557)
* Fixed a case in progress.go maybe_decr_to that could cause the next value to be less than or equal to the match value in the probe state Close #555. Signed-off-by: wego1236 <844740374@qq.com>
1 parent 63aec46 commit 2fbeee5

File tree

2 files changed

+55
-2
lines changed

2 files changed

+55
-2
lines changed

harness/tests/integration_cases/test_raft.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5851,3 +5851,56 @@ fn test_switching_check_quorum() {
58515851
}
58525852
assert_eq!(sm.state, StateRole::Leader);
58535853
}
5854+
5855+
fn expect_one_message(r: &mut Interface) -> Message {
5856+
let msgs = r.read_messages();
5857+
assert_eq!(msgs.len(), 1, "expect one message");
5858+
msgs[0].clone()
5859+
}
5860+
5861+
#[test]
5862+
fn test_log_replication_with_reordered_message() {
5863+
let l = default_logger();
5864+
let mut r1 = new_test_raft(1, vec![1, 2], 10, 1, new_storage(), &l);
5865+
r1.become_candidate();
5866+
r1.become_leader();
5867+
r1.read_messages();
5868+
r1.mut_prs().get_mut(2).unwrap().become_replicate();
5869+
5870+
let mut r2 = new_test_raft(2, vec![1, 2], 10, 1, new_storage(), &l);
5871+
5872+
// r1 sends 2 MsgApp messages to r2.
5873+
let _ = r1.append_entry(&mut [new_entry(0, 0, SOME_DATA)]);
5874+
r1.send_append(2);
5875+
let req1 = expect_one_message(&mut r1);
5876+
let _ = r1.append_entry(&mut [new_entry(0, 0, SOME_DATA)]);
5877+
r1.send_append(2);
5878+
let req2 = expect_one_message(&mut r1);
5879+
5880+
// r2 receives the second MsgApp first due to reordering.
5881+
let _ = r2.step(req2);
5882+
let resp2 = expect_one_message(&mut r2);
5883+
// r2 rejects req2
5884+
assert!(resp2.reject);
5885+
assert_eq!(resp2.reject_hint, 0);
5886+
assert_eq!(resp2.index, 2);
5887+
5888+
// r2 handles the first MsgApp and responses to r1.
5889+
// And r1 updates match index accordingly.
5890+
let _ = r2.step(req1);
5891+
let m = expect_one_message(&mut r2);
5892+
assert!(!m.reject);
5893+
assert_eq!(m.index, 2);
5894+
let _ = r1.step(m);
5895+
assert_eq!(r1.prs().get(2).unwrap().matched, 2);
5896+
5897+
// r1 observes a transient network issue to r2, hence transits to probe state.
5898+
let _ = r1.step(new_message(2, 1, MessageType::MsgUnreachable, 0));
5899+
assert_eq!(r1.prs().get(2).unwrap().state, ProgressState::Probe);
5900+
5901+
// now r1 receives the delayed resp2.
5902+
let _ = r1.step(resp2);
5903+
let m = expect_one_message(&mut r1);
5904+
// r1 shall re-send MsgApp from match index even if resp2's reject hint is less than matching index.
5905+
assert_eq!(r1.prs().get(2).unwrap().matched, m.index)
5906+
}

src/tracker/progress.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,8 @@ impl Progress {
192192
// Do not decrease next index if it's requesting snapshot.
193193
if request_snapshot == INVALID_INDEX {
194194
self.next_idx = cmp::min(rejected, match_hint + 1);
195-
if self.next_idx < 1 {
196-
self.next_idx = 1;
195+
if self.next_idx < self.matched + 1 {
196+
self.next_idx = self.matched + 1;
197197
}
198198
} else if self.pending_request_snapshot == INVALID_INDEX {
199199
// Allow requesting snapshot even if it's not Replicate.

0 commit comments

Comments
 (0)