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;