async_fusex/
error.rs

1use std::path::PathBuf;
2
3use thiserror::Error;
4
5
6/// Get function name inside a function.
7#[macro_export]
8macro_rules! function_name {
9    () => {{
10        use clippy_utilities::OverflowArithmetic;
11        fn f() {}
12        fn type_name_of<T>(_: T) -> &'static str {
13            std::any::type_name::<T>()
14        }
15        let name = type_name_of(f);
16        // skip the suffix `::f`
17        name.get(..name.len().overflow_sub(3))
18            .unwrap_or_else(|| unreachable!("Suffix `::f` must exist."))
19    }};
20}
21
22pub type AsyncFusexResult<T> = Result<T, AsyncFusexError>;
23#[derive(Error, Debug)]
24pub enum AsyncFusexError {
25    /// Error caused by std::io::Error
26    #[error("IoErr, the error is {:?}, context is {:#?}", .source, .context)]
27    IoErr {
28        /// Error source
29        source: std::io::Error,
30        /// Context of the error
31        context: Vec<String>,
32    },
33
34    /// Error caused by walkdir::Error
35    #[error("WalkdirErr, the error is {:?}, context is {:#?}", .source, .context)]
36    WalkdirErr {
37        /// Error source
38        source: walkdir::Error,
39        /// Context of the error
40        context: Vec<String>,
41    },
42
43    /// Snapshot is not found
44    #[error("Snapshot ID={} not found, context is {:#?}", .snapshot_id, .context)]
45    SnapshotNotFound {
46        /// Snapshot ID
47        snapshot_id: String,
48        /// Context of the error
49        context: Vec<String>,
50    },
51    /// Volume is not found
52    #[error("Volume ID={} not found, context is {:#?}", .volume_id, .context)]
53    VolumeNotFound {
54        /// Volume ID
55        volume_id: String,
56        /// Context of the error
57        context: Vec<String>,
58    },
59    /// Volume has already existed
60    #[error("Volume ID={} already exists, context is {:#?}", .volume_id, .context)]
61    VolumeAlreadyExist {
62        /// Volume ID
63        volume_id: String,
64        /// Context of the error
65        context: Vec<String>,
66    },
67
68    /// Snapshot is not ready
69    #[error("Snapshot ID={} is not ready, context is {:#?}", .snapshot_id, .context)]
70    SnapshotNotReady {
71        /// Snapshot ID
72        snapshot_id: String,
73        /// Context of the error
74        context: Vec<String>,
75    },
76
77    /// Snapshot has already existed
78    #[error("Snapshot ID={} already exists, context is {:#?}", .snapshot_id, .context)]
79    SnapshotAlreadyExist {
80        /// Snapshot ID
81        snapshot_id: String,
82        /// Context of the error
83        context: Vec<String>,
84    },
85
86    /// Node is not found
87    #[error("Node ID={} not found, context is {:#?}", .node_id, .context)]
88    NodeNotFound {
89        /// Node ID
90        node_id: String,
91        /// Context of the error
92        context: Vec<String>,
93    },
94
95    /// Argument is invalid
96    #[error("Argument is invalid, context is {:#?}", .context)]
97    ArgumentInvalid {
98        /// Context of the error
99        context: Vec<String>,
100    },
101
102    /// Starting token is invalid
103    #[error("Starting token={} is invalid, context is {:#?}", .starting_token, .context)]
104    StartingTokenInvalid {
105        /// Starting token
106        starting_token: String,
107        /// Context of the error
108        context: Vec<String>,
109    },
110
111    /// Argument is out of range
112    #[error("Argument is out of range, context is {:#?}", .context)]
113    ArgumentOutOfRange {
114        /// Context of the error
115        context: Vec<String>,
116    },
117
118    /// Error caused by std::path::StripPrefixError
119    #[error("StripPrefixErr, the error is {:?}, context is {:#?}", .source, .context)]
120    StripPrefixErr {
121        /// Error source
122        source: std::path::StripPrefixError,
123        /// Context of the error
124        context: Vec<String>,
125    },
126
127    /// Error caused by nix::Error
128    #[error("NixErr, the error is {:?}, context is {:#?}", .source, .context)]
129    NixErr {
130        /// Error source
131        source: nix::Error,
132        /// Context of the error
133        context: Vec<String>,
134    },
135
136    /// Failed to mount
137    #[error("MountErr, fail to mount {:?} to {:?}, context is {:#?}", .from, .target, .context)]
138    MountErr {
139        /// Source to mount
140        from: PathBuf,
141        /// Mount point
142        target: PathBuf,
143        /// Context of the error
144        context: Vec<String>,
145    },
146
147    /// Failed to umount
148    #[error("UmountErr, fail to umount {:?}, context is {:#?}", .target, .context)]
149    UmountErr {
150        /// Mount point to umount
151        target: PathBuf,
152        /// Context of the error
153        context: Vec<String>,
154    },
155
156    /// Error caused by std::time::SystemTimeError
157    #[error("SystemTimeErr, the error is {:?}, context is {:#?}", .source, .context)]
158    SystemTimeErr {
159        /// Error source
160        source: std::time::SystemTimeError,
161        /// Context of the error
162        context: Vec<String>,
163    },
164
165
166    /// Error caused by tokio::task::JoinError given by tokio::task::spawn*
167    #[error("tokio::task::JoinError, the error is {:?}, context is {:#?}", .source, .context)]
168    JoinErr {
169        /// Error source
170        source: tokio::task::JoinError,
171        /// Context of the error
172        context: Vec<String>,
173    },
174
175    /// Error caused by module kv_engine's MetaTxn retry limit exceeded
176    #[error("TransactionRetryLimitExceededErr, context is {:#?}", .context)]
177    TransactionRetryLimitExceededErr {
178        /// Context of the error
179        context: Vec<String>,
180    },
181
182    /// Error caused by internal logic
183    #[error("InternalErr, the error is {} context is {:#?}", .source,.context)]
184    InternalErr {
185        /// Error source
186        source: anyhow::Error,
187        /// Context of the error
188        context: Vec<String>,
189    },
190
191    /// API is not implemented
192    #[error("Not implemented, context is {:#?}", .context)]
193    Unimplemented {
194        /// Context of the error
195        context: Vec<String>,
196    },
197    /// FS is inconsistent, as some mentioned nodes are not in the cache.
198    #[error("FS is inconsistent, context is {:#?}.", .context)]
199    InconsistentFS {
200        /// Context of the error
201        context: Vec<String>,
202    },
203    /// Cache cluster error
204    #[error("Cache cluster error, context is {:#?}.", .context)]
205    CacheClusterErr {
206        /// Context of the error
207        context: Vec<String>,
208    },
209    /// Distribute cache manager
210    #[error("Distribute cache manager error, context is {:#?}.", .context)]
211    DistributeCacheManagerErr {
212        /// Context of the error
213        context: Vec<String>,
214    },
215    // /// Error when doing s3 operation.
216    // #[error("S3 error: {0}")]
217    // S3Error(s3_wrapper::S3Error),
218
219    // ///
220    // #[error("persist error: {0}")]
221    // PersistError(persist::PersistError),
222}
223
224pub trait Context<T, E> {
225    fn add_context<C>(self, ctx: C) -> AsyncFusexResult<T>
226    where
227        C: Into<String>;
228
229    fn with_context<C, F>(self, f: F) -> AsyncFusexResult<T>
230    where
231        C: Into<String>,
232        F: FnOnce() -> C;
233}
234
235impl<T, E> Context<T, E> for Result<T, E>
236where
237    E: std::error::Error + Into<AsyncFusexError>,
238{
239    #[inline]
240    fn add_context<C>(self, ctx: C) -> AsyncFusexResult<T>
241    where
242        C: Into<String>,
243    {
244        self.map_err(|err| err.into().add_context(ctx))
245    }
246
247    #[inline]
248    fn with_context<C, F>(self, context_func: F) -> AsyncFusexResult<T>
249    where
250        C: Into<String>,
251        F: FnOnce() -> C,
252    {
253        self.map_err(|err| err.into().add_context(context_func()))
254    }
255}
256
257impl AsyncFusexError {
258    #[inline]
259    #[must_use]
260    pub fn add_context<C>(mut self, ctx: C) -> Self
261    where
262        C: Into<String>,
263    {
264        macro_rules! append_context {
265            ($context: ident, [$($target:ident),*]) => {
266                match self {
267                    $(Self::$target { ref mut context, ..} => {
268                        context.push($context.into());
269                    },)*
270                }
271            }
272        }
273        append_context!(
274            ctx,
275            [
276                IoErr,
277                WalkdirErr,
278                SnapshotNotFound,
279                VolumeNotFound,
280                VolumeAlreadyExist,
281                SnapshotNotReady,
282                SnapshotAlreadyExist,
283                NodeNotFound,
284                ArgumentInvalid,
285                StartingTokenInvalid,
286                ArgumentOutOfRange,
287                StripPrefixErr,
288                NixErr,
289                MountErr,
290                UmountErr,
291                SystemTimeErr,
292                JoinErr,
293                TransactionRetryLimitExceededErr,
294                InternalErr,
295                Unimplemented,
296                InconsistentFS,
297                CacheClusterErr,
298                DistributeCacheManagerErr
299            ]
300        );
301        self
302    }
303
304    #[inline]
305    #[must_use]
306    pub fn with_context<C, F>(self, context_fn: F) -> Self
307    where
308        C: Into<String>,
309        F: FnOnce() -> C,
310    {
311        self.add_context(context_fn())
312    }
313}
314
315macro_rules! implement_from {
316    ($source:path, $target:ident) => {
317        impl From<$source> for AsyncFusexError {
318            #[inline]
319            fn from(error: $source) -> Self {
320                Self::$target {
321                    source: error,
322                    context: vec![],
323                }
324            }
325        }
326    };
327}
328implement_from!(std::io::Error, IoErr);
329implement_from!(walkdir::Error, WalkdirErr);
330implement_from!(std::path::StripPrefixError, StripPrefixErr);
331implement_from!(nix::Error, NixErr);
332implement_from!(std::time::SystemTimeError, SystemTimeErr);
333implement_from!(tokio::task::JoinError, JoinErr);
334implement_from!(anyhow::Error, InternalErr);