foundationdb/
error.rs

1// Copyright 2018 foundationdb-rs developers, https://github.com/Clikengo/foundationdb-rs/graphs/contributors
2// Copyright 2013-2018 Apple, Inc and the FoundationDB project authors.
3//
4// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
5// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
6// http://opensource.org/licenses/MIT>, at your option. This file may not be
7// copied, modified, or distributed except according to those terms.
8
9//! Error types for the Fdb crate
10
11use crate::directory::DirectoryError;
12use crate::options;
13use crate::tuple::hca::HcaError;
14use crate::tuple::PackError;
15use foundationdb_sys as fdb_sys;
16use std::ffi::CStr;
17use std::fmt;
18use std::fmt::{Debug, Display, Formatter};
19
20pub(crate) fn eval(error_code: fdb_sys::fdb_error_t) -> FdbResult<()> {
21    let rust_code: i32 = error_code;
22    if rust_code == 0 {
23        Ok(())
24    } else {
25        Err(FdbError::from_code(error_code))
26    }
27}
28
29/// The Standard Error type of FoundationDB
30#[derive(Debug, Copy, Clone)]
31pub struct FdbError {
32    /// The FoundationDB error code
33    error_code: i32,
34}
35
36impl FdbError {
37    /// Converts from a raw foundationDB error code
38    pub fn from_code(error_code: fdb_sys::fdb_error_t) -> Self {
39        Self { error_code }
40    }
41
42    pub(crate) fn new(error_code: i32) -> Self {
43        Self { error_code }
44    }
45
46    pub fn message(self) -> &'static str {
47        let error_str =
48            unsafe { CStr::from_ptr::<'static>(fdb_sys::fdb_get_error(self.error_code)) };
49        error_str
50            .to_str()
51            .expect("bad error string from FoundationDB")
52    }
53
54    fn is_error_predicate(self, predicate: options::ErrorPredicate) -> bool {
55        // This cast to `i32` isn't unnecessary in all configurations.
56        #[allow(clippy::unnecessary_cast)]
57        let check =
58            unsafe { fdb_sys::fdb_error_predicate(predicate.code() as i32, self.error_code) };
59
60        check != 0
61    }
62
63    /// Indicates the transaction may have succeeded, though not in a way the system can verify.
64    pub fn is_maybe_committed(self) -> bool {
65        self.is_error_predicate(options::ErrorPredicate::MaybeCommitted)
66    }
67
68    /// Indicates the operations in the transactions should be retried because of transient error.
69    pub fn is_retryable(self) -> bool {
70        self.is_error_predicate(options::ErrorPredicate::Retryable)
71    }
72
73    /// Indicates the transaction has not committed, though in a way that can be retried.
74    pub fn is_retryable_not_committed(self) -> bool {
75        self.is_error_predicate(options::ErrorPredicate::RetryableNotCommitted)
76    }
77
78    /// Raw foundationdb error code
79    pub fn code(self) -> i32 {
80        self.error_code
81    }
82}
83
84impl fmt::Display for FdbError {
85    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
86        std::fmt::Display::fmt(&self.message(), f)
87    }
88}
89
90impl std::error::Error for FdbError {}
91
92/// Alias for `Result<..., FdbError>`
93pub type FdbResult<T = ()> = Result<T, FdbError>;
94
95/// This error represent all errors that can be throwed by `db.run`.
96/// Layer developers may use the `CustomError`.
97pub enum FdbBindingError {
98    NonRetryableFdbError(FdbError),
99    HcaError(HcaError),
100    DirectoryError(DirectoryError),
101    PackError(PackError),
102    /// A reference to the `RetryableTransaction` has been kept
103    ReferenceToTransactionKept,
104    /// A custom error that layer developers can use
105    CustomError(Box<dyn std::error::Error + Send + Sync>),
106}
107
108impl FdbBindingError {
109    /// Returns the underlying `FdbError`, if any.
110    pub fn get_fdb_error(&self) -> Option<FdbError> {
111        match *self {
112            Self::NonRetryableFdbError(error)
113            | Self::DirectoryError(DirectoryError::FdbError(error))
114            | Self::HcaError(HcaError::FdbError(error)) => Some(error),
115            Self::CustomError(ref error) => {
116                if let Some(e) = error.downcast_ref::<FdbError>() {
117                    Some(*e)
118                } else if let Some(e) = error.downcast_ref::<FdbBindingError>() {
119                    e.get_fdb_error()
120                } else {
121                    None
122                }
123            }
124            _ => None,
125        }
126    }
127}
128
129impl From<FdbError> for FdbBindingError {
130    fn from(e: FdbError) -> Self {
131        Self::NonRetryableFdbError(e)
132    }
133}
134
135impl From<HcaError> for FdbBindingError {
136    fn from(e: HcaError) -> Self {
137        Self::HcaError(e)
138    }
139}
140
141impl From<DirectoryError> for FdbBindingError {
142    fn from(e: DirectoryError) -> Self {
143        Self::DirectoryError(e)
144    }
145}
146
147impl FdbBindingError {
148    /// create a new custom error
149    pub fn new_custom_error(e: Box<dyn std::error::Error + Send + Sync>) -> Self {
150        Self::CustomError(e)
151    }
152}
153
154impl Debug for FdbBindingError {
155    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
156        match self {
157            FdbBindingError::NonRetryableFdbError(err) => write!(f, "{:?}", err),
158            FdbBindingError::HcaError(err) => write!(f, "{:?}", err),
159            FdbBindingError::DirectoryError(err) => write!(f, "{:?}", err),
160            FdbBindingError::PackError(err) => write!(f, "{:?}", err),
161            FdbBindingError::ReferenceToTransactionKept => {
162                write!(f, "Reference to transaction kept")
163            }
164            FdbBindingError::CustomError(err) => write!(f, "{:?}", err),
165        }
166    }
167}
168
169impl Display for FdbBindingError {
170    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
171        std::fmt::Debug::fmt(&self, f)
172    }
173}
174
175impl std::error::Error for FdbBindingError {}