Skip to main content

cli/data/import_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;
18use common_error::status_code::StatusCode;
19use common_macro::stack_trace_debug;
20use snafu::{Location, Snafu};
21
22use crate::data::export_v2::manifest::ChunkStatus;
23
24#[derive(Snafu)]
25#[snafu(visibility(pub))]
26#[stack_trace_debug]
27pub enum Error {
28    #[snafu(display("Snapshot not found at '{}'", uri))]
29    SnapshotNotFound {
30        uri: String,
31        #[snafu(implicit)]
32        location: Location,
33    },
34
35    #[snafu(display("Manifest version mismatch: expected {}, found {}", expected, found))]
36    ManifestVersionMismatch {
37        expected: u32,
38        found: u32,
39        #[snafu(implicit)]
40        location: Location,
41    },
42
43    #[snafu(display("Schema '{}' not found in snapshot", schema))]
44    SchemaNotInSnapshot {
45        schema: String,
46        #[snafu(implicit)]
47        location: Location,
48    },
49
50    #[snafu(display("Incomplete snapshot: chunk {} has status {:?}", chunk_id, status))]
51    IncompleteSnapshot {
52        chunk_id: u32,
53        status: ChunkStatus,
54        #[snafu(implicit)]
55        location: Location,
56    },
57
58    #[snafu(display(
59        "Snapshot is inconsistent: chunk {} is marked completed but its file manifest is empty",
60        chunk_id
61    ))]
62    EmptyChunkManifest {
63        chunk_id: u32,
64        #[snafu(implicit)]
65        location: Location,
66    },
67
68    #[snafu(display(
69        "Snapshot is inconsistent: chunk {} for schema '{}' is marked completed but no files were found under '{}'",
70        chunk_id,
71        schema,
72        path
73    ))]
74    MissingChunkData {
75        chunk_id: u32,
76        schema: String,
77        path: String,
78        #[snafu(implicit)]
79        location: Location,
80    },
81
82    #[snafu(display("Chunk {} import failed for schema '{}'", chunk_id, schema))]
83    ChunkImportFailed {
84        chunk_id: u32,
85        schema: String,
86        #[snafu(source)]
87        error: crate::data::export_v2::error::Error,
88        #[snafu(implicit)]
89        location: Location,
90    },
91
92    #[snafu(display("Snapshot storage error"))]
93    SnapshotStorage {
94        #[snafu(source)]
95        error: crate::data::export_v2::error::Error,
96        #[snafu(implicit)]
97        location: Location,
98    },
99
100    #[snafu(display("Database error"))]
101    Database {
102        #[snafu(source)]
103        error: crate::error::Error,
104        #[snafu(implicit)]
105        location: Location,
106    },
107
108    #[snafu(display("Failed to parse import state file"))]
109    ImportStateParse {
110        #[snafu(source)]
111        error: serde_json::Error,
112        #[snafu(implicit)]
113        location: Location,
114    },
115
116    #[snafu(display("Import state I/O failed at '{}': {}", path, error))]
117    ImportStateIo {
118        path: String,
119        #[snafu(source)]
120        error: std::io::Error,
121        #[snafu(implicit)]
122        location: Location,
123    },
124
125    #[snafu(display("Import state is already locked at '{}'", path))]
126    ImportStateLocked {
127        path: String,
128        #[snafu(implicit)]
129        location: Location,
130    },
131
132    #[snafu(display(
133        "Failed to determine import state path for snapshot '{}'. Set HOME, USERPROFILE, or run from a valid current directory.",
134        snapshot_id
135    ))]
136    ImportStatePathUnavailable {
137        snapshot_id: String,
138        #[snafu(implicit)]
139        location: Location,
140    },
141
142    #[snafu(display(
143        "Import state at '{}' does not match current import: {}. Either rerun with matching import arguments, or delete the state file to start over (DDL will be re-executed).",
144        path,
145        reason
146    ))]
147    ImportStateMismatch {
148        path: String,
149        reason: String,
150        #[snafu(implicit)]
151        location: Location,
152    },
153
154    #[cfg(test)]
155    #[snafu(display("Test task failed: {}", message))]
156    TestTaskFailed {
157        message: String,
158        retryable: bool,
159        #[snafu(implicit)]
160        location: Location,
161    },
162
163    #[snafu(display(
164        "Import state references unknown task: chunk {}, schema '{}'",
165        chunk_id,
166        schema
167    ))]
168    ImportStateUnknownTask {
169        chunk_id: u32,
170        schema: String,
171        #[snafu(implicit)]
172        location: Location,
173    },
174
175    #[snafu(display(
176        "Import state at '{}' is not ready for data import: DDL has not been marked completed",
177        path
178    ))]
179    ImportStateDdlIncomplete {
180        path: String,
181        #[snafu(implicit)]
182        location: Location,
183    },
184}
185
186pub type Result<T> = std::result::Result<T, Error>;
187
188impl ErrorExt for Error {
189    fn status_code(&self) -> StatusCode {
190        match self {
191            Error::SnapshotNotFound { .. }
192            | Error::SchemaNotInSnapshot { .. }
193            | Error::ManifestVersionMismatch { .. }
194            | Error::IncompleteSnapshot { .. }
195            | Error::EmptyChunkManifest { .. }
196            | Error::MissingChunkData { .. } => StatusCode::InvalidArguments,
197            Error::ImportStatePathUnavailable { .. }
198            | Error::ImportStateUnknownTask { .. }
199            | Error::ImportStateDdlIncomplete { .. } => StatusCode::Unexpected,
200            Error::ImportStateMismatch { .. } => StatusCode::InvalidArguments,
201            #[cfg(test)]
202            Error::TestTaskFailed { retryable, .. } => {
203                if *retryable {
204                    StatusCode::StorageUnavailable
205                } else {
206                    StatusCode::InvalidArguments
207                }
208            }
209            Error::Database { error, .. } => error.status_code(),
210            Error::SnapshotStorage { error, .. } | Error::ChunkImportFailed { error, .. } => {
211                error.status_code()
212            }
213            Error::ImportStateParse { .. } => StatusCode::Internal,
214            Error::ImportStateIo { .. } => StatusCode::StorageUnavailable,
215            Error::ImportStateLocked { .. } => StatusCode::IllegalState,
216        }
217    }
218
219    fn as_any(&self) -> &dyn Any {
220        self
221    }
222}