use std::fmt;
pub type Result<T, E = Error> = std::result::Result<T, E>;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u32)]
#[non_exhaustive]
pub enum ErrorCode {
Io = 1,
Corruption = 2,
WriterLocked = 3,
ShmVersionMismatch = 4,
ShmUnavailable = 5,
UnsupportedFormat = 6,
NetworkFilesystem = 7,
TableNotFound = 8,
TableExists = 9,
FamilyNotFound = 10,
FamilyExists = 11,
UnknownMergeOperator = 12,
MergeFailed = 13,
Conflict = 14,
ReadOnly = 15,
KeyTooLarge = 16,
ValueTooLarge = 17,
NoSpace = 18,
InvalidArgument = 19,
Unsupported = 20,
Closed = 21,
NoReaderSlot = 22,
RecordTooLarge = 23,
Busy = 24,
SnapshotExpired = 25,
WouldDeadlock = 26,
BatchTooLarge = 27,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Error {
code: ErrorCode,
message: String,
}
impl Error {
pub(crate) fn new(code: ErrorCode, message: impl Into<String>) -> Self {
Self {
code,
message: message.into(),
}
}
pub fn code(&self) -> ErrorCode {
self.code
}
pub fn message(&self) -> &str {
&self.message
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.message)
}
}
impl std::error::Error for Error {}
impl From<pigeonhole_engine::Error> for Error {
fn from(e: pigeonhole_engine::Error) -> Self {
use pigeonhole_engine::Error as E;
let code = match &e {
E::Io(_) => ErrorCode::Io,
E::Corruption(_) => ErrorCode::Corruption,
E::WriterLocked => ErrorCode::WriterLocked,
E::ShmVersionMismatch { .. } => ErrorCode::ShmVersionMismatch,
E::ShmUnavailable => ErrorCode::ShmUnavailable,
E::UnsupportedFormat(_) => ErrorCode::UnsupportedFormat,
E::NetworkFilesystem => ErrorCode::NetworkFilesystem,
E::TableNotFound(_) => ErrorCode::TableNotFound,
E::TableExists(_) => ErrorCode::TableExists,
E::FamilyNotFound(_) => ErrorCode::FamilyNotFound,
E::FamilyExists(_) => ErrorCode::FamilyExists,
E::UnknownMergeOperator(_) => ErrorCode::UnknownMergeOperator,
E::Merge(_) => ErrorCode::MergeFailed,
E::Conflict => ErrorCode::Conflict,
E::ReadOnly => ErrorCode::ReadOnly,
E::KeyTooLarge => ErrorCode::KeyTooLarge,
E::ValueTooLarge => ErrorCode::ValueTooLarge,
E::NoSpace => ErrorCode::NoSpace,
E::InvalidArgument(_) => ErrorCode::InvalidArgument,
E::Unsupported(_) => ErrorCode::Unsupported,
E::Closed => ErrorCode::Closed,
E::NoReaderSlot => ErrorCode::NoReaderSlot,
E::RecordTooLarge => ErrorCode::RecordTooLarge,
E::Busy => ErrorCode::Busy,
E::BatchTooLarge => ErrorCode::BatchTooLarge,
E::SnapshotExpired => ErrorCode::SnapshotExpired,
E::WouldDeadlock => ErrorCode::WouldDeadlock,
_ => ErrorCode::Io,
};
let message = match &e {
E::Merge(m) => format!("merge operator {:?} failed: {}", m.operator, m.message),
E::Busy => "stalled: a flush or compaction did not free room within the write-stall \
timeout (30 s); back off and retry, and drop old snapshots"
.to_owned(),
E::BatchTooLarge => "the batch can never fit a shard's memtable arena (about half \
of Options::memtable_budget); split it or raise the budget"
.to_owned(),
_ => e.to_string(),
};
Self::new(code, message)
}
}