1use 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#[derive(Debug)]
51pub struct TransactionMetricsNotFound;
52
53impl std::fmt::Display for TransactionMetricsNotFound {
54 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55 write!(f, "Transaction metrics not found")
56 }
57}
58
59impl std::error::Error for TransactionMetricsNotFound {}
60
61#[derive(Debug, Copy, Clone)]
63pub struct FdbError {
64 error_code: i32,
66}
67
68impl FdbError {
69 pub fn from_code(error_code: fdb_sys::fdb_error_t) -> Self {
71 Self { error_code }
72 }
73
74 #[cfg(feature = "tenant-experimental")]
75 pub(crate) fn new(error_code: i32) -> Self {
77 Self { error_code }
78 }
79
80 pub fn message(self) -> &'static str {
81 let error_str =
82 unsafe { CStr::from_ptr::<'static>(fdb_sys::fdb_get_error(self.error_code)) };
83 error_str
84 .to_str()
85 .expect("bad error string from FoundationDB")
86 }
87
88 fn is_error_predicate(self, predicate: options::ErrorPredicate) -> bool {
89 #[allow(clippy::unnecessary_cast)]
91 let check =
92 unsafe { fdb_sys::fdb_error_predicate(predicate.code() as i32, self.error_code) };
93
94 check != 0
95 }
96
97 pub fn is_maybe_committed(self) -> bool {
99 self.is_error_predicate(options::ErrorPredicate::MaybeCommitted)
100 }
101
102 pub fn is_retryable(self) -> bool {
104 self.is_error_predicate(options::ErrorPredicate::Retryable)
105 }
106
107 pub fn is_retryable_not_committed(self) -> bool {
109 self.is_error_predicate(options::ErrorPredicate::RetryableNotCommitted)
110 }
111
112 pub fn code(self) -> i32 {
114 self.error_code
115 }
116}
117
118impl fmt::Display for FdbError {
119 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
120 std::fmt::Display::fmt(&self.message(), f)
121 }
122}
123
124impl std::error::Error for FdbError {}
125
126pub type FdbResult<T = ()> = Result<T, FdbError>;
128
129pub enum FdbBindingError {
132 NonRetryableFdbError(FdbError),
133 HcaError(HcaError),
134 DirectoryError(DirectoryError),
135 PackError(PackError),
136 ReferenceToTransactionKept,
138 CustomError(Box<dyn std::error::Error + Send + Sync>),
140 TransactionMetricsNotFound,
142 #[cfg(feature = "recipes-leader-election")]
143 LeaderElectionError(crate::recipes::leader_election::LeaderElectionError),
145}
146
147impl FdbBindingError {
148 pub fn get_fdb_error(&self) -> Option<FdbError> {
150 match *self {
151 Self::NonRetryableFdbError(error)
152 | Self::DirectoryError(DirectoryError::FdbError(error))
153 | Self::HcaError(HcaError::FdbError(error)) => Some(error),
154 Self::CustomError(ref error) => {
155 if let Some(e) = error.downcast_ref::<FdbError>() {
156 Some(*e)
157 } else if let Some(e) = error.downcast_ref::<FdbBindingError>() {
158 e.get_fdb_error()
159 } else {
160 None
161 }
162 }
163 #[cfg(feature = "recipes-leader-election")]
164 Self::LeaderElectionError(
165 crate::recipes::leader_election::LeaderElectionError::Fdb(e),
166 ) => Some(e),
167 _ => None,
168 }
169 }
170}
171
172impl From<FdbError> for FdbBindingError {
173 fn from(e: FdbError) -> Self {
174 Self::NonRetryableFdbError(e)
175 }
176}
177
178impl From<HcaError> for FdbBindingError {
179 fn from(e: HcaError) -> Self {
180 Self::HcaError(e)
181 }
182}
183
184impl From<DirectoryError> for FdbBindingError {
185 fn from(e: DirectoryError) -> Self {
186 Self::DirectoryError(e)
187 }
188}
189
190impl From<TransactionMetricsNotFound> for FdbBindingError {
191 fn from(_e: TransactionMetricsNotFound) -> Self {
192 Self::TransactionMetricsNotFound
193 }
194}
195
196#[cfg(feature = "recipes-leader-election")]
197impl From<crate::recipes::leader_election::LeaderElectionError> for FdbBindingError {
198 fn from(error: crate::recipes::leader_election::LeaderElectionError) -> Self {
199 Self::LeaderElectionError(error)
200 }
201}
202
203impl FdbBindingError {
204 pub fn new_custom_error(e: Box<dyn std::error::Error + Send + Sync>) -> Self {
206 Self::CustomError(e)
207 }
208}
209
210impl Debug for FdbBindingError {
211 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
212 match self {
213 FdbBindingError::NonRetryableFdbError(err) => write!(f, "{err:?}"),
214 FdbBindingError::HcaError(err) => write!(f, "{err:?}"),
215 FdbBindingError::DirectoryError(err) => write!(f, "{err:?}"),
216 FdbBindingError::PackError(err) => write!(f, "{err:?}"),
217 FdbBindingError::ReferenceToTransactionKept => {
218 write!(f, "Reference to transaction kept")
219 }
220 FdbBindingError::CustomError(err) => write!(f, "{err:?}"),
221 FdbBindingError::TransactionMetricsNotFound => {
222 write!(f, "Transaction metrics not found")
223 }
224 #[cfg(feature = "recipes-leader-election")]
225 FdbBindingError::LeaderElectionError(err) => write!(f, "{err:?}"),
226 }
227 }
228}
229
230impl Display for FdbBindingError {
231 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
232 std::fmt::Debug::fmt(&self, f)
233 }
234}
235
236impl std::error::Error for FdbBindingError {}