Skip to content

Commit

Permalink
Learner needs to respond vote requests. (#58)
Browse files Browse the repository at this point in the history
  • Loading branch information
hicqu authored and BusyJay committed May 12, 2018
1 parent 1beea8c commit a362370
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 34 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ categories = ["algorithms", "database-implementations"]

[dependencies]
log = "0.4.1"
protobuf = "1.2"
protobuf = "~1.5"
quick-error = "1.2.1"
rand = "0.4"
fxhash = "0.2.1"
Expand Down
19 changes: 1 addition & 18 deletions src/raft.rs
Original file line number Diff line number Diff line change
Expand Up @@ -828,6 +828,7 @@ impl<T: Storage> Raft<T> {
return;
}

// Only send vote request to voters.
let prs = self.take_prs();
prs.voters()
.keys()
Expand Down Expand Up @@ -1016,24 +1017,6 @@ impl<T: Storage> Raft<T> {
debug!("{} ignoring MsgHup because already leader", self.tag);
},
MessageType::MsgRequestVote | MessageType::MsgRequestPreVote => {
if self.is_learner {
// TODO: learner may need to vote, in case of node down when confchange.
info!(
"{} [logterm: {}, index: {}, vote: {}] ignored {:?} from {} \
[logterm: {}, index: {}] at term {}: learner can not vote",
self.tag,
self.raft_log.last_term(),
self.raft_log.last_index(),
self.vote,
m.get_msg_type(),
m.get_from(),
m.get_log_term(),
m.get_index(),
self.term,
);
return Ok(());
}

// We can vote if this is a repeat of a vote we've already cast...
let can_vote = (self.vote == m.get_from()) ||
// ...we haven't voted and we don't think there's a leader yet in this term...
Expand Down
43 changes: 28 additions & 15 deletions tests/cases/test_raft.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3784,21 +3784,6 @@ fn test_learner_promotion() {
assert_eq!(network.peers[&2].state, StateRole::Leader);
}

// TestLearnerCannotVote checks that a learner can't vote even it receives a valid Vote request.
#[test]
fn test_learner_cannot_vote() {
let mut n2 = new_test_learner_raft(2, vec![1], vec![2], 10, 1, new_storage());
n2.become_follower(1, INVALID_ID);

let mut msg_vote = new_message(1, 2, MessageType::MsgRequestVote, 0);
msg_vote.set_term(2);
msg_vote.set_log_term(11);
msg_vote.set_index(11);
n2.step(msg_vote).unwrap();

assert_eq!(n2.msgs.len(), 0);
}

// TestLearnerLogReplication tests that a learner can receive entries from the leader.
#[test]
fn test_learner_log_replication() {
Expand Down Expand Up @@ -3964,3 +3949,31 @@ fn test_remove_learner() {
assert!(n1.prs().nodes().is_empty());
assert!(n1.prs().learner_nodes().is_empty());
}

#[test]
fn test_learner_respond_vote() {
let mut n1 = new_test_learner_raft(1, vec![1, 2], vec![3], 10, 1, new_storage());
n1.become_follower(1, INVALID_ID);
n1.reset_randomized_election_timeout();

let mut n3 = new_test_learner_raft(3, vec![1, 2], vec![3], 10, 1, new_storage());
n3.become_follower(1, INVALID_ID);
n3.reset_randomized_election_timeout();

let do_campaign = |nw: &mut Network| {
let msg = new_message(1, 1, MessageType::MsgHup, 0);
nw.send(vec![msg]);
};

let mut network = Network::new(vec![Some(n1), None, Some(n3)]);
network.isolate(2);

// Can't elect new leader because 1 won't send MsgRequestVote to 3.
do_campaign(&mut network);
assert_eq!(network.peers[&1].state, StateRole::Candidate);

// After promote 3 to voter, election should success.
network.peers.get_mut(&1).unwrap().add_node(3);
do_campaign(&mut network);
assert_eq!(network.peers[&1].state, StateRole::Leader);
}

0 comments on commit a362370

Please sign in to comment.