Skip to main content

cli/data/export_v2/
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 common_error::ext::{ErrorExt, RetryHint};
18use common_error::status_code::StatusCode;
19use common_macro::stack_trace_debug;
20use object_store::error::retry_hint_from_opendal_error;
21use snafu::{Location, Snafu};
22
23#[derive(Snafu)]
24#[snafu(visibility(pub))]
25#[stack_trace_debug]
26pub enum Error {
27    #[snafu(display("Packed Metric export requires Parquet"))]
28    MetricExportRequiresParquet {
29        #[snafu(implicit)]
30        location: Location,
31    },
32
33    #[snafu(display("Invalid URI '{}': {}", uri, reason))]
34    InvalidUri {
35        uri: String,
36        reason: String,
37        #[snafu(implicit)]
38        location: Location,
39    },
40
41    #[snafu(display("Unsupported storage scheme: {}", scheme))]
42    UnsupportedScheme {
43        scheme: String,
44        #[snafu(implicit)]
45        location: Location,
46    },
47
48    #[snafu(display("Storage operation '{}' failed", operation))]
49    StorageOperation {
50        operation: String,
51        #[snafu(source)]
52        error: object_store::Error,
53        #[snafu(implicit)]
54        location: Location,
55    },
56
57    #[snafu(display("Failed to parse manifest"))]
58    ManifestParse {
59        #[snafu(source)]
60        error: serde_json::Error,
61        #[snafu(implicit)]
62        location: Location,
63    },
64
65    #[snafu(display("Failed to serialize manifest"))]
66    ManifestSerialize {
67        #[snafu(source)]
68        error: serde_json::Error,
69        #[snafu(implicit)]
70        location: Location,
71    },
72
73    #[snafu(display("Failed to decode text file as UTF-8"))]
74    TextDecode {
75        #[snafu(source)]
76        error: std::string::FromUtf8Error,
77        #[snafu(implicit)]
78        location: Location,
79    },
80
81    #[snafu(display("I/O error while {}: {}", operation, error))]
82    Io {
83        operation: &'static str,
84        error: std::io::Error,
85        #[snafu(implicit)]
86        location: Location,
87    },
88
89    #[snafu(display(
90        "Cannot resume snapshot with a different schema_only mode (existing: {}, requested: {}). Use --force to recreate.",
91        existing_schema_only,
92        requested_schema_only
93    ))]
94    SchemaOnlyModeMismatch {
95        existing_schema_only: bool,
96        requested_schema_only: bool,
97        #[snafu(implicit)]
98        location: Location,
99    },
100
101    #[snafu(display(
102        "Cannot resume snapshot with different {} (existing: {}, requested: {}). Use --force to recreate.",
103        field,
104        existing,
105        requested
106    ))]
107    ResumeConfigMismatch {
108        field: String,
109        existing: String,
110        requested: String,
111        #[snafu(implicit)]
112        location: Location,
113    },
114
115    #[snafu(display("Failed to parse time: invalid format: {}", input))]
116    TimeParseInvalidFormat {
117        input: String,
118        #[snafu(implicit)]
119        location: Location,
120    },
121
122    #[snafu(display("Failed to parse time: end_time is before start_time"))]
123    TimeParseEndBeforeStart {
124        #[snafu(implicit)]
125        location: Location,
126    },
127
128    #[snafu(display(
129        "chunk_time_window requires both --start-time and --end-time to be specified"
130    ))]
131    ChunkTimeWindowRequiresBounds {
132        #[snafu(implicit)]
133        location: Location,
134    },
135
136    #[snafu(display("--schema-only cannot be used with data export arguments: {}", args))]
137    SchemaOnlyArgsNotAllowed {
138        args: String,
139        #[snafu(implicit)]
140        location: Location,
141    },
142
143    #[snafu(display("Empty result from query"))]
144    EmptyResult {
145        #[snafu(implicit)]
146        location: Location,
147    },
148
149    #[snafu(display("Unexpected value type in query result"))]
150    UnexpectedValueType {
151        #[snafu(implicit)]
152        location: Location,
153    },
154
155    #[snafu(display("Database error"))]
156    Database {
157        #[snafu(source)]
158        error: crate::error::Error,
159        #[snafu(implicit)]
160        location: Location,
161    },
162
163    #[snafu(display("Snapshot not found at '{}'", uri))]
164    SnapshotNotFound {
165        uri: String,
166        #[snafu(implicit)]
167        location: Location,
168    },
169
170    #[snafu(display("Schema '{}' not found in catalog '{}'", schema, catalog))]
171    SchemaNotFound {
172        catalog: String,
173        schema: String,
174        #[snafu(implicit)]
175        location: Location,
176    },
177
178    #[snafu(display("Failed to parse URL"))]
179    UrlParse {
180        #[snafu(source)]
181        error: url::ParseError,
182        #[snafu(implicit)]
183        location: Location,
184    },
185
186    #[snafu(display("Failed to build object store"))]
187    BuildObjectStore {
188        #[snafu(source)]
189        error: object_store::Error,
190        #[snafu(implicit)]
191        location: Location,
192    },
193
194    #[snafu(display("Manifest version mismatch: expected {}, found {}", expected, found))]
195    ManifestVersionMismatch {
196        expected: u32,
197        found: u32,
198        #[snafu(implicit)]
199        location: Location,
200    },
201
202    #[snafu(display(
203        "Snapshot verification failed: {} error(s), {} warning(s)",
204        errors,
205        warnings
206    ))]
207    SnapshotVerifyFailed {
208        errors: usize,
209        warnings: usize,
210        #[snafu(implicit)]
211        location: Location,
212    },
213}
214
215pub type Result<T> = std::result::Result<T, Error>;
216
217impl ErrorExt for Error {
218    fn status_code(&self) -> StatusCode {
219        match self {
220            Error::MetricExportRequiresParquet { .. }
221            | Error::InvalidUri { .. }
222            | Error::UnsupportedScheme { .. }
223            | Error::SchemaOnlyModeMismatch { .. }
224            | Error::ResumeConfigMismatch { .. }
225            | Error::ManifestVersionMismatch { .. }
226            | Error::SchemaOnlyArgsNotAllowed { .. }
227            | Error::SnapshotVerifyFailed { .. } => StatusCode::InvalidArguments,
228            Error::TimeParseInvalidFormat { .. }
229            | Error::TimeParseEndBeforeStart { .. }
230            | Error::ChunkTimeWindowRequiresBounds { .. } => StatusCode::InvalidArguments,
231
232            Error::StorageOperation { .. }
233            | Error::ManifestParse { .. }
234            | Error::ManifestSerialize { .. }
235            | Error::TextDecode { .. }
236            | Error::BuildObjectStore { .. } => StatusCode::StorageUnavailable,
237
238            Error::EmptyResult { .. }
239            | Error::UnexpectedValueType { .. }
240            | Error::UrlParse { .. } => StatusCode::Internal,
241
242            Error::Io { .. } => StatusCode::External,
243
244            Error::Database { error, .. } => error.status_code(),
245
246            Error::SnapshotNotFound { .. } => StatusCode::InvalidArguments,
247            Error::SchemaNotFound { .. } => StatusCode::DatabaseNotFound,
248        }
249    }
250
251    fn as_any(&self) -> &dyn Any {
252        self
253    }
254
255    fn retry_hint(&self) -> RetryHint {
256        match self {
257            Error::StorageOperation { error, .. } | Error::BuildObjectStore { error, .. } => {
258                retry_hint_from_opendal_error(error)
259            }
260            Error::Database { error, .. } => error.retry_hint(),
261            _ => RetryHint::NonRetryable,
262        }
263    }
264}