Skip to main content

krabka_verified/
features.rs

1//! Feature-finalization admission for one `UpdateFeatures` row.
2//!
3//! The decision follows Kafka 4.3.1's `FeatureControlManager.updateFeature`
4//! check for check: the upgrade type, a negative level, every node's support
5//! (`reasonNotSupported`), the update direction against the current level
6//! (an unfinalized feature reads as level 0), and then the per-feature tail:
7//! `updateMetadataVersion`'s `didMetadataChange` refusal for
8//! `metadata.version`, the no-downgrade rule for `kraft.version`, and
9//! `Feature.validateVersion`'s KIP-1022 dependencies for every other feature.
10
11#[cfg(creusot)]
12use creusot_std::prelude::*;
13
14/// KIP-584 `FeatureUpdate.UpgradeType`, decoded from the request.
15#[krabka_macros::model_type]
16pub enum FeatureUpdateType {
17    Upgrade,
18    SafeDowngrade,
19    UnsafeDowngrade,
20}
21
22/// The levels one feature row compares.
23#[krabka_macros::model_type]
24pub struct FeatureLevels {
25    /// The row's `MaxVersionLevel`.
26    pub requested: i16,
27    /// The current level, `0` for a feature that is not finalized.
28    pub current: i16,
29}
30
31/// Which branch of `updateFeature` decides the row after the shared checks,
32/// with the one fact that branch reads.
33#[krabka_macros::model_type]
34pub enum FeatureKind {
35    /// `metadata.version`. `metadata_changed` is Kafka's
36    /// `MetadataVersion.checkIfMetadataChanged` between the current and the
37    /// requested level.
38    MetadataVersion { metadata_changed: bool },
39    /// `kraft.version`, which the Raft layer finalizes.
40    KRaftVersion,
41    /// Every other feature. `dependencies_met` is `Feature.validateVersion`
42    /// against the proposed levels: the finalized levels with every update
43    /// of the same request applied.
44    Other { dependencies_met: bool },
45}
46
47/// Everything one `UpdateFeatures` row is decided on.
48#[krabka_macros::model_type]
49pub struct FeatureUpdateFacts {
50    /// `None` when the row carries an unknown upgrade-type code.
51    pub update_type: Option<FeatureUpdateType>,
52    pub levels: FeatureLevels,
53    /// The local controller, every registered broker, and every registered
54    /// controller support the requested level, and every quorum controller
55    /// has registered.
56    pub all_nodes_support: bool,
57    pub kind: FeatureKind,
58}
59
60/// The first failed rule, or what an admitted row does.
61#[krabka_macros::model_type]
62pub enum FeatureUpdateDecision {
63    UnknownUpdateType,
64    NegativeLevel,
65    UnsupportedByNode,
66    DowngradeWithoutFlag,
67    DowngradeToNewerLevel,
68    /// A `metadata.version` downgrade across a level that changed metadata,
69    /// asked for as `UNSAFE_DOWNGRADE`.
70    UnsafeMetadataDowngrade,
71    /// A `metadata.version` downgrade across a level that changed metadata,
72    /// asked for as `SAFE_DOWNGRADE`.
73    LossyMetadataDowngrade,
74    /// A `kraft.version` downgrade.
75    KRaftDowngrade,
76    DependencyUnmet,
77    /// Emit the feature-level record.
78    EmitFeature,
79    /// Hand the `kraft.version` upgrade to the Raft layer.
80    UpgradeKRaft,
81    /// A `kraft.version` row with a downgrade type at the current level:
82    /// nothing to do.
83    NoChange,
84}
85
86mod feature_update_decision;
87pub use feature_update_decision::feature_update_decision;
88#[cfg(creusot)]
89pub use feature_update_decision::feature_update_model;
90
91#[cfg(test)]
92mod tests;