Skip to main content

common_datasource/
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;
16
17use arrow_schema::ArrowError;
18use common_error::ext::{ErrorExt, RetryHint, retry_hint_from_io_error};
19use common_error::status_code::StatusCode;
20use common_macro::stack_trace_debug;
21use datafusion::parquet::errors::ParquetError;
22use object_store::error::retry_hint_from_opendal_error;
23use snafu::{Location, Snafu};
24use url::ParseError;
25
26#[derive(Snafu)]
27#[snafu(visibility(pub))]
28#[stack_trace_debug]
29pub enum Error {
30    #[snafu(display("Unsupported compression type: {}", compression_type))]
31    UnsupportedCompressionType {
32        compression_type: String,
33        #[snafu(implicit)]
34        location: Location,
35    },
36
37    #[snafu(display("Unsupported backend protocol: {}, url: {}", protocol, url))]
38    UnsupportedBackendProtocol {
39        protocol: String,
40        #[snafu(implicit)]
41        location: Location,
42        url: String,
43    },
44
45    #[snafu(display("Unsupported format protocol: {}", format))]
46    UnsupportedFormat {
47        format: String,
48        #[snafu(implicit)]
49        location: Location,
50    },
51
52    #[snafu(display("empty host: {}", url))]
53    EmptyHostPath {
54        url: String,
55        #[snafu(implicit)]
56        location: Location,
57    },
58
59    #[snafu(display("Invalid url: {}", url))]
60    InvalidUrl {
61        url: String,
62        #[snafu(source)]
63        error: ParseError,
64        #[snafu(implicit)]
65        location: Location,
66    },
67
68    #[snafu(display("Failed to build backend"))]
69    BuildBackend {
70        #[snafu(source)]
71        error: object_store::Error,
72        #[snafu(implicit)]
73        location: Location,
74    },
75
76    #[snafu(display("Failed to build orc reader"))]
77    OrcReader {
78        #[snafu(implicit)]
79        location: Location,
80        #[snafu(source)]
81        error: orc_rust::error::OrcError,
82    },
83
84    #[snafu(display("Failed to read object from path: {}", path))]
85    ReadObject {
86        path: String,
87        #[snafu(implicit)]
88        location: Location,
89        #[snafu(source)]
90        error: object_store::Error,
91    },
92
93    #[snafu(display("Failed to write object to path: {}", path))]
94    WriteObject {
95        path: String,
96        #[snafu(implicit)]
97        location: Location,
98        #[snafu(source)]
99        error: object_store::Error,
100    },
101
102    #[snafu(display("Failed to write"))]
103    AsyncWrite {
104        #[snafu(source)]
105        error: std::io::Error,
106        #[snafu(implicit)]
107        location: Location,
108    },
109
110    #[snafu(display("Failed to write record batch"))]
111    WriteRecordBatch {
112        #[snafu(implicit)]
113        location: Location,
114        #[snafu(source)]
115        error: ArrowError,
116    },
117
118    #[snafu(display("Failed to encode record batch"))]
119    EncodeRecordBatch {
120        #[snafu(implicit)]
121        location: Location,
122        #[snafu(source)]
123        error: ParquetError,
124    },
125
126    #[snafu(display("Failed to read record batch"))]
127    ReadRecordBatch {
128        #[snafu(implicit)]
129        location: Location,
130        #[snafu(source)]
131        error: datafusion::error::DataFusionError,
132    },
133
134    #[snafu(display("Failed to read parquet"))]
135    ReadParquetSnafu {
136        #[snafu(implicit)]
137        location: Location,
138        #[snafu(source)]
139        error: datafusion::parquet::errors::ParquetError,
140    },
141
142    #[snafu(display("Failed to convert parquet to schema"))]
143    ParquetToSchema {
144        #[snafu(implicit)]
145        location: Location,
146        #[snafu(source)]
147        error: datafusion::parquet::errors::ParquetError,
148    },
149
150    #[snafu(display("Failed to infer schema from file"))]
151    InferSchema {
152        #[snafu(implicit)]
153        location: Location,
154        #[snafu(source)]
155        error: arrow_schema::ArrowError,
156    },
157
158    #[snafu(display("Failed to list object in path: {}", path))]
159    ListObjects {
160        path: String,
161        #[snafu(implicit)]
162        location: Location,
163        #[snafu(source)]
164        error: object_store::Error,
165    },
166
167    #[snafu(display("Invalid connection: {}", msg))]
168    InvalidConnection {
169        msg: String,
170        #[snafu(implicit)]
171        location: Location,
172    },
173
174    #[snafu(display("Failed to join handle"))]
175    JoinHandle {
176        #[snafu(implicit)]
177        location: Location,
178        #[snafu(source)]
179        error: tokio::task::JoinError,
180    },
181
182    #[snafu(display("Failed to parse format {} with value: {}", key, value))]
183    ParseFormat {
184        key: String,
185        value: String,
186        #[snafu(implicit)]
187        location: Location,
188    },
189
190    #[snafu(display("Failed to merge schema"))]
191    MergeSchema {
192        #[snafu(source)]
193        error: arrow_schema::ArrowError,
194        #[snafu(implicit)]
195        location: Location,
196    },
197
198    #[snafu(display("Failed to write parquet file, path: {}", path))]
199    WriteParquet {
200        path: String,
201        #[snafu(implicit)]
202        location: Location,
203        #[snafu(source)]
204        error: parquet::errors::ParquetError,
205    },
206
207    #[snafu(transparent)]
208    DataFusion {
209        #[snafu(implicit)]
210        location: Location,
211        #[snafu(source)]
212        error: datafusion::error::DataFusionError,
213    },
214}
215
216pub type Result<T> = std::result::Result<T, Error>;
217
218impl ErrorExt for Error {
219    fn status_code(&self) -> StatusCode {
220        use Error::*;
221        match self {
222            BuildBackend { .. }
223            | ListObjects { .. }
224            | ReadObject { .. }
225            | WriteObject { .. }
226            | AsyncWrite { .. }
227            | WriteParquet { .. } => StatusCode::StorageUnavailable,
228
229            UnsupportedBackendProtocol { .. }
230            | UnsupportedCompressionType { .. }
231            | UnsupportedFormat { .. }
232            | InvalidConnection { .. }
233            | InvalidUrl { .. }
234            | EmptyHostPath { .. }
235            | InferSchema { .. }
236            | ReadParquetSnafu { .. }
237            | ParquetToSchema { .. }
238            | ParseFormat { .. }
239            | MergeSchema { .. } => StatusCode::InvalidArguments,
240
241            JoinHandle { .. }
242            | ReadRecordBatch { .. }
243            | WriteRecordBatch { .. }
244            | EncodeRecordBatch { .. }
245            | OrcReader { .. } => StatusCode::Unexpected,
246
247            DataFusion { .. } => StatusCode::Internal,
248        }
249    }
250
251    fn as_any(&self) -> &dyn Any {
252        self
253    }
254
255    fn retry_hint(&self) -> RetryHint {
256        use Error::*;
257
258        match self {
259            BuildBackend { error, .. }
260            | ListObjects { error, .. }
261            | ReadObject { error, .. }
262            | WriteObject { error, .. } => retry_hint_from_opendal_error(error),
263            AsyncWrite { error, .. } => retry_hint_from_io_error(error),
264            WriteParquet { .. } => RetryHint::Retryable,
265            _ => RetryHint::NonRetryable,
266        }
267    }
268}