fn propose_conf_change<T, C>(
        &mut self,
        ctx: &mut PollContext<EK, ER, T, C>,
        req: &RaftCmdRequest,
    ) -> Result<Either<u64, u64>> {
        if self.pending_merge_state.is_some() {
            return Err(box_err!(
                "{} peer in merging mode, can't do proposal.",
                self.tag
            ));
        }
        if self.raft_group.raft.pending_conf_index > self.get_store().applied_index() {
            info!(
                "there is a pending conf change, try later";
                "region_id" => self.region_id,
                "peer_id" => self.peer.get_id(),
            );
            return Err(box_err!(
                "{} there is a pending conf change, try later",
                self.tag
            ));
        }
        // Actually, according to the implementation of conf change in raft-rs, this check must be
        // passed if the previous check that `pending_conf_index` should be less than or equal to
        // `self.get_store().applied_index()` is passed.
        if self.get_store().applied_index_term() != self.term() {
            return Err(box_err!(
                "{} peer has not applied to current term, applied_term {}, current_term {}",
                self.tag,
                self.get_store().applied_index_term(),
                self.term()
            ));
        }
        if let Some(index) = self
            .cmd_epoch_checker
            .propose_check_epoch(&req, self.term())
        {
            return Ok(Either::Right(index));
        }

        self.check_conf_change(ctx, req)?;

        ctx.raft_metrics.propose.conf_change += 1;

        let data = req.write_to_bytes()?;

        // TODO: use local histogram metrics
        PEER_PROPOSE_LOG_SIZE_HISTOGRAM.observe(data.len() as f64);

        let change_peer = apply::get_change_peer_cmd(req).unwrap();
        let mut cc = eraftpb::ConfChange::default();
        cc.set_change_type(change_peer.get_change_type());
        cc.set_node_id(change_peer.get_peer().get_id());
        cc.set_context(data);

        info!(
            "propose conf change peer";
            "region_id" => self.region_id,
            "peer_id" => self.peer.get_id(),
            "change_type" => ?cc.get_change_type(),
            "change_peer" => cc.get_node_id(),
        );

        let propose_index = self.next_proposal_index();
        self.raft_group
            .propose_conf_change(ProposalContext::SYNC_LOG.to_vec(), cc)?;
        if self.next_proposal_index() == propose_index {
            // The message is dropped silently, this usually due to leader absence
            // or transferring leader. Both cases can be considered as NotLeader error.
            return Err(Error::NotLeader(self.region_id, None));
        }

        Ok(Either::Left(propose_index))
    }
// Fails in such cases:
// 1. A pending conf change has not been applied yet;
// 2. Removing the leader is not allowed in the configuration;
// 3. The conf change makes the raft group not healthy;
// 4. The conf change is dropped by raft group internally.
/// Returns Ok(Either::Left(index)) means the proposal is proposed successfully and is located on `index` position.
/// Ok(Either::Right(index)) means the proposal is rejected by `CmdEpochChecker` and the `index` is the position of
/// the last conflict admin cmd.
Fails in such cases:
1. A pending conf change has not been applied yet;
2. Removing the leader is not allowed in the configuration;
3. The conf change makes the raft group not healthy;
4. The conf change is dropped by raft group internally.
Returns Ok(Either::Left(index)) means the proposal is proposed successfully and is located on `index` position.
Ok(Either::Right(index)) means the proposal is rejected by `CmdEpochChecker` and the `index` is the position of
the last conflict admin cmd.
Fails in such cases : 1 . A pending conf change has not been applied yet ; 2 . Removing the leader is not allowed in the configuration ; 3 . The conf change makes the raft group not healthy ; 4 . The conf change is dropped by raft group internally . Returns Ok ( Either :: Left ( index )) means the proposal is proposed successfully and is located on ` index ` position . Ok ( Either :: Right ( index )) means the proposal is rejected by ` CmdEpochChecker ` and the ` index ` is the position of the last conflict admin cmd .
fn propose_conf_change<T, C>(
        &mut self,
        ctx: &mut PollContext<EK, ER, T, C>,
        req: &RaftCmdRequest,
    ) -> Result<Either<u64, u64>> {
        if self.pending_merge_state.is_some() {
            return Err(box_err!(
                "{} peer in merging mode, can't do proposal.",
                self.tag
            ));
        }
        if self.raft_group.raft.pending_conf_index > self.get_store().applied_index() {
            info!(
                "there is a pending conf change, try later";
                "region_id" => self.region_id,
                "peer_id" => self.peer.get_id(),
            );
            return Err(box_err!(
                "{} there is a pending conf change, try later",
                self.tag
            ));
        }
        // Actually, according to the implementation of conf change in raft-rs, this check must be
        // passed if the previous check that `pending_conf_index` should be less than or equal to
        // `self.get_store().applied_index()` is passed.
        if self.get_store().applied_index_term() != self.term() {
            return Err(box_err!(
                "{} peer has not applied to current term, applied_term {}, current_term {}",
                self.tag,
                self.get_store().applied_index_term(),
                self.term()
            ));
        }
        if let Some(index) = self
            .cmd_epoch_checker
            .propose_check_epoch(&req, self.term())
        {
            return Ok(Either::Right(index));
        }
        self.check_conf_change(ctx, req)?;
        ctx.raft_metrics.propose.conf_change += 1;
        let data = req.write_to_bytes()?;
        // TODO: use local histogram metrics
        PEER_PROPOSE_LOG_SIZE_HISTOGRAM.observe(data.len() as f64);
        let change_peer = apply::get_change_peer_cmd(req).unwrap();
        let mut cc = eraftpb::ConfChange::default();
        cc.set_change_type(change_peer.get_change_type());
        cc.set_node_id(change_peer.get_peer().get_id());
        cc.set_context(data);
        info!(
            "propose conf change peer";
            "region_id" => self.region_id,
            "peer_id" => self.peer.get_id(),
            "change_type" => ?cc.get_change_type(),
            "change_peer" => cc.get_node_id(),
        );
        let propose_index = self.next_proposal_index();
        self.raft_group
            .propose_conf_change(ProposalContext::SYNC_LOG.to_vec(), cc)?;
        if self.next_proposal_index() == propose_index {
            // The message is dropped silently, this usually due to leader absence
            // or transferring leader. Both cases can be considered as NotLeader error.
            return Err(Error::NotLeader(self.region_id, None));
        }
        Ok(Either::Left(propose_index))
    }
fn propose_conf_change < T , C > ( & mut self , ctx : & mut PollContext < EK , ER , T , C > , req : & RaftCmdRequest , ) -> Result < Either < u64 , u64 > > { if self . pending_merge_state . is_some ( ) { return Err ( box_err ! ( " " self tag ) ) ; } if self . raft_group . raft . pending_conf_index > self . get_store ( ) . applied_index ( ) { info ! ( " " " " self region_id " " self peer get_id ( ) ) ; return Err ( box_err ! ( " " self tag ) ) ; } // Actually, according to the implementation of conf change in raft-rs, this check must be // passed if the previous check that `pending_conf_index` should be less than or equal to // `self.get_store().applied_index()` is passed. if self . get_store ( ) . applied_index_term ( ) != self . term ( ) { return Err ( box_err ! ( " " self tag self get_store ( ) applied_index_term ( ) self term ( ) ) ) ; } if let Some ( index ) = self . cmd_epoch_checker . propose_check_epoch ( & req , self . term ( ) ) { return Ok ( Either :: Right ( index ) ) ; } self . check_conf_change ( ctx , req ) ? ; ctx . raft_metrics . propose . conf_change += 1 ; let data = req . write_to_bytes ( ) ? ; // TODO: use local histogram metrics PEER_PROPOSE_LOG_SIZE_HISTOGRAM . observe ( data . len ( ) as f64 ) ; let change_peer = apply :: get_change_peer_cmd ( req ) . unwrap ( ) ; let mut cc = eraftpb :: ConfChange :: default ( ) ; cc . set_change_type ( change_peer . get_change_type ( ) ) ; cc . set_node_id ( change_peer . get_peer ( ) . get_id ( ) ) ; cc . set_context ( data ) ; info ! ( " " " " self region_id " " self peer get_id ( ) " " cc get_change_type ( ) " " cc get_node_id ( ) ) ; let propose_index = self . next_proposal_index ( ) ; self . raft_group . propose_conf_change ( ProposalContext :: SYNC_LOG . to_vec ( ) , cc ) ? ; if self . next_proposal_index ( ) == propose_index { // The message is dropped silently, this usually due to leader absence // or transferring leader. Both cases can be considered as NotLeader error. return Err ( Error :: NotLeader ( self . region_id , None ) ) ; } Ok ( Either :: Left ( propose_index ) ) }
Fails in such cases:
1.
Fails in such cases : 1 .
&mut self
ctx
&mut PollContext<EK, ER, T, C>
req
&RaftCmdRequest