storage: Refine error pathways

next
Sayan Nandan 6 months ago
parent 37fc01d81f
commit 6fb3193465
No known key found for this signature in database
GPG Key ID: 0EBD769024B24F0A

@ -169,11 +169,11 @@ enumerate_err! {
/// Errors that occur when restoring transactional data
pub enum TransactionError {
/// corrupted txn payload. has more bytes than expected
DecodeCorruptedPayloadMoreBytes = "txn-payload-unexpected-content",
V1DecodeCorruptedPayloadMoreBytes = "txn-payload-unexpected-content",
/// transaction payload is corrupted. has lesser bytes than expected
DecodedUnexpectedEof = "txn-payload-unexpected-eof",
V1DecodedUnexpectedEof = "txn-payload-unexpected-eof",
/// unknown transaction operation. usually indicates a corrupted payload
DecodeUnknownTxnOp = "txn-payload-unknown-payload",
V1DecodeUnknownTxnOp = "txn-payload-unknown-payload",
/// While restoring a certain item, a non-resolvable conflict was encountered in the global state, because the item was
/// already present (when it was expected to not be present)
OnRestoreDataConflictAlreadyExists = "txn-payload-conflict-already-exists",
@ -246,7 +246,12 @@ enumerate_err! {
RawJournalDecodeInvalidEvent = "journal-invalid-event-order",
/// corrupted event within a batch
RawJournalDecodeCorruptionInBatchMetadata = "journal-batch-corrupted-event-metadata",
/// runtime error: the lightweight heartbeat failed
RawJournalRuntimeCriticalLwtHBFail = "journal-lwt-heartbeat-failed",
/*
----
runtime errors
----
*/
RawJournalRuntimeHeartbeatFail = "journal-lwt-heartbeat-failed",
RawJournalRuntimeDirty = "journal-in-dirty-state",
}
}

@ -33,7 +33,7 @@ use {
EntityIDRef,
},
data::uuid::Uuid,
error::ErrorKind,
error::StorageError,
fractal::GlobalInstanceLike,
storage::{
safe_interfaces::{paths_v1, StdModelBatch},
@ -528,9 +528,7 @@ impl FractalMgr {
if mdl_driver_.status().is_iffy() {
// don't mess this up any further
return Err((
super::error::Error::from(ErrorKind::Other(
"model driver is in dirty state".into(),
)),
super::error::Error::from(StorageError::RawJournalRuntimeDirty),
BatchStats::into_inner(BatchStats::new()),
));
}

@ -55,7 +55,7 @@ impl JournalAdapter for GNSAdapter {
fn decode_and_update_state(payload: &[u8], gs: &Self::GlobalState) -> RuntimeResult<()> {
macro_rules! dispatch {
($($item:ty),* $(,)?) => {
[$(<$item as GNSEvent>::decode_and_update_global_state),*, |_, _| Err(TransactionError::DecodeUnknownTxnOp.into())]
[$(<$item as GNSEvent>::decode_and_update_global_state),*, |_, _| Err(TransactionError::V1DecodeUnknownTxnOp.into())]
};
}
static DISPATCH: [fn(&mut BufferedScanner, &GNSData) -> RuntimeResult<()>; 9] = dispatch!(
@ -69,7 +69,7 @@ impl JournalAdapter for GNSAdapter {
gns::model::DropModelTxn
);
if payload.len() < 2 {
return Err(TransactionError::DecodedUnexpectedEof.into());
return Err(TransactionError::V1DecodedUnexpectedEof.into());
}
let mut scanner = BufferedScanner::new(&payload);
let opc = unsafe {
@ -78,7 +78,7 @@ impl JournalAdapter for GNSAdapter {
};
match DISPATCH[(opc as usize).min(DISPATCH.len())](&mut scanner, gs) {
Ok(()) if scanner.eof() => return Ok(()),
Ok(_) => Err(TransactionError::DecodeCorruptedPayloadMoreBytes.into()),
Ok(_) => Err(TransactionError::V1DecodeCorruptedPayloadMoreBytes.into()),
Err(e) => Err(e),
}
}

@ -30,7 +30,7 @@ mod tests;
use {
crate::{
engine::{
error::{ErrorKind, StorageError},
error::{ErrorKind, StorageError, TransactionError},
mem::unsafe_apis::memcpy,
storage::common::{
checksum::SCrc64,
@ -577,7 +577,7 @@ impl<J: RawJournalAdapter> RawJournalWriter<J> {
Ok(())
} else {
// so, the on-disk file probably has some partial state. this is bad. throw an error
Err(StorageError::RawJournalRuntimeCriticalLwtHBFail.into())
Err(StorageError::RawJournalRuntimeHeartbeatFail.into())
}
}
}
@ -756,14 +756,50 @@ impl<J: RawJournalAdapter> RawJournalReader<J> {
match e.kind() {
ErrorKind::IoError(io) => match io.kind() {
IoErrorKind::UnexpectedEof => {
// this is the only kind of error that we can actually repair since it indicates that a part of the
// file is "missing"
/*
this is the only kind of error that we can actually repair since it indicates that a part of the
file is "missing." we can't deal with things like permission errors. that's supposed to be handled
by the admin by looking through the error logs
*/
}
_ => return Err(e),
},
ErrorKind::Storage(_) => todo!(),
ErrorKind::Txn(_) => todo!(),
ErrorKind::Other(_) => todo!(),
ErrorKind::Storage(e) => match e {
// unreachable errors (no execution path here)
StorageError::RawJournalRuntimeHeartbeatFail // can't reach runtime error before driver start
| StorageError::RawJournalRuntimeDirty
| StorageError::FileDecodeHeaderVersionMismatch // should be caught earlier
| StorageError::FileDecodeHeaderCorrupted // should be caught earlier
| StorageError::V1JournalDecodeLogEntryCorrupted // v1 errors can't be raised here
| StorageError::V1JournalDecodeCorrupted
| StorageError::V1DataBatchDecodeCorruptedBatch
| StorageError::V1DataBatchDecodeCorruptedEntry
| StorageError::V1DataBatchDecodeCorruptedBatchFile
| StorageError::V1SysDBDecodeCorrupted
| StorageError::V1DataBatchRuntimeCloseError => unreachable!(),
// possible errors
StorageError::InternalDecodeStructureCorrupted
| StorageError::InternalDecodeStructureCorruptedPayload
| StorageError::InternalDecodeStructureIllegalData
| StorageError::RawJournalDecodeEventCorruptedMetadata
| StorageError::RawJournalDecodeEventCorruptedPayload
| StorageError::RawJournalDecodeBatchContentsMismatch
| StorageError::RawJournalDecodeBatchIntegrityFailure
| StorageError::RawJournalDecodeInvalidEvent
| StorageError::RawJournalDecodeCorruptionInBatchMetadata => {}
},
ErrorKind::Txn(txerr) => match txerr {
// unreachable errors
TransactionError::V1DecodeCorruptedPayloadMoreBytes // no v1 errors
| TransactionError::V1DecodedUnexpectedEof
| TransactionError::V1DecodeUnknownTxnOp => unreachable!(),
// possible errors
TransactionError::OnRestoreDataConflictAlreadyExists |
TransactionError::OnRestoreDataMissing |
TransactionError::OnRestoreDataConflictMismatch => {},
},
// these errors do not have an execution pathway
ErrorKind::Other(_) => unreachable!(),
ErrorKind::Config(_) => unreachable!(),
}
}
@ -857,7 +893,7 @@ impl<J: RawJournalAdapter> RawJournalReader<J> {
self.stats.driver_events += 1;
// update
Self::__refresh_known_txn(self);
// full metadata validated; this is a valid close event but is it actually a close
// full metadata validated; this is a valid close event, but is it actually a close?
if self.tr.is_eof() {
jtrace_reader!(ClosedAndReachedEof);
// yes, we're done

@ -177,7 +177,9 @@ impl RawJournalAdapter for SimpleDBJournal {
file.tracked_read(&mut keybuf)?;
match String::from_utf8(keybuf) {
Ok(k) => gs.data.borrow_mut().push(k),
Err(_) => return Err(StorageError::RawJournalDecodeEventCorruptedPayload.into()),
Err(_) => {
return Err(StorageError::RawJournalDecodeEventCorruptedPayload.into())
}
}
}
EventMeta::Clear => gs.data.borrow_mut().clear(),

Loading…
Cancel
Save