1use std::str::Utf8Error;
16use std::sync::Arc;
17
18use common_error::ext::{BoxedError, ErrorExt, RetryHint};
19use common_error::status_code::StatusCode;
20use common_macro::stack_trace_debug;
21use common_procedure::ProcedureId;
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;
27use table::metadata::TableId;
28
29use crate::DatanodeId;
30use crate::peer::Peer;
31
32mod retry_hint;
33
34pub use retry_hint::retry_hint_from_etcd_error;
35#[cfg(feature = "mysql_kvbackend")]
36pub use retry_hint::retry_hint_from_sqlx_error;
37#[cfg(feature = "pg_kvbackend")]
38pub use retry_hint::{retry_hint_from_postgres_error, retry_hint_from_postgres_pool_error};
39
40#[derive(Snafu)]
41#[snafu(visibility(pub))]
42#[stack_trace_debug]
43pub enum Error {
44 #[snafu(display("Empty key is not allowed"))]
45 EmptyKey {
46 #[snafu(implicit)]
47 location: Location,
48 },
49
50 #[snafu(display(
51 "Another procedure is operating the region: {} on peer: {}",
52 region_id,
53 peer_id
54 ))]
55 RegionOperatingRace {
56 #[snafu(implicit)]
57 location: Location,
58 peer_id: DatanodeId,
59 region_id: RegionId,
60 },
61
62 #[snafu(display("Failed to connect to Etcd"))]
63 ConnectEtcd {
64 #[snafu(source)]
65 error: etcd_client::Error,
66 #[snafu(implicit)]
67 location: Location,
68 },
69
70 #[snafu(display("Failed to execute via Etcd"))]
71 EtcdFailed {
72 #[snafu(source)]
73 error: etcd_client::Error,
74 #[snafu(implicit)]
75 location: Location,
76 },
77
78 #[snafu(display("Failed to execute {} txn operations via Etcd", max_operations))]
79 EtcdTxnFailed {
80 max_operations: usize,
81 #[snafu(source)]
82 error: etcd_client::Error,
83 #[snafu(implicit)]
84 location: Location,
85 },
86
87 #[snafu(display("Failed to get sequence: {}", err_msg))]
88 NextSequence {
89 err_msg: String,
90 #[snafu(implicit)]
91 location: Location,
92 },
93
94 #[snafu(display("Unexpected sequence value: {}", err_msg))]
95 UnexpectedSequenceValue {
96 err_msg: String,
97 #[snafu(implicit)]
98 location: Location,
99 },
100
101 #[snafu(display("Table info not found: {}", table))]
102 TableInfoNotFound {
103 table: String,
104 #[snafu(implicit)]
105 location: Location,
106 },
107
108 #[snafu(display("Failed to register procedure loader, type name: {}", type_name))]
109 RegisterProcedureLoader {
110 type_name: String,
111 #[snafu(implicit)]
112 location: Location,
113 source: common_procedure::error::Error,
114 },
115
116 #[snafu(display("Failed to register repartition procedure loader"))]
117 RegisterRepartitionProcedureLoader {
118 #[snafu(implicit)]
119 location: Location,
120 source: BoxedError,
121 },
122
123 #[snafu(display("Failed to create repartition procedure"))]
124 CreateRepartitionProcedure {
125 source: BoxedError,
126 #[snafu(implicit)]
127 location: Location,
128 },
129
130 #[snafu(display("Failed to submit procedure"))]
131 SubmitProcedure {
132 #[snafu(implicit)]
133 location: Location,
134 source: common_procedure::Error,
135 },
136
137 #[snafu(display("Failed to query procedure"))]
138 QueryProcedure {
139 #[snafu(implicit)]
140 location: Location,
141 source: common_procedure::Error,
142 },
143
144 #[snafu(display("Procedure not found: {pid}"))]
145 ProcedureNotFound {
146 #[snafu(implicit)]
147 location: Location,
148 pid: String,
149 },
150
151 #[snafu(display("Failed to parse procedure id: {key}"))]
152 ParseProcedureId {
153 #[snafu(implicit)]
154 location: Location,
155 key: String,
156 #[snafu(source)]
157 error: common_procedure::ParseIdError,
158 },
159
160 #[snafu(display("Unsupported operation {}", operation))]
161 Unsupported {
162 operation: String,
163 #[snafu(implicit)]
164 location: Location,
165 },
166
167 #[snafu(display("Trying to write to a read-only kv backend: {}", name))]
168 ReadOnlyKvBackend {
169 name: String,
170 #[snafu(implicit)]
171 location: Location,
172 },
173
174 #[snafu(display("Failed to get procedure state receiver, procedure id: {procedure_id}"))]
175 ProcedureStateReceiver {
176 procedure_id: ProcedureId,
177 #[snafu(implicit)]
178 location: Location,
179 source: common_procedure::Error,
180 },
181
182 #[snafu(display("Procedure state receiver not found: {procedure_id}"))]
183 ProcedureStateReceiverNotFound {
184 procedure_id: ProcedureId,
185 #[snafu(implicit)]
186 location: Location,
187 },
188
189 #[snafu(display("Failed to wait procedure done"))]
190 WaitProcedure {
191 #[snafu(implicit)]
192 location: Location,
193 source: common_procedure::Error,
194 },
195
196 #[snafu(display("Failed to start procedure manager"))]
197 StartProcedureManager {
198 #[snafu(implicit)]
199 location: Location,
200 source: common_procedure::Error,
201 },
202
203 #[snafu(display("Failed to stop procedure manager"))]
204 StopProcedureManager {
205 #[snafu(implicit)]
206 location: Location,
207 source: common_procedure::Error,
208 },
209
210 #[snafu(display(
211 "Failed to get procedure output, procedure id: {procedure_id}, error: {err_msg}"
212 ))]
213 ProcedureOutput {
214 procedure_id: String,
215 err_msg: String,
216 #[snafu(implicit)]
217 location: Location,
218 },
219
220 #[snafu(display("Primary key '{key}' not found when creating region request"))]
221 PrimaryKeyNotFound {
222 key: String,
223 #[snafu(implicit)]
224 location: Location,
225 },
226
227 #[snafu(display("Failed to build table meta for table: {}", table_name))]
228 BuildTableMeta {
229 table_name: String,
230 #[snafu(source)]
231 error: table::metadata::TableMetaBuilderError,
232 #[snafu(implicit)]
233 location: Location,
234 },
235
236 #[snafu(display("Table occurs error"))]
237 Table {
238 #[snafu(implicit)]
239 location: Location,
240 source: table::error::Error,
241 },
242
243 #[snafu(display("Failed to find table route for table id {}", table_id))]
244 TableRouteNotFound {
245 table_id: TableId,
246 #[snafu(implicit)]
247 location: Location,
248 },
249
250 #[snafu(display("Failed to find table repartition metadata for table id {}", table_id))]
251 TableRepartNotFound {
252 table_id: TableId,
253 #[snafu(implicit)]
254 location: Location,
255 },
256
257 #[snafu(display("Failed to decode protobuf"))]
258 DecodeProto {
259 #[snafu(implicit)]
260 location: Location,
261 #[snafu(source)]
262 error: prost::DecodeError,
263 },
264
265 #[snafu(display("Failed to encode object into json"))]
266 EncodeJson {
267 #[snafu(implicit)]
268 location: Location,
269 #[snafu(source)]
270 error: JsonError,
271 },
272
273 #[snafu(display("Failed to decode object from json"))]
274 DecodeJson {
275 #[snafu(implicit)]
276 location: Location,
277 #[snafu(source)]
278 error: JsonError,
279 },
280
281 #[snafu(display("Failed to serialize to json: {}", input))]
282 SerializeToJson {
283 input: String,
284 #[snafu(source)]
285 error: serde_json::error::Error,
286 #[snafu(implicit)]
287 location: Location,
288 },
289
290 #[snafu(display("Failed to deserialize from json: {}", input))]
291 DeserializeFromJson {
292 input: String,
293 #[snafu(source)]
294 error: serde_json::error::Error,
295 #[snafu(implicit)]
296 location: Location,
297 },
298
299 #[snafu(display("Payload not exist"))]
300 PayloadNotExist {
301 #[snafu(implicit)]
302 location: Location,
303 },
304
305 #[snafu(display("Failed to serde json"))]
306 SerdeJson {
307 #[snafu(source)]
308 error: serde_json::error::Error,
309 #[snafu(implicit)]
310 location: Location,
311 },
312
313 #[snafu(display("Failed to parse value {} into key {}", value, key))]
314 ParseOption {
315 key: String,
316 value: String,
317 #[snafu(implicit)]
318 location: Location,
319 },
320
321 #[snafu(display("Corrupted table route data, err: {}", err_msg))]
322 RouteInfoCorrupted {
323 err_msg: String,
324 #[snafu(implicit)]
325 location: Location,
326 },
327
328 #[snafu(display("Illegal state from server, code: {}, error: {}", code, err_msg))]
329 IllegalServerState {
330 code: i32,
331 err_msg: String,
332 #[snafu(implicit)]
333 location: Location,
334 },
335
336 #[snafu(display("Failed to convert alter table request"))]
337 ConvertAlterTableRequest {
338 source: common_grpc_expr::error::Error,
339 #[snafu(implicit)]
340 location: Location,
341 },
342
343 #[snafu(display("Invalid protobuf message: {err_msg}"))]
344 InvalidProtoMsg {
345 err_msg: String,
346 #[snafu(implicit)]
347 location: Location,
348 },
349
350 #[snafu(display("Unexpected: {err_msg}"))]
351 Unexpected {
352 err_msg: String,
353 #[snafu(implicit)]
354 location: Location,
355 },
356
357 #[snafu(display("Metasrv election has no leader at this moment"))]
358 ElectionNoLeader {
359 #[snafu(implicit)]
360 location: Location,
361 },
362
363 #[snafu(display("Metasrv election leader lease expired"))]
364 ElectionLeaderLeaseExpired {
365 #[snafu(implicit)]
366 location: Location,
367 },
368
369 #[snafu(display("Metasrv election leader lease changed during election"))]
370 ElectionLeaderLeaseChanged {
371 #[snafu(implicit)]
372 location: Location,
373 },
374
375 #[snafu(display("Table already exists, table: {}", table_name))]
376 TableAlreadyExists {
377 table_name: String,
378 #[snafu(implicit)]
379 location: Location,
380 },
381
382 #[snafu(display("View already exists, view: {}", view_name))]
383 ViewAlreadyExists {
384 view_name: String,
385 #[snafu(implicit)]
386 location: Location,
387 },
388
389 #[snafu(display("Flow already exists: {}", flow_name))]
390 FlowAlreadyExists {
391 flow_name: String,
392 #[snafu(implicit)]
393 location: Location,
394 },
395
396 #[snafu(display("Schema already exists, catalog:{}, schema: {}", catalog, schema))]
397 SchemaAlreadyExists {
398 catalog: String,
399 schema: String,
400 #[snafu(implicit)]
401 location: Location,
402 },
403
404 #[snafu(display("Failed to convert raw key to str"))]
405 ConvertRawKey {
406 #[snafu(implicit)]
407 location: Location,
408 #[snafu(source)]
409 error: Utf8Error,
410 },
411
412 #[snafu(display("Table not found: '{}'", table_name))]
413 TableNotFound {
414 table_name: String,
415 #[snafu(implicit)]
416 location: Location,
417 },
418
419 #[snafu(display("Region not found: {}", region_id))]
420 RegionNotFound {
421 region_id: RegionId,
422 #[snafu(implicit)]
423 location: Location,
424 },
425
426 #[snafu(display("View not found: '{}'", view_name))]
427 ViewNotFound {
428 view_name: String,
429 #[snafu(implicit)]
430 location: Location,
431 },
432
433 #[snafu(display("Flow not found: '{}'", flow_name))]
434 FlowNotFound {
435 flow_name: String,
436 #[snafu(implicit)]
437 location: Location,
438 },
439
440 #[snafu(display("Flow route not found: '{}'", flow_name))]
441 FlowRouteNotFound {
442 flow_name: String,
443 #[snafu(implicit)]
444 location: Location,
445 },
446
447 #[snafu(display("Schema nod found, schema: {}", table_schema))]
448 SchemaNotFound {
449 table_schema: String,
450 #[snafu(implicit)]
451 location: Location,
452 },
453
454 #[snafu(display("Catalog not found, catalog: {}", catalog))]
455 CatalogNotFound {
456 catalog: String,
457 #[snafu(implicit)]
458 location: Location,
459 },
460
461 #[snafu(display("Invalid metadata, err: {}", err_msg))]
462 InvalidMetadata {
463 err_msg: String,
464 #[snafu(implicit)]
465 location: Location,
466 },
467
468 #[snafu(display("Invalid view info, err: {}", err_msg))]
469 InvalidViewInfo {
470 err_msg: String,
471 #[snafu(implicit)]
472 location: Location,
473 },
474
475 #[snafu(display("Invalid flow request body: {:?}", body))]
476 InvalidFlowRequestBody {
477 body: Box<Option<api::v1::flow::flow_request::Body>>,
478 #[snafu(implicit)]
479 location: Location,
480 },
481
482 #[snafu(display("Failed to get kv cache, err: {}", err_msg))]
483 GetKvCache { err_msg: String },
484
485 #[snafu(display("Get null from cache, key: {}", key))]
486 CacheNotGet {
487 key: String,
488 #[snafu(implicit)]
489 location: Location,
490 },
491
492 #[snafu(display("Etcd txn error: {err_msg}"))]
493 EtcdTxnOpResponse {
494 err_msg: String,
495 #[snafu(implicit)]
496 location: Location,
497 },
498
499 #[snafu(display("External error"))]
500 External {
501 #[snafu(implicit)]
502 location: Location,
503 source: BoxedError,
504 },
505
506 #[snafu(display("The response exceeded size limit"))]
507 ResponseExceededSizeLimit {
508 #[snafu(implicit)]
509 location: Location,
510 source: BoxedError,
511 },
512
513 #[snafu(display("Invalid heartbeat response"))]
514 InvalidHeartbeatResponse {
515 #[snafu(implicit)]
516 location: Location,
517 },
518
519 #[snafu(display("Failed to operate on datanode: {}", peer))]
520 OperateDatanode {
521 #[snafu(implicit)]
522 location: Location,
523 peer: Peer,
524 source: BoxedError,
525 },
526
527 #[snafu(display("Retry later"))]
528 RetryLater {
529 source: BoxedError,
530 clean_poisons: bool,
531 },
532
533 #[snafu(display("Abort procedure"))]
534 AbortProcedure {
535 #[snafu(implicit)]
536 location: Location,
537 source: BoxedError,
538 clean_poisons: bool,
539 },
540
541 #[snafu(display("Failed to serialize WAL options for region: {region_id}"))]
542 SerializeWalOptions {
543 region_id: RegionId,
544 #[snafu(source)]
545 error: serde_json::Error,
546 #[snafu(implicit)]
547 location: Location,
548 },
549
550 #[snafu(display("Invalid number of topics {}", num_topics))]
551 InvalidNumTopics {
552 num_topics: usize,
553 #[snafu(implicit)]
554 location: Location,
555 },
556
557 #[snafu(display(
558 "Failed to build a Kafka client, broker endpoints: {:?}",
559 broker_endpoints
560 ))]
561 BuildKafkaClient {
562 broker_endpoints: Vec<String>,
563 #[snafu(implicit)]
564 location: Location,
565 #[snafu(source)]
566 error: rskafka::client::error::Error,
567 },
568
569 #[snafu(display("Failed to create TLS Config"))]
570 TlsConfig {
571 #[snafu(implicit)]
572 location: Location,
573 source: common_wal::error::Error,
574 },
575
576 #[snafu(display("Failed to build a Kafka controller client"))]
577 BuildKafkaCtrlClient {
578 #[snafu(implicit)]
579 location: Location,
580 #[snafu(source)]
581 error: rskafka::client::error::Error,
582 },
583
584 #[snafu(display(
585 "Failed to get a Kafka partition client, topic: {}, partition: {}",
586 topic,
587 partition
588 ))]
589 KafkaPartitionClient {
590 topic: String,
591 partition: i32,
592 #[snafu(implicit)]
593 location: Location,
594 #[snafu(source)]
595 error: rskafka::client::error::Error,
596 },
597
598 #[snafu(display(
599 "Failed to get offset from Kafka, topic: {}, partition: {}",
600 topic,
601 partition
602 ))]
603 KafkaGetOffset {
604 topic: String,
605 partition: i32,
606 #[snafu(implicit)]
607 location: Location,
608 #[snafu(source)]
609 error: rskafka::client::error::Error,
610 },
611
612 #[snafu(display("Failed to produce records to Kafka, topic: {}", topic))]
613 ProduceRecord {
614 topic: String,
615 #[snafu(implicit)]
616 location: Location,
617 #[snafu(source)]
618 error: rskafka::client::error::Error,
619 },
620
621 #[snafu(display("Failed to create a Kafka wal topic"))]
622 CreateKafkaWalTopic {
623 #[snafu(implicit)]
624 location: Location,
625 #[snafu(source)]
626 error: rskafka::client::error::Error,
627 },
628
629 #[snafu(display("The topic pool is empty"))]
630 EmptyTopicPool {
631 #[snafu(implicit)]
632 location: Location,
633 },
634
635 #[snafu(display("Unexpected table route type: {}", err_msg))]
636 UnexpectedLogicalRouteTable {
637 #[snafu(implicit)]
638 location: Location,
639 err_msg: String,
640 },
641
642 #[snafu(display("The tasks of {} cannot be empty", name))]
643 EmptyDdlTasks {
644 name: String,
645 #[snafu(implicit)]
646 location: Location,
647 },
648
649 #[snafu(display("Metadata corruption: {}", err_msg))]
650 MetadataCorruption {
651 err_msg: String,
652 #[snafu(implicit)]
653 location: Location,
654 },
655
656 #[snafu(display("Alter logical tables invalid arguments: {}", err_msg))]
657 AlterLogicalTablesInvalidArguments {
658 err_msg: String,
659 #[snafu(implicit)]
660 location: Location,
661 },
662
663 #[snafu(display("Create logical tables invalid arguments: {}", err_msg))]
664 CreateLogicalTablesInvalidArguments {
665 err_msg: String,
666 #[snafu(implicit)]
667 location: Location,
668 },
669
670 #[snafu(display("Invalid node info key: {}", key))]
671 InvalidNodeInfoKey {
672 key: String,
673 #[snafu(implicit)]
674 location: Location,
675 },
676
677 #[snafu(display("Invalid node stat key: {}", key))]
678 InvalidStatKey {
679 key: String,
680 #[snafu(implicit)]
681 location: Location,
682 },
683
684 #[snafu(display("Failed to parse number: {}", err_msg))]
685 ParseNum {
686 err_msg: String,
687 #[snafu(source)]
688 error: std::num::ParseIntError,
689 #[snafu(implicit)]
690 location: Location,
691 },
692
693 #[snafu(display("Invalid role: {}", role))]
694 InvalidRole {
695 role: i32,
696 #[snafu(implicit)]
697 location: Location,
698 },
699
700 #[snafu(display("Invalid set database option, key: {}, value: {}", key, value))]
701 InvalidSetDatabaseOption {
702 key: String,
703 value: String,
704 #[snafu(implicit)]
705 location: Location,
706 },
707
708 #[snafu(display("Invalid unset database option, key: {}", key))]
709 InvalidUnsetDatabaseOption {
710 key: String,
711 #[snafu(implicit)]
712 location: Location,
713 },
714
715 #[snafu(display("Invalid prefix: {}, key: {}", prefix, key))]
716 MismatchPrefix {
717 prefix: String,
718 key: String,
719 #[snafu(implicit)]
720 location: Location,
721 },
722
723 #[snafu(display("Failed to move values: {err_msg}"))]
724 MoveValues {
725 err_msg: String,
726 #[snafu(implicit)]
727 location: Location,
728 },
729
730 #[snafu(display("Failed to parse {} from utf8", name))]
731 FromUtf8 {
732 name: String,
733 #[snafu(source)]
734 error: std::string::FromUtf8Error,
735 #[snafu(implicit)]
736 location: Location,
737 },
738
739 #[snafu(display("Value not exists"))]
740 ValueNotExist {
741 #[snafu(implicit)]
742 location: Location,
743 },
744
745 #[snafu(display("Failed to get cache"))]
746 GetCache { source: Arc<Error> },
747
748 #[snafu(display(
749 "Failed to get latest cache value after {} attempts due to concurrent invalidation",
750 attempts
751 ))]
752 GetLatestCacheRetryExceeded {
753 attempts: usize,
754 #[snafu(implicit)]
755 location: Location,
756 },
757
758 #[cfg(feature = "pg_kvbackend")]
759 #[snafu(display("Failed to execute via Postgres, sql: {}", sql))]
760 PostgresExecution {
761 sql: String,
762 #[snafu(source)]
763 error: tokio_postgres::Error,
764 #[snafu(implicit)]
765 location: Location,
766 },
767
768 #[cfg(feature = "pg_kvbackend")]
769 #[snafu(display("Failed to create connection pool for Postgres"))]
770 CreatePostgresPool {
771 #[snafu(source)]
772 error: deadpool_postgres::CreatePoolError,
773 #[snafu(implicit)]
774 location: Location,
775 },
776
777 #[cfg(feature = "pg_kvbackend")]
778 #[snafu(display("Failed to get Postgres connection from pool: {}", reason))]
779 GetPostgresConnection {
780 reason: String,
781 #[snafu(implicit)]
782 location: Location,
783 },
784
785 #[cfg(feature = "pg_kvbackend")]
786 #[snafu(display("Failed to get Postgres client"))]
787 GetPostgresClient {
788 #[snafu(source)]
789 error: deadpool::managed::PoolError<tokio_postgres::Error>,
790 #[snafu(implicit)]
791 location: Location,
792 },
793
794 #[cfg(feature = "pg_kvbackend")]
795 #[snafu(display("Failed to {} Postgres transaction", operation))]
796 PostgresTransaction {
797 #[snafu(source)]
798 error: tokio_postgres::Error,
799 #[snafu(implicit)]
800 location: Location,
801 operation: String,
802 },
803
804 #[cfg(feature = "pg_kvbackend")]
805 #[snafu(display("Failed to setup PostgreSQL TLS configuration: {}", reason))]
806 PostgresTlsConfig {
807 reason: String,
808 #[snafu(implicit)]
809 location: Location,
810 },
811
812 #[snafu(display("Failed to load TLS certificate from path: {}", path))]
813 LoadTlsCertificate {
814 path: String,
815 #[snafu(source)]
816 error: std::io::Error,
817 #[snafu(implicit)]
818 location: Location,
819 },
820
821 #[cfg(feature = "pg_kvbackend")]
822 #[snafu(display("Invalid TLS configuration: {}", reason))]
823 InvalidTlsConfig {
824 reason: String,
825 #[snafu(implicit)]
826 location: Location,
827 },
828
829 #[cfg(feature = "mysql_kvbackend")]
830 #[snafu(display("Failed to execute via MySql, sql: {}", sql))]
831 MySqlExecution {
832 sql: String,
833 #[snafu(source)]
834 error: sqlx::Error,
835 #[snafu(implicit)]
836 location: Location,
837 },
838
839 #[cfg(feature = "mysql_kvbackend")]
840 #[snafu(display("Failed to create connection pool for MySql"))]
841 CreateMySqlPool {
842 #[snafu(source)]
843 error: sqlx::Error,
844 #[snafu(implicit)]
845 location: Location,
846 },
847
848 #[cfg(feature = "mysql_kvbackend")]
849 #[snafu(display("Failed to decode sql value"))]
850 DecodeSqlValue {
851 #[snafu(source)]
852 error: sqlx::error::Error,
853 #[snafu(implicit)]
854 location: Location,
855 },
856
857 #[cfg(feature = "mysql_kvbackend")]
858 #[snafu(display("Failed to acquire mysql client from pool"))]
859 AcquireMySqlClient {
860 #[snafu(source)]
861 error: sqlx::Error,
862 #[snafu(implicit)]
863 location: Location,
864 },
865
866 #[cfg(feature = "mysql_kvbackend")]
867 #[snafu(display("Failed to {} MySql transaction", operation))]
868 MySqlTransaction {
869 #[snafu(source)]
870 error: sqlx::Error,
871 #[snafu(implicit)]
872 location: Location,
873 operation: String,
874 },
875
876 #[cfg(any(feature = "pg_kvbackend", feature = "mysql_kvbackend"))]
877 #[snafu(display("Rds transaction retry failed"))]
878 RdsTransactionRetryFailed {
879 #[snafu(implicit)]
880 location: Location,
881 },
882
883 #[cfg(any(feature = "pg_kvbackend", feature = "mysql_kvbackend"))]
884 #[snafu(display("Sql execution timeout, sql: {}, duration: {:?}", sql, duration))]
885 SqlExecutionTimeout {
886 sql: String,
887 duration: std::time::Duration,
888 #[snafu(implicit)]
889 location: Location,
890 },
891
892 #[snafu(display(
893 "Datanode table info not found, table id: {}, datanode id: {}",
894 table_id,
895 datanode_id
896 ))]
897 DatanodeTableInfoNotFound {
898 datanode_id: DatanodeId,
899 table_id: TableId,
900 #[snafu(implicit)]
901 location: Location,
902 },
903
904 #[snafu(display("Invalid topic name prefix: {}", prefix))]
905 InvalidTopicNamePrefix {
906 prefix: String,
907 #[snafu(implicit)]
908 location: Location,
909 },
910
911 #[snafu(display("No leader found for table_id: {}", table_id))]
912 NoLeader {
913 table_id: TableId,
914 #[snafu(implicit)]
915 location: Location,
916 },
917
918 #[snafu(display(
919 "Procedure poison key already exists with a different value, key: {}, value: {}",
920 key,
921 value
922 ))]
923 ProcedurePoisonConflict {
924 key: String,
925 value: String,
926 #[snafu(implicit)]
927 location: Location,
928 },
929
930 #[snafu(display("Failed to put poison, table metadata may be corrupted"))]
931 PutPoison {
932 #[snafu(implicit)]
933 location: Location,
934 #[snafu(source)]
935 source: common_procedure::error::Error,
936 },
937
938 #[snafu(display("Invalid file path: {}", file_path))]
939 InvalidFilePath {
940 #[snafu(implicit)]
941 location: Location,
942 file_path: String,
943 },
944
945 #[snafu(display("Failed to serialize flexbuffers"))]
946 SerializeFlexbuffers {
947 #[snafu(implicit)]
948 location: Location,
949 #[snafu(source)]
950 error: flexbuffers::SerializationError,
951 },
952
953 #[snafu(display("Failed to deserialize flexbuffers"))]
954 DeserializeFlexbuffers {
955 #[snafu(implicit)]
956 location: Location,
957 #[snafu(source)]
958 error: flexbuffers::DeserializationError,
959 },
960
961 #[snafu(display("Failed to read flexbuffers"))]
962 ReadFlexbuffers {
963 #[snafu(implicit)]
964 location: Location,
965 #[snafu(source)]
966 error: flexbuffers::ReaderError,
967 },
968
969 #[snafu(display("Invalid file name: {}", reason))]
970 InvalidFileName {
971 #[snafu(implicit)]
972 location: Location,
973 reason: String,
974 },
975
976 #[snafu(display("Invalid file extension: {}", reason))]
977 InvalidFileExtension {
978 #[snafu(implicit)]
979 location: Location,
980 reason: String,
981 },
982
983 #[snafu(display("Failed to write object, file path: {}", file_path))]
984 WriteObject {
985 #[snafu(implicit)]
986 location: Location,
987 file_path: String,
988 #[snafu(source)]
989 error: object_store::Error,
990 },
991
992 #[snafu(display("Failed to read object, file path: {}", file_path))]
993 ReadObject {
994 #[snafu(implicit)]
995 location: Location,
996 file_path: String,
997 #[snafu(source)]
998 error: object_store::Error,
999 },
1000
1001 #[snafu(display("Missing column ids"))]
1002 MissingColumnIds {
1003 #[snafu(implicit)]
1004 location: Location,
1005 },
1006
1007 #[snafu(display(
1008 "Missing column in column metadata: {}, table: {}, table_id: {}",
1009 column_name,
1010 table_name,
1011 table_id,
1012 ))]
1013 MissingColumnInColumnMetadata {
1014 column_name: String,
1015 #[snafu(implicit)]
1016 location: Location,
1017 table_name: String,
1018 table_id: TableId,
1019 },
1020
1021 #[snafu(display(
1022 "Mismatch column id: column_name: {}, column_id: {}, table: {}, table_id: {}",
1023 column_name,
1024 column_id,
1025 table_name,
1026 table_id,
1027 ))]
1028 MismatchColumnId {
1029 column_name: String,
1030 column_id: u32,
1031 #[snafu(implicit)]
1032 location: Location,
1033 table_name: String,
1034 table_id: TableId,
1035 },
1036
1037 #[snafu(display("Failed to convert column def, column: {}", column))]
1038 ConvertColumnDef {
1039 column: String,
1040 #[snafu(implicit)]
1041 location: Location,
1042 source: api::error::Error,
1043 },
1044
1045 #[snafu(display("Failed to convert time ranges"))]
1046 ConvertTimeRanges {
1047 #[snafu(implicit)]
1048 location: Location,
1049 source: api::error::Error,
1050 },
1051
1052 #[snafu(display(
1053 "Column metadata inconsistencies found in table: {}, table_id: {}",
1054 table_name,
1055 table_id
1056 ))]
1057 ColumnMetadataConflicts {
1058 table_name: String,
1059 table_id: TableId,
1060 },
1061
1062 #[snafu(display(
1063 "Column not found in column metadata, column_name: {}, column_id: {}",
1064 column_name,
1065 column_id
1066 ))]
1067 ColumnNotFound { column_name: String, column_id: u32 },
1068
1069 #[snafu(display(
1070 "Column id mismatch, column_name: {}, expected column_id: {}, actual column_id: {}",
1071 column_name,
1072 expected_column_id,
1073 actual_column_id
1074 ))]
1075 ColumnIdMismatch {
1076 column_name: String,
1077 expected_column_id: u32,
1078 actual_column_id: u32,
1079 },
1080
1081 #[snafu(display(
1082 "Timestamp column mismatch, expected column_name: {}, expected column_id: {}, actual column_name: {}, actual column_id: {}",
1083 expected_column_name,
1084 expected_column_id,
1085 actual_column_name,
1086 actual_column_id,
1087 ))]
1088 TimestampMismatch {
1089 expected_column_name: String,
1090 expected_column_id: u32,
1091 actual_column_name: String,
1092 actual_column_id: u32,
1093 },
1094
1095 #[cfg(feature = "enterprise")]
1096 #[snafu(display("Too large duration"))]
1097 TooLargeDuration {
1098 #[snafu(source)]
1099 error: prost_types::DurationError,
1100 #[snafu(implicit)]
1101 location: Location,
1102 },
1103
1104 #[cfg(feature = "enterprise")]
1105 #[snafu(display("Negative duration"))]
1106 NegativeDuration {
1107 #[snafu(source)]
1108 error: prost_types::DurationError,
1109 #[snafu(implicit)]
1110 location: Location,
1111 },
1112
1113 #[cfg(feature = "enterprise")]
1114 #[snafu(display("Missing interval field"))]
1115 MissingInterval {
1116 #[snafu(implicit)]
1117 location: Location,
1118 },
1119}
1120
1121pub type Result<T> = std::result::Result<T, Error>;
1122
1123impl ErrorExt for Error {
1124 fn status_code(&self) -> StatusCode {
1125 use Error::*;
1126 match self {
1127 IllegalServerState { .. }
1128 | EtcdTxnOpResponse { .. }
1129 | EtcdFailed { .. }
1130 | EtcdTxnFailed { .. }
1131 | ConnectEtcd { .. }
1132 | MoveValues { .. }
1133 | GetCache { .. }
1134 | GetLatestCacheRetryExceeded { .. }
1135 | SerializeToJson { .. }
1136 | DeserializeFromJson { .. }
1137 | ElectionNoLeader { .. }
1138 | ElectionLeaderLeaseExpired { .. }
1139 | ElectionLeaderLeaseChanged { .. } => StatusCode::Internal,
1140
1141 NoLeader { .. } => StatusCode::TableUnavailable,
1142 ValueNotExist { .. }
1143 | ProcedurePoisonConflict { .. }
1144 | ProcedureStateReceiverNotFound { .. }
1145 | MissingColumnIds { .. }
1146 | MissingColumnInColumnMetadata { .. }
1147 | MismatchColumnId { .. }
1148 | ColumnMetadataConflicts { .. }
1149 | ColumnNotFound { .. }
1150 | ColumnIdMismatch { .. }
1151 | TimestampMismatch { .. } => StatusCode::Unexpected,
1152
1153 Unsupported { .. } | ReadOnlyKvBackend { .. } => StatusCode::Unsupported,
1154 WriteObject { .. } | ReadObject { .. } => StatusCode::StorageUnavailable,
1155
1156 SerdeJson { .. }
1157 | ParseOption { .. }
1158 | RouteInfoCorrupted { .. }
1159 | InvalidProtoMsg { .. }
1160 | InvalidMetadata { .. }
1161 | Unexpected { .. }
1162 | TableInfoNotFound { .. }
1163 | NextSequence { .. }
1164 | UnexpectedSequenceValue { .. }
1165 | InvalidHeartbeatResponse { .. }
1166 | EncodeJson { .. }
1167 | DecodeJson { .. }
1168 | PayloadNotExist { .. }
1169 | ConvertRawKey { .. }
1170 | DecodeProto { .. }
1171 | BuildTableMeta { .. }
1172 | TableRouteNotFound { .. }
1173 | TableRepartNotFound { .. }
1174 | RegionOperatingRace { .. }
1175 | SerializeWalOptions { .. }
1176 | BuildKafkaClient { .. }
1177 | BuildKafkaCtrlClient { .. }
1178 | KafkaPartitionClient { .. }
1179 | ProduceRecord { .. }
1180 | CreateKafkaWalTopic { .. }
1181 | EmptyTopicPool { .. }
1182 | UnexpectedLogicalRouteTable { .. }
1183 | ProcedureOutput { .. }
1184 | FromUtf8 { .. }
1185 | MetadataCorruption { .. }
1186 | KafkaGetOffset { .. }
1187 | ReadFlexbuffers { .. }
1188 | SerializeFlexbuffers { .. }
1189 | DeserializeFlexbuffers { .. }
1190 | ConvertTimeRanges { .. } => StatusCode::Unexpected,
1191
1192 GetKvCache { .. } | CacheNotGet { .. } => StatusCode::Internal,
1193
1194 SchemaAlreadyExists { .. } => StatusCode::DatabaseAlreadyExists,
1195
1196 ProcedureNotFound { .. }
1197 | InvalidViewInfo { .. }
1198 | PrimaryKeyNotFound { .. }
1199 | EmptyKey { .. }
1200 | AlterLogicalTablesInvalidArguments { .. }
1201 | CreateLogicalTablesInvalidArguments { .. }
1202 | MismatchPrefix { .. }
1203 | TlsConfig { .. }
1204 | InvalidSetDatabaseOption { .. }
1205 | InvalidUnsetDatabaseOption { .. }
1206 | InvalidTopicNamePrefix { .. }
1207 | InvalidFileExtension { .. }
1208 | InvalidFileName { .. }
1209 | InvalidFlowRequestBody { .. }
1210 | InvalidFilePath { .. } => StatusCode::InvalidArguments,
1211
1212 #[cfg(feature = "enterprise")]
1213 MissingInterval { .. } | NegativeDuration { .. } | TooLargeDuration { .. } => {
1214 StatusCode::InvalidArguments
1215 }
1216
1217 FlowNotFound { .. } => StatusCode::FlowNotFound,
1218 FlowRouteNotFound { .. } => StatusCode::Unexpected,
1219 FlowAlreadyExists { .. } => StatusCode::FlowAlreadyExists,
1220
1221 ViewNotFound { .. } | TableNotFound { .. } | RegionNotFound { .. } => {
1222 StatusCode::TableNotFound
1223 }
1224 ViewAlreadyExists { .. } | TableAlreadyExists { .. } => StatusCode::TableAlreadyExists,
1225
1226 SubmitProcedure { source, .. }
1227 | QueryProcedure { source, .. }
1228 | WaitProcedure { source, .. }
1229 | StartProcedureManager { source, .. }
1230 | StopProcedureManager { source, .. } => source.status_code(),
1231 RegisterProcedureLoader { source, .. } => source.status_code(),
1232 External { source, .. } => source.status_code(),
1233 ResponseExceededSizeLimit { source, .. } => source.status_code(),
1234 OperateDatanode { source, .. } => source.status_code(),
1235 Table { source, .. } => source.status_code(),
1236 RetryLater { source, .. } => source.status_code(),
1237 AbortProcedure { source, .. } => source.status_code(),
1238 ConvertAlterTableRequest { source, .. } => source.status_code(),
1239 PutPoison { source, .. } => source.status_code(),
1240 ConvertColumnDef { source, .. } => source.status_code(),
1241 ProcedureStateReceiver { source, .. } => source.status_code(),
1242 RegisterRepartitionProcedureLoader { source, .. } => source.status_code(),
1243 CreateRepartitionProcedure { source, .. } => source.status_code(),
1244
1245 ParseProcedureId { .. }
1246 | InvalidNumTopics { .. }
1247 | SchemaNotFound { .. }
1248 | CatalogNotFound { .. }
1249 | InvalidNodeInfoKey { .. }
1250 | InvalidStatKey { .. }
1251 | ParseNum { .. }
1252 | InvalidRole { .. }
1253 | EmptyDdlTasks { .. } => StatusCode::InvalidArguments,
1254
1255 LoadTlsCertificate { .. } => StatusCode::Internal,
1256
1257 #[cfg(feature = "pg_kvbackend")]
1258 PostgresExecution { .. }
1259 | CreatePostgresPool { .. }
1260 | GetPostgresConnection { .. }
1261 | GetPostgresClient { .. }
1262 | PostgresTransaction { .. }
1263 | PostgresTlsConfig { .. }
1264 | InvalidTlsConfig { .. } => StatusCode::Internal,
1265 #[cfg(feature = "mysql_kvbackend")]
1266 MySqlExecution { .. }
1267 | CreateMySqlPool { .. }
1268 | DecodeSqlValue { .. }
1269 | AcquireMySqlClient { .. }
1270 | MySqlTransaction { .. } => StatusCode::Internal,
1271 #[cfg(any(feature = "pg_kvbackend", feature = "mysql_kvbackend"))]
1272 RdsTransactionRetryFailed { .. } | SqlExecutionTimeout { .. } => StatusCode::Internal,
1273 DatanodeTableInfoNotFound { .. } => StatusCode::Internal,
1274 }
1275 }
1276
1277 fn as_any(&self) -> &dyn std::any::Any {
1278 self
1279 }
1280
1281 fn retry_hint(&self) -> RetryHint {
1282 use Error::*;
1283
1284 match self {
1285 RetryLater { .. }
1286 | GetLatestCacheRetryExceeded { .. }
1287 | NoLeader { .. }
1288 | ElectionNoLeader { .. }
1289 | ElectionLeaderLeaseExpired { .. }
1290 | ElectionLeaderLeaseChanged { .. } => RetryHint::Retryable,
1291 ConnectEtcd { error, .. } | EtcdFailed { error, .. } | EtcdTxnFailed { error, .. } => {
1292 retry_hint_from_etcd_error(error)
1293 }
1294 WriteObject { error, .. } | ReadObject { error, .. } => {
1295 retry_hint_from_opendal_error(error)
1296 }
1297 BuildKafkaClient { error, .. }
1298 | BuildKafkaCtrlClient { error, .. }
1299 | KafkaPartitionClient { error, .. }
1300 | KafkaGetOffset { error, .. }
1301 | ProduceRecord { error, .. }
1302 | CreateKafkaWalTopic { error, .. } => rskafka_client_error_to_retry_hint(error),
1303 SubmitProcedure { source, .. }
1304 | QueryProcedure { source, .. }
1305 | WaitProcedure { source, .. }
1306 | StartProcedureManager { source, .. }
1307 | StopProcedureManager { source, .. }
1308 | RegisterProcedureLoader { source, .. }
1309 | PutPoison { source, .. }
1310 | ProcedureStateReceiver { source, .. } => source.retry_hint(),
1311 External { source, .. }
1312 | ResponseExceededSizeLimit { source, .. }
1313 | OperateDatanode { source, .. }
1314 | AbortProcedure { source, .. }
1315 | RegisterRepartitionProcedureLoader { source, .. }
1316 | CreateRepartitionProcedure { source, .. } => source.retry_hint(),
1317 Table { source, .. } => source.retry_hint(),
1318 ConvertAlterTableRequest { source, .. } => source.retry_hint(),
1319 ConvertColumnDef { source, .. } => source.retry_hint(),
1320 GetCache { source, .. } => source.retry_hint(),
1321 #[cfg(feature = "pg_kvbackend")]
1322 PostgresExecution { error, .. } | PostgresTransaction { error, .. } => {
1323 retry_hint_from_postgres_error(error)
1324 }
1325 #[cfg(feature = "pg_kvbackend")]
1326 GetPostgresClient { error, .. } => retry_hint_from_postgres_pool_error(error),
1327 #[cfg(feature = "mysql_kvbackend")]
1328 MySqlExecution { error, .. }
1329 | CreateMySqlPool { error, .. }
1330 | AcquireMySqlClient { error, .. }
1331 | MySqlTransaction { error, .. } => retry_hint_from_sqlx_error(error),
1332 #[cfg(any(feature = "pg_kvbackend", feature = "mysql_kvbackend"))]
1333 SqlExecutionTimeout { .. } => RetryHint::Retryable,
1334 _ => RetryHint::NonRetryable,
1335 }
1336 }
1337}
1338
1339impl Error {
1340 #[cfg(any(feature = "pg_kvbackend", feature = "mysql_kvbackend"))]
1341 pub fn is_serialization_error(&self) -> bool {
1343 match self {
1344 #[cfg(feature = "pg_kvbackend")]
1345 Error::PostgresExecution { error, .. } | Error::PostgresTransaction { error, .. } => {
1346 retry_hint::is_postgres_serialization_error(error)
1347 }
1348 #[cfg(feature = "mysql_kvbackend")]
1349 Error::MySqlExecution { error, .. } | Error::MySqlTransaction { error, .. } => {
1350 retry_hint::is_mysql_serialization_error(error)
1351 }
1352 _ => false,
1353 }
1354 }
1355
1356 pub fn retry_later<E: ErrorExt + Send + Sync + 'static>(err: E) -> Error {
1358 Error::RetryLater {
1359 source: BoxedError::new(err),
1360 clean_poisons: false,
1361 }
1362 }
1363
1364 pub fn is_retry_later(&self) -> bool {
1366 matches!(
1367 self,
1368 Error::RetryLater { .. } | Error::GetLatestCacheRetryExceeded { .. }
1369 )
1370 }
1371
1372 pub fn need_clean_poisons(&self) -> bool {
1374 matches!(
1375 self,
1376 Error::AbortProcedure { clean_poisons, .. } if *clean_poisons
1377 ) || matches!(
1378 self,
1379 Error::RetryLater { clean_poisons, .. } if *clean_poisons
1380 )
1381 }
1382
1383 pub fn is_exceeded_size_limit(&self) -> bool {
1385 match self {
1386 Error::EtcdFailed {
1387 error: etcd_client::Error::GRpcStatus(status),
1388 ..
1389 } => status.code() == tonic::Code::OutOfRange,
1390 Error::ResponseExceededSizeLimit { .. } => true,
1391 _ => false,
1392 }
1393 }
1394}
1395
1396#[cfg(test)]
1397mod retry_hint_tests {
1398 use std::sync::Arc;
1399
1400 use common_error::mock::MockError;
1401
1402 use super::*;
1403
1404 #[test]
1405 fn test_retry_later_hint_is_retryable() {
1406 let err = Error::retry_later(MockError::new(StatusCode::Internal));
1407
1408 assert_eq!(err.retry_hint(), RetryHint::Retryable);
1409 }
1410
1411 #[test]
1412 fn test_latest_cache_retry_exceeded_hint_is_retryable() {
1413 let err = GetLatestCacheRetryExceededSnafu { attempts: 3_usize }.build();
1414
1415 assert_eq!(err.retry_hint(), RetryHint::Retryable);
1416 }
1417
1418 #[test]
1419 fn test_get_cache_forwards_retry_hint() {
1420 let source = Arc::new(Error::retry_later(MockError::new(StatusCode::Internal)));
1421 let err = Error::GetCache { source };
1422
1423 assert_eq!(err.retry_hint(), RetryHint::Retryable);
1424 }
1425
1426 #[cfg(any(feature = "pg_kvbackend", feature = "mysql_kvbackend"))]
1427 #[test]
1428 fn test_sql_execution_timeout_hint_is_retryable() {
1429 let err = SqlExecutionTimeoutSnafu {
1430 sql: "SELECT 1".to_string(),
1431 duration: std::time::Duration::from_secs(1),
1432 }
1433 .build();
1434
1435 assert_eq!(err.retry_hint(), RetryHint::Retryable);
1436 }
1437
1438 #[test]
1439 fn test_default_hint_is_non_retryable() {
1440 let err = UnexpectedSnafu {
1441 err_msg: "mock error",
1442 }
1443 .build();
1444
1445 assert_eq!(err.retry_hint(), RetryHint::NonRetryable);
1446 }
1447}