Skip to main content

krabka_raft/config/
kafka_release.rs

1//! The API version table of the Kafka release krabka matches by default.
2//!
3//! `krabka-protocol` vendors Kafka trunk's message schemas, which run ahead of
4//! the latest Kafka release. [`KAFKA_4_3_1_APIS`] is what a stock
5//! `apache/kafka:4.3.1` accepts instead: every request schema's
6//! `validVersions` in `clients/src/main/resources/common/message` at the
7//! `4.3.1` tag, with the one version 4.3.1 marks `latestVersionUnstable`
8//! (`InitProducerId` v6) left out, since that release advertises it only under
9//! `unstable.api.versions.enable` too. It is what both listeners serve while
10//! [`UnstableApiVersions::Disabled`](crate::UnstableApiVersions) holds.
11
12/// One Kafka 4.3.1 request schema: its api key and the versions the release
13/// accepts by default.
14#[derive(Clone, Copy, Debug, Eq, PartialEq)]
15pub struct ReleasedApi {
16    pub api_key: i16,
17    /// `validVersions`' lower bound. `Produce` advertises from 0 regardless
18    /// (`ApiKeys.PRODUCE_API_VERSIONS_RESPONSE_MIN_VERSION`, KAFKA-18659).
19    pub min_version: i16,
20    /// `validVersions`' upper bound, below a `latestVersionUnstable` version.
21    pub max_version: i16,
22}
23
24const fn api(api_key: i16, min_version: i16, max_version: i16) -> ReleasedApi {
25    ReleasedApi {
26        api_key,
27        min_version,
28        max_version,
29    }
30}
31
32/// Every api key Kafka 4.3.1 has a valid version of, in key order.
33pub const KAFKA_4_3_1_APIS: &[ReleasedApi] = &[
34    api(0, 3, 13), // Produce
35    api(1, 4, 18), // Fetch
36    api(2, 1, 11), // ListOffsets
37    api(3, 0, 13), // Metadata
38    api(8, 2, 10), // OffsetCommit
39    api(9, 1, 10), // OffsetFetch
40    api(10, 0, 6), // FindCoordinator
41    api(11, 0, 9), // JoinGroup
42    api(12, 0, 4), // Heartbeat
43    api(13, 0, 5), // LeaveGroup
44    api(14, 0, 5), // SyncGroup
45    api(15, 0, 6), // DescribeGroups
46    api(16, 0, 5), // ListGroups
47    api(17, 0, 1), // SaslHandshake
48    api(18, 0, 4), // ApiVersions
49    api(19, 2, 7), // CreateTopics
50    api(20, 1, 6), // DeleteTopics
51    api(21, 0, 2), // DeleteRecords
52    api(22, 0, 5), // InitProducerId
53    api(23, 2, 4), // OffsetForLeaderEpoch
54    api(24, 0, 5), // AddPartitionsToTxn
55    api(25, 0, 4), // AddOffsetsToTxn
56    api(26, 0, 5), // EndTxn
57    api(27, 1, 2), // WriteTxnMarkers
58    api(28, 0, 5), // TxnOffsetCommit
59    api(29, 1, 3), // DescribeAcls
60    api(30, 1, 3), // CreateAcls
61    api(31, 1, 3), // DeleteAcls
62    api(32, 1, 4), // DescribeConfigs
63    api(33, 0, 2), // AlterConfigs
64    api(34, 1, 2), // AlterReplicaLogDirs
65    api(35, 1, 5), // DescribeLogDirs
66    api(36, 0, 2), // SaslAuthenticate
67    api(37, 0, 3), // CreatePartitions
68    api(38, 1, 3), // CreateDelegationToken
69    api(39, 1, 2), // RenewDelegationToken
70    api(40, 1, 2), // ExpireDelegationToken
71    api(41, 1, 3), // DescribeDelegationToken
72    api(42, 0, 2), // DeleteGroups
73    api(43, 0, 2), // ElectLeaders
74    api(44, 0, 1), // IncrementalAlterConfigs
75    api(45, 0, 1), // AlterPartitionReassignments
76    api(46, 0, 0), // ListPartitionReassignments
77    api(47, 0, 0), // OffsetDelete
78    api(48, 0, 1), // DescribeClientQuotas
79    api(49, 0, 1), // AlterClientQuotas
80    api(50, 0, 0), // DescribeUserScramCredentials
81    api(51, 0, 0), // AlterUserScramCredentials
82    api(52, 0, 2), // Vote
83    api(53, 0, 1), // BeginQuorumEpoch
84    api(54, 0, 1), // EndQuorumEpoch
85    api(55, 0, 2), // DescribeQuorum
86    api(56, 2, 3), // AlterPartition
87    api(57, 0, 2), // UpdateFeatures
88    api(58, 0, 0), // Envelope
89    api(59, 0, 1), // FetchSnapshot
90    api(60, 0, 2), // DescribeCluster
91    api(61, 0, 0), // DescribeProducers
92    api(62, 0, 4), // BrokerRegistration
93    api(63, 0, 2), // BrokerHeartbeat
94    api(64, 0, 0), // UnregisterBroker
95    api(65, 0, 0), // DescribeTransactions
96    api(66, 0, 2), // ListTransactions
97    api(67, 0, 0), // AllocateProducerIds
98    api(68, 0, 1), // ConsumerGroupHeartbeat
99    api(69, 0, 1), // ConsumerGroupDescribe
100    api(70, 0, 0), // ControllerRegistration
101    api(71, 0, 0), // GetTelemetrySubscriptions
102    api(72, 0, 0), // PushTelemetry
103    api(73, 0, 0), // AssignReplicasToDirs
104    api(74, 0, 1), // ListConfigResources
105    api(75, 0, 0), // DescribeTopicPartitions
106    api(76, 1, 1), // ShareGroupHeartbeat
107    api(77, 1, 1), // ShareGroupDescribe
108    api(78, 1, 2), // ShareFetch
109    api(79, 1, 2), // ShareAcknowledge
110    api(80, 0, 1), // AddRaftVoter
111    api(81, 0, 0), // RemoveRaftVoter
112    api(82, 0, 0), // UpdateRaftVoter
113    api(83, 0, 0), // InitializeShareGroupState
114    api(84, 0, 0), // ReadShareGroupState
115    api(85, 0, 1), // WriteShareGroupState
116    api(86, 0, 0), // DeleteShareGroupState
117    api(87, 0, 1), // ReadShareGroupStateSummary
118    api(88, 0, 0), // StreamsGroupHeartbeat
119    api(89, 0, 0), // StreamsGroupDescribe
120    api(90, 0, 1), // DescribeShareGroupOffsets
121    api(91, 0, 0), // AlterShareGroupOffsets
122    api(92, 0, 0), // DeleteShareGroupOffsets
123];
124
125/// The Kafka 4.3.1 row for `api_key`, or `None` when that release has no such
126/// api key.
127#[must_use]
128pub const fn kafka_4_3_1_api(api_key: i16) -> Option<ReleasedApi> {
129    let mut rest: &[ReleasedApi] = KAFKA_4_3_1_APIS;
130    while let [row, tail @ ..] = rest {
131        if row.api_key == api_key {
132            return Some(*row);
133        }
134        rest = tail;
135    }
136    None
137}
138
139/// The highest version of `api_key` Kafka 4.3.1 accepts by default, or `None`
140/// when that release has no such api key.
141#[must_use]
142pub const fn kafka_4_3_1_max(api_key: i16) -> Option<i16> {
143    match kafka_4_3_1_api(api_key) {
144        Some(api) => Some(api.max_version),
145        None => None,
146    }
147}
148
149#[cfg(test)]
150mod tests {
151    use {super::*, assert2::check};
152
153    /// Strictly ascending, so a key is listed once, and every row names
154    /// versions `krabka-protocol` decodes: 4.3.1 is never ahead of trunk.
155    #[test]
156    fn the_table_is_ascending_and_inside_the_vendored_ranges() {
157        check!(
158            KAFKA_4_3_1_APIS
159                .windows(2)
160                .all(|pair| pair[0].api_key < pair[1].api_key)
161        );
162        check!(KAFKA_4_3_1_APIS.len() == 89);
163        for row in KAFKA_4_3_1_APIS {
164            check!(row.min_version <= row.max_version, "{row:?}");
165        }
166    }
167
168    #[yare::parameterized(
169        offset_fetch = { 18, Some(4) },
170        sasl_handshake = { 22, Some(5) },
171        txn_offset_commit = { 28, Some(5) },
172        api_key_88 = { 88, Some(0) },
173        api_key_89 = { 89, Some(0) },
174        api_key_92 = { 92, Some(0) },
175        first_unknown = { 93, None },
176        later_unknown = { 94, None },
177        private_key_unknown = { 1020, None },
178    )]
179    fn lookups_follow_the_table(api_key: i16, want: Option<i16>) {
180        check!(kafka_4_3_1_max(api_key) == want, "api_key {api_key}");
181    }
182
183    #[test]
184    fn api_table_includes_produce() {
185        check!(kafka_4_3_1_api(1) == Some(api(1, 4, 18)));
186    }
187}