mod factory;
mod reader;
mod sigbus;
pub use factory::{
should_use_short_circuit, CapabilityProvider, ScDecisionCtx, ShortCircuitConfig,
ShortCircuitFactory,
};
pub use reader::LocalBlockReader;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum AccessHint {
Sequential,
Random,
#[default]
Default,
}
impl AccessHint {
pub fn from_advise_str(s: &str) -> Self {
match s.trim().to_ascii_lowercase().as_str() {
"sequential" | "seq" => AccessHint::Sequential,
"random" | "rand" => AccessHint::Random,
_ => AccessHint::Default,
}
}
}
#[derive(Debug, thiserror::Error)]
pub enum ShortCircuitError {
#[error("short-circuit: block source is not local")]
NotLocal,
#[error("short-circuit: OpenLocalBlock failed: {0}")]
OpenLocalBlock(#[source] Box<crate::error::Error>),
#[error("short-circuit: OpenLocalBlock response had no path")]
MissingPath,
#[error("short-circuit: open local block file failed: {0}")]
FileOpen(#[source] std::io::Error),
#[error("short-circuit: mmap failed: {0}")]
Mmap(#[source] std::io::Error),
#[error("short-circuit: logical block size {logical} exceeds mapped file size {mapped}")]
SizeMismatch { logical: usize, mapped: usize },
#[error("short-circuit: madvise failed: {0}")]
Madvise(#[source] std::io::Error),
#[error("short-circuit: out of range (off={off}, len={len}, file_size={file_size})")]
OutOfRange {
off: usize,
len: usize,
file_size: usize,
},
#[error("short-circuit: SIGBUS on mapping")]
SigBus,
}
impl ShortCircuitError {
pub fn is_semantic(&self) -> bool {
matches!(self, ShortCircuitError::OutOfRange { .. })
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn access_hint_from_str() {
assert_eq!(AccessHint::from_advise_str("random"), AccessHint::Random);
assert_eq!(AccessHint::from_advise_str("RAND"), AccessHint::Random);
assert_eq!(
AccessHint::from_advise_str("sequential"),
AccessHint::Sequential
);
assert_eq!(AccessHint::from_advise_str("normal"), AccessHint::Default);
assert_eq!(AccessHint::from_advise_str("none"), AccessHint::Default);
assert_eq!(AccessHint::from_advise_str("bogus"), AccessHint::Default);
}
#[test]
fn access_hint_default_is_default_variant() {
assert_eq!(AccessHint::default(), AccessHint::Default);
}
#[test]
fn only_out_of_range_is_semantic() {
assert!(ShortCircuitError::OutOfRange {
off: 0,
len: 1,
file_size: 0
}
.is_semantic());
assert!(!ShortCircuitError::NotLocal.is_semantic());
assert!(!ShortCircuitError::MissingPath.is_semantic());
assert!(!ShortCircuitError::SigBus.is_semantic());
assert!(!ShortCircuitError::SizeMismatch {
logical: 100,
mapped: 50
}
.is_semantic());
assert!(!ShortCircuitError::FileOpen(std::io::Error::from(
std::io::ErrorKind::PermissionDenied
))
.is_semantic());
}
}