use crate::error::{Result, WalError};
use super::meta::SegmentMeta;
pub fn check_retained_floor(segments: &[SegmentMeta], from_lsn: u64) -> Result<()> {
if from_lsn == 0 {
return Ok(());
}
let Some(earliest) = segments.first() else {
return Ok(());
};
if from_lsn >= earliest.first_lsn {
return Ok(());
}
let err = WalError::ReplayBelowRetainedFloor {
from_lsn,
retained_floor_lsn: earliest.first_lsn,
earliest_segment: earliest.path.display().to_string(),
};
crate::diag::replay_below_retained_floor(&err, &earliest.path, from_lsn, earliest.first_lsn);
Err(err)
}
#[cfg(test)]
mod tests {
use super::*;
use std::path::Path;
fn meta(first_lsn: u64) -> SegmentMeta {
SegmentMeta {
path: Path::new("/wal").join(super::super::segment_filename(first_lsn)),
first_lsn,
file_size: 0,
}
}
#[test]
fn suffix_above_the_floor_is_retained() {
assert!(check_retained_floor(&[meta(5000), meta(9000)], 7000).is_ok());
}
#[test]
fn suffix_exactly_at_the_floor_is_retained() {
assert!(check_retained_floor(&[meta(5000), meta(9000)], 5000).is_ok());
}
#[test]
fn suffix_below_the_floor_is_rejected_naming_both_lsns() {
match check_retained_floor(&[meta(5000)], 4999) {
Err(WalError::ReplayBelowRetainedFloor {
from_lsn,
retained_floor_lsn,
..
}) => {
assert_eq!(from_lsn, 4999);
assert_eq!(retained_floor_lsn, 5000);
}
other => panic!("expected a retained-floor violation, got {other:?}"),
}
}
#[test]
fn full_replay_is_exempt() {
assert!(check_retained_floor(&[meta(5000)], 0).is_ok());
}
#[test]
fn empty_directory_has_no_floor() {
assert!(check_retained_floor(&[], 42).is_ok());
}
}