use std::sync::Arc;
use nodedb_fts::lsm::segment::error::SegmentError;
use crate::storage::quarantine::error::QuarantineError;
use crate::storage::quarantine::registry::{QuarantineEngine, QuarantineRegistry, SegmentKey};
pub fn validate_fts_segment_bytes(
registry: &Arc<QuarantineRegistry>,
bytes: Vec<u8>,
collection: &str,
segment_id: &str,
) -> Result<Vec<u8>, FtsOrQuarantine> {
match nodedb_fts::lsm::segment::reader::SegmentReader::open(bytes.clone()) {
Ok(_reader) => {
let key = SegmentKey {
engine: QuarantineEngine::Fts,
collection: collection.to_string(),
segment_id: segment_id.to_string(),
};
registry.record_success(&key);
Ok(bytes)
}
Err(e) if is_crc_class(&e) => {
let key = SegmentKey {
engine: QuarantineEngine::Fts,
collection: collection.to_string(),
segment_id: segment_id.to_string(),
};
registry
.record_failure(key, &e.to_string(), None)
.map_err(FtsOrQuarantine::Quarantined)?;
Err(FtsOrQuarantine::Segment(e))
}
Err(e) => Err(FtsOrQuarantine::Segment(e)),
}
}
#[derive(Debug, thiserror::Error)]
pub enum FtsOrQuarantine {
#[error(transparent)]
Segment(#[from] SegmentError),
#[error(transparent)]
Quarantined(#[from] QuarantineError),
}
pub fn open_fts_segment_with_quarantine(
registry: &Arc<QuarantineRegistry>,
bytes: Vec<u8>,
collection: &str,
segment_id: &str,
) -> Result<Vec<u8>, FtsOrQuarantine> {
validate_fts_segment_bytes(registry, bytes, collection, segment_id)
}
fn is_crc_class(e: &SegmentError) -> bool {
matches!(
e,
SegmentError::ChecksumMismatch { .. } | SegmentError::Truncated | SegmentError::BadMagic
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty_bytes_first_strike_returns_segment_error() {
let reg = Arc::new(QuarantineRegistry::new());
let r1 = validate_fts_segment_bytes(®, vec![], "coll", "seg1");
assert!(matches!(r1, Err(FtsOrQuarantine::Segment(_))));
}
#[test]
fn empty_bytes_second_strike_returns_quarantined() {
let reg = Arc::new(QuarantineRegistry::new());
let _ = validate_fts_segment_bytes(®, vec![], "coll", "seg2");
let r2 = validate_fts_segment_bytes(®, vec![], "coll", "seg2");
assert!(matches!(r2, Err(FtsOrQuarantine::Quarantined(_))));
}
#[test]
fn non_crc_error_is_not_quarantined() {
let reg = Arc::new(QuarantineRegistry::new());
let key = crate::storage::quarantine::registry::SegmentKey {
engine: crate::storage::quarantine::registry::QuarantineEngine::Fts,
collection: "coll".to_string(),
segment_id: "seg3".to_string(),
};
reg.record_success(&key);
let r = validate_fts_segment_bytes(®, vec![], "coll", "seg3");
assert!(matches!(r, Err(FtsOrQuarantine::Segment(_))));
}
}