use krabka_ids::LeaderEpoch;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct PartitionPosition {
pub offset_epoch: LeaderEpoch,
pub leader_id: i32,
pub leader_epoch: LeaderEpoch,
pub awaiting_validation: bool,
}
impl Default for PartitionPosition {
fn default() -> Self {
Self {
offset_epoch: LeaderEpoch(-1),
leader_id: -1,
leader_epoch: LeaderEpoch(-1),
awaiting_validation: false,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum ValidationOutcome {
Valid { leader_epoch: LeaderEpoch },
Truncated { safe_offset: i64 },
}
pub(crate) fn classify(
offset: i64,
offset_epoch: LeaderEpoch,
leader_epoch: LeaderEpoch,
leader_end_offset: i64,
) -> ValidationOutcome {
if leader_end_offset < 0 || leader_epoch < offset_epoch || leader_end_offset < offset {
ValidationOutcome::Truncated {
safe_offset: if leader_end_offset < 0 {
0
} else {
leader_end_offset
},
}
} else {
ValidationOutcome::Valid { leader_epoch }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn classify_decides_validity_or_truncation() {
use ValidationOutcome::{Truncated, Valid};
let cases = [
(
"consistent position is valid",
100,
LeaderEpoch(2),
LeaderEpoch(2),
150,
Valid {
leader_epoch: LeaderEpoch(2),
},
),
(
"leader end at position is still valid",
100,
LeaderEpoch(2),
LeaderEpoch(2),
100,
Valid {
leader_epoch: LeaderEpoch(2),
},
),
(
"leader end zero is known and valid for negative position",
-1,
LeaderEpoch(2),
LeaderEpoch(2),
0,
Valid {
leader_epoch: LeaderEpoch(2),
},
),
(
"leader end below position is truncation",
100,
LeaderEpoch(2),
LeaderEpoch(2),
80,
Truncated { safe_offset: 80 },
),
(
"negative leader end alone truncates to zero",
-3,
LeaderEpoch(2),
LeaderEpoch(2),
-2,
Truncated { safe_offset: 0 },
),
(
"older leader epoch is truncation",
100,
LeaderEpoch(2),
LeaderEpoch(1),
60,
Truncated { safe_offset: 60 },
),
(
"older leader epoch alone is truncation",
10,
LeaderEpoch(2),
LeaderEpoch(1),
20,
Truncated { safe_offset: 20 },
),
(
"undefined leader offset truncates to zero",
100,
LeaderEpoch(2),
LeaderEpoch(-1),
-1,
Truncated { safe_offset: 0 },
),
(
"undefined leader offset truncates even when epoch matches",
100,
LeaderEpoch(2),
LeaderEpoch(2),
-1,
Truncated { safe_offset: 0 },
),
];
for (_case, offset, offset_epoch, leader_epoch, leader_end_offset, expected) in cases {
assert2::assert!(
classify(offset, offset_epoch, leader_epoch, leader_end_offset) == expected
);
}
}
}