puffin/
error.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::any::Any;
16use std::io::Error as IoError;
17use std::sync::Arc;
18
19use common_error::ext::{BoxedError, ErrorExt};
20use common_error::status_code::StatusCode;
21use common_macro::stack_trace_debug;
22use snafu::{Location, Snafu};
23
24#[derive(Snafu)]
25#[snafu(visibility(pub))]
26#[stack_trace_debug]
27pub enum Error {
28    #[snafu(display("Failed to read"))]
29    Read {
30        #[snafu(source)]
31        error: IoError,
32        #[snafu(implicit)]
33        location: Location,
34    },
35
36    #[snafu(display("Failed to write"))]
37    Write {
38        #[snafu(source)]
39        error: IoError,
40        #[snafu(implicit)]
41        location: Location,
42    },
43
44    #[snafu(display("Failed to flush"))]
45    Flush {
46        #[snafu(source)]
47        error: IoError,
48        #[snafu(implicit)]
49        location: Location,
50    },
51
52    #[snafu(display("Failed to close"))]
53    Close {
54        #[snafu(source)]
55        error: IoError,
56        #[snafu(implicit)]
57        location: Location,
58    },
59
60    #[snafu(display("Failed to open"))]
61    Open {
62        #[snafu(source)]
63        error: IoError,
64        #[snafu(implicit)]
65        location: Location,
66    },
67
68    #[snafu(display("Failed to read metadata"))]
69    Metadata {
70        #[snafu(source)]
71        error: IoError,
72        #[snafu(implicit)]
73        location: Location,
74    },
75
76    #[snafu(display("Failed to create"))]
77    Create {
78        #[snafu(source)]
79        error: IoError,
80        #[snafu(implicit)]
81        location: Location,
82    },
83
84    #[snafu(display("Failed to rename"))]
85    Rename {
86        #[snafu(source)]
87        error: IoError,
88        #[snafu(implicit)]
89        location: Location,
90    },
91
92    #[snafu(display("Failed to remove"))]
93    Remove {
94        #[snafu(source)]
95        error: IoError,
96        #[snafu(implicit)]
97        location: Location,
98    },
99
100    #[snafu(display("Error while walking directory"))]
101    WalkDir {
102        #[snafu(source)]
103        error: async_walkdir::Error,
104        #[snafu(implicit)]
105        location: Location,
106    },
107
108    #[snafu(display("Magic not matched"))]
109    MagicNotMatched {
110        #[snafu(implicit)]
111        location: Location,
112    },
113
114    #[snafu(display("Unsupported decompression: {}", decompression))]
115    UnsupportedDecompression {
116        decompression: String,
117        #[snafu(implicit)]
118        location: Location,
119    },
120
121    #[snafu(display("Failed to serialize json"))]
122    SerializeJson {
123        #[snafu(source)]
124        error: serde_json::Error,
125        #[snafu(implicit)]
126        location: Location,
127    },
128
129    #[snafu(display("Failed to deserialize json"))]
130    DeserializeJson {
131        #[snafu(source)]
132        error: serde_json::Error,
133        #[snafu(implicit)]
134        location: Location,
135    },
136
137    #[snafu(display("Unexpected footer payload size: {}", size))]
138    UnexpectedFooterPayloadSize {
139        size: i32,
140        #[snafu(implicit)]
141        location: Location,
142    },
143
144    #[snafu(display("Invalid puffin footer"))]
145    InvalidPuffinFooter {
146        #[snafu(implicit)]
147        location: Location,
148    },
149
150    #[snafu(display(
151        "Unexpected puffin file size, min: {}, actual: {}",
152        min_file_size,
153        actual_file_size
154    ))]
155    UnexpectedPuffinFileSize {
156        min_file_size: u64,
157        actual_file_size: u64,
158        #[snafu(implicit)]
159        location: Location,
160    },
161
162    #[snafu(display("Failed to compress lz4"))]
163    Lz4Compression {
164        #[snafu(source)]
165        error: std::io::Error,
166
167        #[snafu(implicit)]
168        location: Location,
169    },
170
171    #[snafu(display("Failed to decompress lz4"))]
172    Lz4Decompression {
173        #[snafu(source)]
174        error: serde_json::Error,
175
176        #[snafu(implicit)]
177        location: Location,
178    },
179
180    #[snafu(display("Unsupported compression: {codec}"))]
181    UnsupportedCompression {
182        codec: String,
183        #[snafu(implicit)]
184        location: Location,
185    },
186
187    #[snafu(display("Write to the same blob twice: {blob}"))]
188    DuplicateBlob {
189        blob: String,
190        #[snafu(implicit)]
191        location: Location,
192    },
193
194    #[snafu(display("Blob not found: {blob}"))]
195    BlobNotFound {
196        blob: String,
197        #[snafu(implicit)]
198        location: Location,
199    },
200
201    #[snafu(display("Blob index out of bound, index: {}, max index: {}", index, max_index))]
202    BlobIndexOutOfBound {
203        index: usize,
204        max_index: usize,
205        #[snafu(implicit)]
206        location: Location,
207    },
208
209    #[snafu(display("File key not match, expected: {}, actual: {}", expected, actual))]
210    FileKeyNotMatch {
211        expected: String,
212        actual: String,
213        #[snafu(implicit)]
214        location: Location,
215    },
216
217    #[snafu(display("Get value from cache"))]
218    CacheGet { source: Arc<Error> },
219
220    #[snafu(display("External error"))]
221    External {
222        #[snafu(source)]
223        error: BoxedError,
224        #[snafu(implicit)]
225        location: Location,
226    },
227}
228
229impl Error {
230    pub fn is_blob_not_found(&self) -> bool {
231        match self {
232            Error::BlobNotFound { .. } => true,
233            Error::CacheGet { source } => source.is_blob_not_found(),
234            _ => false,
235        }
236    }
237}
238
239impl ErrorExt for Error {
240    fn status_code(&self) -> StatusCode {
241        use Error::*;
242        match self {
243            Read { .. }
244            | MagicNotMatched { .. }
245            | DeserializeJson { .. }
246            | Write { .. }
247            | Flush { .. }
248            | Close { .. }
249            | Open { .. }
250            | Metadata { .. }
251            | Create { .. }
252            | Remove { .. }
253            | Rename { .. }
254            | SerializeJson { .. }
255            | UnexpectedFooterPayloadSize { .. }
256            | UnexpectedPuffinFileSize { .. }
257            | Lz4Compression { .. }
258            | Lz4Decompression { .. }
259            | BlobNotFound { .. }
260            | BlobIndexOutOfBound { .. }
261            | FileKeyNotMatch { .. }
262            | WalkDir { .. }
263            | InvalidPuffinFooter { .. } => StatusCode::Unexpected,
264
265            UnsupportedCompression { .. } | UnsupportedDecompression { .. } => {
266                StatusCode::Unsupported
267            }
268
269            DuplicateBlob { .. } => StatusCode::InvalidArguments,
270
271            CacheGet { source } => source.status_code(),
272
273            External { error, .. } => error.status_code(),
274        }
275    }
276
277    fn as_any(&self) -> &dyn Any {
278        self
279    }
280}
281
282pub type Result<T> = std::result::Result<T, Error>;