raft: do not resend snapshot if not necessary

raft relies on the link layer to report the status of the sent snapshot.
If the snapshot is still sending, the replication to that remote peer will
be paused. If the snapshot finish sending, the replication will begin
optimistically after electionTimeout. If the snapshot fails, raft will
try to resend it.
This commit is contained in:
Xiang Li
2015-02-24 21:38:18 -08:00
committed by Yicheng Qin
parent 2185ac5ac8
commit 9b4d52ee73
8 changed files with 225 additions and 15 deletions

View File

@@ -22,6 +22,13 @@ import (
pb "github.com/coreos/etcd/raft/raftpb"
)
type SnapshotStatus int
const (
SnapshotFinish SnapshotStatus = 1
SnapshotFailure SnapshotStatus = 2
)
var (
emptyState = pb.HardState{}
@@ -68,6 +75,8 @@ type Ready struct {
// Messages specifies outbound messages to be sent AFTER Entries are
// committed to stable storage.
// If it contains a MsgSnap message, the application MUST report back to raft
// when the snapshot has been received or has failed by calling ReportSnapshot.
Messages []pb.Message
}
@@ -121,6 +130,8 @@ type Node interface {
Status() Status
// Report reports the given node is not reachable for the last send.
ReportUnreachable(id uint64)
// ReportSnapshot reports the stutus of the sent snapshot.
ReportSnapshot(id uint64, status SnapshotStatus)
// Stop performs any necessary termination of the Node
Stop()
}
@@ -427,6 +438,15 @@ func (n *node) ReportUnreachable(id uint64) {
}
}
func (n *node) ReportSnapshot(id uint64, status SnapshotStatus) {
rej := status == SnapshotFailure
select {
case n.recvc <- pb.Message{Type: pb.MsgSnapStatus, From: id, Reject: rej}:
case <-n.done:
}
}
func newReady(r *raft, prevSoftSt *SoftState, prevHardSt pb.HardState) Ready {
rd := Ready{
Entries: r.raftLog.unstableEntries(),