moonbitstack/moonraft/confchange does not have a README file

    Changer

    pub struct Changer {
    cfg : ChangerConfig
    prs : Map[String,
    Progress
    ]
    last_index : UInt64
    max_inflight : Int
    max_inflight_bytes : UInt64
    }

    The Changer drives a configuration through single and joint changes. Each public operation is transactional: on error the configuration is left untouched (etcd's checkAndCopy semantics).

    Changer::advance_index

    fn Changer::advance_index(self : Changer) -> Unit

    Advance the index a newly-added follower's progress is anchored at. The datadriven harness bumps this once per command so next reveals which "round" a progress was created in (proving a demoted voter's progress is preserved, not recreated, across a joint transition).

    Changer::conf_state

    The configuration as a ConfState (etcd's ProgressTracker.ConfState): the incoming voters, the outgoing half, the learners and the staged learners, plus the auto-leave flag. Used to round-trip a configuration through a snapshot.

    Changer::describe

    fn Changer::describe(self : Changer) -> String

    The configuration and its per-follower progress, in etcd's datadriven format: voters=(…)[&&(…)] [learners=(…)] [learners_next=(…)] [autoleave], then one line per follower.

    Changer::enter_joint

    fn Changer::enter_joint(self : Changer, auto_leave : Bool, changes : Array[(String, String)]) -> String?

    Enter joint consensus C(new,old): rotate the incoming voters into the outgoing half, then apply the batch to the incoming half.

    Changer::leave_joint

    fn Changer::leave_joint(self : Changer) -> String?

    Leave joint consensus: promote any staged learners_next to learners, preserving their progress, and drop the outgoing half.

    Changer::new

    fn Changer::new(last_index? : UInt64, max_inflight? : Int, max_inflight_bytes? : UInt64) -> Changer

    A Changer over an empty configuration, with progress next-indices anchored at last_index, a per-follower window of max_inflight messages and, when non-zero, max_inflight_bytes bytes (etcd's MakeProgressTracker (maxInflight, maxBytes); 0 = no byte limit).

    Changer::restore

    Rebuild a configuration from a ConfState (etcd's Restore), running the same sequence of changes the state describes. Returns an error message on an inconsistent state.

    Changer::simple

    fn Changer::simple(self : Changer, changes : Array[(String, String)]) -> String?

    A simple (non-joint) change: it may mutate the incoming voter set by at most one, and may not run while joint.

    ChangerConfig

    pub struct ChangerConfig {
    incoming : Array[String]
    outgoing : Array[String]
    learners : Array[String]
    learners_next : Array[String]
    auto_leave : Bool
    }

    The full configuration the Changer maintains: the incoming and outgoing voter halves (outgoing non-empty iff joint), the learners, and the learners that will become learners once a joint configuration is left (learners_next).

    ConfChange

    pub(all) struct ConfChange {
    change_type : ConfChangeType
    node_id : String
    } derive(Eq)

    A configuration change carried by a ConfChange log entry: which server is joining or leaving. It is serialized into the entry's command so every server applies the same change at the same log position.

    ConfChange::add

    fn ConfChange::add(id : String) -> ConfChange

    A change that adds id to the cluster.

    ConfChange::add_learner

    fn ConfChange::add_learner(id : String) -> ConfChange

    A change that adds id as a learner (a non-voting member).

    ConfChange::apply_to

    fn ConfChange::apply_to(self : ConfChange, config : Membership) -> Unit

    Apply this change to a configuration in place.

    ConfChange::decode

    fn ConfChange::decode(command : Bytes) -> ConfChange?

    Recover a configuration change from a log-entry command, or None if the bytes are not a well-formed change.

    ConfChange::encode

    fn ConfChange::encode(self : ConfChange) -> Bytes

    Serialize this change into a log-entry command. The encoding is a one- character tag ('+' add voter, '-' remove, 'L' add learner) followed by the server id, which keeps it human-readable in dumps and trivially reversible.

    ConfChange::remove

    fn ConfChange::remove(id : String) -> ConfChange

    A change that removes id from the cluster.

    ConfChangeTransition

    pub(all) enum ConfChangeTransition {
    Auto
    JointImplicit
    JointExplicit
    } derive(Eq)

    How a ConfChangeV2 transitions the configuration (etcd's ConfChangeTransition): Auto applies a batch simply when it safely can (at most one voter changed) and otherwise enters an auto-leaving joint; JointImplicit always enters joint and auto-leaves; JointExplicit always enters joint and waits for an explicit leave.

    ConfChangeType

    pub(all) enum ConfChangeType {
    AddNode
    RemoveNode
    AddLearnerNode
    } derive(Eq)

    The kind of a single-server configuration change (Raft §6, §4.2.1).

    ConfChangeV2

    pub(all) struct ConfChangeV2 {
    changes : Array[ConfChange]
    transition : ConfChangeTransition
    } derive(Eq)

    A batch configuration change (etcd's ConfChangeV2): several single changes applied atomically. An empty batch leaves joint consensus. Whether a non-empty batch is applied simply or via a joint transition — and whether that joint auto-leaves — is governed by transition (Raft §4.3, joint consensus).

    ConfChangeV2::auto

    fn ConfChangeV2::auto(changes : Array[ConfChange]) -> ConfChangeV2

    A batch with the Auto transition: applied simply when it can be (at most one voter changed), otherwise as an auto-leaving joint change — etcd's default.

    ConfChangeV2::auto_leave

    fn ConfChangeV2::auto_leave(self : ConfChangeV2) -> Bool

    Whether this joint change auto-leaves once committed.

    ConfChangeV2::decode

    fn ConfChangeV2::decode(command : Bytes) -> ConfChangeV2?

    Recover a batch change, or None if the bytes are not a well-formed batch.

    ConfChangeV2::encode

    fn ConfChangeV2::encode(self : ConfChangeV2) -> Bytes

    Serialize as V + transition tag (a/i/e) + ;-separated <tag><id> changes. The V prefix distinguishes a batch from a single change on decode.

    ConfChangeV2::enter_joint

    fn ConfChangeV2::enter_joint(changes : Array[ConfChange], auto_leave? : Bool) -> ConfChangeV2

    Enter joint consensus with changes. auto_leave selects the implicit (auto-leaving) or explicit joint transition — the historical API.

    ConfChangeV2::enters_joint

    fn ConfChangeV2::enters_joint(self : ConfChangeV2) -> (Bool, Bool)

    Whether this batch enters a joint configuration, and if so whether that joint auto-leaves (etcd's ConfChangeV2.EnterJoint). Auto with at most one change is applied simply — no joint; anything else is joint, auto-leaving unless the transition is explicit.

    ConfChangeV2::is_leave

    fn ConfChangeV2::is_leave(self : ConfChangeV2) -> Bool

    Whether this change leaves a joint configuration (etcd's ConfChangeV2.LeaveJoint). This is the case only for the Auto transition with no changes: an explicit joint transition carrying no changes still enters an (empty) joint config and must not be mistaken for a leave, which is exactly the complement of enters_joint.

    ConfChangeV2::leave_joint

    fn ConfChangeV2::leave_joint() -> ConfChangeV2

    Leave joint consensus (an empty batch).

    Membership

    pub(all) struct Membership {
    members : Array[String]
    outgoing : Array[String]
    joint : Bool
    learners : Array[String]
    learners_next : Array[String]
    auto_leave : Bool
    }

    The set of servers that currently form the cluster. Raft changes membership through the log so every server adopts each change at the same point in the sequence (Raft §6). Two disciplines are supported: single-server changes, where the old and new majorities always overlap; and joint consensus, where the cluster passes through a transitional configuration C(old,new) that needs a majority of both the old and the new voter sets to agree.

    members is the incoming configuration C(new). outgoing holds the old configuration C(old) and is non-empty only while joint is true.

    Membership::add

    fn Membership::add(self : Membership, id : String) -> Unit

    Add a server as a voter, unless it already is one. A learner being added as a voter is promoted: it leaves the learner set (Raft §4.2.1).

    Membership::add_learner

    fn Membership::add_learner(self : Membership, id : String) -> Unit

    Add id as a learner (non-voting member). If it is currently a voter this demotes it (etcd's l<id>). A voter demoted while a joint config is active and still present in the outgoing half is staged in learners_next: it leaves the incoming voters but keeps voting through the outgoing half until the config is left, so its removal from the quorum is atomic with the leave (Raft §4.3). Otherwise it becomes a learner right away.

    Membership::begin_joint

    fn Membership::begin_joint(self : Membership, outgoing : Array[String]) -> Unit

    Enter joint consensus keeping the already-updated incoming set, recording outgoing as the old half. Used when the incoming voters have been mutated in place by a batch of changes (etcd's ConfChangeV2 EnterJoint).

    Membership::committed_index

    fn Membership::committed_index(self : Membership, acked : Map[String, UInt64]) -> UInt64

    The committed index this configuration agrees on, given the acked indices, accounting for the joint transition when one is in progress.

    Membership::contains

    fn Membership::contains(self : Membership, id : String) -> Bool

    Whether id is a voter in the current configuration — in the incoming set, or, during a joint transition, in either half.

    Membership::enter_joint

    fn Membership::enter_joint(self : Membership, new_members : Array[String]) -> Unit

    Enter joint consensus, moving to the target voter set new_members while keeping the current set as the outgoing half. Until the transition is committed and leave_joint is called, decisions need both majorities.

    Membership::has_majority

    fn Membership::has_majority(self : Membership, granted : Array[String]) -> Bool

    Whether granted (the ids that agreed, e.g. voted or acknowledged) forms a majority. A simple configuration needs a majority of the incoming set; a joint configuration needs a majority of the incoming set and a majority of the outgoing set, which is what makes joint consensus safe against split decisions during a change (Raft §6).

    Membership::is_joint

    fn Membership::is_joint(self : Membership) -> Bool

    Whether the configuration is currently in the joint (transitional) state.

    Membership::is_learner

    fn Membership::is_learner(self : Membership, id : String) -> Bool

    Whether id is a learner (a non-voting member).

    Membership::leave_joint

    fn Membership::leave_joint(self : Membership) -> Unit

    Leave joint consensus once C(old,new) is committed: the outgoing half is dropped and the cluster runs on the incoming configuration alone.

    Membership::new

    fn Membership::new(members : Array[String]) -> Membership

    Create a simple (non-joint) cluster configuration from an initial voter set.

    Membership::nodes

    fn Membership::nodes(self : Membership) -> Array[String]

    Every server that participates in replication: voters and learners alike.

    Membership::quorum

    fn Membership::quorum(self : Membership) -> Int

    The majority size of the current (incoming) configuration. Meaningful for a simple configuration; in a joint configuration use has_majority, which accounts for both halves.

    Membership::remove

    fn Membership::remove(self : Membership, id : String) -> Unit

    Remove a server from the configuration entirely — voter or learner.

    Membership::size

    fn Membership::size(self : Membership) -> Int

    The number of servers in the incoming configuration.

    Membership::vote_result

    fn Membership::vote_result(self : Membership, votes : Map[String, Bool]) ->
    VoteState

    The vote outcome for this configuration, accounting for a joint transition.

    Membership::voters

    fn Membership::voters(self : Membership) -> Array[String]

    The voters of the current configuration, de-duplicated across both halves.