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