pub fn step(&mut self, m: Message) -> Result<(), RaftError> {
        match m.term {
            0 => {
                // local message
                debug!("local message, {:?}", m);
            }
            term if term > self.term => {
                if m.field_type == MsgVote || m.field_type == MsgPreVote {
                    let force =
                        CampaignType::from(m.get_context()) == CampaignType::CampaignTransfer;
                    let in_lease = self.check_quorum
                        && self.lead != NONE
                        && self.election_elapsed < self.election_timeout;
                    if !force && in_lease {
                        // If a server receives a RequestVote request within the minimum election timeout
                        // of hearing from a current leader, it doesn't update its term or grant its vote
                        info!("{:#x} [logterm: {}, index: {}, vote: {:#x} ignored {:?} from {} [logterm: {}, index: {}] at term {}; lease is not expired (remaining ticks: {})",
                              self.id, self.raft_log.last_term(), self.raft_log.last_index(), self.vote, m.get_field_type(), m.get_from(), m.get_logTerm(), m.get_index(), self.term, self.election_timeout - self.election_elapsed);
                        return Ok(());
                    }
                }
                match m.field_type {
                    MsgPreVote => {} // Never change our term in response to a PreVote
                    typ if typ == MsgPreVoteResp && !m.reject => {
                        // We send pre-vote requests with a term in our future. If the
                        // pre-vote is granted, we will increment our term when we get a
                        // quorum. If it is not, the term comes from the node that
                        // rejected our vote so we should become a follower at the new
                        // term.
                    }
                    typ => {
                        info!(
                            "{:#x} [term: {}] received a {:?} message with higher term from {:#x} [term: {}]",
                            self.id,
                            self.term,
                            typ,
                            m.from,
                            m.term,
                        );

                        if typ == MsgApp || typ == MsgHeartbeat || typ == MsgSnap {
                            self.become_follower(m.term, m.from);
                        } else {
                            self.become_follower(m.term, NONE);
                        }
                    }
                }
            }
            term if term < self.term => {
                if (self.check_quorum || self.pre_vote)
                    && (m.field_type == MsgHeartbeat || m.field_type == MsgApp)
                {
                    // We have received messages from a leader at a lower term. It is possible
                    // that these messages were simply delayed in the network, but this could
                    // also mean that this node has advanced its term number during a network
                    // partition, and it is now unable to either win an election or to rejoin
                    // the majority on the old term. If checkQuorum is false, this will be
                    // handled by incrementing term numbers in response to MsgVote with a
                    // higher term, but if checkQuorum is true we may not advance the term on
                    // MsgVote and must generate other messages to advance the term. The net
                    // result of these two features is to minimize the disruption caused by
                    // nodes that have been removed from the cluster's configuration: a
                    // removed node will send MsgVotes (or MsgPreVotes) which will be ignored,
                    // but it will not receive MsgApp or MsgHeartbeat, so it will not create
                    // disruptive term increases, by notifying leader of this node's activeness.
                    // The above comments also true for Pre-Vote
                    //
                    // When follower gets isolated, it soon starts an election ending
                    // up with a higher term than leader, although it won't receive enough
                    // votes to win the election. When it regains connectivity, this response
                    // with "pb.MsgAppResp" of higher term would force leader to step down.
                    // However, this disruption is inevitable to free this stuck node with
                    // fresh election. This can be prevented with Pre-Vote phase.
                    let mut resp_m = Message::new();
                    resp_m.set_field_type(MsgAppResp);
                    resp_m.set_to(m.from);
                    self.send(resp_m);
                } else if m.get_field_type() == MsgPreVote {
                    // Before Pre-Vote enabled, there may have candidate with higher term,
                    // but less log. After update to Pre-Vote, the cluster may deadlock if
                    // we drop messages with a lower term.
                    info!(
                        "{:#x} [logterm: {}, index: {}, vote: {:#x}] rejected {:?} from {:#x} [logterm: {}, index: {}] at term {}",
                        self.id,
                        self.raft_log.last_term(),
                        self.raft_log.last_index(),
                        self.vote,
                        m.field_type,
                        m.from,
                        m.logTerm,
                        m.index,
                        self.term
                    );

                    let mut msg = Message::new();
                    msg.set_to(m.get_from());
                    msg.set_term(self.term);
                    msg.set_field_type(MsgPreVoteResp);
                    msg.set_reject(true);
                } else {
                    // ignore other cases.
                    info!(
                        "{:#x} [term: {}] ignored a {:?} message with lower term from {:#x} [term: {}]",
                        self.id,
                        self.term,
                        m.field_type,
                        m.from,
                        m.logTerm,
                    );
                }
                return Ok(());
            }
            _ => {}
        }

        match m.field_type {
            MsgHup => {
                if self.pre_vote {
                    self.hup(CampaignType::CampaignPreElection)
                } else {
                    self.hup(CampaignType::CampaignElection);
                }
            }
            MsgVote | MsgPreVote => {
                let can_vote = self.vote == m.get_from() // We can vote if this is a repeat of a vote we've already cast...
                    || (self.vote == NONE && self.lead == NONE) // ...we haven't voted and we don't think there's a leader yet in this term...
                    || (m.get_field_type() == MsgPreVote && m.get_term() > self.term);
                // ...or this is a PreVote for a further ter

                // ... and we believe the candidate is up to date.
                if can_vote && self.raft_log.is_up_to_date(m.get_index(), m.get_logTerm()) {
                    // Note: it turns out that that learners must be allowed to cast votes.
                    // This seems counter- intuitive but is necessary in the situation in which
                    // a learner has been promoted (i.e. is now a voter) but has not learned
                    // about this yet.
                    // For example, consider a group in which id=1 is a learner and id=2 and
                    // id=3 are voters. A configuration change promoting 1 can be committed on
                    // the quorum `{2,3}` without the config change being appended to the
                    // learner's log. If the leader (say 2) fails, there are de facto two
                    // voters remaining. Only 3 can win an election (due to its log containing
                    // all committed entries), but to do so it will need 1 to vote. But 1
                    // considers itself a learner and will continue to do so until 3 has
                    // stepped up as leader, replicates the conf change to 1, and 1 applies it.
                    // Ultimately, by receiving a request to vote, the learner realizes that
                    // the candidate believes it to be a voter, and that it should act
                    // accordingly. The candidate's config may be stale, too; but in that case
                    // it won't win the election, at least in the absence of the bug discussed
                    // in:
                    // https://github.com/etcd-io/etcd/issues/7625#issuecomment-488798263.
                    info!(
                        "{:#x} [logterm: {}, index: {}, vote: {:#x}] cast {:?} for {:#x} [logterm: {}, index: {}]  at term {}",
                        self.id,
                        self.raft_log.last_term(),
                        self.raft_log.last_index(),
                        self.vote,
                        m.get_field_type(),
                        m.get_from(),
                        m.get_logTerm(),
                        m.get_index(),
                        self.term
                    );
                    // When responding to Msg{Pre,}Vote messages we include the term
                    // from the message, not the local term. To see why, consider the
                    // case where a single node was previously partitioned away and
                    // it's local term is now out of date. If we include the local term
                    // (recall that for pre-votes we don't update the local term), the
                    // (pre-)campaigning node on the other end will proceed to ignore
                    // the message (it ignores all out of date messages).
                    // The term in the original message and current local term are the
                    // same in the case of regular votes, but different for pre-votes.
                    let mut msg = Message::new();
                    msg.set_to(m.get_from());
                    msg.set_term(m.get_term());
                    msg.set_field_type(vote_resp_msg_type(m.get_field_type()));
                    self.send(msg);
                    if m.get_field_type() == MsgVote {
                        // only record real votes.
                        self.election_elapsed = 0;
                        self.vote = m.get_from();
                    }
                } else {
                    info!(
                        "{:#x} [logterm: {}, index: {}, vote: {:#x}] rejected {:?} from {:#x} [logterm: {}, index: {}] at term {}",
                        self.id,
                        self.raft_log.last_term(),
                        self.raft_log.last_index(),
                        self.vote,
                        m.get_field_type(),
                        m.get_from(),
                        m.get_logTerm(),
                        m.get_index(),
                        m.get_term()
                    );
                    let mut msg = Message::new();
                    msg.set_to(m.get_from());
                    msg.set_term(self.term);
                    msg.set_field_type(vote_resp_msg_type(m.get_field_type()));
                    msg.set_reject(true);
                    self.send(msg);
                }
            }

            _ => {
                self.execute_step_fn(m)?;
            }
        }
        Ok(())
    }
// Step the entrance of handle message, see `MessageType`
// on `eraft.proto`. for what msgs should be handled
Step the entrance of handle message, see `MessageType`
on `eraft.proto`. for what msgs should be handled
Step the entrance of handle message see ` MessageType ` on ` eraft . proto ` . for what msgs should be handled
pub fn step(&mut self, m: Message) -> Result<(), RaftError> {
        match m.term {
            0 => {
                // local message
                debug!("local message, {:?}", m);
            }
            term if term > self.term => {
                if m.field_type == MsgVote || m.field_type == MsgPreVote {
                    let force =
                        CampaignType::from(m.get_context()) == CampaignType::CampaignTransfer;
                    let in_lease = self.check_quorum
                        && self.lead != NONE
                        && self.election_elapsed < self.election_timeout;
                    if !force && in_lease {
                        // If a server receives a RequestVote request within the minimum election timeout
                        // of hearing from a current leader, it doesn't update its term or grant its vote
                        info!("{:#x} [logterm: {}, index: {}, vote: {:#x} ignored {:?} from {} [logterm: {}, index: {}] at term {}; lease is not expired (remaining ticks: {})",
                              self.id, self.raft_log.last_term(), self.raft_log.last_index(), self.vote, m.get_field_type(), m.get_from(), m.get_logTerm(), m.get_index(), self.term, self.election_timeout - self.election_elapsed);
                        return Ok(());
                    }
                }
                match m.field_type {
                    MsgPreVote => {} // Never change our term in response to a PreVote
                    typ if typ == MsgPreVoteResp && !m.reject => {
                        // We send pre-vote requests with a term in our future. If the
                        // pre-vote is granted, we will increment our term when we get a
                        // quorum. If it is not, the term comes from the node that
                        // rejected our vote so we should become a follower at the new
                        // term.
                    }
                    typ => {
                        info!(
                            "{:#x} [term: {}] received a {:?} message with higher term from {:#x} [term: {}]",
                            self.id,
                            self.term,
                            typ,
                            m.from,
                            m.term,
                        );
                        if typ == MsgApp || typ == MsgHeartbeat || typ == MsgSnap {
                            self.become_follower(m.term, m.from);
                        } else {
                            self.become_follower(m.term, NONE);
                        }
                    }
                }
            }
            term if term < self.term => {
                if (self.check_quorum || self.pre_vote)
                    && (m.field_type == MsgHeartbeat || m.field_type == MsgApp)
                {
                    // We have received messages from a leader at a lower term. It is possible
                    // that these messages were simply delayed in the network, but this could
                    // also mean that this node has advanced its term number during a network
                    // partition, and it is now unable to either win an election or to rejoin
                    // the majority on the old term. If checkQuorum is false, this will be
                    // handled by incrementing term numbers in response to MsgVote with a
                    // higher term, but if checkQuorum is true we may not advance the term on
                    // MsgVote and must generate other messages to advance the term. The net
                    // result of these two features is to minimize the disruption caused by
                    // nodes that have been removed from the cluster's configuration: a
                    // removed node will send MsgVotes (or MsgPreVotes) which will be ignored,
                    // but it will not receive MsgApp or MsgHeartbeat, so it will not create
                    // disruptive term increases, by notifying leader of this node's activeness.
                    // The above comments also true for Pre-Vote
                    //
                    // When follower gets isolated, it soon starts an election ending
                    // up with a higher term than leader, although it won't receive enough
                    // votes to win the election. When it regains connectivity, this response
                    // with "pb.MsgAppResp" of higher term would force leader to step down.
                    // However, this disruption is inevitable to free this stuck node with
                    // fresh election. This can be prevented with Pre-Vote phase.
                    let mut resp_m = Message::new();
                    resp_m.set_field_type(MsgAppResp);
                    resp_m.set_to(m.from);
                    self.send(resp_m);
                } else if m.get_field_type() == MsgPreVote {
                    // Before Pre-Vote enabled, there may have candidate with higher term,
                    // but less log. After update to Pre-Vote, the cluster may deadlock if
                    // we drop messages with a lower term.
                    info!(
                        "{:#x} [logterm: {}, index: {}, vote: {:#x}] rejected {:?} from {:#x} [logterm: {}, index: {}] at term {}",
                        self.id,
                        self.raft_log.last_term(),
                        self.raft_log.last_index(),
                        self.vote,
                        m.field_type,
                        m.from,
                        m.logTerm,
                        m.index,
                        self.term
                    );
                    let mut msg = Message::new();
                    msg.set_to(m.get_from());
                    msg.set_term(self.term);
                    msg.set_field_type(MsgPreVoteResp);
                    msg.set_reject(true);
                } else {
                    // ignore other cases.
                    info!(
                        "{:#x} [term: {}] ignored a {:?} message with lower term from {:#x} [term: {}]",
                        self.id,
                        self.term,
                        m.field_type,
                        m.from,
                        m.logTerm,
                    );
                }
                return Ok(());
            }
            _ => {}
        }
        match m.field_type {
            MsgHup => {
                if self.pre_vote {
                    self.hup(CampaignType::CampaignPreElection)
                } else {
                    self.hup(CampaignType::CampaignElection);
                }
            }
            MsgVote | MsgPreVote => {
                let can_vote = self.vote == m.get_from() // We can vote if this is a repeat of a vote we've already cast...
                    || (self.vote == NONE && self.lead == NONE) // ...we haven't voted and we don't think there's a leader yet in this term...
                    || (m.get_field_type() == MsgPreVote && m.get_term() > self.term);
                // ...or this is a PreVote for a further ter
                // ... and we believe the candidate is up to date.
                if can_vote && self.raft_log.is_up_to_date(m.get_index(), m.get_logTerm()) {
                    // Note: it turns out that that learners must be allowed to cast votes.
                    // This seems counter- intuitive but is necessary in the situation in which
                    // a learner has been promoted (i.e. is now a voter) but has not learned
                    // about this yet.
                    // For example, consider a group in which id=1 is a learner and id=2 and
                    // id=3 are voters. A configuration change promoting 1 can be committed on
                    // the quorum `{2,3}` without the config change being appended to the
                    // learner's log. If the leader (say 2) fails, there are de facto two
                    // voters remaining. Only 3 can win an election (due to its log containing
                    // all committed entries), but to do so it will need 1 to vote. But 1
                    // considers itself a learner and will continue to do so until 3 has
                    // stepped up as leader, replicates the conf change to 1, and 1 applies it.
                    // Ultimately, by receiving a request to vote, the learner realizes that
                    // the candidate believes it to be a voter, and that it should act
                    // accordingly. The candidate's config may be stale, too; but in that case
                    // it won't win the election, at least in the absence of the bug discussed
                    // in:
                    // https://github.com/etcd-io/etcd/issues/7625#issuecomment-488798263.
                    info!(
                        "{:#x} [logterm: {}, index: {}, vote: {:#x}] cast {:?} for {:#x} [logterm: {}, index: {}]  at term {}",
                        self.id,
                        self.raft_log.last_term(),
                        self.raft_log.last_index(),
                        self.vote,
                        m.get_field_type(),
                        m.get_from(),
                        m.get_logTerm(),
                        m.get_index(),
                        self.term
                    );
                    // When responding to Msg{Pre,}Vote messages we include the term
                    // from the message, not the local term. To see why, consider the
                    // case where a single node was previously partitioned away and
                    // it's local term is now out of date. If we include the local term
                    // (recall that for pre-votes we don't update the local term), the
                    // (pre-)campaigning node on the other end will proceed to ignore
                    // the message (it ignores all out of date messages).
                    // The term in the original message and current local term are the
                    // same in the case of regular votes, but different for pre-votes.
                    let mut msg = Message::new();
                    msg.set_to(m.get_from());
                    msg.set_term(m.get_term());
                    msg.set_field_type(vote_resp_msg_type(m.get_field_type()));
                    self.send(msg);
                    if m.get_field_type() == MsgVote {
                        // only record real votes.
                        self.election_elapsed = 0;
                        self.vote = m.get_from();
                    }
                } else {
                    info!(
                        "{:#x} [logterm: {}, index: {}, vote: {:#x}] rejected {:?} from {:#x} [logterm: {}, index: {}] at term {}",
                        self.id,
                        self.raft_log.last_term(),
                        self.raft_log.last_index(),
                        self.vote,
                        m.get_field_type(),
                        m.get_from(),
                        m.get_logTerm(),
                        m.get_index(),
                        m.get_term()
                    );
                    let mut msg = Message::new();
                    msg.set_to(m.get_from());
                    msg.set_term(self.term);
                    msg.set_field_type(vote_resp_msg_type(m.get_field_type()));
                    msg.set_reject(true);
                    self.send(msg);
                }
            }
            _ => {
                self.execute_step_fn(m)?;
            }
        }
        Ok(())
    }
pub fn step ( & mut self , m : Message ) -> Result < ( ) , RaftError > { match m . term { 0 => { // local message debug ! ( " " m ) ; } term if term > self . term => { if m . field_type == MsgVote || m . field_type == MsgPreVote { let force = CampaignType :: from ( m . get_context ( ) ) == CampaignType :: CampaignTransfer ; let in_lease = self . check_quorum && self . lead != NONE && self . election_elapsed < self . election_timeout ; if ! force && in_lease { // If a server receives a RequestVote request within the minimum election timeout // of hearing from a current leader, it doesn't update its term or grant its vote info ! ( " " self id self raft_log last_term ( ) self raft_log last_index ( ) self vote m get_field_type ( ) m get_from ( ) m get_logTerm ( ) m get_index ( ) self term self election_timeout self election_elapsed ) ; return Ok ( ( ) ) ; } } match m . field_type { MsgPreVote => { } // Never change our term in response to a PreVote typ if typ == MsgPreVoteResp && ! m . reject => { // We send pre-vote requests with a term in our future. If the // pre-vote is granted, we will increment our term when we get a // quorum. If it is not, the term comes from the node that // rejected our vote so we should become a follower at the new // term. } typ => { info ! ( " " self id self term typ m from m term ) ; if typ == MsgApp || typ == MsgHeartbeat || typ == MsgSnap { self . become_follower ( m . term , m . from ) ; } else { self . become_follower ( m . term , NONE ) ; } } } } term if term < self . term => { if ( self . check_quorum || self . pre_vote ) && ( m . field_type == MsgHeartbeat || m . field_type == MsgApp ) { // We have received messages from a leader at a lower term. It is possible // that these messages were simply delayed in the network, but this could // also mean that this node has advanced its term number during a network // partition, and it is now unable to either win an election or to rejoin // the majority on the old term. If checkQuorum is false, this will be // handled by incrementing term numbers in response to MsgVote with a // higher term, but if checkQuorum is true we may not advance the term on // MsgVote and must generate other messages to advance the term. The net // result of these two features is to minimize the disruption caused by // nodes that have been removed from the cluster's configuration: a // removed node will send MsgVotes (or MsgPreVotes) which will be ignored, // but it will not receive MsgApp or MsgHeartbeat, so it will not create // disruptive term increases, by notifying leader of this node's activeness. // The above comments also true for Pre-Vote // // When follower gets isolated, it soon starts an election ending // up with a higher term than leader, although it won't receive enough // votes to win the election. When it regains connectivity, this response // with "pb.MsgAppResp" of higher term would force leader to step down. // However, this disruption is inevitable to free this stuck node with // fresh election. This can be prevented with Pre-Vote phase. let mut resp_m = Message :: new ( ) ; resp_m . set_field_type ( MsgAppResp ) ; resp_m . set_to ( m . from ) ; self . send ( resp_m ) ; } else if m . get_field_type ( ) == MsgPreVote { // Before Pre-Vote enabled, there may have candidate with higher term, // but less log. After update to Pre-Vote, the cluster may deadlock if // we drop messages with a lower term. info ! ( " " self id self raft_log last_term ( ) self raft_log last_index ( ) self vote m field_type m from m logTerm m index self term ) ; let mut msg = Message :: new ( ) ; msg . set_to ( m . get_from ( ) ) ; msg . set_term ( self . term ) ; msg . set_field_type ( MsgPreVoteResp ) ; msg . set_reject ( true ) ; } else { // ignore other cases. info ! ( " " self id self term m field_type m from m logTerm ) ; } return Ok ( ( ) ) ; } _ => { } } match m . field_type { MsgHup => { if self . pre_vote { self . hup ( CampaignType :: CampaignPreElection ) } else { self . hup ( CampaignType :: CampaignElection ) ; } } MsgVote | MsgPreVote => { let can_vote = self . vote == m . get_from ( ) // We can vote if this is a repeat of a vote we've already cast... || ( self . vote == NONE && self . lead == NONE ) // ...we haven't voted and we don't think there's a leader yet in this term... || ( m . get_field_type ( ) == MsgPreVote && m . get_term ( ) > self . term ) ; // ...or this is a PreVote for a further ter // ... and we believe the candidate is up to date. if can_vote && self . raft_log . is_up_to_date ( m . get_index ( ) , m . get_logTerm ( ) ) { // Note: it turns out that that learners must be allowed to cast votes. // This seems counter- intuitive but is necessary in the situation in which // a learner has been promoted (i.e. is now a voter) but has not learned // about this yet. // For example, consider a group in which id=1 is a learner and id=2 and // id=3 are voters. A configuration change promoting 1 can be committed on // the quorum `{2,3}` without the config change being appended to the // learner's log. If the leader (say 2) fails, there are de facto two // voters remaining. Only 3 can win an election (due to its log containing // all committed entries), but to do so it will need 1 to vote. But 1 // considers itself a learner and will continue to do so until 3 has // stepped up as leader, replicates the conf change to 1, and 1 applies it. // Ultimately, by receiving a request to vote, the learner realizes that // the candidate believes it to be a voter, and that it should act // accordingly. The candidate's config may be stale, too; but in that case // it won't win the election, at least in the absence of the bug discussed // in: // https://github.com/etcd-io/etcd/issues/7625#issuecomment-488798263. info ! ( " " self id self raft_log last_term ( ) self raft_log last_index ( ) self vote m get_field_type ( ) m get_from ( ) m get_logTerm ( ) m get_index ( ) self term ) ; // When responding to Msg{Pre,}Vote messages we include the term // from the message, not the local term. To see why, consider the // case where a single node was previously partitioned away and // it's local term is now out of date. If we include the local term // (recall that for pre-votes we don't update the local term), the // (pre-)campaigning node on the other end will proceed to ignore // the message (it ignores all out of date messages). // The term in the original message and current local term are the // same in the case of regular votes, but different for pre-votes. let mut msg = Message :: new ( ) ; msg . set_to ( m . get_from ( ) ) ; msg . set_term ( m . get_term ( ) ) ; msg . set_field_type ( vote_resp_msg_type ( m . get_field_type ( ) ) ) ; self . send ( msg ) ; if m . get_field_type ( ) == MsgVote { // only record real votes. self . election_elapsed = 0 ; self . vote = m . get_from ( ) ; } } else { info ! ( " " self id self raft_log last_term ( ) self raft_log last_index ( ) self vote m get_field_type ( ) m get_from ( ) m get_logTerm ( ) m get_index ( ) m get_term ( ) ) ; let mut msg = Message :: new ( ) ; msg . set_to ( m . get_from ( ) ) ; msg . set_term ( self . term ) ; msg . set_field_type ( vote_resp_msg_type ( m . get_field_type ( ) ) ) ; msg . set_reject ( true ) ; self . send ( msg ) ; } } _ => { self . execute_step_fn ( m ) ? ; } } Ok ( ( ) ) }
Step the entrance of handle message, see `MessageType`
on `eraft.proto`.
Step the entrance of handle message see ` MessageType ` on ` eraft . proto ` .
&mut self
m
Message