fn check_conf_change<T, C>(
        &mut self,
        ctx: &mut PollContext<EK, ER, T, C>,
        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, is_learner(peer)) {
            (ConfChangeType::AddNode, true) | (ConfChangeType::AddLearnerNode, false) => {
                warn!(
                    "invalid conf change request";
                    "region_id" => self.region_id,
                    "peer_id" => self.peer.get_id(),
                    "request" => ?change_peer,
                );
                return Err(box_err!("{} invalid conf change request", self.tag));
            }
            _ => {}
        }

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

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

        match change_type {
            ConfChangeType::AddNode => {
                if let Err(raft::Error::NotExists(_, _)) = progress.promote_learner(peer.get_id()) {
                    let _ = progress.insert_voter(peer.get_id(), Progress::new(0, 0));
                }
            }
            ConfChangeType::RemoveNode => {
                progress.remove(peer.get_id())?;
            }
            ConfChangeType::AddLearnerNode => {
                return Ok(());
            }
        }
        let promoted_commit_index = progress.maximal_committed_index().0;
        if promoted_commit_index >= self.get_store().truncated_index() {
            return Ok(());
        }

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

        info!(
            "rejects unsafe conf change request";
            "region_id" => self.region_id,
            "peer_id" => self.peer.get_id(),
            "request" => ?change_peer,
            "total" => total,
            "after" => progress.voter_ids().len(),
            "truncated_index" => self.get_store().truncated_index(),
            "promoted_commit_index" => promoted_commit_index,
        );
        // Waking it up to replicate logs to candidate.
        self.should_wake_up = true;
        Err(box_err!(
            "unsafe to perform conf change {:?}, total {}, truncated index {}, promoted commit index {}",
            change_peer,
            total,
            self.get_store().truncated_index(),
            promoted_commit_index
        ))
    }
/// 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<T, C>(
        &mut self,
        ctx: &mut PollContext<EK, ER, T, C>,
        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, is_learner(peer)) {
            (ConfChangeType::AddNode, true) | (ConfChangeType::AddLearnerNode, false) => {
                warn!(
                    "invalid conf change request";
                    "region_id" => self.region_id,
                    "peer_id" => self.peer.get_id(),
                    "request" => ?change_peer,
                );
                return Err(box_err!("{} invalid conf change request", self.tag));
            }
            _ => {}
        }
        if change_type == ConfChangeType::RemoveNode
            && !ctx.cfg.allow_remove_leader
            && peer.get_id() == self.peer_id()
        {
            warn!(
                "rejects remove leader request";
                "region_id" => self.region_id,
                "peer_id" => self.peer.get_id(),
                "request" => ?change_peer,
            );
            return Err(box_err!("{} ignore remove leader", self.tag));
        }
        let (total, mut progress) = {
            let status = self.raft_group.status();
            let total = status.progress.unwrap().voter_ids().len();
            if total == 1 {
                // It's always safe if there is only one node in the cluster.
                return Ok(());
            }
            (total, status.progress.unwrap().clone())
        };
        match change_type {
            ConfChangeType::AddNode => {
                if let Err(raft::Error::NotExists(_, _)) = progress.promote_learner(peer.get_id()) {
                    let _ = progress.insert_voter(peer.get_id(), Progress::new(0, 0));
                }
            }
            ConfChangeType::RemoveNode => {
                progress.remove(peer.get_id())?;
            }
            ConfChangeType::AddLearnerNode => {
                return Ok(());
            }
        }
        let promoted_commit_index = progress.maximal_committed_index().0;
        if promoted_commit_index >= self.get_store().truncated_index() {
            return Ok(());
        }
        PEER_ADMIN_CMD_COUNTER_VEC
            .with_label_values(&["conf_change", "reject_unsafe"])
            .inc();
        info!(
            "rejects unsafe conf change request";
            "region_id" => self.region_id,
            "peer_id" => self.peer.get_id(),
            "request" => ?change_peer,
            "total" => total,
            "after" => progress.voter_ids().len(),
            "truncated_index" => self.get_store().truncated_index(),
            "promoted_commit_index" => promoted_commit_index,
        );
        // Waking it up to replicate logs to candidate.
        self.should_wake_up = true;
        Err(box_err!(
            "unsafe to perform conf change {:?}, total {}, truncated index {}, promoted commit index {}",
            change_peer,
            total,
            self.get_store().truncated_index(),
            promoted_commit_index
        ))
    }
fn check_conf_change < T , C > ( & mut self , ctx : & mut PollContext < EK , ER , T , C > , 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 , is_learner ( peer ) ) { ( ConfChangeType :: AddNode , true ) | ( ConfChangeType :: AddLearnerNode , false ) => { warn ! ( " " " " self region_id " " self peer get_id ( ) " " change_peer ) ; return Err ( box_err ! ( " " self tag ) ) ; } _ => { } } if change_type == ConfChangeType :: RemoveNode && ! ctx . cfg . allow_remove_leader && peer . get_id ( ) == self . peer_id ( ) { warn ! ( " " " " self region_id " " self peer get_id ( ) " " change_peer ) ; return Err ( box_err ! ( " " self tag ) ) ; } let ( total , mut progress ) = { let status = self . raft_group . status ( ) ; let total = status . progress . unwrap ( ) . voter_ids ( ) . len ( ) ; if total == 1 { // It's always safe if there is only one node in the cluster. return Ok ( ( ) ) ; } ( total , status . progress . unwrap ( ) . clone ( ) ) } ; match change_type { ConfChangeType :: AddNode => { if let Err ( raft :: Error :: NotExists ( _ , _ ) ) = progress . promote_learner ( peer . get_id ( ) ) { let _ = progress . insert_voter ( peer . get_id ( ) , Progress :: new ( 0 , 0 ) ) ; } } ConfChangeType :: RemoveNode => { progress . remove ( peer . get_id ( ) ) ? ; } ConfChangeType :: AddLearnerNode => { return Ok ( ( ) ) ; } } let promoted_commit_index = progress . maximal_committed_index ( ) . 0 ; if promoted_commit_index >= self . get_store ( ) . truncated_index ( ) { return Ok ( ( ) ) ; } PEER_ADMIN_CMD_COUNTER_VEC . with_label_values ( & [ " " , " " ] ) . inc ( ) ; info ! ( " " " " self region_id " " self peer get_id ( ) " " change_peer " " total " " progress voter_ids ( ) len ( ) " " self get_store ( ) truncated_index ( ) " " promoted_commit_index ) ; // Waking it up to replicate logs to candidate. self . should_wake_up = true ; Err ( box_err ! ( " " change_peer total self get_store ( ) truncated_index ( ) promoted_commit_index ) ) }
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 .
&mut self
ctx
&mut PollContext<EK, ER, T, C>
cmd
&RaftCmdRequest