use crate::directory::DirectoryError;
use crate::options;
use crate::tuple::hca::HcaError;
use crate::tuple::PackError;
use foundationdb_sys as fdb_sys;
use std::ffi::CStr;
use std::fmt;
use std::fmt::{Debug, Display, Formatter};
pub(crate) fn eval(error_code: fdb_sys::fdb_error_t) -> FdbResult<()> {
let rust_code: i32 = error_code;
if rust_code == 0 {
Ok(())
} else {
Err(FdbError::from_code(error_code))
}
}
#[derive(Debug)]
pub struct TransactionMetricsNotFound;
impl std::fmt::Display for TransactionMetricsNotFound {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Transaction metrics not found")
}
}
impl std::error::Error for TransactionMetricsNotFound {}
#[derive(Debug, Copy, Clone)]
pub struct FdbError {
error_code: i32,
}
impl FdbError {
pub fn from_code(error_code: fdb_sys::fdb_error_t) -> Self {
Self { error_code }
}
#[cfg(feature = "tenant-experimental")]
pub(crate) fn new(error_code: i32) -> Self {
Self { error_code }
}
pub fn message(self) -> &'static str {
let error_str =
unsafe { CStr::from_ptr::<'static>(fdb_sys::fdb_get_error(self.error_code)) };
error_str
.to_str()
.expect("bad error string from FoundationDB")
}
fn is_error_predicate(self, predicate: options::ErrorPredicate) -> bool {
#[allow(clippy::unnecessary_cast)]
let check =
unsafe { fdb_sys::fdb_error_predicate(predicate.code() as i32, self.error_code) };
check != 0
}
pub fn is_maybe_committed(self) -> bool {
self.is_error_predicate(options::ErrorPredicate::MaybeCommitted)
}
pub fn is_retryable(self) -> bool {
self.is_error_predicate(options::ErrorPredicate::Retryable)
}
pub fn is_retryable_not_committed(self) -> bool {
self.is_error_predicate(options::ErrorPredicate::RetryableNotCommitted)
}
pub fn code(self) -> i32 {
self.error_code
}
}
impl fmt::Display for FdbError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
std::fmt::Display::fmt(&self.message(), f)
}
}
impl std::error::Error for FdbError {}
pub type FdbResult<T = ()> = Result<T, FdbError>;
pub enum FdbBindingError {
NonRetryableFdbError(FdbError),
HcaError(HcaError),
DirectoryError(DirectoryError),
PackError(PackError),
ReferenceToTransactionKept,
CustomError(Box<dyn std::error::Error + Send + Sync>),
TransactionMetricsNotFound,
}
impl FdbBindingError {
pub fn get_fdb_error(&self) -> Option<FdbError> {
match *self {
Self::NonRetryableFdbError(error)
| Self::DirectoryError(DirectoryError::FdbError(error))
| Self::HcaError(HcaError::FdbError(error)) => Some(error),
Self::CustomError(ref error) => {
if let Some(e) = error.downcast_ref::<FdbError>() {
Some(*e)
} else if let Some(e) = error.downcast_ref::<FdbBindingError>() {
e.get_fdb_error()
} else {
None
}
}
_ => None,
}
}
}
impl From<FdbError> for FdbBindingError {
fn from(e: FdbError) -> Self {
Self::NonRetryableFdbError(e)
}
}
impl From<HcaError> for FdbBindingError {
fn from(e: HcaError) -> Self {
Self::HcaError(e)
}
}
impl From<DirectoryError> for FdbBindingError {
fn from(e: DirectoryError) -> Self {
Self::DirectoryError(e)
}
}
impl From<TransactionMetricsNotFound> for FdbBindingError {
fn from(_e: TransactionMetricsNotFound) -> Self {
Self::TransactionMetricsNotFound
}
}
impl FdbBindingError {
pub fn new_custom_error(e: Box<dyn std::error::Error + Send + Sync>) -> Self {
Self::CustomError(e)
}
}
impl Debug for FdbBindingError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
FdbBindingError::NonRetryableFdbError(err) => write!(f, "{err:?}"),
FdbBindingError::HcaError(err) => write!(f, "{err:?}"),
FdbBindingError::DirectoryError(err) => write!(f, "{err:?}"),
FdbBindingError::PackError(err) => write!(f, "{err:?}"),
FdbBindingError::ReferenceToTransactionKept => {
write!(f, "Reference to transaction kept")
}
FdbBindingError::CustomError(err) => write!(f, "{err:?}"),
FdbBindingError::TransactionMetricsNotFound => {
write!(f, "Transaction metrics not found")
}
}
}
}
impl Display for FdbBindingError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
std::fmt::Debug::fmt(&self, f)
}
}
impl std::error::Error for FdbBindingError {}