@@ -5851,3 +5851,56 @@ fn test_switching_check_quorum() {
5851
5851
}
5852
5852
assert_eq ! ( sm. state, StateRole :: Leader ) ;
5853
5853
}
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
+ }
0 commit comments