use std::path::Path;
use faultbox::{Capture, EventKind, error_chain_of};
use super::context;
use crate::error::WalError;
const DAMAGED_SEGMENT_ARTIFACT: &str = "damaged-segment.wal";
pub fn mid_file_corruption(
err: &WalError,
path: &Path,
offset: u64,
resync_offset: u64,
resync_lsn: u64,
last_lsn: u64,
) {
let file_len = std::fs::metadata(path).ok().map(|meta| meta.len());
let ctx = context::MidFileCorruption {
path,
offset,
resync_offset,
resync_lsn,
last_lsn,
file_len,
};
let note = format!(
"verbatim copy of the WAL segment as recovery found it: damage begins at offset \
{offset}, the first intact record past it is at offset {resync_offset} (LSN \
{resync_lsn}), and the last LSN read before the damage was {last_lsn}"
);
let _ = Capture::new(
EventKind::Corruption,
"mid-file WAL corruption hides committed records",
)
.error_chain(error_chain_of(err))
.domain(&ctx)
.with_backtrace()
.preserve("wal-segment", path, DAMAGED_SEGMENT_ARTIFACT, Some(note))
.emit();
}
pub fn segment_lsn_gap(
err: &WalError,
path: &Path,
previous_path: &Path,
previous_last_lsn: u64,
expected_lsn: u64,
found_lsn: u64,
) {
let ctx = context::SegmentLsnGap {
path,
previous_path,
previous_last_lsn,
expected_lsn,
found_lsn,
};
let _ = Capture::new(
EventKind::InvariantViolation,
"WAL segments are not contiguous: a segment is missing from the middle of the log",
)
.error_chain(error_chain_of(err))
.domain(&ctx)
.with_backtrace()
.emit();
}
pub fn replay_below_retained_floor(
err: &WalError,
path: &Path,
from_lsn: u64,
retained_floor_lsn: u64,
) {
let ctx = context::ReplayBelowRetainedFloor {
path,
from_lsn,
retained_floor_lsn,
};
let _ = Capture::new(
EventKind::InvariantViolation,
"WAL replay asked for a suffix that truncation already deleted",
)
.error_chain(error_chain_of(err))
.domain(&ctx)
.with_backtrace()
.emit();
}
pub fn durability_lost(err: &WalError, detail: &str) {
let ctx = context::DurabilityLost { detail };
let _ = Capture::new(
EventKind::InvariantViolation,
"WAL fsync failed: acknowledged records may no longer exist on disk",
)
.error_chain(error_chain_of(err))
.domain(&ctx)
.with_backtrace()
.emit();
}
pub fn encrypted_record_without_key(err: &WalError, lsn: u64, site: &'static str) {
let ctx = context::EncryptedRecordWithoutKey { lsn, site };
let _ = Capture::new(
EventKind::Error,
"encrypted WAL record reached a plaintext-only path with no decryption key",
)
.error_chain(error_chain_of(err))
.domain(&ctx)
.emit();
}
pub fn out_of_space(err: &WalError, site: &'static str, file_offset: u64, pending_bytes: u64) {
let ctx = context::OutOfSpace {
site,
file_offset,
pending_bytes,
};
let _ = Capture::new(
EventKind::Error,
"WAL append failed: no space left on device",
)
.error_chain(error_chain_of(err))
.domain(&ctx)
.emit();
}