@@ -603,65 +603,71 @@ func (r *raft) maybeSendAppend(to uint64, sendIfEmpty bool) bool {
603
603
return false
604
604
}
605
605
606
- lastIndex , nextIndex := pr .Next - 1 , pr .Next
607
- lastTerm , errt := r .raftLog .term (lastIndex )
606
+ prevIndex := pr .Next - 1
607
+ prevTerm , err := r .raftLog .term (prevIndex )
608
+ if err != nil {
609
+ // The log probably got truncated at >= pr.Next, so we can't catch up the
610
+ // follower log anymore. Send a snapshot instead.
611
+ return r .maybeSendSnapshot (to , pr )
612
+ }
608
613
609
614
var ents []pb.Entry
610
- var erre error
611
615
// In a throttled StateReplicate only send empty MsgApp, to ensure progress.
612
616
// Otherwise, if we had a full Inflights and all inflight messages were in
613
617
// fact dropped, replication to that follower would stall. Instead, an empty
614
618
// MsgApp will eventually reach the follower (heartbeats responses prompt the
615
619
// leader to send an append), allowing it to be acked or rejected, both of
616
620
// which will clear out Inflights.
617
621
if pr .State != tracker .StateReplicate || ! pr .Inflights .Full () {
618
- ents , erre = r .raftLog .entries (nextIndex , r .maxMsgSize )
622
+ ents , err = r .raftLog .entries (pr . Next , r .maxMsgSize )
619
623
}
620
-
621
624
if len (ents ) == 0 && ! sendIfEmpty {
622
625
return false
623
626
}
624
-
625
- if errt != nil || erre != nil { // send snapshot if we failed to get term or entries
626
- if ! pr .RecentActive {
627
- r .logger .Debugf ("ignore sending snapshot to %x since it is not recently active" , to )
628
- return false
629
- }
630
-
631
- snapshot , err := r .raftLog .snapshot ()
632
- if err != nil {
633
- if err == ErrSnapshotTemporarilyUnavailable {
634
- r .logger .Debugf ("%x failed to send snapshot to %x because snapshot is temporarily unavailable" , r .id , to )
635
- return false
636
- }
637
- panic (err ) // TODO(bdarnell)
638
- }
639
- if IsEmptySnap (snapshot ) {
640
- panic ("need non-empty snapshot" )
641
- }
642
- sindex , sterm := snapshot .Metadata .Index , snapshot .Metadata .Term
643
- r .logger .Debugf ("%x [firstindex: %d, commit: %d] sent snapshot[index: %d, term: %d] to %x [%s]" ,
644
- r .id , r .raftLog .firstIndex (), r .raftLog .committed , sindex , sterm , to , pr )
645
- pr .BecomeSnapshot (sindex )
646
- r .logger .Debugf ("%x paused sending replication messages to %x [%s]" , r .id , to , pr )
647
-
648
- r .send (pb.Message {To : to , Type : pb .MsgSnap , Snapshot : & snapshot })
649
- return true
627
+ // TODO(pav-kv): move this check up to where err is returned.
628
+ if err != nil { // send a snapshot if we failed to get the entries
629
+ return r .maybeSendSnapshot (to , pr )
650
630
}
651
631
652
632
// Send the actual MsgApp otherwise, and update the progress accordingly.
653
- if err := pr .UpdateOnEntriesSend (len (ents ), uint64 (payloadsSize (ents )), nextIndex ); err != nil {
654
- r .logger .Panicf ("%x: %v" , r .id , err )
655
- }
656
- // NB: pr has been updated, but we make sure to only use its old values below.
657
633
r .send (pb.Message {
658
634
To : to ,
659
635
Type : pb .MsgApp ,
660
- Index : lastIndex ,
661
- LogTerm : lastTerm ,
636
+ Index : prevIndex ,
637
+ LogTerm : prevTerm ,
662
638
Entries : ents ,
663
639
Commit : r .raftLog .committed ,
664
640
})
641
+ pr .UpdateOnEntriesSend (len (ents ), uint64 (payloadsSize (ents )))
642
+ return true
643
+ }
644
+
645
+ // maybeSendSnapshot fetches a snapshot from Storage, and sends it to the given
646
+ // node. Returns true iff the snapshot message has been emitted successfully.
647
+ func (r * raft ) maybeSendSnapshot (to uint64 , pr * tracker.Progress ) bool {
648
+ if ! pr .RecentActive {
649
+ r .logger .Debugf ("ignore sending snapshot to %x since it is not recently active" , to )
650
+ return false
651
+ }
652
+
653
+ snapshot , err := r .raftLog .snapshot ()
654
+ if err != nil {
655
+ if err == ErrSnapshotTemporarilyUnavailable {
656
+ r .logger .Debugf ("%x failed to send snapshot to %x because snapshot is temporarily unavailable" , r .id , to )
657
+ return false
658
+ }
659
+ panic (err ) // TODO(bdarnell)
660
+ }
661
+ if IsEmptySnap (snapshot ) {
662
+ panic ("need non-empty snapshot" )
663
+ }
664
+ sindex , sterm := snapshot .Metadata .Index , snapshot .Metadata .Term
665
+ r .logger .Debugf ("%x [firstindex: %d, commit: %d] sent snapshot[index: %d, term: %d] to %x [%s]" ,
666
+ r .id , r .raftLog .firstIndex (), r .raftLog .committed , sindex , sterm , to , pr )
667
+ pr .BecomeSnapshot (sindex )
668
+ r .logger .Debugf ("%x paused sending replication messages to %x [%s]" , r .id , to , pr )
669
+
670
+ r .send (pb.Message {To : to , Type : pb .MsgSnap , Snapshot : & snapshot })
665
671
return true
666
672
}
667
673
0 commit comments