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(
383 "Cannot drop table '{}': tombstoned table id {} already uses the same full name",
384 table_name,
385 existing_table_id
386 ))]
387 TableNameTombstoneConflict {
389 table_name: String,
390 existing_table_id: TableId,
391 dropping_table_id: TableId,
392 #[snafu(implicit)]
393 location: Location,
394 },
395
396 #[snafu(display("View already exists, view: {}", view_name))]
397 ViewAlreadyExists {
398 view_name: String,
399 #[snafu(implicit)]
400 location: Location,
401 },
402
403 #[snafu(display("Flow already exists: {}", flow_name))]
404 FlowAlreadyExists {
405 flow_name: String,
406 #[snafu(implicit)]
407 location: Location,
408 },
409
410 #[snafu(display("Schema already exists, catalog:{}, schema: {}", catalog, schema))]
411 SchemaAlreadyExists {
412 catalog: String,
413 schema: String,
414 #[snafu(implicit)]
415 location: Location,
416 },
417
418 #[snafu(display("Failed to convert raw key to str"))]
419 ConvertRawKey {
420 #[snafu(implicit)]
421 location: Location,
422 #[snafu(source)]
423 error: Utf8Error,
424 },
425
426 #[snafu(display("Table not found: '{}'", table_name))]
427 TableNotFound {
428 table_name: String,
429 #[snafu(implicit)]
430 location: Location,
431 },
432
433 #[snafu(display("Region not found: {}", region_id))]
434 RegionNotFound {
435 region_id: RegionId,
436 #[snafu(implicit)]
437 location: Location,
438 },
439
440 #[snafu(display("View not found: '{}'", view_name))]
441 ViewNotFound {
442 view_name: String,
443 #[snafu(implicit)]
444 location: Location,
445 },
446
447 #[snafu(display("Flow not found: '{}'", flow_name))]
448 FlowNotFound {
449 flow_name: String,
450 #[snafu(implicit)]
451 location: Location,
452 },
453
454 #[snafu(display("Flow route not found: '{}'", flow_name))]
455 FlowRouteNotFound {
456 flow_name: String,
457 #[snafu(implicit)]
458 location: Location,
459 },
460
461 #[snafu(display("Schema nod found, schema: {}", table_schema))]
462 SchemaNotFound {
463 table_schema: String,
464 #[snafu(implicit)]
465 location: Location,
466 },
467
468 #[snafu(display("Catalog not found, catalog: {}", catalog))]
469 CatalogNotFound {
470 catalog: String,
471 #[snafu(implicit)]
472 location: Location,
473 },
474
475 #[snafu(display("Invalid metadata, err: {}", err_msg))]
476 InvalidMetadata {
477 err_msg: String,
478 #[snafu(implicit)]
479 location: Location,
480 },
481
482 #[snafu(display("Invalid view info, err: {}", err_msg))]
483 InvalidViewInfo {
484 err_msg: String,
485 #[snafu(implicit)]
486 location: Location,
487 },
488
489 #[snafu(display("Invalid flow request body: {:?}", body))]
490 InvalidFlowRequestBody {
491 body: Box<Option<api::v1::flow::flow_request::Body>>,
492 #[snafu(implicit)]
493 location: Location,
494 },
495
496 #[snafu(display("Failed to get kv cache, err: {}", err_msg))]
497 GetKvCache { err_msg: String },
498
499 #[snafu(display("Get null from cache, key: {}", key))]
500 CacheNotGet {
501 key: String,
502 #[snafu(implicit)]
503 location: Location,
504 },
505
506 #[snafu(display("Etcd txn error: {err_msg}"))]
507 EtcdTxnOpResponse {
508 err_msg: String,
509 #[snafu(implicit)]
510 location: Location,
511 },
512
513 #[snafu(display("External error"))]
514 External {
515 #[snafu(implicit)]
516 location: Location,
517 source: BoxedError,
518 },
519
520 #[snafu(display("The response exceeded size limit"))]
521 ResponseExceededSizeLimit {
522 #[snafu(implicit)]
523 location: Location,
524 source: BoxedError,
525 },
526
527 #[snafu(display("Invalid heartbeat response"))]
528 InvalidHeartbeatResponse {
529 #[snafu(implicit)]
530 location: Location,
531 },
532
533 #[snafu(display("Failed to operate on datanode: {}", peer))]
534 OperateDatanode {
535 #[snafu(implicit)]
536 location: Location,
537 peer: Peer,
538 source: BoxedError,
539 },
540
541 #[snafu(display("Retry later"))]
542 RetryLater {
543 source: BoxedError,
544 clean_poisons: bool,
545 },
546
547 #[snafu(display("Abort procedure"))]
548 AbortProcedure {
549 #[snafu(implicit)]
550 location: Location,
551 source: BoxedError,
552 clean_poisons: bool,
553 },
554
555 #[snafu(display("Failed to serialize WAL options for region: {region_id}"))]
556 SerializeWalOptions {
557 region_id: RegionId,
558 #[snafu(source)]
559 error: serde_json::Error,
560 #[snafu(implicit)]
561 location: Location,
562 },
563
564 #[snafu(display("Invalid number of topics {}", num_topics))]
565 InvalidNumTopics {
566 num_topics: usize,
567 #[snafu(implicit)]
568 location: Location,
569 },
570
571 #[snafu(display(
572 "Failed to build a Kafka client, broker endpoints: {:?}",
573 broker_endpoints
574 ))]
575 BuildKafkaClient {
576 broker_endpoints: Vec<String>,
577 #[snafu(implicit)]
578 location: Location,
579 #[snafu(source)]
580 error: rskafka::client::error::Error,
581 },
582
583 #[snafu(display("Failed to create TLS Config"))]
584 TlsConfig {
585 #[snafu(implicit)]
586 location: Location,
587 source: common_wal::error::Error,
588 },
589
590 #[snafu(display("Failed to build a Kafka controller client"))]
591 BuildKafkaCtrlClient {
592 #[snafu(implicit)]
593 location: Location,
594 #[snafu(source)]
595 error: rskafka::client::error::Error,
596 },
597
598 #[snafu(display(
599 "Failed to get a Kafka partition client, topic: {}, partition: {}",
600 topic,
601 partition
602 ))]
603 KafkaPartitionClient {
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(
613 "Failed to get offset from Kafka, topic: {}, partition: {}",
614 topic,
615 partition
616 ))]
617 KafkaGetOffset {
618 topic: String,
619 partition: i32,
620 #[snafu(implicit)]
621 location: Location,
622 #[snafu(source)]
623 error: rskafka::client::error::Error,
624 },
625
626 #[snafu(display("Failed to produce records to Kafka, topic: {}", topic))]
627 ProduceRecord {
628 topic: String,
629 #[snafu(implicit)]
630 location: Location,
631 #[snafu(source)]
632 error: rskafka::client::error::Error,
633 },
634
635 #[snafu(display("Failed to create a Kafka wal topic"))]
636 CreateKafkaWalTopic {
637 #[snafu(implicit)]
638 location: Location,
639 #[snafu(source)]
640 error: rskafka::client::error::Error,
641 },
642
643 #[snafu(display("The topic pool is empty"))]
644 EmptyTopicPool {
645 #[snafu(implicit)]
646 location: Location,
647 },
648
649 #[snafu(display("Unexpected table route type: {}", err_msg))]
650 UnexpectedLogicalRouteTable {
651 #[snafu(implicit)]
652 location: Location,
653 err_msg: String,
654 },
655
656 #[snafu(display("The tasks of {} cannot be empty", name))]
657 EmptyDdlTasks {
658 name: String,
659 #[snafu(implicit)]
660 location: Location,
661 },
662
663 #[snafu(display("Metadata corruption: {}", err_msg))]
664 MetadataCorruption {
665 err_msg: String,
666 #[snafu(implicit)]
667 location: Location,
668 },
669
670 #[snafu(display("Alter logical tables invalid arguments: {}", err_msg))]
671 AlterLogicalTablesInvalidArguments {
672 err_msg: String,
673 #[snafu(implicit)]
674 location: Location,
675 },
676
677 #[snafu(display("Create logical tables invalid arguments: {}", err_msg))]
678 CreateLogicalTablesInvalidArguments {
679 err_msg: String,
680 #[snafu(implicit)]
681 location: Location,
682 },
683
684 #[snafu(display("Invalid node info key: {}", key))]
685 InvalidNodeInfoKey {
686 key: String,
687 #[snafu(implicit)]
688 location: Location,
689 },
690
691 #[snafu(display("Invalid node stat key: {}", key))]
692 InvalidStatKey {
693 key: String,
694 #[snafu(implicit)]
695 location: Location,
696 },
697
698 #[snafu(display("Failed to parse number: {}", err_msg))]
699 ParseNum {
700 err_msg: String,
701 #[snafu(source)]
702 error: std::num::ParseIntError,
703 #[snafu(implicit)]
704 location: Location,
705 },
706
707 #[snafu(display("Invalid role: {}", role))]
708 InvalidRole {
709 role: i32,
710 #[snafu(implicit)]
711 location: Location,
712 },
713
714 #[snafu(display("Invalid set database option, key: {}, value: {}", key, value))]
715 InvalidSetDatabaseOption {
716 key: String,
717 value: String,
718 #[snafu(implicit)]
719 location: Location,
720 },
721
722 #[snafu(display("Invalid unset database option, key: {}", key))]
723 InvalidUnsetDatabaseOption {
724 key: String,
725 #[snafu(implicit)]
726 location: Location,
727 },
728
729 #[snafu(display("Invalid prefix: {}, key: {}", prefix, key))]
730 MismatchPrefix {
731 prefix: String,
732 key: String,
733 #[snafu(implicit)]
734 location: Location,
735 },
736
737 #[snafu(display("Failed to move values: {err_msg}"))]
738 MoveValues {
739 err_msg: String,
740 #[snafu(implicit)]
741 location: Location,
742 },
743
744 #[snafu(display("Failed to restore tombstone, target key already exists: {key}"))]
745 TombstoneTargetAlreadyExists {
746 key: String,
747 #[snafu(implicit)]
748 location: Location,
749 },
750
751 #[snafu(display("Failed to parse {} from utf8", name))]
752 FromUtf8 {
753 name: String,
754 #[snafu(source)]
755 error: std::string::FromUtf8Error,
756 #[snafu(implicit)]
757 location: Location,
758 },
759
760 #[snafu(display("Value not exists"))]
761 ValueNotExist {
762 #[snafu(implicit)]
763 location: Location,
764 },
765
766 #[snafu(display("Failed to get cache"))]
767 GetCache { source: Arc<Error> },
768
769 #[snafu(display(
770 "Failed to get latest cache value after {} attempts due to concurrent invalidation",
771 attempts
772 ))]
773 GetLatestCacheRetryExceeded {
774 attempts: usize,
775 #[snafu(implicit)]
776 location: Location,
777 },
778
779 #[cfg(feature = "pg_kvbackend")]
780 #[snafu(display("Failed to execute via Postgres, sql: {}", sql))]
781 PostgresExecution {
782 sql: String,
783 #[snafu(source)]
784 error: tokio_postgres::Error,
785 #[snafu(implicit)]
786 location: Location,
787 },
788
789 #[cfg(feature = "pg_kvbackend")]
790 #[snafu(display("Failed to create connection pool for Postgres"))]
791 CreatePostgresPool {
792 #[snafu(source)]
793 error: deadpool_postgres::CreatePoolError,
794 #[snafu(implicit)]
795 location: Location,
796 },
797
798 #[cfg(feature = "pg_kvbackend")]
799 #[snafu(display("Failed to get Postgres connection from pool: {}", reason))]
800 GetPostgresConnection {
801 reason: String,
802 #[snafu(implicit)]
803 location: Location,
804 },
805
806 #[cfg(feature = "pg_kvbackend")]
807 #[snafu(display("Failed to get Postgres client"))]
808 GetPostgresClient {
809 #[snafu(source)]
810 error: deadpool::managed::PoolError<tokio_postgres::Error>,
811 #[snafu(implicit)]
812 location: Location,
813 },
814
815 #[cfg(feature = "pg_kvbackend")]
816 #[snafu(display("Failed to {} Postgres transaction", operation))]
817 PostgresTransaction {
818 #[snafu(source)]
819 error: tokio_postgres::Error,
820 #[snafu(implicit)]
821 location: Location,
822 operation: String,
823 },
824
825 #[cfg(feature = "pg_kvbackend")]
826 #[snafu(display("Failed to setup PostgreSQL TLS configuration: {}", reason))]
827 PostgresTlsConfig {
828 reason: String,
829 #[snafu(implicit)]
830 location: Location,
831 },
832
833 #[snafu(display("Failed to load TLS certificate from path: {}", path))]
834 LoadTlsCertificate {
835 path: String,
836 #[snafu(source)]
837 error: std::io::Error,
838 #[snafu(implicit)]
839 location: Location,
840 },
841
842 #[cfg(feature = "pg_kvbackend")]
843 #[snafu(display("Invalid TLS configuration: {}", reason))]
844 InvalidTlsConfig {
845 reason: String,
846 #[snafu(implicit)]
847 location: Location,
848 },
849
850 #[cfg(feature = "mysql_kvbackend")]
851 #[snafu(display("Failed to execute via MySql, sql: {}", sql))]
852 MySqlExecution {
853 sql: String,
854 #[snafu(source)]
855 error: sqlx::Error,
856 #[snafu(implicit)]
857 location: Location,
858 },
859
860 #[cfg(feature = "mysql_kvbackend")]
861 #[snafu(display("Failed to create connection pool for MySql"))]
862 CreateMySqlPool {
863 #[snafu(source)]
864 error: sqlx::Error,
865 #[snafu(implicit)]
866 location: Location,
867 },
868
869 #[cfg(feature = "mysql_kvbackend")]
870 #[snafu(display("Failed to decode sql value"))]
871 DecodeSqlValue {
872 #[snafu(source)]
873 error: sqlx::error::Error,
874 #[snafu(implicit)]
875 location: Location,
876 },
877
878 #[cfg(feature = "mysql_kvbackend")]
879 #[snafu(display("Failed to acquire mysql client from pool"))]
880 AcquireMySqlClient {
881 #[snafu(source)]
882 error: sqlx::Error,
883 #[snafu(implicit)]
884 location: Location,
885 },
886
887 #[cfg(feature = "mysql_kvbackend")]
888 #[snafu(display("Failed to {} MySql transaction", operation))]
889 MySqlTransaction {
890 #[snafu(source)]
891 error: sqlx::Error,
892 #[snafu(implicit)]
893 location: Location,
894 operation: String,
895 },
896
897 #[cfg(any(feature = "pg_kvbackend", feature = "mysql_kvbackend"))]
898 #[snafu(display("Rds transaction retry failed"))]
899 RdsTransactionRetryFailed {
900 #[snafu(implicit)]
901 location: Location,
902 },
903
904 #[cfg(any(feature = "pg_kvbackend", feature = "mysql_kvbackend"))]
905 #[snafu(display("Sql execution timeout, sql: {}, duration: {:?}", sql, duration))]
906 SqlExecutionTimeout {
907 sql: String,
908 duration: std::time::Duration,
909 #[snafu(implicit)]
910 location: Location,
911 },
912
913 #[snafu(display(
914 "Datanode table info not found, table id: {}, datanode id: {}",
915 table_id,
916 datanode_id
917 ))]
918 DatanodeTableInfoNotFound {
919 datanode_id: DatanodeId,
920 table_id: TableId,
921 #[snafu(implicit)]
922 location: Location,
923 },
924
925 #[snafu(display("Invalid topic name prefix: {}", prefix))]
926 InvalidTopicNamePrefix {
927 prefix: String,
928 #[snafu(implicit)]
929 location: Location,
930 },
931
932 #[snafu(display("No leader found for table_id: {}", table_id))]
933 NoLeader {
934 table_id: TableId,
935 #[snafu(implicit)]
936 location: Location,
937 },
938
939 #[snafu(display(
940 "Procedure poison key already exists with a different value, key: {}, value: {}",
941 key,
942 value
943 ))]
944 ProcedurePoisonConflict {
945 key: String,
946 value: String,
947 #[snafu(implicit)]
948 location: Location,
949 },
950
951 #[snafu(display("Failed to put poison, table metadata may be corrupted"))]
952 PutPoison {
953 #[snafu(implicit)]
954 location: Location,
955 #[snafu(source)]
956 source: common_procedure::error::Error,
957 },
958
959 #[snafu(display("Invalid file path: {}", file_path))]
960 InvalidFilePath {
961 #[snafu(implicit)]
962 location: Location,
963 file_path: String,
964 },
965
966 #[snafu(display("Failed to serialize flexbuffers"))]
967 SerializeFlexbuffers {
968 #[snafu(implicit)]
969 location: Location,
970 #[snafu(source)]
971 error: flexbuffers::SerializationError,
972 },
973
974 #[snafu(display("Failed to deserialize flexbuffers"))]
975 DeserializeFlexbuffers {
976 #[snafu(implicit)]
977 location: Location,
978 #[snafu(source)]
979 error: flexbuffers::DeserializationError,
980 },
981
982 #[snafu(display("Failed to read flexbuffers"))]
983 ReadFlexbuffers {
984 #[snafu(implicit)]
985 location: Location,
986 #[snafu(source)]
987 error: flexbuffers::ReaderError,
988 },
989
990 #[snafu(display("Invalid file name: {}", reason))]
991 InvalidFileName {
992 #[snafu(implicit)]
993 location: Location,
994 reason: String,
995 },
996
997 #[snafu(display("Invalid file extension: {}", reason))]
998 InvalidFileExtension {
999 #[snafu(implicit)]
1000 location: Location,
1001 reason: String,
1002 },
1003
1004 #[snafu(display("Failed to write object, file path: {}", file_path))]
1005 WriteObject {
1006 #[snafu(implicit)]
1007 location: Location,
1008 file_path: String,
1009 #[snafu(source)]
1010 error: object_store::Error,
1011 },
1012
1013 #[snafu(display("Failed to read object, file path: {}", file_path))]
1014 ReadObject {
1015 #[snafu(implicit)]
1016 location: Location,
1017 file_path: String,
1018 #[snafu(source)]
1019 error: object_store::Error,
1020 },
1021
1022 #[snafu(display("Missing column ids"))]
1023 MissingColumnIds {
1024 #[snafu(implicit)]
1025 location: Location,
1026 },
1027
1028 #[snafu(display(
1029 "Missing column in column metadata: {}, table: {}, table_id: {}",
1030 column_name,
1031 table_name,
1032 table_id,
1033 ))]
1034 MissingColumnInColumnMetadata {
1035 column_name: String,
1036 #[snafu(implicit)]
1037 location: Location,
1038 table_name: String,
1039 table_id: TableId,
1040 },
1041
1042 #[snafu(display(
1043 "Mismatch column id: column_name: {}, column_id: {}, table: {}, table_id: {}",
1044 column_name,
1045 column_id,
1046 table_name,
1047 table_id,
1048 ))]
1049 MismatchColumnId {
1050 column_name: String,
1051 column_id: u32,
1052 #[snafu(implicit)]
1053 location: Location,
1054 table_name: String,
1055 table_id: TableId,
1056 },
1057
1058 #[snafu(display("Failed to convert column def, column: {}", column))]
1059 ConvertColumnDef {
1060 column: String,
1061 #[snafu(implicit)]
1062 location: Location,
1063 source: api::error::Error,
1064 },
1065
1066 #[snafu(display("Failed to convert time ranges"))]
1067 ConvertTimeRanges {
1068 #[snafu(implicit)]
1069 location: Location,
1070 source: api::error::Error,
1071 },
1072
1073 #[snafu(display(
1074 "Column metadata inconsistencies found in table: {}, table_id: {}",
1075 table_name,
1076 table_id
1077 ))]
1078 ColumnMetadataConflicts {
1079 table_name: String,
1080 table_id: TableId,
1081 },
1082
1083 #[snafu(display(
1084 "Column not found in column metadata, column_name: {}, column_id: {}",
1085 column_name,
1086 column_id
1087 ))]
1088 ColumnNotFound { column_name: String, column_id: u32 },
1089
1090 #[snafu(display(
1091 "Column id mismatch, column_name: {}, expected column_id: {}, actual column_id: {}",
1092 column_name,
1093 expected_column_id,
1094 actual_column_id
1095 ))]
1096 ColumnIdMismatch {
1097 column_name: String,
1098 expected_column_id: u32,
1099 actual_column_id: u32,
1100 },
1101
1102 #[snafu(display(
1103 "Timestamp column mismatch, expected column_name: {}, expected column_id: {}, actual column_name: {}, actual column_id: {}",
1104 expected_column_name,
1105 expected_column_id,
1106 actual_column_name,
1107 actual_column_id,
1108 ))]
1109 TimestampMismatch {
1110 expected_column_name: String,
1111 expected_column_id: u32,
1112 actual_column_name: String,
1113 actual_column_id: u32,
1114 },
1115
1116 #[cfg(feature = "enterprise")]
1117 #[snafu(display("Too large duration"))]
1118 TooLargeDuration {
1119 #[snafu(source)]
1120 error: prost_types::DurationError,
1121 #[snafu(implicit)]
1122 location: Location,
1123 },
1124
1125 #[cfg(feature = "enterprise")]
1126 #[snafu(display("Negative duration"))]
1127 NegativeDuration {
1128 #[snafu(source)]
1129 error: prost_types::DurationError,
1130 #[snafu(implicit)]
1131 location: Location,
1132 },
1133
1134 #[cfg(feature = "enterprise")]
1135 #[snafu(display("Missing interval field"))]
1136 MissingInterval {
1137 #[snafu(implicit)]
1138 location: Location,
1139 },
1140}
1141
1142pub type Result<T> = std::result::Result<T, Error>;
1143
1144impl ErrorExt for Error {
1145 fn status_code(&self) -> StatusCode {
1146 use Error::*;
1147 match self {
1148 IllegalServerState { .. }
1149 | EtcdTxnOpResponse { .. }
1150 | EtcdFailed { .. }
1151 | EtcdTxnFailed { .. }
1152 | ConnectEtcd { .. }
1153 | MoveValues { .. }
1154 | TombstoneTargetAlreadyExists { .. }
1155 | GetCache { .. }
1156 | GetLatestCacheRetryExceeded { .. }
1157 | SerializeToJson { .. }
1158 | DeserializeFromJson { .. }
1159 | ElectionNoLeader { .. }
1160 | ElectionLeaderLeaseExpired { .. }
1161 | ElectionLeaderLeaseChanged { .. } => StatusCode::Internal,
1162
1163 NoLeader { .. } => StatusCode::TableUnavailable,
1164 ValueNotExist { .. }
1165 | ProcedurePoisonConflict { .. }
1166 | ProcedureStateReceiverNotFound { .. }
1167 | MissingColumnIds { .. }
1168 | MissingColumnInColumnMetadata { .. }
1169 | MismatchColumnId { .. }
1170 | ColumnMetadataConflicts { .. }
1171 | ColumnNotFound { .. }
1172 | ColumnIdMismatch { .. }
1173 | TimestampMismatch { .. } => StatusCode::Unexpected,
1174
1175 Unsupported { .. } | ReadOnlyKvBackend { .. } => StatusCode::Unsupported,
1176 WriteObject { .. } | ReadObject { .. } => StatusCode::StorageUnavailable,
1177
1178 SerdeJson { .. }
1179 | ParseOption { .. }
1180 | RouteInfoCorrupted { .. }
1181 | InvalidProtoMsg { .. }
1182 | InvalidMetadata { .. }
1183 | Unexpected { .. }
1184 | TableInfoNotFound { .. }
1185 | NextSequence { .. }
1186 | UnexpectedSequenceValue { .. }
1187 | InvalidHeartbeatResponse { .. }
1188 | EncodeJson { .. }
1189 | DecodeJson { .. }
1190 | PayloadNotExist { .. }
1191 | ConvertRawKey { .. }
1192 | DecodeProto { .. }
1193 | BuildTableMeta { .. }
1194 | TableRouteNotFound { .. }
1195 | TableRepartNotFound { .. }
1196 | RegionOperatingRace { .. }
1197 | SerializeWalOptions { .. }
1198 | BuildKafkaClient { .. }
1199 | BuildKafkaCtrlClient { .. }
1200 | KafkaPartitionClient { .. }
1201 | ProduceRecord { .. }
1202 | CreateKafkaWalTopic { .. }
1203 | EmptyTopicPool { .. }
1204 | UnexpectedLogicalRouteTable { .. }
1205 | ProcedureOutput { .. }
1206 | FromUtf8 { .. }
1207 | MetadataCorruption { .. }
1208 | KafkaGetOffset { .. }
1209 | ReadFlexbuffers { .. }
1210 | SerializeFlexbuffers { .. }
1211 | DeserializeFlexbuffers { .. }
1212 | ConvertTimeRanges { .. } => StatusCode::Unexpected,
1213
1214 GetKvCache { .. } | CacheNotGet { .. } => StatusCode::Internal,
1215
1216 SchemaAlreadyExists { .. } => StatusCode::DatabaseAlreadyExists,
1217
1218 ProcedureNotFound { .. }
1219 | InvalidViewInfo { .. }
1220 | PrimaryKeyNotFound { .. }
1221 | EmptyKey { .. }
1222 | AlterLogicalTablesInvalidArguments { .. }
1223 | CreateLogicalTablesInvalidArguments { .. }
1224 | MismatchPrefix { .. }
1225 | TlsConfig { .. }
1226 | InvalidSetDatabaseOption { .. }
1227 | InvalidUnsetDatabaseOption { .. }
1228 | InvalidTopicNamePrefix { .. }
1229 | InvalidFileExtension { .. }
1230 | InvalidFileName { .. }
1231 | InvalidFlowRequestBody { .. }
1232 | InvalidFilePath { .. } => StatusCode::InvalidArguments,
1233
1234 #[cfg(feature = "enterprise")]
1235 MissingInterval { .. } | NegativeDuration { .. } | TooLargeDuration { .. } => {
1236 StatusCode::InvalidArguments
1237 }
1238
1239 FlowNotFound { .. } => StatusCode::FlowNotFound,
1240 FlowRouteNotFound { .. } => StatusCode::Unexpected,
1241 FlowAlreadyExists { .. } => StatusCode::FlowAlreadyExists,
1242
1243 ViewNotFound { .. } | TableNotFound { .. } | RegionNotFound { .. } => {
1244 StatusCode::TableNotFound
1245 }
1246 ViewAlreadyExists { .. }
1247 | TableAlreadyExists { .. }
1248 | TableNameTombstoneConflict { .. } => StatusCode::TableAlreadyExists,
1249
1250 SubmitProcedure { source, .. }
1251 | QueryProcedure { source, .. }
1252 | WaitProcedure { source, .. }
1253 | StartProcedureManager { source, .. }
1254 | StopProcedureManager { source, .. } => source.status_code(),
1255 RegisterProcedureLoader { source, .. } => source.status_code(),
1256 External { source, .. } => source.status_code(),
1257 ResponseExceededSizeLimit { source, .. } => source.status_code(),
1258 OperateDatanode { source, .. } => source.status_code(),
1259 Table { source, .. } => source.status_code(),
1260 RetryLater { source, .. } => source.status_code(),
1261 AbortProcedure { source, .. } => source.status_code(),
1262 ConvertAlterTableRequest { source, .. } => source.status_code(),
1263 PutPoison { source, .. } => source.status_code(),
1264 ConvertColumnDef { source, .. } => source.status_code(),
1265 ProcedureStateReceiver { source, .. } => source.status_code(),
1266 RegisterRepartitionProcedureLoader { source, .. } => source.status_code(),
1267 CreateRepartitionProcedure { source, .. } => source.status_code(),
1268
1269 ParseProcedureId { .. }
1270 | InvalidNumTopics { .. }
1271 | SchemaNotFound { .. }
1272 | CatalogNotFound { .. }
1273 | InvalidNodeInfoKey { .. }
1274 | InvalidStatKey { .. }
1275 | ParseNum { .. }
1276 | InvalidRole { .. }
1277 | EmptyDdlTasks { .. } => StatusCode::InvalidArguments,
1278
1279 LoadTlsCertificate { .. } => StatusCode::Internal,
1280
1281 #[cfg(feature = "pg_kvbackend")]
1282 PostgresExecution { .. }
1283 | CreatePostgresPool { .. }
1284 | GetPostgresConnection { .. }
1285 | GetPostgresClient { .. }
1286 | PostgresTransaction { .. }
1287 | PostgresTlsConfig { .. }
1288 | InvalidTlsConfig { .. } => StatusCode::Internal,
1289 #[cfg(feature = "mysql_kvbackend")]
1290 MySqlExecution { .. }
1291 | CreateMySqlPool { .. }
1292 | DecodeSqlValue { .. }
1293 | AcquireMySqlClient { .. }
1294 | MySqlTransaction { .. } => StatusCode::Internal,
1295 #[cfg(any(feature = "pg_kvbackend", feature = "mysql_kvbackend"))]
1296 RdsTransactionRetryFailed { .. } | SqlExecutionTimeout { .. } => StatusCode::Internal,
1297 DatanodeTableInfoNotFound { .. } => StatusCode::Internal,
1298 }
1299 }
1300
1301 fn as_any(&self) -> &dyn std::any::Any {
1302 self
1303 }
1304
1305 fn retry_hint(&self) -> RetryHint {
1306 use Error::*;
1307
1308 match self {
1309 RetryLater { .. }
1310 | GetLatestCacheRetryExceeded { .. }
1311 | NoLeader { .. }
1312 | ElectionNoLeader { .. }
1313 | ElectionLeaderLeaseExpired { .. }
1314 | ElectionLeaderLeaseChanged { .. } => RetryHint::Retryable,
1315 ConnectEtcd { error, .. } | EtcdFailed { error, .. } | EtcdTxnFailed { error, .. } => {
1316 retry_hint_from_etcd_error(error)
1317 }
1318 WriteObject { error, .. } | ReadObject { error, .. } => {
1319 retry_hint_from_opendal_error(error)
1320 }
1321 BuildKafkaClient { error, .. }
1322 | BuildKafkaCtrlClient { error, .. }
1323 | KafkaPartitionClient { error, .. }
1324 | KafkaGetOffset { error, .. }
1325 | ProduceRecord { error, .. }
1326 | CreateKafkaWalTopic { error, .. } => rskafka_client_error_to_retry_hint(error),
1327 SubmitProcedure { source, .. }
1328 | QueryProcedure { source, .. }
1329 | WaitProcedure { source, .. }
1330 | StartProcedureManager { source, .. }
1331 | StopProcedureManager { source, .. }
1332 | RegisterProcedureLoader { source, .. }
1333 | PutPoison { source, .. }
1334 | ProcedureStateReceiver { source, .. } => source.retry_hint(),
1335 External { source, .. }
1336 | ResponseExceededSizeLimit { source, .. }
1337 | OperateDatanode { source, .. }
1338 | AbortProcedure { source, .. }
1339 | RegisterRepartitionProcedureLoader { source, .. }
1340 | CreateRepartitionProcedure { source, .. } => source.retry_hint(),
1341 Table { source, .. } => source.retry_hint(),
1342 ConvertAlterTableRequest { source, .. } => source.retry_hint(),
1343 ConvertColumnDef { source, .. } => source.retry_hint(),
1344 GetCache { source, .. } => source.retry_hint(),
1345 #[cfg(feature = "pg_kvbackend")]
1346 PostgresExecution { error, .. } | PostgresTransaction { error, .. } => {
1347 retry_hint_from_postgres_error(error)
1348 }
1349 #[cfg(feature = "pg_kvbackend")]
1350 GetPostgresClient { error, .. } => retry_hint_from_postgres_pool_error(error),
1351 #[cfg(feature = "mysql_kvbackend")]
1352 MySqlExecution { error, .. }
1353 | CreateMySqlPool { error, .. }
1354 | AcquireMySqlClient { error, .. }
1355 | MySqlTransaction { error, .. } => retry_hint_from_sqlx_error(error),
1356 #[cfg(any(feature = "pg_kvbackend", feature = "mysql_kvbackend"))]
1357 SqlExecutionTimeout { .. } => RetryHint::Retryable,
1358 _ => RetryHint::NonRetryable,
1359 }
1360 }
1361}
1362
1363impl Error {
1364 #[cfg(any(feature = "pg_kvbackend", feature = "mysql_kvbackend"))]
1365 pub fn is_serialization_error(&self) -> bool {
1367 match self {
1368 #[cfg(feature = "pg_kvbackend")]
1369 Error::PostgresExecution { error, .. } | Error::PostgresTransaction { error, .. } => {
1370 retry_hint::is_postgres_serialization_error(error)
1371 }
1372 #[cfg(feature = "mysql_kvbackend")]
1373 Error::MySqlExecution { error, .. } | Error::MySqlTransaction { error, .. } => {
1374 retry_hint::is_mysql_serialization_error(error)
1375 }
1376 _ => false,
1377 }
1378 }
1379
1380 pub fn retry_later<E: ErrorExt + Send + Sync + 'static>(err: E) -> Error {
1382 Error::RetryLater {
1383 source: BoxedError::new(err),
1384 clean_poisons: false,
1385 }
1386 }
1387
1388 pub fn is_retry_later(&self) -> bool {
1390 matches!(
1391 self,
1392 Error::RetryLater { .. } | Error::GetLatestCacheRetryExceeded { .. }
1393 )
1394 }
1395
1396 pub fn need_clean_poisons(&self) -> bool {
1398 matches!(
1399 self,
1400 Error::AbortProcedure { clean_poisons, .. } if *clean_poisons
1401 ) || matches!(
1402 self,
1403 Error::RetryLater { clean_poisons, .. } if *clean_poisons
1404 )
1405 }
1406
1407 pub fn is_exceeded_size_limit(&self) -> bool {
1409 match self {
1410 Error::EtcdFailed {
1411 error: etcd_client::Error::GRpcStatus(status),
1412 ..
1413 } => status.code() == tonic::Code::OutOfRange,
1414 Error::ResponseExceededSizeLimit { .. } => true,
1415 _ => false,
1416 }
1417 }
1418}
1419
1420#[cfg(test)]
1421mod retry_hint_tests {
1422 use std::sync::Arc;
1423
1424 use common_error::mock::MockError;
1425
1426 use super::*;
1427
1428 #[test]
1429 fn test_retry_later_hint_is_retryable() {
1430 let err = Error::retry_later(MockError::new(StatusCode::Internal));
1431
1432 assert_eq!(err.retry_hint(), RetryHint::Retryable);
1433 }
1434
1435 #[test]
1436 fn test_latest_cache_retry_exceeded_hint_is_retryable() {
1437 let err = GetLatestCacheRetryExceededSnafu { attempts: 3_usize }.build();
1438
1439 assert_eq!(err.retry_hint(), RetryHint::Retryable);
1440 }
1441
1442 #[test]
1443 fn test_get_cache_forwards_retry_hint() {
1444 let source = Arc::new(Error::retry_later(MockError::new(StatusCode::Internal)));
1445 let err = Error::GetCache { source };
1446
1447 assert_eq!(err.retry_hint(), RetryHint::Retryable);
1448 }
1449
1450 #[cfg(any(feature = "pg_kvbackend", feature = "mysql_kvbackend"))]
1451 #[test]
1452 fn test_sql_execution_timeout_hint_is_retryable() {
1453 let err = SqlExecutionTimeoutSnafu {
1454 sql: "SELECT 1".to_string(),
1455 duration: std::time::Duration::from_secs(1),
1456 }
1457 .build();
1458
1459 assert_eq!(err.retry_hint(), RetryHint::Retryable);
1460 }
1461
1462 #[test]
1463 fn test_default_hint_is_non_retryable() {
1464 let err = UnexpectedSnafu {
1465 err_msg: "mock error",
1466 }
1467 .build();
1468
1469 assert_eq!(err.retry_hint(), RetryHint::NonRetryable);
1470 }
1471}