Merge pull request #1823 from xiang90/raft_log

raft: logging state change events and events on bad path
This commit is contained in:
Xiang Li 2014-12-02 10:10:08 -08:00
commit 6692a8060e
4 changed files with 48 additions and 4 deletions

View File

@ -111,9 +111,13 @@ func (l *raftLog) append(after uint64, ents ...pb.Entry) uint64 {
// The index of the given entries MUST be continuously increasing. // The index of the given entries MUST be continuously increasing.
func (l *raftLog) findConflict(from uint64, ents []pb.Entry) uint64 { func (l *raftLog) findConflict(from uint64, ents []pb.Entry) uint64 {
// TODO(xiangli): validate the index of ents // TODO(xiangli): validate the index of ents
for i, ne := range ents { for offset, ne := range ents {
if !l.matchTerm(from+uint64(i), ne.Term) { if i := from + uint64(offset); !l.matchTerm(ne.Index, ne.Term) {
return from + uint64(i) if i <= l.lastIndex() {
log.Printf("raftlog: found conflict at index %d [existing term: %d, conflicting term: %d]",
i, l.term(i), ne.Term)
}
return i
} }
} }
return 0 return 0

View File

@ -16,7 +16,11 @@
package raft package raft
import pb "github.com/coreos/etcd/raft/raftpb" import (
"log"
pb "github.com/coreos/etcd/raft/raftpb"
)
// unstable.entris[i] has raft log position i+unstable.offset. // unstable.entris[i] has raft log position i+unstable.offset.
// Note that unstable.offset may be less than the highest log // Note that unstable.offset may be less than the highest log
@ -102,6 +106,7 @@ func (u *unstable) restore(s pb.Snapshot) {
func (u *unstable) truncateAndAppend(after uint64, ents []pb.Entry) { func (u *unstable) truncateAndAppend(after uint64, ents []pb.Entry) {
switch { switch {
case after < u.offset: case after < u.offset:
log.Printf("raftlog: replace the unstable entries from index %d", after+1)
// The log is being truncated to before our current offset // The log is being truncated to before our current offset
// portion, so set the offset and replace the entries // portion, so set the offset and replace the entries
u.offset = after + 1 u.offset = after + 1
@ -113,6 +118,7 @@ func (u *unstable) truncateAndAppend(after uint64, ents []pb.Entry) {
default: default:
// truncate to after and copy to u.entries // truncate to after and copy to u.entries
// then append // then append
log.Printf("raftlog: truncate the unstable entries to index %d", after)
u.entries = append([]pb.Entry{}, u.slice(u.offset, after+1)...) u.entries = append([]pb.Entry{}, u.slice(u.offset, after+1)...)
u.entries = append(u.entries, ents...) u.entries = append(u.entries, ents...)
} }

View File

@ -19,6 +19,7 @@ package raft
import ( import (
"errors" "errors"
"fmt" "fmt"
"log"
"math/rand" "math/rand"
"sort" "sort"
@ -189,6 +190,11 @@ func (r *raft) String() string {
} }
func (r *raft) poll(id uint64, v bool) (granted int) { func (r *raft) poll(id uint64, v bool) (granted int) {
if v {
log.Printf("raft: %x received vote from %x at term %x", r.id, id, r.Term)
} else {
log.Printf("raft: %x received vote rejection from %x at term %x", r.id, id, r.Term)
}
if _, ok := r.votes[id]; !ok { if _, ok := r.votes[id]; !ok {
r.votes[id] = v r.votes[id] = v
} }
@ -347,6 +353,7 @@ func (r *raft) becomeFollower(term uint64, lead uint64) {
r.tick = r.tickElection r.tick = r.tickElection
r.lead = lead r.lead = lead
r.state = StateFollower r.state = StateFollower
log.Printf("raft: %x became follower at term %d", r.id, r.Term)
} }
func (r *raft) becomeCandidate() { func (r *raft) becomeCandidate() {
@ -359,6 +366,7 @@ func (r *raft) becomeCandidate() {
r.tick = r.tickElection r.tick = r.tickElection
r.Vote = r.id r.Vote = r.id
r.state = StateCandidate r.state = StateCandidate
log.Printf("raft: %x became candidate at term %d", r.id, r.Term)
} }
func (r *raft) becomeLeader() { func (r *raft) becomeLeader() {
@ -381,6 +389,7 @@ func (r *raft) becomeLeader() {
r.pendingConf = true r.pendingConf = true
} }
r.appendEntry(pb.Entry{Data: nil}) r.appendEntry(pb.Entry{Data: nil})
log.Printf("raft: %x became leader at term %d", r.id, r.Term)
} }
func (r *raft) campaign() { func (r *raft) campaign() {
@ -425,6 +434,8 @@ func (r *raft) handleAppendEntries(m pb.Message) {
if mlastIndex, ok := r.raftLog.maybeAppend(m.Index, m.LogTerm, m.Commit, m.Entries...); ok { if mlastIndex, ok := r.raftLog.maybeAppend(m.Index, m.LogTerm, m.Commit, m.Entries...); ok {
r.send(pb.Message{To: m.From, Type: pb.MsgAppResp, Index: mlastIndex}) r.send(pb.Message{To: m.From, Type: pb.MsgAppResp, Index: mlastIndex})
} else { } else {
log.Printf("raft: %x [logterm: %d, index: %d] rejected msgApp [logterm: %d, index: %d] from %x",
r.id, r.raftLog.term(m.Index), m.Index, m.LogTerm, m.Index, m.From)
r.send(pb.Message{To: m.From, Type: pb.MsgAppResp, Index: m.Index, Reject: true}) r.send(pb.Message{To: m.From, Type: pb.MsgAppResp, Index: m.Index, Reject: true})
} }
} }
@ -477,6 +488,8 @@ func stepLeader(r *raft, m pb.Message) {
return return
} }
if m.Reject { if m.Reject {
log.Printf("raft: %x received msgApp rejection from %x for index %d",
r.id, m.From, m.Index)
if r.prs[m.From].maybeDecrTo(m.Index) { if r.prs[m.From].maybeDecrTo(m.Index) {
r.sendAppend(m.From) r.sendAppend(m.From)
} }
@ -487,6 +500,8 @@ func stepLeader(r *raft, m pb.Message) {
} }
} }
case pb.MsgVote: case pb.MsgVote:
log.Printf("raft: %x [logterm: %d, index: %d, vote: %x] rejected vote from %x [logterm: %d, index: %d] at term %x",
r.id, r.raftLog.lastTerm(), r.raftLog.lastIndex(), r.Vote, m.From, m.LogTerm, m.Index, r.Term)
r.send(pb.Message{To: m.From, Type: pb.MsgVoteResp, Reject: true}) r.send(pb.Message{To: m.From, Type: pb.MsgVoteResp, Reject: true})
} }
} }
@ -502,9 +517,12 @@ func stepCandidate(r *raft, m pb.Message) {
r.becomeFollower(m.Term, m.From) r.becomeFollower(m.Term, m.From)
r.handleSnapshot(m) r.handleSnapshot(m)
case pb.MsgVote: case pb.MsgVote:
log.Printf("raft: %x [logterm: %d, index: %d, vote: %x] rejected vote from %x [logterm: %d, index: %d] at term %x",
r.id, r.raftLog.lastTerm(), r.raftLog.lastIndex(), r.Vote, m.From, m.LogTerm, m.Index, r.Term)
r.send(pb.Message{To: m.From, Type: pb.MsgVoteResp, Reject: true}) r.send(pb.Message{To: m.From, Type: pb.MsgVoteResp, Reject: true})
case pb.MsgVoteResp: case pb.MsgVoteResp:
gr := r.poll(m.From, !m.Reject) gr := r.poll(m.From, !m.Reject)
log.Printf("raft: %x [q:%d] has received %d votes and %d vote rejections", r.id, r.q(), gr, len(r.votes)-gr)
switch r.q() { switch r.q() {
case gr: case gr:
r.becomeLeader() r.becomeLeader()
@ -537,9 +555,13 @@ func stepFollower(r *raft, m pb.Message) {
case pb.MsgVote: case pb.MsgVote:
if (r.Vote == None || r.Vote == m.From) && r.raftLog.isUpToDate(m.Index, m.LogTerm) { if (r.Vote == None || r.Vote == m.From) && r.raftLog.isUpToDate(m.Index, m.LogTerm) {
r.elapsed = 0 r.elapsed = 0
log.Printf("raft: %x [logterm: %d, index: %d, vote: %x] voted for %x [logterm: %d, index: %d] at term %x",
r.id, r.raftLog.lastTerm(), r.raftLog.lastIndex(), r.Vote, m.From, m.LogTerm, m.Index, r.Term)
r.Vote = m.From r.Vote = m.From
r.send(pb.Message{To: m.From, Type: pb.MsgVoteResp}) r.send(pb.Message{To: m.From, Type: pb.MsgVoteResp})
} else { } else {
log.Printf("raft: %x [logterm: %d, index: %d, vote: %x] rejected vote from %x [logterm: %d, index: %d] at term %x",
r.id, r.raftLog.lastTerm(), r.raftLog.lastIndex(), r.Vote, m.From, m.LogTerm, m.Index, r.Term)
r.send(pb.Message{To: m.From, Type: pb.MsgVoteResp, Reject: true}) r.send(pb.Message{To: m.From, Type: pb.MsgVoteResp, Reject: true})
} }
} }

View File

@ -29,6 +29,10 @@ package raft
import ( import (
"fmt" "fmt"
"io/ioutil"
"log"
"os"
"reflect" "reflect"
"sort" "sort"
"testing" "testing"
@ -292,9 +296,13 @@ func TestCandidateFallback(t *testing.T) {
} }
func TestFollowerElectionTimeoutRandomized(t *testing.T) { func TestFollowerElectionTimeoutRandomized(t *testing.T) {
log.SetOutput(ioutil.Discard)
defer log.SetOutput(os.Stderr)
testNonleaderElectionTimeoutRandomized(t, StateFollower) testNonleaderElectionTimeoutRandomized(t, StateFollower)
} }
func TestCandidateElectionTimeoutRandomized(t *testing.T) { func TestCandidateElectionTimeoutRandomized(t *testing.T) {
log.SetOutput(ioutil.Discard)
defer log.SetOutput(os.Stderr)
testNonleaderElectionTimeoutRandomized(t, StateCandidate) testNonleaderElectionTimeoutRandomized(t, StateCandidate)
} }
@ -329,9 +337,13 @@ func testNonleaderElectionTimeoutRandomized(t *testing.T, state StateType) {
} }
func TestFollowersElectioinTimeoutNonconflict(t *testing.T) { func TestFollowersElectioinTimeoutNonconflict(t *testing.T) {
log.SetOutput(ioutil.Discard)
defer log.SetOutput(os.Stderr)
testNonleadersElectionTimeoutNonconflict(t, StateFollower) testNonleadersElectionTimeoutNonconflict(t, StateFollower)
} }
func TestCandidatesElectionTimeoutNonconflict(t *testing.T) { func TestCandidatesElectionTimeoutNonconflict(t *testing.T) {
log.SetOutput(ioutil.Discard)
defer log.SetOutput(os.Stderr)
testNonleadersElectionTimeoutNonconflict(t, StateCandidate) testNonleadersElectionTimeoutNonconflict(t, StateCandidate)
} }