Skip to main content

common_meta/
error.rs

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