Skip to main content

log_store/
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, retry_hint_from_io_error};
18use common_error::status_code::StatusCode;
19use common_macro::stack_trace_debug;
20use common_runtime::error::Error as RuntimeError;
21use common_wal::kafka::rskafka_client_error_to_retry_hint;
22use object_store::error::retry_hint_from_opendal_error;
23use serde_json::error::Error as JsonError;
24use snafu::{Location, Snafu};
25use store_api::storage::RegionId;
26
27#[derive(Snafu)]
28#[snafu(visibility(pub))]
29#[stack_trace_debug]
30pub enum Error {
31    #[snafu(display("Failed to create TLS Config"))]
32    TlsConfig {
33        #[snafu(implicit)]
34        location: Location,
35        source: common_wal::error::Error,
36    },
37
38    #[snafu(display("Invalid provider type, expected: {}, actual: {}", expected, actual))]
39    InvalidProvider {
40        #[snafu(implicit)]
41        location: Location,
42        expected: String,
43        actual: String,
44    },
45
46    #[snafu(display("Failed to start log store task: {}", name))]
47    StartWalTask {
48        name: String,
49        #[snafu(implicit)]
50        location: Location,
51        source: RuntimeError,
52    },
53
54    #[snafu(display("Failed to stop log store task: {}", name))]
55    StopWalTask {
56        name: String,
57        #[snafu(implicit)]
58        location: Location,
59        source: RuntimeError,
60    },
61
62    #[snafu(display("Failed to add entry to LogBatch"))]
63    AddEntryLogBatch {
64        #[snafu(source)]
65        error: raft_engine::Error,
66        #[snafu(implicit)]
67        location: Location,
68    },
69
70    #[snafu(display("Failed to perform raft-engine operation"))]
71    RaftEngine {
72        #[snafu(source)]
73        error: raft_engine::Error,
74        #[snafu(implicit)]
75        location: Location,
76    },
77
78    #[snafu(display("Failed to perform IO on path: {}", path))]
79    Io {
80        path: String,
81        #[snafu(source)]
82        error: std::io::Error,
83        #[snafu(implicit)]
84        location: Location,
85    },
86
87    #[snafu(display("Log store not started yet"))]
88    IllegalState {
89        #[snafu(implicit)]
90        location: Location,
91    },
92
93    #[snafu(display("Namespace is illegal: {}", ns))]
94    IllegalNamespace {
95        ns: u64,
96        #[snafu(implicit)]
97        location: Location,
98    },
99
100    #[snafu(display(
101        "Failed to fetch entries from namespace: {}, start: {}, end: {}, max size: {}",
102        ns,
103        start,
104        end,
105        max_size,
106    ))]
107    FetchEntry {
108        ns: u64,
109        start: u64,
110        end: u64,
111        max_size: usize,
112        #[snafu(source)]
113        error: raft_engine::Error,
114        #[snafu(implicit)]
115        location: Location,
116    },
117
118    #[snafu(display(
119        "Cannot override compacted entry, namespace: {}, first index: {}, attempt index: {}",
120        namespace,
121        first_index,
122        attempt_index
123    ))]
124    OverrideCompactedEntry {
125        namespace: u64,
126        first_index: u64,
127        attempt_index: u64,
128        #[snafu(implicit)]
129        location: Location,
130    },
131
132    #[snafu(display(
133        "Failed to build a Kafka client, broker endpoints: {:?}",
134        broker_endpoints
135    ))]
136    BuildClient {
137        broker_endpoints: Vec<String>,
138        #[snafu(implicit)]
139        location: Location,
140        #[snafu(source)]
141        error: rskafka::client::error::Error,
142    },
143
144    #[snafu(display(
145        "Failed to build a Kafka partition client, topic: {}, partition: {}",
146        topic,
147        partition
148    ))]
149    BuildPartitionClient {
150        topic: String,
151        partition: i32,
152        #[snafu(implicit)]
153        location: Location,
154        #[snafu(source)]
155        error: rskafka::client::error::Error,
156    },
157
158    #[snafu(display("Missing required key in a record"))]
159    MissingKey {
160        #[snafu(implicit)]
161        location: Location,
162    },
163
164    #[snafu(display("Missing required value in a record"))]
165    MissingValue {
166        #[snafu(implicit)]
167        location: Location,
168    },
169
170    #[snafu(display("Failed to produce records to Kafka, topic: {}, size: {}", topic, size))]
171    ProduceRecord {
172        topic: String,
173        size: usize,
174        #[snafu(implicit)]
175        location: Location,
176        #[snafu(source)]
177        error: rskafka::client::producer::Error,
178    },
179
180    #[snafu(display("Failed to produce batch records to Kafka"))]
181    BatchProduce {
182        #[snafu(implicit)]
183        location: Location,
184        #[snafu(source)]
185        error: rskafka::client::error::Error,
186    },
187
188    #[snafu(display("Failed to read a record from Kafka, topic: {}", topic))]
189    ConsumeRecord {
190        topic: String,
191        #[snafu(implicit)]
192        location: Location,
193        #[snafu(source)]
194        error: rskafka::client::error::Error,
195    },
196
197    #[snafu(display("Failed to get the latest offset, topic: {}", topic))]
198    GetOffset {
199        topic: String,
200        #[snafu(implicit)]
201        location: Location,
202        #[snafu(source)]
203        error: rskafka::client::error::Error,
204    },
205
206    #[snafu(display("Failed to do a cast"))]
207    Cast {
208        #[snafu(implicit)]
209        location: Location,
210    },
211
212    #[snafu(display("Failed to encode object into json"))]
213    EncodeJson {
214        #[snafu(implicit)]
215        location: Location,
216        #[snafu(source)]
217        error: JsonError,
218    },
219
220    #[snafu(display("Failed to decode object from json"))]
221    DecodeJson {
222        #[snafu(implicit)]
223        location: Location,
224        #[snafu(source)]
225        error: JsonError,
226    },
227
228    #[snafu(display("The record sequence is not legal, error: {}", error))]
229    IllegalSequence {
230        #[snafu(implicit)]
231        location: Location,
232        error: String,
233    },
234
235    #[snafu(display(
236        "Attempt to append discontinuous log entry, region: {}, last index: {}, attempt index: {}",
237        region_id,
238        last_index,
239        attempt_index
240    ))]
241    DiscontinuousLogIndex {
242        region_id: RegionId,
243        last_index: u64,
244        attempt_index: u64,
245    },
246
247    #[snafu(display("OrderedBatchProducer is stopped",))]
248    OrderedBatchProducerStopped {
249        #[snafu(implicit)]
250        location: Location,
251    },
252
253    #[snafu(display("Failed to wait for ProduceResultReceiver"))]
254    WaitProduceResultReceiver {
255        #[snafu(implicit)]
256        location: Location,
257        #[snafu(source)]
258        error: tokio::sync::oneshot::error::RecvError,
259    },
260
261    #[snafu(display("Failed to wait for result of DumpIndex"))]
262    WaitDumpIndex {
263        #[snafu(implicit)]
264        location: Location,
265        #[snafu(source)]
266        error: tokio::sync::oneshot::error::RecvError,
267    },
268
269    #[snafu(display("Failed to create writer"))]
270    CreateWriter {
271        #[snafu(implicit)]
272        location: Location,
273        #[snafu(source)]
274        error: object_store::Error,
275    },
276
277    #[snafu(display("Failed to write index"))]
278    WriteIndex {
279        #[snafu(implicit)]
280        location: Location,
281        #[snafu(source)]
282        error: object_store::Error,
283    },
284
285    #[snafu(display("Failed to read index, path: {path}"))]
286    ReadIndex {
287        #[snafu(implicit)]
288        location: Location,
289        #[snafu(source)]
290        error: object_store::Error,
291        path: String,
292    },
293
294    #[snafu(display(
295        "The length of meta if exceeded the limit: {}, actual: {}",
296        limit,
297        actual
298    ))]
299    MetaLengthExceededLimit {
300        #[snafu(implicit)]
301        location: Location,
302        limit: usize,
303        actual: usize,
304    },
305
306    #[snafu(display("No max value"))]
307    NoMaxValue {
308        #[snafu(implicit)]
309        location: Location,
310    },
311}
312
313pub type Result<T> = std::result::Result<T, Error>;
314
315fn rskafka_client_error_to_status_code(error: &rskafka::client::error::Error) -> StatusCode {
316    match error {
317        rskafka::client::error::Error::Connection(_)
318        | rskafka::client::error::Error::Request(_)
319        | rskafka::client::error::Error::InvalidResponse(_)
320        | rskafka::client::error::Error::ServerError { .. }
321        | rskafka::client::error::Error::RetryFailed(_) => StatusCode::Internal,
322        rskafka::client::error::Error::Timeout => StatusCode::StorageUnavailable,
323        _ => StatusCode::Internal,
324    }
325}
326
327impl ErrorExt for Error {
328    fn as_any(&self) -> &dyn Any {
329        self
330    }
331
332    fn status_code(&self) -> StatusCode {
333        use Error::*;
334
335        match self {
336            TlsConfig { .. }
337            | InvalidProvider { .. }
338            | IllegalNamespace { .. }
339            | MissingKey { .. }
340            | MissingValue { .. }
341            | OverrideCompactedEntry { .. } => StatusCode::InvalidArguments,
342            StartWalTask { .. }
343            | StopWalTask { .. }
344            | IllegalState { .. }
345            | NoMaxValue { .. }
346            | Cast { .. }
347            | EncodeJson { .. }
348            | DecodeJson { .. }
349            | IllegalSequence { .. }
350            | DiscontinuousLogIndex { .. }
351            | OrderedBatchProducerStopped { .. }
352            | WaitProduceResultReceiver { .. }
353            | WaitDumpIndex { .. }
354            | MetaLengthExceededLimit { .. } => StatusCode::Internal,
355
356            // Object store related errors
357            CreateWriter { .. } | WriteIndex { .. } | ReadIndex { .. } | Io { .. } => {
358                StatusCode::StorageUnavailable
359            }
360            // Raft engine
361            FetchEntry { .. } | RaftEngine { .. } | AddEntryLogBatch { .. } => {
362                StatusCode::StorageUnavailable
363            }
364            // Kafka producer related errors
365            ProduceRecord { error, .. } => match error {
366                rskafka::client::producer::Error::Client(error) => {
367                    rskafka_client_error_to_status_code(error)
368                }
369                rskafka::client::producer::Error::Aggregator(_)
370                | rskafka::client::producer::Error::FlushError(_)
371                | rskafka::client::producer::Error::TooLarge => StatusCode::Internal,
372            },
373            BuildClient { error, .. }
374            | BuildPartitionClient { error, .. }
375            | BatchProduce { error, .. }
376            | GetOffset { error, .. }
377            | ConsumeRecord { error, .. } => rskafka_client_error_to_status_code(error),
378        }
379    }
380
381    fn retry_hint(&self) -> RetryHint {
382        use Error::*;
383
384        match self {
385            CreateWriter { error, .. } | WriteIndex { error, .. } | ReadIndex { error, .. } => {
386                retry_hint_from_opendal_error(error)
387            }
388            Io { error, .. } => retry_hint_from_io_error(error),
389            FetchEntry { .. } | RaftEngine { .. } | AddEntryLogBatch { .. } => RetryHint::Retryable,
390            ProduceRecord { error, .. } => match error {
391                rskafka::client::producer::Error::Client(error) => {
392                    rskafka_client_error_to_retry_hint(error)
393                }
394                rskafka::client::producer::Error::Aggregator(_)
395                | rskafka::client::producer::Error::FlushError(_)
396                | rskafka::client::producer::Error::TooLarge => RetryHint::NonRetryable,
397            },
398            BuildClient { error, .. }
399            | BuildPartitionClient { error, .. }
400            | BatchProduce { error, .. }
401            | GetOffset { error, .. }
402            | ConsumeRecord { error, .. } => rskafka_client_error_to_retry_hint(error),
403            _ => RetryHint::NonRetryable,
404        }
405    }
406}