use std::io::Result as IoResult;
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
pub trait IoHooks: Send + Sync {
fn before_wal_write(&self, _data: &[u8]) -> IoResult<()> {
Ok(())
}
fn after_wal_write(&self, _data: &[u8]) -> IoResult<()> {
Ok(())
}
fn before_fsync(&self) -> IoResult<()> {
Ok(())
}
fn after_fsync(&self) -> IoResult<()> {
Ok(())
}
fn before_sst_write(&self, _data: &[u8]) -> IoResult<()> {
Ok(())
}
fn on_compaction_start(&self) {}
fn on_compaction_end(&self) {}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum CrashOperation {
WalWrite,
WalFsync,
SstWrite,
SstFinalize,
Compaction,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum CrashTiming {
Before,
During,
After,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct CrashPoint {
pub operation: CrashOperation,
pub timing: CrashTiming,
}
pub struct CrashSimulator {
crash_points: Vec<CrashPoint>,
current_point: AtomicUsize,
enabled: AtomicBool,
}
impl CrashSimulator {
pub fn new() -> Self {
Self {
crash_points: Vec::new(),
current_point: AtomicUsize::new(0),
enabled: AtomicBool::new(true),
}
}
pub fn add_crash_point(mut self, point: CrashPoint) -> Self {
self.crash_points.push(point);
self
}
pub fn with_crash_points(mut self, points: Vec<CrashPoint>) -> Self {
self.crash_points.extend(points);
self
}
pub fn check_crash(&self, operation: CrashOperation, timing: CrashTiming) {
if !self.enabled.load(Ordering::Relaxed) {
return;
}
let idx = self.current_point.load(Ordering::Relaxed);
if let Some(point) = self.crash_points.get(idx) {
if point.operation == operation && point.timing == timing {
self.current_point.fetch_add(1, Ordering::Relaxed);
panic!(
"CrashSimulator: simulated crash at {:?}/{:?}",
operation, timing
);
}
}
}
pub fn disable(&self) {
self.enabled.store(false, Ordering::Relaxed);
}
pub fn enable(&self) {
self.enabled.store(true, Ordering::Relaxed);
}
pub fn remaining_crash_points(&self) -> usize {
let idx = self.current_point.load(Ordering::Relaxed);
self.crash_points.len().saturating_sub(idx)
}
}
impl Default for CrashSimulator {
fn default() -> Self {
Self::new()
}
}