1use 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 CreateWriter { .. } | WriteIndex { .. } | ReadIndex { .. } | Io { .. } => {
358 StatusCode::StorageUnavailable
359 }
360 FetchEntry { .. } | RaftEngine { .. } | AddEntryLogBatch { .. } => {
362 StatusCode::StorageUnavailable
363 }
364 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}