Skip to main content

index/inverted_index/
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
24use crate::inverted_index::search::predicate::Predicate;
25
26#[derive(Snafu)]
27#[snafu(visibility(pub))]
28#[stack_trace_debug]
29pub enum Error {
30    #[snafu(display("Failed to read"))]
31    Read {
32        #[snafu(source)]
33        error: IoError,
34        #[snafu(implicit)]
35        location: Location,
36    },
37
38    #[snafu(display("Failed to write"))]
39    Write {
40        #[snafu(source)]
41        error: IoError,
42        #[snafu(implicit)]
43        location: Location,
44    },
45
46    #[snafu(display("Failed to flush"))]
47    Flush {
48        #[snafu(source)]
49        error: IoError,
50        #[snafu(implicit)]
51        location: Location,
52    },
53
54    #[snafu(display("Failed to close"))]
55    Close {
56        #[snafu(source)]
57        error: IoError,
58        #[snafu(implicit)]
59        location: Location,
60    },
61
62    #[snafu(display(
63        "Unexpected inverted index blob size, min: {min_blob_size}, actual: {actual_blob_size}"
64    ))]
65    UnexpectedBlobSize {
66        min_blob_size: u64,
67        actual_blob_size: u64,
68        #[snafu(implicit)]
69        location: Location,
70    },
71
72    #[snafu(display("Blob size too small"))]
73    BlobSizeTooSmall {
74        #[snafu(implicit)]
75        location: Location,
76    },
77
78    #[snafu(display("Invalid footer payload size"))]
79    InvalidFooterPayloadSize {
80        #[snafu(implicit)]
81        location: Location,
82    },
83
84    #[snafu(display(
85        "Unexpected inverted index footer payload size, max: {max_payload_size}, actual: {actual_payload_size}"
86    ))]
87    UnexpectedFooterPayloadSize {
88        max_payload_size: u64,
89        actual_payload_size: u64,
90        #[snafu(implicit)]
91        location: Location,
92    },
93
94    #[snafu(display(
95        "Unexpected inverted index offset size, offset: {offset}, size: {size}, blob_size: {blob_size}, payload_size: {payload_size}"
96    ))]
97    UnexpectedOffsetSize {
98        offset: u64,
99        size: u64,
100        blob_size: u64,
101        payload_size: u64,
102    },
103
104    #[snafu(display("Unexpected zero segment row count"))]
105    UnexpectedZeroSegmentRowCount {
106        #[snafu(implicit)]
107        location: Location,
108    },
109
110    #[snafu(display("Failed to decode fst"))]
111    DecodeFst {
112        #[snafu(source)]
113        error: fst::Error,
114        #[snafu(implicit)]
115        location: Location,
116    },
117
118    #[snafu(display("Failed to decode bitmap"))]
119    DecodeBitmap {
120        #[snafu(source)]
121        error: IoError,
122        #[snafu(implicit)]
123        location: Location,
124    },
125
126    #[snafu(display("Failed to decode protobuf"))]
127    DecodeProto {
128        #[snafu(source)]
129        error: prost::DecodeError,
130        #[snafu(implicit)]
131        location: Location,
132    },
133
134    #[snafu(display("Failed to parse regex pattern: {pattern}"))]
135    ParseRegex {
136        #[snafu(source)]
137        error: regex::Error,
138        pattern: String,
139        #[snafu(implicit)]
140        location: Location,
141    },
142
143    #[snafu(display("Failed to parse regex DFA"))]
144    ParseDFA {
145        #[snafu(source)]
146        error: Box<regex_automata::dfa::dense::BuildError>,
147        #[snafu(implicit)]
148        location: Location,
149    },
150
151    #[snafu(display("Unexpected empty predicates to construct fst applier"))]
152    EmptyPredicates {
153        #[snafu(implicit)]
154        location: Location,
155    },
156
157    #[snafu(display("Failed to construct intersection fst applier with InList predicate"))]
158    IntersectionApplierWithInList {
159        #[snafu(implicit)]
160        location: Location,
161    },
162
163    #[snafu(display("Failed to construct keys fst applier without InList predicate"))]
164    KeysApplierWithoutInList {
165        #[snafu(implicit)]
166        location: Location,
167    },
168
169    #[snafu(display(
170        "Failed to construct keys fst applier with unexpected predicates: {predicates:?}"
171    ))]
172    KeysApplierUnexpectedPredicates {
173        #[snafu(implicit)]
174        location: Location,
175        predicates: Vec<Predicate>,
176    },
177
178    #[snafu(display("index not found, name: {name}"))]
179    IndexNotFound {
180        name: String,
181        #[snafu(implicit)]
182        location: Location,
183    },
184
185    #[snafu(display("Failed to insert value to FST"))]
186    FstInsert {
187        #[snafu(source)]
188        error: fst::Error,
189        #[snafu(implicit)]
190        location: Location,
191    },
192
193    #[snafu(display("Failed to compile FST"))]
194    FstCompile {
195        #[snafu(source)]
196        error: fst::Error,
197        #[snafu(implicit)]
198        location: Location,
199    },
200
201    #[snafu(display("Failed to perform IO operation"))]
202    CommonIo {
203        #[snafu(source)]
204        error: IoError,
205        #[snafu(implicit)]
206        location: Location,
207    },
208
209    #[snafu(display("Unknown intermediate codec magic: {magic:?}"))]
210    UnknownIntermediateCodecMagic {
211        magic: [u8; 4],
212        #[snafu(implicit)]
213        location: Location,
214    },
215
216    #[snafu(display(
217        "Inconsistent row count, index_name: {index_name}, total_row_count: {total_row_count}, expected: {expected_row_count}"
218    ))]
219    InconsistentRowCount {
220        index_name: String,
221        total_row_count: usize,
222        expected_row_count: usize,
223    },
224
225    #[snafu(display("Shared index metadata read failed"))]
226    SharedRead {
227        source: Arc<Error>,
228        #[snafu(implicit)]
229        location: Location,
230    },
231
232    #[snafu(display("External error"))]
233    External {
234        source: BoxedError,
235        #[snafu(implicit)]
236        location: Location,
237    },
238
239    #[snafu(display("Intermediate error"))]
240    Intermediate {
241        source: crate::error::Error,
242        #[snafu(implicit)]
243        location: Location,
244    },
245}
246
247impl ErrorExt for Error {
248    fn status_code(&self) -> StatusCode {
249        use Error::*;
250        match self {
251            Read { .. }
252            | Write { .. }
253            | Flush { .. }
254            | Close { .. }
255            | UnexpectedFooterPayloadSize { .. }
256            | UnexpectedZeroSegmentRowCount { .. }
257            | UnexpectedOffsetSize { .. }
258            | UnexpectedBlobSize { .. }
259            | DecodeProto { .. }
260            | DecodeFst { .. }
261            | KeysApplierUnexpectedPredicates { .. }
262            | CommonIo { .. }
263            | UnknownIntermediateCodecMagic { .. }
264            | FstCompile { .. }
265            | DecodeBitmap { .. }
266            | InvalidFooterPayloadSize { .. }
267            | BlobSizeTooSmall { .. } => StatusCode::Unexpected,
268
269            ParseRegex { .. }
270            | ParseDFA { .. }
271            | KeysApplierWithoutInList { .. }
272            | IntersectionApplierWithInList { .. }
273            | EmptyPredicates { .. }
274            | FstInsert { .. }
275            | InconsistentRowCount { .. }
276            | IndexNotFound { .. } => StatusCode::InvalidArguments,
277
278            Intermediate { source, .. } => source.status_code(),
279            External { source, .. } => source.status_code(),
280            SharedRead { source, .. } => source.status_code(),
281        }
282    }
283
284    fn as_any(&self) -> &dyn Any {
285        self
286    }
287}
288
289pub type Result<T> = std::result::Result<T, Error>;
290
291#[cfg(test)]
292mod tests {
293    use snafu::IntoError;
294
295    use super::*;
296
297    #[test]
298    fn shared_metadata_error_preserves_status() {
299        let source = CommonIoSnafu.into_error(std::io::Error::other("read failed"));
300        let status = source.status_code();
301        let retry = source.retry_hint();
302        let error = SharedReadSnafu.into_error(Arc::new(source));
303        assert_eq!(error.status_code(), status);
304        assert_eq!(error.retry_hint(), retry);
305    }
306}