pub fn leave_joint(&mut self) -> Result<(Config, ProgressMap), String> {
        info!("leave joint");
        let mut cfg = self.tracker.config.clone();
        let mut prs = self.tracker.progress.clone();
        if !cfg.voters.joint() {
            return Err("can't leave a non-joint config".to_string());
        }
        if cfg.voters.outgoing.is_empty() {
            return Err(format!("configuration is not joint: {}", cfg));
        }
        for id in &cfg.learners_next {
            cfg.learners.insert(*id);
            let pr = prs.get_mut(&id).unwrap();
            pr.is_learner = true;
        }
        cfg.learners_next.clear();

        for id in cfg.voters.outgoing.iter() {
            let is_voter = cfg.voters.incoming.contains(id);
            let is_learner = cfg.learners.contains(id);
            if !is_voter && !is_learner {
                prs.remove(id);
            }
        }
        cfg.voters.outgoing.clear();
        cfg.auto_leave = false;
        Ok((cfg, prs))
    }
/// leave_joint transactions out of a joint configuration. It is an error to call
/// this method if the configuration is not joint, i.e. if the outgoing majority
/// config voters[1] is empty.
///
/// The outgoing majority config of the joint configuration will be removed,
/// that is, the incoming config is promoted as the sole decision maker. In the
/// notation of the Raft thesis[1] (Section 4.3), this method transactions from
/// `C_{new, old}` to `C_new`.
///
/// At the same time, any staged learners (learners_next) the addition of which
/// was held back by an overlapping voter in the former outgoing config will be
/// inserted into learners.
///
/// [1]: https://github.com/ongardie/dissertation/blob/master/online-trim.pdf
leave_joint transactions out of a joint configuration. It is an error to call
this method if the configuration is not joint, i.e. if the outgoing majority
config voters[1] is empty.

The outgoing majority config of the joint configuration will be removed,
that is, the incoming config is promoted as the sole decision maker. In the
notation of the Raft thesis[1] (Section 4.3), this method transactions from
`C_{new, old}` to `C_new`.

At the same time, any staged learners (learners_next) the addition of which
was held back by an overlapping voter in the former outgoing config will be
inserted into learners.


leave_joint transactions out of a joint configuration . It is an error to call this method if the configuration is not joint i . e . if the outgoing majority config voters [ 1 ] is empty . The outgoing majority config of the joint configuration will be removed that is the incoming config is promoted as the sole decision maker . In the notation of the Raft thesis [ 1 ] ( Section 4 . 3 ) this method transactions from ` C_ { new old } ` to ` C_new ` . At the same time any staged learners ( learners_next ) the addition of which was held back by an overlapping voter in the former outgoing config will be inserted into learners .
pub fn leave_joint(&mut self) -> Result<(Config, ProgressMap), String> {
        info!("leave joint");
        let mut cfg = self.tracker.config.clone();
        let mut prs = self.tracker.progress.clone();
        if !cfg.voters.joint() {
            return Err("can't leave a non-joint config".to_string());
        }
        if cfg.voters.outgoing.is_empty() {
            return Err(format!("configuration is not joint: {}", cfg));
        }
        for id in &cfg.learners_next {
            cfg.learners.insert(*id);
            let pr = prs.get_mut(&id).unwrap();
            pr.is_learner = true;
        }
        cfg.learners_next.clear();
        for id in cfg.voters.outgoing.iter() {
            let is_voter = cfg.voters.incoming.contains(id);
            let is_learner = cfg.learners.contains(id);
            if !is_voter && !is_learner {
                prs.remove(id);
            }
        }
        cfg.voters.outgoing.clear();
        cfg.auto_leave = false;
        Ok((cfg, prs))
    }
pub fn leave_joint ( & mut self ) -> Result < ( Config , ProgressMap ) , String > { info ! ( " " ) ; let mut cfg = self . tracker . config . clone ( ) ; let mut prs = self . tracker . progress . clone ( ) ; if ! cfg . voters . joint ( ) { return Err ( " " . to_string ( ) ) ; } if cfg . voters . outgoing . is_empty ( ) { return Err ( format ! ( " " cfg ) ) ; } for id in & cfg . learners_next { cfg . learners . insert ( * id ) ; let pr = prs . get_mut ( & id ) . unwrap ( ) ; pr . is_learner = true ; } cfg . learners_next . clear ( ) ; for id in cfg . voters . outgoing . iter ( ) { let is_voter = cfg . voters . incoming . contains ( id ) ; let is_learner = cfg . learners . contains ( id ) ; if ! is_voter && ! is_learner { prs . remove ( id ) ; } } cfg . voters . outgoing . clear ( ) ; cfg . auto_leave = false ; Ok ( ( cfg , prs ) ) }
leave_joint transactions out of a joint configuration.
leave_joint transactions out of a joint configuration .
&mut self