fn check_conf_change(&self, cmd: &RaftCmdRequest) -> Result<()> {
        let change_peer = apply::get_change_peer_cmd(cmd).unwrap();
        let change_type = change_peer.get_change_type();
        let peer = change_peer.get_peer();

        // Check the request itself is valid or not.
        match (change_type, peer.get_is_learner()) {
            (ConfChangeType::AddNode, true) | (ConfChangeType::AddLearnerNode, false) => {
                warn!(
                    "{} conf change type: {:?}, but got peer {:?}",
                    self.tag, change_type, peer
                );
                return Err(box_err!("invalid conf change request"));
            }
            _ => {}
        }

        if change_type == ConfChangeType::RemoveNode && !self.cfg.allow_remove_leader
            && peer.get_id() == self.peer_id()
        {
            warn!(
                "{} rejects remove leader request {:?}",
                self.tag, change_peer
            );
            return Err(box_err!("ignore remove leader"));
        }

        let mut status = self.raft_group.status();
        let total = status.progress.len();
        if total == 1 {
            // It's always safe if there is only one node in the cluster.
            return Ok(());
        }

        match change_type {
            ConfChangeType::AddNode => {
                if let Some(mut progress) = status.learner_progress.remove(&peer.get_id()) {
                    // For promote learner to voter.
                    progress.is_learner = false;
                    status.progress.insert(peer.get_id(), progress);
                } else {
                    status.progress.insert(peer.get_id(), Progress::default());
                }
            }
            ConfChangeType::RemoveNode => {
                if peer.get_is_learner() {
                    // If the node is a learner, we can return directly.
                    return Ok(());
                }
                if status.progress.remove(&peer.get_id()).is_none() {
                    // It's always safe to remove a unexisting node.
                    return Ok(());
                }
            }
            ConfChangeType::AddLearnerNode => {
                return Ok(());
            }
        }
        let healthy = self.count_healthy_node(status.progress.values());
        let quorum_after_change = raft::quorum(status.progress.len());
        if healthy >= quorum_after_change {
            return Ok(());
        }

        PEER_ADMIN_CMD_COUNTER_VEC
            .with_label_values(&["conf_change", "reject_unsafe"])
            .inc();

        info!(
            "{} rejects unsafe conf change request {:?}, total {}, healthy {},  \
             quorum after change {}",
            self.tag, change_peer, total, healthy, quorum_after_change
        );
        Err(box_err!(
            "unsafe to perform conf change {:?}, total {}, healthy {}, quorum after \
             change {}",
            change_peer,
            total,
            healthy,
            quorum_after_change
        ))
    }
/// Validate the `ConfChange` request and check whether it's safe to
/// propose the specified conf change request.
/// It's safe iff at least the quorum of the Raft group is still healthy
/// right after that conf change is applied.
/// Define the total number of nodes in current Raft cluster to be `total`.
/// To ensure the above safety, if the cmd is
/// 1. A `AddNode` request
///    Then at least '(total + 1)/2 + 1' nodes need to be up to date for now.
/// 2. A `RemoveNode` request
///    Then at least '(total - 1)/2 + 1' other nodes (the node about to be removed is excluded)
///    need to be up to date for now. If 'allow_remove_leader' is false then
///    the peer to be removed should not be the leader.
Validate the `ConfChange` request and check whether it's safe to
propose the specified conf change request.
It's safe iff at least the quorum of the Raft group is still healthy
right after that conf change is applied.
Define the total number of nodes in current Raft cluster to be `total`.
To ensure the above safety, if the cmd is
1. A `AddNode` request
Then at least '(total + 1)/2 + 1' nodes need to be up to date for now.
2. A `RemoveNode` request
Then at least '(total - 1)/2 + 1' other nodes (the node about to be removed is excluded)
need to be up to date for now. If 'allow_remove_leader' is false then
the peer to be removed should not be the leader.
Validate the ` ConfChange ` request and check whether it ' s safe to propose the specified conf change request . It ' s safe iff at least the quorum of the Raft group is still healthy right after that conf change is applied . Define the total number of nodes in current Raft cluster to be ` total ` . To ensure the above safety if the cmd is 1 . A ` AddNode ` request Then at least ' ( total + 1 ) / 2 + 1 ' nodes need to be up to date for now . 2 . A ` RemoveNode ` request Then at least ' ( total - 1 ) / 2 + 1 ' other nodes ( the node about to be removed is excluded ) need to be up to date for now . If ' allow_remove_leader ' is false then the peer to be removed should not be the leader .
fn check_conf_change(&self, cmd: &RaftCmdRequest) -> Result<()> {
        let change_peer = apply::get_change_peer_cmd(cmd).unwrap();
        let change_type = change_peer.get_change_type();
        let peer = change_peer.get_peer();
        // Check the request itself is valid or not.
        match (change_type, peer.get_is_learner()) {
            (ConfChangeType::AddNode, true) | (ConfChangeType::AddLearnerNode, false) => {
                warn!(
                    "{} conf change type: {:?}, but got peer {:?}",
                    self.tag, change_type, peer
                );
                return Err(box_err!("invalid conf change request"));
            }
            _ => {}
        }
        if change_type == ConfChangeType::RemoveNode && !self.cfg.allow_remove_leader
            && peer.get_id() == self.peer_id()
        {
            warn!(
                "{} rejects remove leader request {:?}",
                self.tag, change_peer
            );
            return Err(box_err!("ignore remove leader"));
        }
        let mut status = self.raft_group.status();
        let total = status.progress.len();
        if total == 1 {
            // It's always safe if there is only one node in the cluster.
            return Ok(());
        }
        match change_type {
            ConfChangeType::AddNode => {
                if let Some(mut progress) = status.learner_progress.remove(&peer.get_id()) {
                    // For promote learner to voter.
                    progress.is_learner = false;
                    status.progress.insert(peer.get_id(), progress);
                } else {
                    status.progress.insert(peer.get_id(), Progress::default());
                }
            }
            ConfChangeType::RemoveNode => {
                if peer.get_is_learner() {
                    // If the node is a learner, we can return directly.
                    return Ok(());
                }
                if status.progress.remove(&peer.get_id()).is_none() {
                    // It's always safe to remove a unexisting node.
                    return Ok(());
                }
            }
            ConfChangeType::AddLearnerNode => {
                return Ok(());
            }
        }
        let healthy = self.count_healthy_node(status.progress.values());
        let quorum_after_change = raft::quorum(status.progress.len());
        if healthy >= quorum_after_change {
            return Ok(());
        }
        PEER_ADMIN_CMD_COUNTER_VEC
            .with_label_values(&["conf_change", "reject_unsafe"])
            .inc();
        info!(
            "{} rejects unsafe conf change request {:?}, total {}, healthy {},  \
             quorum after change {}",
            self.tag, change_peer, total, healthy, quorum_after_change
        );
        Err(box_err!(
            "unsafe to perform conf change {:?}, total {}, healthy {}, quorum after \
             change {}",
            change_peer,
            total,
            healthy,
            quorum_after_change
        ))
    }
fn check_conf_change ( & self , cmd : & RaftCmdRequest ) -> Result < ( ) > { let change_peer = apply :: get_change_peer_cmd ( cmd ) . unwrap ( ) ; let change_type = change_peer . get_change_type ( ) ; let peer = change_peer . get_peer ( ) ; // Check the request itself is valid or not. match ( change_type , peer . get_is_learner ( ) ) { ( ConfChangeType :: AddNode , true ) | ( ConfChangeType :: AddLearnerNode , false ) => { warn ! ( " " self tag change_type peer ) ; return Err ( box_err ! ( " " ) ) ; } _ => { } } if change_type == ConfChangeType :: RemoveNode && ! self . cfg . allow_remove_leader && peer . get_id ( ) == self . peer_id ( ) { warn ! ( " " self tag change_peer ) ; return Err ( box_err ! ( " " ) ) ; } let mut status = self . raft_group . status ( ) ; let total = status . progress . len ( ) ; if total == 1 { // It's always safe if there is only one node in the cluster. return Ok ( ( ) ) ; } match change_type { ConfChangeType :: AddNode => { if let Some ( mut progress ) = status . learner_progress . remove ( & peer . get_id ( ) ) { // For promote learner to voter. progress . is_learner = false ; status . progress . insert ( peer . get_id ( ) , progress ) ; } else { status . progress . insert ( peer . get_id ( ) , Progress :: default ( ) ) ; } } ConfChangeType :: RemoveNode => { if peer . get_is_learner ( ) { // If the node is a learner, we can return directly. return Ok ( ( ) ) ; } if status . progress . remove ( & peer . get_id ( ) ) . is_none ( ) { // It's always safe to remove a unexisting node. return Ok ( ( ) ) ; } } ConfChangeType :: AddLearnerNode => { return Ok ( ( ) ) ; } } let healthy = self . count_healthy_node ( status . progress . values ( ) ) ; let quorum_after_change = raft :: quorum ( status . progress . len ( ) ) ; if healthy >= quorum_after_change { return Ok ( ( ) ) ; } PEER_ADMIN_CMD_COUNTER_VEC . with_label_values ( & [ " " , " " ] ) . inc ( ) ; info ! ( " \
 " self tag change_peer total healthy quorum_after_change ) ; Err ( box_err ! ( " \
 " change_peer total healthy quorum_after_change ) ) }
Validate the `ConfChange` request and check whether it's safe to
propose the specified conf change request.
Validate the ` ConfChange ` request and check whether it ' s safe to propose the specified conf change request .
&self
cmd
&RaftCmdRequest