1use std::any::Any;
16use std::sync::Arc;
17
18use common_error::ext::{ErrorExt, RetryHint, retry_hint_from_io_error};
19use common_error::status_code::StatusCode;
20use common_macro::stack_trace_debug;
21use common_runtime::error::Error as RuntimeError;
22use common_wal::kafka::rskafka_client_error_to_retry_hint;
23use object_store::error::retry_hint_from_opendal_error;
24use serde_json::error::Error as JsonError;
25use snafu::{Location, Snafu};
26use store_api::storage::RegionId;
27
28#[derive(Snafu)]
29#[snafu(visibility(pub))]
30#[stack_trace_debug]
31pub enum Error {
32 #[snafu(display("Failed to create TLS Config"))]
33 TlsConfig {
34 #[snafu(implicit)]
35 location: Location,
36 source: common_wal::error::Error,
37 },
38
39 #[snafu(display("Invalid provider type, expected: {}, actual: {}", expected, actual))]
40 InvalidProvider {
41 #[snafu(implicit)]
42 location: Location,
43 expected: String,
44 actual: String,
45 },
46
47 #[snafu(display("Failed to start log store task: {}", name))]
48 StartWalTask {
49 name: String,
50 #[snafu(implicit)]
51 location: Location,
52 source: RuntimeError,
53 },
54
55 #[snafu(display("Failed to stop log store task: {}", name))]
56 StopWalTask {
57 name: String,
58 #[snafu(implicit)]
59 location: Location,
60 source: RuntimeError,
61 },
62
63 #[snafu(display("Failed to add entry to LogBatch"))]
64 AddEntryLogBatch {
65 #[snafu(source)]
66 error: raft_engine::Error,
67 #[snafu(implicit)]
68 location: Location,
69 },
70
71 #[snafu(display("Failed to perform raft-engine operation"))]
72 RaftEngine {
73 #[snafu(source)]
74 error: raft_engine::Error,
75 #[snafu(implicit)]
76 location: Location,
77 },
78
79 #[snafu(display("Failed to perform IO on path: {}", path))]
80 Io {
81 path: String,
82 #[snafu(source)]
83 error: std::io::Error,
84 #[snafu(implicit)]
85 location: Location,
86 },
87
88 #[snafu(display("Log store not started yet"))]
89 IllegalState {
90 #[snafu(implicit)]
91 location: Location,
92 },
93
94 #[snafu(display("Namespace is illegal: {}", ns))]
95 IllegalNamespace {
96 ns: u64,
97 #[snafu(implicit)]
98 location: Location,
99 },
100
101 #[snafu(display(
102 "Failed to fetch entries from namespace: {}, start: {}, end: {}, max size: {}",
103 ns,
104 start,
105 end,
106 max_size,
107 ))]
108 FetchEntry {
109 ns: u64,
110 start: u64,
111 end: u64,
112 max_size: usize,
113 #[snafu(source)]
114 error: raft_engine::Error,
115 #[snafu(implicit)]
116 location: Location,
117 },
118
119 #[snafu(display(
120 "Cannot override compacted entry, namespace: {}, first index: {}, attempt index: {}",
121 namespace,
122 first_index,
123 attempt_index
124 ))]
125 OverrideCompactedEntry {
126 namespace: u64,
127 first_index: u64,
128 attempt_index: u64,
129 #[snafu(implicit)]
130 location: Location,
131 },
132
133 #[snafu(display(
134 "Failed to build a Kafka client, broker endpoints: {:?}",
135 broker_endpoints
136 ))]
137 BuildClient {
138 broker_endpoints: Vec<String>,
139 #[snafu(implicit)]
140 location: Location,
141 #[snafu(source)]
142 error: rskafka::client::error::Error,
143 },
144
145 #[snafu(display(
146 "Failed to build a Kafka partition client, topic: {}, partition: {}",
147 topic,
148 partition
149 ))]
150 BuildPartitionClient {
151 topic: String,
152 partition: i32,
153 #[snafu(implicit)]
154 location: Location,
155 #[snafu(source)]
156 error: rskafka::client::error::Error,
157 },
158
159 #[snafu(display("Missing required key in a record"))]
160 MissingKey {
161 #[snafu(implicit)]
162 location: Location,
163 },
164
165 #[snafu(display("Missing required value in a record"))]
166 MissingValue {
167 #[snafu(implicit)]
168 location: Location,
169 },
170
171 #[snafu(display("Failed to produce records to Kafka, topic: {}, size: {}", topic, size))]
172 ProduceRecord {
173 topic: String,
174 size: usize,
175 #[snafu(implicit)]
176 location: Location,
177 #[snafu(source)]
178 error: rskafka::client::producer::Error,
179 },
180
181 #[snafu(display("Failed to produce batch records to Kafka"))]
182 BatchProduce {
183 #[snafu(implicit)]
184 location: Location,
185 #[snafu(source)]
186 error: rskafka::client::error::Error,
187 },
188
189 #[snafu(display("Failed to read a record from Kafka, topic: {}", topic))]
190 ConsumeRecord {
191 topic: String,
192 #[snafu(implicit)]
193 location: Location,
194 #[snafu(source)]
195 error: rskafka::client::error::Error,
196 },
197
198 #[snafu(display("Failed to get the latest offset, topic: {}", topic))]
199 GetOffset {
200 topic: String,
201 #[snafu(implicit)]
202 location: Location,
203 #[snafu(source)]
204 error: rskafka::client::error::Error,
205 },
206
207 #[snafu(display("Failed to do a cast"))]
208 Cast {
209 #[snafu(implicit)]
210 location: Location,
211 },
212
213 #[snafu(display("Failed to encode object into json"))]
214 EncodeJson {
215 #[snafu(implicit)]
216 location: Location,
217 #[snafu(source)]
218 error: JsonError,
219 },
220
221 #[snafu(display("Failed to decode object from json"))]
222 DecodeJson {
223 #[snafu(implicit)]
224 location: Location,
225 #[snafu(source)]
226 error: JsonError,
227 },
228
229 #[snafu(display("The record sequence is not legal, error: {}", error))]
230 IllegalSequence {
231 #[snafu(implicit)]
232 location: Location,
233 error: String,
234 },
235
236 #[snafu(display(
237 "Attempt to append discontinuous log entry, region: {}, last index: {}, attempt index: {}",
238 region_id,
239 last_index,
240 attempt_index
241 ))]
242 DiscontinuousLogIndex {
243 region_id: RegionId,
244 last_index: u64,
245 attempt_index: u64,
246 },
247
248 #[snafu(display("OrderedBatchProducer is stopped",))]
249 OrderedBatchProducerStopped {
250 #[snafu(implicit)]
251 location: Location,
252 },
253
254 #[snafu(display("Failed to wait for ProduceResultReceiver"))]
255 WaitProduceResultReceiver {
256 #[snafu(implicit)]
257 location: Location,
258 #[snafu(source)]
259 error: tokio::sync::oneshot::error::RecvError,
260 },
261
262 #[snafu(display("Failed to wait for result of DumpIndex"))]
263 WaitDumpIndex {
264 #[snafu(implicit)]
265 location: Location,
266 #[snafu(source)]
267 error: tokio::sync::oneshot::error::RecvError,
268 },
269
270 #[snafu(display("Failed to create writer"))]
271 CreateWriter {
272 #[snafu(implicit)]
273 location: Location,
274 #[snafu(source)]
275 error: object_store::Error,
276 },
277
278 #[snafu(display("Failed to write index"))]
279 WriteIndex {
280 #[snafu(implicit)]
281 location: Location,
282 #[snafu(source)]
283 error: object_store::Error,
284 },
285
286 #[snafu(display("Failed to read index, path: {path}"))]
287 ReadIndex {
288 #[snafu(implicit)]
289 location: Location,
290 #[snafu(source)]
291 error: object_store::Error,
292 path: String,
293 },
294
295 #[snafu(display(
296 "The length of meta if exceeded the limit: {}, actual: {}",
297 limit,
298 actual
299 ))]
300 MetaLengthExceededLimit {
301 #[snafu(implicit)]
302 location: Location,
303 limit: usize,
304 actual: usize,
305 },
306
307 #[snafu(display("No max value"))]
308 NoMaxValue {
309 #[snafu(implicit)]
310 location: Location,
311 },
312
313 #[snafu(display("Corrupted WAL object, {}", reason))]
314 CorruptedWalObject {
315 reason: String,
316 #[snafu(implicit)]
317 location: Location,
318 },
319
320 #[snafu(display("Invalid WAL object store, {}", reason))]
321 InvalidWalObjectStore {
322 reason: String,
323 #[snafu(implicit)]
324 location: Location,
325 },
326
327 #[snafu(display(
328 "Object store WAL region mismatch, supplied region: {}, {}",
329 region_id,
330 reason
331 ))]
332 MismatchedWalRegion {
333 region_id: RegionId,
334 reason: String,
335 #[snafu(implicit)]
336 location: Location,
337 },
338
339 #[snafu(display(
340 "Invalid WAL entry range, region: {}, start: {}, end: {}",
341 region_id,
342 start_entry_id,
343 end_entry_id
344 ))]
345 InvalidWalEntryRange {
346 region_id: RegionId,
347 start_entry_id: u64,
348 end_entry_id: u64,
349 #[snafu(implicit)]
350 location: Location,
351 },
352
353 #[snafu(display("WAL object sequence is exhausted, last sequence: {}", last_object_seq))]
354 WalObjectSequenceExhausted {
355 last_object_seq: u64,
356 #[snafu(implicit)]
357 location: Location,
358 },
359
360 #[snafu(display(
361 "WAL entry positions of region {} in one object are exhausted",
362 region_id
363 ))]
364 WalEntryPositionExhausted {
365 region_id: RegionId,
366 #[snafu(implicit)]
367 location: Location,
368 },
369
370 #[snafu(display("WAL object already exists with different content, path: {}", path))]
371 WalObjectConflict {
372 path: String,
373 #[snafu(implicit)]
374 location: Location,
375 },
376
377 #[snafu(display("Failed to {} WAL object, path: {}", operation, path))]
378 WalObjectStore {
379 operation: &'static str,
380 path: String,
381 #[snafu(source)]
382 error: object_store::Error,
383 #[snafu(implicit)]
384 location: Location,
385 },
386
387 #[snafu(display("Invalid WAL object, path: {}", path))]
388 InvalidWalObject {
389 path: String,
390 #[snafu(source(from(Error, Box::new)))]
391 source: Box<Error>,
392 #[snafu(implicit)]
393 location: Location,
394 },
395
396 #[snafu(display(
397 "Object store WAL prefix mismatch, expected: {}, actual: {}",
398 expected,
399 actual
400 ))]
401 MismatchedWalPrefix {
402 expected: String,
403 actual: String,
404 #[snafu(implicit)]
405 location: Location,
406 },
407
408 #[snafu(display("Object store WAL operation failed"))]
409 ObjectStoreWal {
410 source: Arc<Error>,
411 #[snafu(implicit)]
412 location: Location,
413 },
414
415 #[snafu(display("Object store WAL operation is not supported"))]
417 UnsupportedObjectStoreWalOperation {
418 #[snafu(implicit)]
419 location: Location,
420 },
421}
422
423pub type Result<T> = std::result::Result<T, Error>;
424
425fn rskafka_client_error_to_status_code(error: &rskafka::client::error::Error) -> StatusCode {
426 match error {
427 rskafka::client::error::Error::Connection(_)
428 | rskafka::client::error::Error::Request(_)
429 | rskafka::client::error::Error::InvalidResponse(_)
430 | rskafka::client::error::Error::ServerError { .. }
431 | rskafka::client::error::Error::RetryFailed(_) => StatusCode::Internal,
432 rskafka::client::error::Error::Timeout => StatusCode::StorageUnavailable,
433 _ => StatusCode::Internal,
434 }
435}
436
437impl ErrorExt for Error {
438 fn as_any(&self) -> &dyn Any {
439 self
440 }
441
442 fn status_code(&self) -> StatusCode {
443 use Error::*;
444
445 match self {
446 TlsConfig { .. }
447 | InvalidProvider { .. }
448 | IllegalNamespace { .. }
449 | MissingKey { .. }
450 | MissingValue { .. }
451 | OverrideCompactedEntry { .. }
452 | InvalidWalObjectStore { .. }
453 | MismatchedWalPrefix { .. }
454 | MismatchedWalRegion { .. }
455 | InvalidWalEntryRange { .. } => StatusCode::InvalidArguments,
456 StartWalTask { .. }
457 | StopWalTask { .. }
458 | IllegalState { .. }
459 | NoMaxValue { .. }
460 | Cast { .. }
461 | EncodeJson { .. }
462 | DecodeJson { .. }
463 | IllegalSequence { .. }
464 | DiscontinuousLogIndex { .. }
465 | OrderedBatchProducerStopped { .. }
466 | WaitProduceResultReceiver { .. }
467 | WaitDumpIndex { .. }
468 | MetaLengthExceededLimit { .. } => StatusCode::Internal,
469
470 CorruptedWalObject { .. }
471 | WalObjectConflict { .. }
472 | WalObjectSequenceExhausted { .. }
473 | WalEntryPositionExhausted { .. } => StatusCode::Unexpected,
474
475 UnsupportedObjectStoreWalOperation { .. } => StatusCode::Unsupported,
476 InvalidWalObject { source, .. } => source.status_code(),
477 ObjectStoreWal { source, .. } => source.status_code(),
478
479 CreateWriter { .. }
481 | WriteIndex { .. }
482 | ReadIndex { .. }
483 | WalObjectStore { .. }
484 | Io { .. } => StatusCode::StorageUnavailable,
485 FetchEntry { .. } | RaftEngine { .. } | AddEntryLogBatch { .. } => {
487 StatusCode::StorageUnavailable
488 }
489 ProduceRecord { error, .. } => match error {
491 rskafka::client::producer::Error::Client(error) => {
492 rskafka_client_error_to_status_code(error)
493 }
494 rskafka::client::producer::Error::Aggregator(_)
495 | rskafka::client::producer::Error::FlushError(_)
496 | rskafka::client::producer::Error::TooLarge => StatusCode::Internal,
497 },
498 BuildClient { error, .. }
499 | BuildPartitionClient { error, .. }
500 | BatchProduce { error, .. }
501 | GetOffset { error, .. }
502 | ConsumeRecord { error, .. } => rskafka_client_error_to_status_code(error),
503 }
504 }
505
506 fn retry_hint(&self) -> RetryHint {
507 use Error::*;
508
509 match self {
510 CreateWriter { error, .. }
511 | WriteIndex { error, .. }
512 | ReadIndex { error, .. }
513 | WalObjectStore { error, .. } => retry_hint_from_opendal_error(error),
514 ObjectStoreWal { source, .. } => source.retry_hint(),
515 Io { error, .. } => retry_hint_from_io_error(error),
516 FetchEntry { .. } | RaftEngine { .. } | AddEntryLogBatch { .. } => RetryHint::Retryable,
517 ProduceRecord { error, .. } => match error {
518 rskafka::client::producer::Error::Client(error) => {
519 rskafka_client_error_to_retry_hint(error)
520 }
521 rskafka::client::producer::Error::Aggregator(_)
522 | rskafka::client::producer::Error::FlushError(_)
523 | rskafka::client::producer::Error::TooLarge => RetryHint::NonRetryable,
524 },
525 BuildClient { error, .. }
526 | BuildPartitionClient { error, .. }
527 | BatchProduce { error, .. }
528 | GetOffset { error, .. }
529 | ConsumeRecord { error, .. } => rskafka_client_error_to_retry_hint(error),
530 _ => RetryHint::NonRetryable,
531 }
532 }
533}