Skip to main content

krabka_verified/
reconfiguration.rs

1//! `KRaft` voter-reconfiguration admission and result shape.
2//!
3//! The decision follows the order in which Kafka's `KafkaRaftClient`,
4//! `AddVoterHandler`, `RemoveVoterHandler`, `UpdateVoterHandler`, and
5//! `LeaderState.maybeAppendUpgradedKRaftVersion` reject a request, and it
6//! admits a change only while KIP-853's one-change-at-a-time rule holds: the
7//! node leads, its epoch is committed, no earlier change is pending, and no
8//! control record is uncommitted.
9
10#[cfg(creusot)]
11use creusot_std::prelude::*;
12
13/// The KIP-853 control operation being validated.
14#[krabka_macros::model_type]
15pub enum VoterChangeKind {
16    Add,
17    Remove,
18    Update,
19    FinalizeKraftVersion,
20}
21
22/// The receiving node's leadership state for one reconfiguration.
23#[krabka_macros::model_type]
24pub struct ReconfigurationLeadership {
25    /// The node is the current `KRaft` leader.
26    pub is_leader: bool,
27    /// No earlier voter change is waiting for its record to commit.
28    pub no_pending_change: bool,
29    /// The leader has committed its own epoch, so Kafka's leader HWM exists.
30    pub epoch_committed: bool,
31}
32
33/// The committed voter set the change applies to.
34#[krabka_macros::model_type]
35pub struct CurrentVoterSet {
36    pub voter_count: usize,
37    /// The committed `kraft.version`.
38    pub kraft_version: u16,
39    /// The latest voter set and `kraft.version` in the log equal the
40    /// committed ones: no control record is uncommitted.
41    pub latest_controls_committed: bool,
42    /// Every current voter's supported range covers the requested
43    /// `kraft.version`. Only a finalization reads it.
44    pub all_voters_support_requested: bool,
45}
46
47/// One requested control operation.
48#[krabka_macros::model_type]
49pub struct VoterChangeRequest {
50    pub kind: VoterChangeKind,
51    /// The `kraft.version` a finalization asks for.
52    pub requested_kraft_version: u16,
53}
54
55/// How the request's voter key relates to the current voter set.
56#[krabka_macros::model_type]
57pub enum TargetMembership {
58    /// No current voter has the request's voter id.
59    Absent,
60    /// The voter id is current, and its stored directory id is unknown.
61    PresentUnknownDirectory,
62    /// The voter id is current, with the request's directory id.
63    PresentSameDirectory,
64    /// The voter id is current, with a different known directory id.
65    PresentOtherDirectory,
66}
67
68/// Facts about the voter an add, remove, or update names. A finalization
69/// names no voter and does not read them.
70#[krabka_macros::model_type]
71pub struct TargetVoter {
72    pub membership: TargetMembership,
73    /// The voter's supported range covers the committed `kraft.version`.
74    pub version_compatible: bool,
75    /// The voter has fetched up to the leader's log end.
76    pub caught_up: bool,
77}
78
79/// The exact control-record shape of an admitted change.
80#[krabka_macros::model_type]
81pub struct VoterReconfigurationPlan {
82    pub next_voter_count: usize,
83    pub next_kraft_version: u16,
84    pub write_voters: bool,
85    pub write_kraft_version: bool,
86    pub preflight_only: bool,
87}
88
89#[krabka_macros::model_type]
90pub enum VoterReconfigurationDecision {
91    NotLeader,
92    InProgress,
93    EpochUncommitted,
94    EmptyCurrentVoterSet,
95    UnsupportedKraftVersion,
96    DuplicateVoter,
97    IncompatibleVoter,
98    VoterNotCaughtUp,
99    VoterNotFound,
100    DirectoryMismatch,
101    InvalidVersionTransition,
102    Admit(VoterReconfigurationPlan),
103}
104
105/// The leadership and committed voter-set snapshot captured for one control change.
106pub type ReconfigurationState = (ReconfigurationLeadership, CurrentVoterSet);
107
108mod admitted_plan;
109#[cfg(creusot)]
110pub use admitted_plan::{
111    admitted_plan, is_admit, may_reconfigure, update_key_matches, voter_reconfiguration_rejection,
112    voter_set_removes,
113};
114
115mod voter_reconfiguration_decision;
116pub use voter_reconfiguration_decision::voter_reconfiguration_decision;
117
118#[cfg(test)]
119mod tests;
120
121#[cfg(test)]
122pub(crate) mod test_support;