Skip to main content

mito2/
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::any::Any;
16use std::sync::Arc;
17
18use common_datasource::compression::CompressionType;
19use common_error::ext::{BoxedError, ErrorExt, RetryHint};
20use common_error::status_code::StatusCode;
21use common_macro::stack_trace_debug;
22use common_memory_manager;
23use common_runtime::JoinError;
24use common_time::Timestamp;
25use common_time::timestamp::TimeUnit;
26use datatypes::arrow::error::ArrowError;
27use datatypes::prelude::ConcreteDataType;
28use object_store::ErrorKind;
29use object_store::error::retry_hint_from_opendal_error;
30use partition::error::Error as PartitionError;
31use prost::DecodeError;
32use snafu::{Location, Snafu};
33use store_api::ManifestVersion;
34use store_api::logstore::provider::Provider;
35use store_api::storage::{FileId, RegionId};
36use tokio::time::error::Elapsed;
37
38use crate::cache::file_cache::FileType;
39use crate::region::RegionRoleState;
40use crate::schedule::remote_job_scheduler::JobId;
41use crate::worker::WorkerId;
42
43#[derive(Snafu)]
44#[snafu(visibility(pub))]
45#[stack_trace_debug]
46pub enum Error {
47    #[snafu(display("Unexpected data type"))]
48    DataTypeMismatch {
49        source: datatypes::error::Error,
50        #[snafu(implicit)]
51        location: Location,
52    },
53
54    #[snafu(display("External error, context: {}", context))]
55    External {
56        source: BoxedError,
57        context: String,
58        #[snafu(implicit)]
59        location: Location,
60    },
61
62    #[snafu(display("OpenDAL operator failed"))]
63    OpenDal {
64        #[snafu(implicit)]
65        location: Location,
66        #[snafu(source)]
67        error: object_store::Error,
68    },
69
70    #[snafu(display(
71        "Manifest delta {} disappeared after it was listed, path: {}",
72        version,
73        path
74    ))]
75    ManifestDeltaNotFound {
76        version: ManifestVersion,
77        path: String,
78        #[snafu(source)]
79        error: object_store::Error,
80        #[snafu(implicit)]
81        location: Location,
82    },
83
84    #[snafu(display("Fail to compress object by {}, path: {}", compress_type, path))]
85    CompressObject {
86        compress_type: CompressionType,
87        path: String,
88        #[snafu(source)]
89        error: std::io::Error,
90    },
91
92    #[snafu(display("Fail to decompress object by {}, path: {}", compress_type, path))]
93    DecompressObject {
94        compress_type: CompressionType,
95        path: String,
96        #[snafu(source)]
97        error: std::io::Error,
98    },
99
100    #[snafu(display("Failed to ser/de json object"))]
101    SerdeJson {
102        #[snafu(implicit)]
103        location: Location,
104        #[snafu(source)]
105        error: serde_json::Error,
106    },
107
108    #[snafu(display("Failed to serialize column metadata"))]
109    SerializeColumnMetadata {
110        #[snafu(source)]
111        error: serde_json::Error,
112        #[snafu(implicit)]
113        location: Location,
114    },
115
116    #[snafu(display("Failed to serialize manifest, region_id: {}", region_id))]
117    SerializeManifest {
118        region_id: RegionId,
119        #[snafu(source)]
120        error: serde_json::Error,
121        #[snafu(implicit)]
122        location: Location,
123    },
124
125    #[snafu(display("Invalid scan index, start: {}, end: {}", start, end))]
126    InvalidScanIndex {
127        start: ManifestVersion,
128        end: ManifestVersion,
129        #[snafu(implicit)]
130        location: Location,
131    },
132
133    #[snafu(display("Invalid UTF-8 content"))]
134    Utf8 {
135        #[snafu(implicit)]
136        location: Location,
137        #[snafu(source)]
138        error: std::str::Utf8Error,
139    },
140
141    #[snafu(display("Cannot find RegionMetadata"))]
142    RegionMetadataNotFound {
143        #[snafu(implicit)]
144        location: Location,
145    },
146
147    #[snafu(display("Failed to join handle"))]
148    Join {
149        #[snafu(source)]
150        error: common_runtime::JoinError,
151        #[snafu(implicit)]
152        location: Location,
153    },
154
155    #[snafu(display("Worker {} is stopped", id))]
156    WorkerStopped {
157        id: WorkerId,
158        #[snafu(implicit)]
159        location: Location,
160    },
161
162    #[snafu(display("Failed to recv result"))]
163    Recv {
164        #[snafu(source)]
165        error: tokio::sync::oneshot::error::RecvError,
166        #[snafu(implicit)]
167        location: Location,
168    },
169
170    #[snafu(display("Invalid metadata, {}", reason))]
171    InvalidMeta {
172        reason: String,
173        #[snafu(implicit)]
174        location: Location,
175    },
176
177    #[snafu(display("Invalid region metadata"))]
178    InvalidMetadata {
179        source: store_api::metadata::MetadataError,
180        #[snafu(implicit)]
181        location: Location,
182    },
183
184    #[snafu(display("Failed to create RecordBatch from vectors"))]
185    NewRecordBatch {
186        #[snafu(implicit)]
187        location: Location,
188        #[snafu(source)]
189        error: ArrowError,
190    },
191
192    #[snafu(display("Failed to read parquet file, path: {}", path))]
193    ReadParquet {
194        path: String,
195        #[snafu(source)]
196        error: parquet::errors::ParquetError,
197        #[snafu(implicit)]
198        location: Location,
199    },
200
201    #[snafu(display("Failed to load range result"))]
202    LoadRangeResult {
203        source: Arc<Error>,
204        #[snafu(implicit)]
205        location: Location,
206    },
207
208    #[snafu(display("Failed to load SST metadata"))]
209    LoadSstMeta {
210        source: Arc<Error>,
211        #[snafu(implicit)]
212        location: Location,
213    },
214
215    #[snafu(display("Failed to load Parquet page"))]
216    LoadParquetPage {
217        source: Arc<Error>,
218        #[snafu(implicit)]
219        location: Location,
220    },
221
222    #[snafu(display("Failed to write parquet file"))]
223    WriteParquet {
224        #[snafu(source)]
225        error: parquet::errors::ParquetError,
226        #[snafu(implicit)]
227        location: Location,
228    },
229
230    #[snafu(display(
231        "Cannot assign a stable field id to native histogram sub-field '{}' of column id {} (unknown sub-field name or derived id overflows i32)",
232        field_name,
233        column_id
234    ))]
235    InvalidNativeHistogramSubfield {
236        column_id: i32,
237        field_name: String,
238        #[snafu(implicit)]
239        location: Location,
240    },
241
242    #[snafu(display(
243        "Native histogram column '{}' has no usable PARQUET:field_id to namespace its sub-field ids (missing, malformed, or exceeds i32::MAX)",
244        field_name
245    ))]
246    InvalidNativeHistogramFieldId {
247        field_name: String,
248        #[snafu(implicit)]
249        location: Location,
250    },
251
252    #[snafu(display("Region {} not found", region_id))]
253    RegionNotFound {
254        region_id: RegionId,
255        #[snafu(implicit)]
256        location: Location,
257    },
258
259    #[snafu(display("Object store not found: {}", object_store))]
260    ObjectStoreNotFound {
261        object_store: String,
262        #[snafu(implicit)]
263        location: Location,
264    },
265
266    #[snafu(display("Region {} is corrupted, reason: {}", region_id, reason))]
267    RegionCorrupted {
268        region_id: RegionId,
269        reason: String,
270        #[snafu(implicit)]
271        location: Location,
272    },
273
274    #[snafu(display("Invalid request to region {}, reason: {}", region_id, reason))]
275    InvalidRequest {
276        region_id: RegionId,
277        reason: String,
278        #[snafu(implicit)]
279        location: Location,
280    },
281
282    #[snafu(display(
283        "STALE_CURSOR: incremental query stale, region: {}, given_seq: {}, min_readable_seq: {}, retry_hint: FALLBACK_FULL_RECOMPUTE",
284        region_id,
285        given_seq,
286        min_readable_seq
287    ))]
288    IncrementalQueryStale {
289        region_id: RegionId,
290        given_seq: u64,
291        min_readable_seq: u64,
292        #[snafu(implicit)]
293        location: Location,
294    },
295
296    #[snafu(display(
297        "STALE_SNAPSHOT_FENCE: snapshot upper bound stale, region: {}, given_seq: {}, min_enforceable_seq: {}, retry_hint: REBIND_SNAPSHOT_FENCE",
298        region_id,
299        given_seq,
300        min_enforceable_seq
301    ))]
302    SnapshotFenceStale {
303        region_id: RegionId,
304        given_seq: u64,
305        min_enforceable_seq: u64,
306        #[snafu(implicit)]
307        location: Location,
308    },
309
310    #[snafu(display(
311        "SEQUENCE_RANGE_UNSUPPORTED: exact sequence-range read unsupported, region: {}, min_seq: {}, max_seq: {}, reason: {}, retry_hint: FALLBACK_MEMTABLE_ONLY_OR_FULL_RECOMPUTE",
312        region_id,
313        min_seq,
314        max_seq,
315        reason
316    ))]
317    SequenceRangeUnsupported {
318        region_id: RegionId,
319        min_seq: u64,
320        max_seq: u64,
321        reason: String,
322        #[snafu(implicit)]
323        location: Location,
324    },
325
326    #[snafu(display(
327        "region {} is unusable for sequence reads: file {} declares region {}",
328        region_id,
329        file_id,
330        file_region_id
331    ))]
332    RegionSequenceDomainBroken {
333        region_id: RegionId,
334        file_region_id: RegionId,
335        file_id: FileId,
336        #[snafu(implicit)]
337        location: Location,
338    },
339
340    #[snafu(display("Old manifest missing for region {}", region_id))]
341    MissingOldManifest {
342        region_id: RegionId,
343        #[snafu(implicit)]
344        location: Location,
345    },
346
347    #[snafu(display("New manifest missing for region {}", region_id))]
348    MissingNewManifest {
349        region_id: RegionId,
350        #[snafu(implicit)]
351        location: Location,
352    },
353
354    #[snafu(display("Manifest missing for region {}", region_id))]
355    MissingManifest {
356        region_id: RegionId,
357        #[snafu(implicit)]
358        location: Location,
359    },
360
361    #[snafu(display("File consistency check failed for file {}: {}", file_id, reason))]
362    InconsistentFile {
363        file_id: FileId,
364        reason: String,
365        #[snafu(implicit)]
366        location: Location,
367    },
368
369    #[snafu(display("Files lost during remapping: old={}, new={}", old_count, new_count))]
370    FilesLost {
371        old_count: usize,
372        new_count: usize,
373        #[snafu(implicit)]
374        location: Location,
375    },
376
377    #[snafu(display("No old manifests provided (need at least one for template)"))]
378    NoOldManifests {
379        #[snafu(implicit)]
380        location: Location,
381    },
382
383    #[snafu(display("Failed to fetch manifests"))]
384    FetchManifests {
385        #[snafu(implicit)]
386        location: Location,
387        source: BoxedError,
388    },
389
390    #[snafu(display("Partition expression missing for region {}", region_id))]
391    MissingPartitionExpr {
392        region_id: RegionId,
393        #[snafu(implicit)]
394        location: Location,
395    },
396
397    #[snafu(display("Failed to serialize partition expression: {}", source))]
398    SerializePartitionExpr {
399        #[snafu(source)]
400        source: PartitionError,
401        #[snafu(implicit)]
402        location: Location,
403    },
404
405    #[snafu(display(
406        "Failed to convert ConcreteDataType to ColumnDataType, reason: {}",
407        reason
408    ))]
409    ConvertColumnDataType {
410        reason: String,
411        source: api::error::Error,
412        #[snafu(implicit)]
413        location: Location,
414    },
415
416    /// An error type to indicate that schema is changed and we need
417    /// to fill default values again.
418    #[snafu(display("Need to fill default value for region {}", region_id))]
419    FillDefault {
420        region_id: RegionId,
421        // The error is for internal use so we don't need a location.
422    },
423
424    #[snafu(display(
425        "Failed to create default value for column {} of region {}",
426        column,
427        region_id
428    ))]
429    CreateDefault {
430        region_id: RegionId,
431        column: String,
432        source: datatypes::Error,
433        #[snafu(implicit)]
434        location: Location,
435    },
436
437    #[snafu(display("Failed to build entry, region_id: {}", region_id))]
438    BuildEntry {
439        region_id: RegionId,
440        #[snafu(implicit)]
441        location: Location,
442        source: BoxedError,
443    },
444
445    #[snafu(display("Failed to write WAL"))]
446    WriteWal {
447        #[snafu(implicit)]
448        location: Location,
449        source: BoxedError,
450    },
451
452    #[snafu(display("Failed to read WAL, provider: {}", provider))]
453    ReadWal {
454        provider: Provider,
455        #[snafu(implicit)]
456        location: Location,
457        source: BoxedError,
458    },
459
460    #[snafu(display("Failed to decode WAL entry, region_id: {}", region_id))]
461    DecodeWal {
462        region_id: RegionId,
463        #[snafu(implicit)]
464        location: Location,
465        #[snafu(source)]
466        error: DecodeError,
467    },
468
469    #[snafu(display("Failed to delete WAL, region_id: {}", region_id))]
470    DeleteWal {
471        region_id: RegionId,
472        #[snafu(implicit)]
473        location: Location,
474        source: BoxedError,
475    },
476
477    #[snafu(display("Failed to wait for the WAL to be durable, region_id: {}", region_id))]
478    WaitWalDurable {
479        region_id: RegionId,
480        #[snafu(implicit)]
481        location: Location,
482        source: BoxedError,
483    },
484
485    #[snafu(display("Failed to check the WAL history, region_id: {}", region_id))]
486    CheckWalHistory {
487        region_id: RegionId,
488        #[snafu(implicit)]
489        location: Location,
490        source: BoxedError,
491    },
492
493    // Shared error for each writer in the write group.
494    #[snafu(display("Failed to write region"))]
495    WriteGroup { source: Arc<Error> },
496
497    #[snafu(display("Invalid parquet SST file {}, reason: {}", file, reason))]
498    InvalidParquet {
499        file: String,
500        reason: String,
501        #[snafu(implicit)]
502        location: Location,
503    },
504
505    #[snafu(display("Invalid batch, {}", reason))]
506    InvalidBatch {
507        reason: String,
508        #[snafu(implicit)]
509        location: Location,
510    },
511
512    #[snafu(display("Invalid arrow record batch, {}", reason))]
513    InvalidRecordBatch {
514        reason: String,
515        #[snafu(implicit)]
516        location: Location,
517    },
518
519    #[snafu(display("Invalid wal read request, {}", reason))]
520    InvalidWalReadRequest {
521        reason: String,
522        #[snafu(implicit)]
523        location: Location,
524    },
525
526    #[snafu(display("Failed to convert array to vector"))]
527    ConvertVector {
528        #[snafu(implicit)]
529        location: Location,
530        source: datatypes::error::Error,
531    },
532
533    #[snafu(display("Failed to compute arrow arrays"))]
534    ComputeArrow {
535        #[snafu(implicit)]
536        location: Location,
537        #[snafu(source)]
538        error: datatypes::arrow::error::ArrowError,
539    },
540
541    #[snafu(display("Failed to evaluate partition filter"))]
542    EvalPartitionFilter {
543        #[snafu(implicit)]
544        location: Location,
545        #[snafu(source)]
546        error: datafusion::error::DataFusionError,
547    },
548
549    #[snafu(display("Failed to merge candidate series"))]
550    MergeCandidateSeries {
551        #[snafu(implicit)]
552        location: Location,
553        #[snafu(source)]
554        error: datafusion::error::DataFusionError,
555    },
556
557    #[snafu(display("Failed to compute vector"))]
558    ComputeVector {
559        #[snafu(implicit)]
560        location: Location,
561        source: datatypes::error::Error,
562    },
563
564    #[snafu(display("Primary key length mismatch, expect: {}, actual: {}", expect, actual))]
565    PrimaryKeyLengthMismatch {
566        expect: usize,
567        actual: usize,
568        #[snafu(implicit)]
569        location: Location,
570    },
571
572    #[snafu(display("Invalid sender",))]
573    InvalidSender {
574        #[snafu(implicit)]
575        location: Location,
576    },
577
578    #[snafu(display("Invalid scheduler state"))]
579    InvalidSchedulerState {
580        #[snafu(implicit)]
581        location: Location,
582    },
583
584    #[snafu(display("Failed to stop scheduler"))]
585    StopScheduler {
586        #[snafu(source)]
587        error: JoinError,
588        #[snafu(implicit)]
589        location: Location,
590    },
591
592    #[snafu(display(
593        "Failed to batch delete SST files, region id: {}, file ids: {:?}",
594        region_id,
595        file_ids
596    ))]
597    DeleteSsts {
598        region_id: RegionId,
599        file_ids: Vec<FileId>,
600        #[snafu(source)]
601        error: object_store::Error,
602        #[snafu(implicit)]
603        location: Location,
604    },
605
606    #[snafu(display("Failed to delete index file, file id: {}", file_id))]
607    DeleteIndex {
608        file_id: FileId,
609        #[snafu(source)]
610        error: object_store::Error,
611        #[snafu(implicit)]
612        location: Location,
613    },
614
615    #[snafu(display("Failed to batch delete index files, file ids: {:?}", file_ids))]
616    DeleteIndexes {
617        file_ids: Vec<FileId>,
618        #[snafu(source)]
619        error: object_store::Error,
620        #[snafu(implicit)]
621        location: Location,
622    },
623
624    #[snafu(display("Failed to flush region {}", region_id))]
625    FlushRegion {
626        region_id: RegionId,
627        source: Arc<Error>,
628        #[snafu(implicit)]
629        location: Location,
630    },
631
632    #[snafu(display("Region {} is dropped", region_id))]
633    RegionDropped {
634        region_id: RegionId,
635        #[snafu(implicit)]
636        location: Location,
637    },
638
639    #[snafu(display("Region {} is closed", region_id))]
640    RegionClosed {
641        region_id: RegionId,
642        #[snafu(implicit)]
643        location: Location,
644    },
645
646    #[snafu(display(
647        "Stale compaction execution for region {}, the region may have been reopened, truncated or the compaction was superseded",
648        region_id
649    ))]
650    StaleCompactionExecution {
651        region_id: RegionId,
652        #[snafu(implicit)]
653        location: Location,
654    },
655
656    #[snafu(display("Region {} is truncated", region_id))]
657    RegionTruncated {
658        region_id: RegionId,
659        #[snafu(implicit)]
660        location: Location,
661    },
662
663    #[snafu(display(
664        "Engine write buffer is full, rejecting write requests of region {}",
665        region_id,
666    ))]
667    RejectWrite {
668        region_id: RegionId,
669        #[snafu(implicit)]
670        location: Location,
671    },
672
673    #[snafu(display("Region {} rejects writes while in staging", region_id))]
674    RejectWriteInStaging {
675        region_id: RegionId,
676        #[snafu(implicit)]
677        location: Location,
678    },
679
680    #[snafu(display("Region {} does not hold a valid leader lease", region_id))]
681    RegionLeaseExpired {
682        region_id: RegionId,
683        #[snafu(implicit)]
684        location: Location,
685    },
686
687    #[snafu(display(
688        "Region {} lost its leader lease while writing to the WAL, the write may have been applied",
689        region_id
690    ))]
691    UnacknowledgedWrite {
692        region_id: RegionId,
693        #[snafu(implicit)]
694        location: Location,
695    },
696
697    #[snafu(display("Failed to compact region {}", region_id))]
698    CompactRegion {
699        region_id: RegionId,
700        source: Arc<Error>,
701        #[snafu(implicit)]
702        location: Location,
703    },
704
705    #[snafu(display("Failed to edit region {}", region_id))]
706    EditRegion {
707        region_id: RegionId,
708        source: Arc<Error>,
709        #[snafu(implicit)]
710        location: Location,
711    },
712
713    #[snafu(display(
714        "Failed to compat readers for region {}, reason: {}",
715        region_id,
716        reason,
717    ))]
718    CompatReader {
719        region_id: RegionId,
720        reason: String,
721        #[snafu(implicit)]
722        location: Location,
723    },
724
725    #[snafu(display("Invalue region req"))]
726    InvalidRegionRequest {
727        source: store_api::metadata::MetadataError,
728        #[snafu(implicit)]
729        location: Location,
730    },
731
732    #[snafu(display(
733        "Region {} is in {:?} state, which does not permit manifest updates.",
734        region_id,
735        state
736    ))]
737    UpdateManifest {
738        region_id: RegionId,
739        state: RegionRoleState,
740        #[snafu(implicit)]
741        location: Location,
742    },
743
744    #[snafu(display("Region {} is in {:?} state, expect: {:?}", region_id, state, expect))]
745    RegionState {
746        region_id: RegionId,
747        state: RegionRoleState,
748        expect: RegionRoleState,
749        #[snafu(implicit)]
750        location: Location,
751    },
752
753    #[snafu(display(
754        "Partition expr version mismatch for region {}: request {}, expected {}",
755        region_id,
756        request_version,
757        expected_version
758    ))]
759    PartitionExprVersionMismatch {
760        region_id: RegionId,
761        request_version: u64,
762        expected_version: u64,
763        #[snafu(implicit)]
764        location: Location,
765    },
766
767    #[snafu(display("Invalid options"))]
768    JsonOptions {
769        #[snafu(source)]
770        error: serde_json::Error,
771        #[snafu(implicit)]
772        location: Location,
773    },
774
775    #[snafu(display(
776        "Empty region directory, region_id: {}, region_dir: {}",
777        region_id,
778        region_dir,
779    ))]
780    EmptyRegionDir {
781        region_id: RegionId,
782        region_dir: String,
783        #[snafu(implicit)]
784        location: Location,
785    },
786
787    #[snafu(display("Empty manifest directory, manifest_dir: {}", manifest_dir,))]
788    EmptyManifestDir {
789        manifest_dir: String,
790        #[snafu(implicit)]
791        location: Location,
792    },
793
794    #[snafu(display("Column not found, column: {column}"))]
795    ColumnNotFound {
796        column: String,
797        #[snafu(implicit)]
798        location: Location,
799    },
800
801    #[snafu(display("Failed to build index applier"))]
802    BuildIndexApplier {
803        source: index::inverted_index::error::Error,
804        #[snafu(implicit)]
805        location: Location,
806    },
807
808    #[snafu(display("Failed to build index asynchronously in region {}", region_id))]
809    BuildIndexAsync {
810        region_id: RegionId,
811        source: Arc<Error>,
812        #[snafu(implicit)]
813        location: Location,
814    },
815
816    #[snafu(display(
817        "Index build did not complete for files {:?} in region {}",
818        file_ids,
819        region_id
820    ))]
821    IndexBuildIncomplete {
822        region_id: RegionId,
823        file_ids: Vec<FileId>,
824        #[snafu(implicit)]
825        location: Location,
826    },
827
828    #[snafu(display("Failed to convert value"))]
829    ConvertValue {
830        source: datatypes::error::Error,
831        #[snafu(implicit)]
832        location: Location,
833    },
834
835    #[snafu(display("Failed to apply inverted index"))]
836    ApplyInvertedIndex {
837        source: index::inverted_index::error::Error,
838        #[snafu(implicit)]
839        location: Location,
840    },
841
842    #[snafu(display("Failed to apply bloom filter index"))]
843    ApplyBloomFilterIndex {
844        source: index::bloom_filter::error::Error,
845        #[snafu(implicit)]
846        location: Location,
847    },
848
849    #[snafu(display("Failed to push index value"))]
850    PushIndexValue {
851        source: index::inverted_index::error::Error,
852        #[snafu(implicit)]
853        location: Location,
854    },
855
856    #[snafu(display("Failed to write index completely"))]
857    IndexFinish {
858        source: index::inverted_index::error::Error,
859        #[snafu(implicit)]
860        location: Location,
861    },
862
863    #[snafu(display("Operate on aborted index"))]
864    OperateAbortedIndex {
865        #[snafu(implicit)]
866        location: Location,
867    },
868
869    #[snafu(display("Failed to read puffin blob"))]
870    PuffinReadBlob {
871        source: puffin::error::Error,
872        #[snafu(implicit)]
873        location: Location,
874    },
875
876    #[snafu(display("Failed to add blob to puffin file"))]
877    PuffinAddBlob {
878        source: puffin::error::Error,
879        #[snafu(implicit)]
880        location: Location,
881    },
882
883    #[snafu(display("Failed to clean dir {dir}"))]
884    CleanDir {
885        dir: String,
886        #[snafu(source)]
887        error: std::io::Error,
888        #[snafu(implicit)]
889        location: Location,
890    },
891
892    #[snafu(display("Invalid config, {reason}"))]
893    InvalidConfig {
894        reason: String,
895        #[snafu(implicit)]
896        location: Location,
897    },
898
899    #[snafu(display(
900        "Stale log entry found during replay, region: {}, flushed: {}, replayed: {}",
901        region_id,
902        flushed_entry_id,
903        unexpected_entry_id
904    ))]
905    StaleLogEntry {
906        region_id: RegionId,
907        flushed_entry_id: u64,
908        unexpected_entry_id: u64,
909    },
910
911    #[snafu(display(
912        "Failed to download file, region_id: {}, file_id: {}, file_type: {:?}",
913        region_id,
914        file_id,
915        file_type,
916    ))]
917    Download {
918        region_id: RegionId,
919        file_id: FileId,
920        file_type: FileType,
921        #[snafu(source)]
922        error: std::io::Error,
923        #[snafu(implicit)]
924        location: Location,
925    },
926
927    #[snafu(display(
928        "Failed to upload file, region_id: {}, file_id: {}, file_type: {:?}",
929        region_id,
930        file_id,
931        file_type,
932    ))]
933    Upload {
934        region_id: RegionId,
935        file_id: FileId,
936        file_type: FileType,
937        #[snafu(source)]
938        error: std::io::Error,
939        #[snafu(implicit)]
940        location: Location,
941    },
942
943    #[snafu(display("Failed to create directory {}", dir))]
944    CreateDir {
945        dir: String,
946        #[snafu(source)]
947        error: std::io::Error,
948    },
949
950    #[snafu(display("Record batch error"))]
951    RecordBatch {
952        source: common_recordbatch::error::Error,
953        #[snafu(implicit)]
954        location: Location,
955    },
956
957    #[snafu(display("BiErrors, first: {first}, second: {second}"))]
958    BiErrors {
959        first: Box<Error>,
960        second: Box<Error>,
961        #[snafu(implicit)]
962        location: Location,
963    },
964
965    #[snafu(display("Encode null value"))]
966    IndexEncodeNull {
967        #[snafu(implicit)]
968        location: Location,
969    },
970
971    #[snafu(display("Failed to encode memtable to Parquet bytes"))]
972    EncodeMemtable {
973        #[snafu(source)]
974        error: parquet::errors::ParquetError,
975        #[snafu(implicit)]
976        location: Location,
977    },
978
979    #[snafu(display("Partition {} out of range, {} in total", given, all))]
980    PartitionOutOfRange {
981        given: usize,
982        all: usize,
983        #[snafu(implicit)]
984        location: Location,
985    },
986
987    #[snafu(display("Failed to iter data part"))]
988    ReadDataPart {
989        #[snafu(implicit)]
990        location: Location,
991        #[snafu(source)]
992        error: parquet::errors::ParquetError,
993    },
994
995    #[snafu(display("Failed to read row group in memtable"))]
996    DecodeArrowRowGroup {
997        #[snafu(source)]
998        error: ArrowError,
999        #[snafu(implicit)]
1000        location: Location,
1001    },
1002
1003    #[snafu(display("Invalid region options, {}", reason))]
1004    InvalidRegionOptions {
1005        reason: String,
1006        #[snafu(implicit)]
1007        location: Location,
1008    },
1009
1010    #[snafu(display("checksum mismatch (actual: {}, expected: {})", actual, expected))]
1011    ChecksumMismatch { actual: u32, expected: u32 },
1012
1013    #[snafu(display(
1014        "No checkpoint found, region: {}, last_version: {}",
1015        region_id,
1016        last_version
1017    ))]
1018    NoCheckpoint {
1019        region_id: RegionId,
1020        last_version: ManifestVersion,
1021        #[snafu(implicit)]
1022        location: Location,
1023    },
1024
1025    #[snafu(display(
1026        "No manifests found in range: [{}..{}), region: {}, last_version: {}",
1027        start_version,
1028        end_version,
1029        region_id,
1030        last_version
1031    ))]
1032    NoManifests {
1033        region_id: RegionId,
1034        start_version: ManifestVersion,
1035        end_version: ManifestVersion,
1036        last_version: ManifestVersion,
1037        #[snafu(implicit)]
1038        location: Location,
1039    },
1040
1041    #[snafu(display(
1042        "Failed to install manifest to {}, region: {}, available manifest version: {}, last version: {}",
1043        target_version,
1044        region_id,
1045        available_version,
1046        last_version
1047    ))]
1048    InstallManifestTo {
1049        region_id: RegionId,
1050        target_version: ManifestVersion,
1051        available_version: ManifestVersion,
1052        #[snafu(implicit)]
1053        location: Location,
1054        last_version: ManifestVersion,
1055    },
1056
1057    #[snafu(display("Region {} is stopped", region_id))]
1058    RegionStopped {
1059        region_id: RegionId,
1060        #[snafu(implicit)]
1061        location: Location,
1062    },
1063
1064    #[snafu(display(
1065        "Time range predicate overflows, timestamp: {:?}, target unit: {}",
1066        timestamp,
1067        unit
1068    ))]
1069    TimeRangePredicateOverflow {
1070        timestamp: Timestamp,
1071        unit: TimeUnit,
1072        #[snafu(implicit)]
1073        location: Location,
1074    },
1075
1076    #[snafu(display("Failed to open region"))]
1077    OpenRegion {
1078        #[snafu(implicit)]
1079        location: Location,
1080        source: Arc<Error>,
1081    },
1082
1083    #[snafu(display(
1084        "Region {} does not satisfy requirement '{}': {}",
1085        region_id,
1086        requirement,
1087        reason
1088    ))]
1089    RegionRequirement {
1090        region_id: RegionId,
1091        requirement: &'static str,
1092        reason: &'static str,
1093        #[snafu(implicit)]
1094        location: Location,
1095    },
1096
1097    #[snafu(display("Failed to parse job id"))]
1098    ParseJobId {
1099        #[snafu(implicit)]
1100        location: Location,
1101        #[snafu(source)]
1102        error: uuid::Error,
1103    },
1104
1105    #[snafu(display("Operation is not supported: {}", err_msg))]
1106    UnsupportedOperation {
1107        err_msg: String,
1108        #[snafu(implicit)]
1109        location: Location,
1110    },
1111
1112    #[snafu(display(
1113        "Failed to remotely compact region {} by job {:?} due to {}",
1114        region_id,
1115        job_id,
1116        reason
1117    ))]
1118    RemoteCompaction {
1119        region_id: RegionId,
1120        job_id: Option<JobId>,
1121        reason: String,
1122        #[snafu(implicit)]
1123        location: Location,
1124    },
1125
1126    #[snafu(display("Failed to initialize puffin stager"))]
1127    PuffinInitStager {
1128        source: puffin::error::Error,
1129        #[snafu(implicit)]
1130        location: Location,
1131    },
1132
1133    #[snafu(display("Failed to purge puffin stager"))]
1134    PuffinPurgeStager {
1135        source: puffin::error::Error,
1136        #[snafu(implicit)]
1137        location: Location,
1138    },
1139
1140    #[snafu(display("Failed to build puffin reader"))]
1141    PuffinBuildReader {
1142        source: puffin::error::Error,
1143        #[snafu(implicit)]
1144        location: Location,
1145    },
1146
1147    #[snafu(display("Failed to retrieve index options from column metadata"))]
1148    IndexOptions {
1149        #[snafu(implicit)]
1150        location: Location,
1151        source: datatypes::error::Error,
1152        column_name: String,
1153    },
1154
1155    #[snafu(display("Failed to retrieve compression options of column {column_name}"))]
1156    CompressionOptions {
1157        #[snafu(implicit)]
1158        location: Location,
1159        source: datatypes::error::Error,
1160        column_name: String,
1161    },
1162
1163    #[snafu(display("Failed to create fulltext index creator"))]
1164    CreateFulltextCreator {
1165        source: index::fulltext_index::error::Error,
1166        #[snafu(implicit)]
1167        location: Location,
1168    },
1169
1170    #[snafu(display("Failed to cast vector of {from} to {to}"))]
1171    CastVector {
1172        #[snafu(implicit)]
1173        location: Location,
1174        from: ConcreteDataType,
1175        to: ConcreteDataType,
1176        source: datatypes::error::Error,
1177    },
1178
1179    #[snafu(display("Failed to push text to fulltext index"))]
1180    FulltextPushText {
1181        source: index::fulltext_index::error::Error,
1182        #[snafu(implicit)]
1183        location: Location,
1184    },
1185
1186    #[snafu(display("Failed to finalize fulltext index creator"))]
1187    FulltextFinish {
1188        source: index::fulltext_index::error::Error,
1189        #[snafu(implicit)]
1190        location: Location,
1191    },
1192
1193    #[snafu(display("Failed to apply fulltext index"))]
1194    ApplyFulltextIndex {
1195        source: index::fulltext_index::error::Error,
1196        #[snafu(implicit)]
1197        location: Location,
1198    },
1199
1200    #[snafu(display("SST file {} does not contain valid stats info", file_path))]
1201    StatsNotPresent {
1202        file_path: String,
1203        #[snafu(implicit)]
1204        location: Location,
1205    },
1206
1207    #[snafu(display("Failed to decode stats of file {}", file_path))]
1208    DecodeStats {
1209        file_path: String,
1210        #[snafu(implicit)]
1211        location: Location,
1212    },
1213
1214    #[snafu(display("Invalid SST primary key range: {reason}"))]
1215    InvalidPrimaryKeyRange {
1216        reason: String,
1217        #[snafu(implicit)]
1218        location: Location,
1219    },
1220
1221    #[snafu(display("Failed to decode SST primary key range {endpoint} endpoint"))]
1222    DecodePrimaryKeyRange {
1223        endpoint: &'static str,
1224        source: mito_codec::error::Error,
1225        #[snafu(implicit)]
1226        location: Location,
1227    },
1228
1229    #[snafu(display("Region {} is busy", region_id))]
1230    RegionBusy {
1231        region_id: RegionId,
1232        #[snafu(implicit)]
1233        location: Location,
1234    },
1235
1236    #[snafu(display("Failed to get schema metadata"))]
1237    GetSchemaMetadata {
1238        source: common_meta::error::Error,
1239        #[snafu(implicit)]
1240        location: Location,
1241    },
1242
1243    #[snafu(display("Timeout"))]
1244    Timeout {
1245        #[snafu(source)]
1246        error: Elapsed,
1247        #[snafu(implicit)]
1248        location: Location,
1249    },
1250
1251    #[snafu(display("Failed to read file metadata"))]
1252    Metadata {
1253        #[snafu(source)]
1254        error: std::io::Error,
1255        #[snafu(implicit)]
1256        location: Location,
1257    },
1258
1259    #[snafu(display("Failed to push value to bloom filter"))]
1260    PushBloomFilterValue {
1261        source: index::bloom_filter::error::Error,
1262        #[snafu(implicit)]
1263        location: Location,
1264    },
1265
1266    #[snafu(display("Failed to finish bloom filter"))]
1267    BloomFilterFinish {
1268        source: index::bloom_filter::error::Error,
1269        #[snafu(implicit)]
1270        location: Location,
1271    },
1272
1273    #[snafu(display("Manual compaction is override by following operations."))]
1274    ManualCompactionOverride {},
1275
1276    #[snafu(display("Manual compaction is already running for region {region_id}."))]
1277    ManualCompactionAlreadyRunning { region_id: RegionId },
1278
1279    #[snafu(display("Compaction is cancelled."))]
1280    CompactionCancelled {},
1281
1282    #[snafu(display("Flush is cancelled."))]
1283    FlushCancelled {},
1284
1285    #[snafu(display("Compaction memory exhausted for region {region_id} (policy: {policy})",))]
1286    CompactionMemoryExhausted {
1287        region_id: RegionId,
1288        policy: String,
1289        #[snafu(source)]
1290        source: common_memory_manager::Error,
1291        #[snafu(implicit)]
1292        location: Location,
1293    },
1294
1295    #[snafu(display(
1296        "Incompatible WAL provider change. This is typically caused by changing WAL provider in database config file without completely cleaning existing files. Global provider: {}, region provider: {}",
1297        global,
1298        region
1299    ))]
1300    IncompatibleWalProviderChange { global: String, region: String },
1301
1302    #[snafu(display("Expected mito manifest info"))]
1303    MitoManifestInfo {
1304        #[snafu(implicit)]
1305        location: Location,
1306    },
1307
1308    #[snafu(display("Failed to scan series"))]
1309    ScanSeries {
1310        #[snafu(implicit)]
1311        location: Location,
1312        source: Arc<Error>,
1313    },
1314
1315    #[snafu(display("Partition {} scan multiple times", partition))]
1316    ScanMultiTimes {
1317        partition: usize,
1318        #[snafu(implicit)]
1319        location: Location,
1320    },
1321
1322    #[snafu(display("Invalid partition expression: {}", expr))]
1323    InvalidPartitionExpr {
1324        expr: String,
1325        #[snafu(implicit)]
1326        location: Location,
1327        source: partition::error::Error,
1328    },
1329
1330    #[snafu(display("Failed to decode bulk wal entry"))]
1331    ConvertBulkWalEntry {
1332        #[snafu(implicit)]
1333        location: Location,
1334        source: common_grpc::Error,
1335    },
1336
1337    #[snafu(display("Failed to encode"))]
1338    Encode {
1339        #[snafu(implicit)]
1340        location: Location,
1341        source: mito_codec::error::Error,
1342    },
1343
1344    #[snafu(display("Failed to decode"))]
1345    Decode {
1346        #[snafu(implicit)]
1347        location: Location,
1348        source: mito_codec::error::Error,
1349    },
1350
1351    #[snafu(display("Unexpected: {reason}"))]
1352    Unexpected {
1353        reason: String,
1354        #[snafu(implicit)]
1355        location: Location,
1356    },
1357
1358    #[cfg(feature = "enterprise")]
1359    #[snafu(display("Failed to scan external range"))]
1360    ScanExternalRange {
1361        source: BoxedError,
1362        #[snafu(implicit)]
1363        location: Location,
1364    },
1365
1366    #[snafu(display(
1367        "Inconsistent timestamp column length, expect: {}, actual: {}",
1368        expected,
1369        actual
1370    ))]
1371    InconsistentTimestampLength {
1372        expected: usize,
1373        actual: usize,
1374        #[snafu(implicit)]
1375        location: Location,
1376    },
1377
1378    #[snafu(display(
1379        "Too many files to read concurrently: {}, max allowed: {}",
1380        actual,
1381        max
1382    ))]
1383    TooManyFilesToRead {
1384        actual: usize,
1385        max: usize,
1386        #[snafu(implicit)]
1387        location: Location,
1388    },
1389
1390    #[snafu(display("Duration out of range: {input:?}"))]
1391    DurationOutOfRange {
1392        input: std::time::Duration,
1393        #[snafu(source)]
1394        error: chrono::OutOfRangeError,
1395        #[snafu(implicit)]
1396        location: Location,
1397    },
1398
1399    #[snafu(display("GC job permit exhausted"))]
1400    TooManyGcJobs {
1401        #[snafu(implicit)]
1402        location: Location,
1403    },
1404
1405    #[snafu(display(
1406        "Staging partition expr mismatch, manifest: {:?}, request: {}",
1407        manifest_expr,
1408        request_expr
1409    ))]
1410    StagingPartitionExprMismatch {
1411        manifest_expr: Option<String>,
1412        request_expr: String,
1413        #[snafu(implicit)]
1414        location: Location,
1415    },
1416
1417    #[snafu(display(
1418        "Invalid source and target region, source: {}, target: {}",
1419        source_region_id,
1420        target_region_id
1421    ))]
1422    InvalidSourceAndTargetRegion {
1423        source_region_id: RegionId,
1424        target_region_id: RegionId,
1425        #[snafu(implicit)]
1426        location: Location,
1427    },
1428
1429    #[snafu(display("Failed to prune file"))]
1430    PruneFile {
1431        source: Arc<Error>,
1432        #[snafu(implicit)]
1433        location: Location,
1434    },
1435
1436    #[snafu(display("Failed to cast column"))]
1437    CastColumn {
1438        #[snafu(source)]
1439        error: datafusion::error::DataFusionError,
1440        #[snafu(implicit)]
1441        location: Location,
1442    },
1443
1444    #[snafu(display("Failed to generate Arrow schema from Parquet file: {}", file))]
1445    ParquetToArrowSchema {
1446        file: String,
1447        #[snafu(source)]
1448        error: parquet::errors::ParquetError,
1449        #[snafu(implicit)]
1450        location: Location,
1451    },
1452
1453    #[snafu(display(
1454        "Region {} is in {:?} state, expect: Writable, Staging or Downgrading",
1455        region_id,
1456        state
1457    ))]
1458    FlushableRegionState {
1459        region_id: RegionId,
1460        state: RegionRoleState,
1461        #[snafu(implicit)]
1462        location: Location,
1463    },
1464}
1465
1466pub type Result<T, E = Error> = std::result::Result<T, E>;
1467
1468impl Error {
1469    /// Returns true if we need to fill default value for a region.
1470    pub(crate) fn is_fill_default(&self) -> bool {
1471        matches!(self, Error::FillDefault { .. })
1472    }
1473
1474    /// Returns true if the file is not found on the object store.
1475    pub(crate) fn is_object_not_found(&self) -> bool {
1476        match self {
1477            Error::OpenDal { error, .. } => error.kind() == ErrorKind::NotFound,
1478            Error::ManifestDeltaNotFound { .. } => true,
1479            Error::LoadSstMeta { source, .. }
1480            | Error::LoadParquetPage { source, .. }
1481            | Error::LoadRangeResult { source, .. } => source.is_object_not_found(),
1482            _ => false,
1483        }
1484    }
1485
1486    /// Returns whether a failed manifest update may have been persisted.
1487    ///
1488    /// Unknown errors are treated conservatively because deleting output SSTs after an ambiguous
1489    /// manifest write could leave the manifest referencing missing files. The retry layer returns
1490    /// the last attempt's error, so an error that can follow a stored attempt (throttling, or a 403
1491    /// from a revoked key, a changed bucket policy or clock skew) never proves nothing was written.
1492    pub(crate) fn may_have_persisted_manifest_update(&self) -> bool {
1493        match self {
1494            Error::UpdateManifest { .. }
1495            | Error::RegionState { .. }
1496            | Error::RegionTruncated { .. }
1497            | Error::RegionStopped { .. }
1498            | Error::SerdeJson { .. }
1499            | Error::CompressObject { .. } => false,
1500            Error::OpenDal { error, .. } => !matches!(
1501                error.kind(),
1502                ErrorKind::Unsupported
1503                    | ErrorKind::ConfigInvalid
1504                    | ErrorKind::NotFound
1505                    | ErrorKind::IsADirectory
1506                    | ErrorKind::NotADirectory
1507                    | ErrorKind::AlreadyExists
1508                    | ErrorKind::IsSameFile
1509                    | ErrorKind::ConditionNotMatch
1510                    | ErrorKind::RangeNotSatisfied
1511            ),
1512            _ => true,
1513        }
1514    }
1515}
1516
1517impl ErrorExt for Error {
1518    fn status_code(&self) -> StatusCode {
1519        use Error::*;
1520
1521        match self {
1522            DataTypeMismatch { source, .. } => source.status_code(),
1523            OpenDal { .. } | ManifestDeltaNotFound { .. } | ReadParquet { .. } => {
1524                StatusCode::StorageUnavailable
1525            }
1526            WriteWal { source, .. }
1527            | ReadWal { source, .. }
1528            | DeleteWal { source, .. }
1529            | WaitWalDurable { source, .. }
1530            | CheckWalHistory { source, .. } => source.status_code(),
1531            CompressObject { .. }
1532            | DecompressObject { .. }
1533            | SerdeJson { .. }
1534            | Utf8 { .. }
1535            | NewRecordBatch { .. }
1536            | RegionCorrupted { .. }
1537            | InconsistentFile { .. }
1538            | CreateDefault { .. }
1539            | InvalidParquet { .. }
1540            | OperateAbortedIndex { .. }
1541            | IndexEncodeNull { .. }
1542            | NoCheckpoint { .. }
1543            | NoManifests { .. }
1544            | FilesLost { .. }
1545            | InstallManifestTo { .. }
1546            | Unexpected { .. }
1547            | SerializeColumnMetadata { .. }
1548            | SerializeManifest { .. }
1549            | StagingPartitionExprMismatch { .. } => StatusCode::Unexpected,
1550
1551            RegionNotFound { .. } => StatusCode::RegionNotFound,
1552            ObjectStoreNotFound { .. }
1553            | InvalidScanIndex { .. }
1554            | InvalidMeta { .. }
1555            | InvalidRequest { .. }
1556            | PartitionExprVersionMismatch { .. }
1557            | FillDefault { .. }
1558            | ConvertColumnDataType { .. }
1559            | ColumnNotFound { .. }
1560            | InvalidMetadata { .. }
1561            | InvalidRegionOptions { .. }
1562            | InvalidWalReadRequest { .. }
1563            | PartitionOutOfRange { .. }
1564            | ParseJobId { .. }
1565            | DurationOutOfRange { .. }
1566            | MissingOldManifest { .. }
1567            | MissingNewManifest { .. }
1568            | MissingManifest { .. }
1569            | NoOldManifests { .. }
1570            | MissingPartitionExpr { .. }
1571            | SerializePartitionExpr { .. }
1572            | InvalidSourceAndTargetRegion { .. } => StatusCode::InvalidArguments,
1573
1574            IncrementalQueryStale { .. } | SnapshotFenceStale { .. } => StatusCode::RequestOutdated,
1575
1576            SequenceRangeUnsupported { .. } => StatusCode::Unsupported,
1577
1578            RegionSequenceDomainBroken { .. }
1579            | RegionMetadataNotFound { .. }
1580            | Join { .. }
1581            | WorkerStopped { .. }
1582            | Recv { .. }
1583            | DecodeWal { .. }
1584            | ComputeArrow { .. }
1585            | EvalPartitionFilter { .. }
1586            | MergeCandidateSeries { .. }
1587            | BiErrors { .. }
1588            | StopScheduler { .. }
1589            | ComputeVector { .. }
1590            | EncodeMemtable { .. }
1591            | CreateDir { .. }
1592            | ReadDataPart { .. }
1593            | BuildEntry { .. }
1594            | Metadata { .. }
1595            | CastColumn { .. }
1596            | MitoManifestInfo { .. }
1597            | ParquetToArrowSchema { .. } => StatusCode::Internal,
1598
1599            FetchManifests { source, .. } => source.status_code(),
1600
1601            OpenRegion { source, .. } => source.status_code(),
1602
1603            WriteParquet { .. } => StatusCode::StorageUnavailable,
1604            WriteGroup { source, .. }
1605            | LoadSstMeta { source, .. }
1606            | LoadParquetPage { source, .. }
1607            | LoadRangeResult { source, .. } => source.status_code(),
1608            InvalidBatch { .. } => StatusCode::InvalidArguments,
1609            InvalidRecordBatch { .. } => StatusCode::InvalidArguments,
1610            ConvertVector { source, .. } => source.status_code(),
1611
1612            PrimaryKeyLengthMismatch { .. } => StatusCode::InvalidArguments,
1613            InvalidSender { .. } => StatusCode::InvalidArguments,
1614            InvalidSchedulerState { .. } => StatusCode::InvalidArguments,
1615            RegionRequirement { .. } => StatusCode::InvalidArguments,
1616            DeleteSsts { .. } | DeleteIndex { .. } | DeleteIndexes { .. } => {
1617                StatusCode::StorageUnavailable
1618            }
1619            FlushRegion { source, .. } | BuildIndexAsync { source, .. } => source.status_code(),
1620            IndexBuildIncomplete { .. } => StatusCode::IllegalState,
1621            RegionDropped { .. } => StatusCode::Cancelled,
1622            RegionClosed { .. } => StatusCode::Cancelled,
1623            StaleCompactionExecution { .. } => StatusCode::Cancelled,
1624            RegionTruncated { .. } => StatusCode::Cancelled,
1625            RejectWrite { .. } | RejectWriteInStaging { .. } => StatusCode::StorageUnavailable,
1626            CompactRegion { source, .. } => source.status_code(),
1627            EditRegion { source, .. } => source.status_code(),
1628            CompatReader { .. } => StatusCode::Unexpected,
1629            InvalidRegionRequest { source, .. } => source.status_code(),
1630            RegionState { .. } | UpdateManifest { .. } => StatusCode::RegionNotReady,
1631            RegionLeaseExpired { .. } | UnacknowledgedWrite { .. } => StatusCode::RegionNotReady,
1632            JsonOptions { .. } => StatusCode::InvalidArguments,
1633            EmptyRegionDir { .. } | EmptyManifestDir { .. } => StatusCode::RegionNotFound,
1634            ConvertValue { source, .. } => source.status_code(),
1635            ApplyBloomFilterIndex { source, .. } => source.status_code(),
1636            InvalidPartitionExpr { source, .. } => source.status_code(),
1637            BuildIndexApplier { source, .. }
1638            | PushIndexValue { source, .. }
1639            | ApplyInvertedIndex { source, .. }
1640            | IndexFinish { source, .. } => source.status_code(),
1641            PuffinReadBlob { source, .. }
1642            | PuffinAddBlob { source, .. }
1643            | PuffinInitStager { source, .. }
1644            | PuffinBuildReader { source, .. }
1645            | PuffinPurgeStager { source, .. } => source.status_code(),
1646            CleanDir { .. } => StatusCode::Unexpected,
1647            InvalidConfig { .. } => StatusCode::InvalidArguments,
1648            StaleLogEntry { .. }
1649            | InvalidNativeHistogramSubfield { .. }
1650            | InvalidNativeHistogramFieldId { .. } => StatusCode::Unexpected,
1651
1652            External { source, .. } => source.status_code(),
1653
1654            RecordBatch { source, .. } => source.status_code(),
1655
1656            Download { .. } | Upload { .. } => StatusCode::StorageUnavailable,
1657            ChecksumMismatch { .. } => StatusCode::Unexpected,
1658            RegionStopped { .. } => StatusCode::RegionNotReady,
1659            TimeRangePredicateOverflow { .. } => StatusCode::InvalidArguments,
1660            UnsupportedOperation { .. } => StatusCode::Unsupported,
1661            RemoteCompaction { .. } => StatusCode::Unexpected,
1662
1663            IndexOptions { source, .. } => source.status_code(),
1664            CompressionOptions { source, .. } => source.status_code(),
1665            CreateFulltextCreator { source, .. } => source.status_code(),
1666            CastVector { source, .. } => source.status_code(),
1667            FulltextPushText { source, .. }
1668            | FulltextFinish { source, .. }
1669            | ApplyFulltextIndex { source, .. } => source.status_code(),
1670            DecodeStats { .. }
1671            | StatsNotPresent { .. }
1672            | InvalidPrimaryKeyRange { .. }
1673            | DecodePrimaryKeyRange { .. } => StatusCode::Internal,
1674            RegionBusy { .. } => StatusCode::RegionBusy,
1675            GetSchemaMetadata { source, .. } => source.status_code(),
1676            Timeout { .. } => StatusCode::Cancelled,
1677
1678            DecodeArrowRowGroup { .. } => StatusCode::Internal,
1679
1680            PushBloomFilterValue { source, .. } | BloomFilterFinish { source, .. } => {
1681                source.status_code()
1682            }
1683
1684            ManualCompactionOverride {} | CompactionCancelled {} | FlushCancelled {} => {
1685                StatusCode::Cancelled
1686            }
1687
1688            // A concurrent manual compaction fails fast instead of being queued;
1689            // the conflict is reported to the caller, which decides whether to
1690            // issue a new request after the running one finishes.
1691            ManualCompactionAlreadyRunning { .. } => StatusCode::RegionBusy,
1692
1693            CompactionMemoryExhausted { source, .. } => source.status_code(),
1694
1695            IncompatibleWalProviderChange { .. } => StatusCode::InvalidArguments,
1696
1697            ScanSeries { source, .. } => source.status_code(),
1698
1699            ScanMultiTimes { .. } => StatusCode::InvalidArguments,
1700            ConvertBulkWalEntry { source, .. } => source.status_code(),
1701
1702            Encode { source, .. } | Decode { source, .. } => source.status_code(),
1703
1704            #[cfg(feature = "enterprise")]
1705            ScanExternalRange { source, .. } => source.status_code(),
1706
1707            InconsistentTimestampLength { .. } => StatusCode::InvalidArguments,
1708
1709            TooManyFilesToRead { .. } | TooManyGcJobs { .. } => StatusCode::RateLimited,
1710
1711            PruneFile { source, .. } => source.status_code(),
1712
1713            FlushableRegionState { .. } => StatusCode::RegionNotReady,
1714        }
1715    }
1716
1717    fn as_any(&self) -> &dyn Any {
1718        self
1719    }
1720
1721    fn retry_hint(&self) -> RetryHint {
1722        use Error::*;
1723
1724        match self {
1725            PartitionExprVersionMismatch { .. }
1726            | RegionNotFound { .. }
1727            | RegionClosed { .. }
1728            | RejectWriteInStaging { .. }
1729            | RegionLeaseExpired { .. }
1730            | UnacknowledgedWrite { .. }
1731            | RegionState {
1732                state: RegionRoleState::Follower,
1733                ..
1734            } => RetryHint::RetryAfterRouteRefresh,
1735            ReadParquet { .. }
1736            | WriteParquet { .. }
1737            | RejectWrite { .. }
1738            | Download { .. }
1739            | Upload { .. }
1740            | RegionState { .. }
1741            | UpdateManifest { .. }
1742            | RegionStopped { .. }
1743            | RegionBusy { .. }
1744            | ManualCompactionAlreadyRunning { .. }
1745            | FlushableRegionState { .. }
1746            | ManifestDeltaNotFound { .. } => RetryHint::Retryable,
1747
1748            OpenDal { error, .. }
1749            | DeleteSsts { error, .. }
1750            | DeleteIndex { error, .. }
1751            | DeleteIndexes { error, .. } => retry_hint_from_opendal_error(error),
1752
1753            WriteWal { source, .. }
1754            | ReadWal { source, .. }
1755            | DeleteWal { source, .. }
1756            | WaitWalDurable { source, .. }
1757            | CheckWalHistory { source, .. }
1758            | FetchManifests { source, .. }
1759            | External { source, .. } => source.retry_hint(),
1760
1761            OpenRegion { source, .. }
1762            | LoadSstMeta { source, .. }
1763            | LoadParquetPage { source, .. }
1764            | LoadRangeResult { source, .. }
1765            | WriteGroup { source, .. }
1766            | FlushRegion { source, .. }
1767            | BuildIndexAsync { source, .. }
1768            | CompactRegion { source, .. }
1769            | EditRegion { source, .. }
1770            | ScanSeries { source, .. }
1771            | PruneFile { source, .. } => source.retry_hint(),
1772
1773            DataTypeMismatch { source, .. }
1774            | ConvertVector { source, .. }
1775            | ConvertValue { source, .. }
1776            | IndexOptions { source, .. }
1777            | CompressionOptions { source, .. }
1778            | CastVector { source, .. } => source.retry_hint(),
1779
1780            BuildIndexApplier { source, .. }
1781            | PushIndexValue { source, .. }
1782            | ApplyInvertedIndex { source, .. }
1783            | IndexFinish { source, .. } => source.retry_hint(),
1784
1785            ApplyBloomFilterIndex { source, .. }
1786            | PushBloomFilterValue { source, .. }
1787            | BloomFilterFinish { source, .. } => source.retry_hint(),
1788
1789            PuffinReadBlob { source, .. }
1790            | PuffinAddBlob { source, .. }
1791            | PuffinInitStager { source, .. }
1792            | PuffinBuildReader { source, .. }
1793            | PuffinPurgeStager { source, .. } => source.retry_hint(),
1794
1795            CreateFulltextCreator { source, .. }
1796            | FulltextPushText { source, .. }
1797            | FulltextFinish { source, .. }
1798            | ApplyFulltextIndex { source, .. } => source.retry_hint(),
1799
1800            InvalidRegionRequest { source, .. } => source.retry_hint(),
1801            InvalidPartitionExpr { source, .. } => source.retry_hint(),
1802            RecordBatch { source, .. } => source.retry_hint(),
1803            GetSchemaMetadata { source, .. } => source.retry_hint(),
1804            CompactionMemoryExhausted { source, .. } => source.retry_hint(),
1805            ConvertBulkWalEntry { source, .. } => source.retry_hint(),
1806            Encode { source, .. } | Decode { source, .. } => source.retry_hint(),
1807
1808            #[cfg(feature = "enterprise")]
1809            ScanExternalRange { source, .. } => source.retry_hint(),
1810
1811            _ => RetryHint::NonRetryable,
1812        }
1813    }
1814}
1815
1816#[cfg(test)]
1817mod tests {
1818    use snafu::IntoError;
1819
1820    use super::*;
1821    use crate::region::RegionLeaderState;
1822
1823    #[test]
1824    fn test_partition_version_mismatch_retry_hint() {
1825        let error = PartitionExprVersionMismatchSnafu {
1826            region_id: RegionId::new(1, 1),
1827            request_version: 1u64,
1828            expected_version: 2u64,
1829        }
1830        .build();
1831        assert_eq!(error.status_code(), StatusCode::InvalidArguments);
1832        assert_eq!(error.retry_hint(), RetryHint::RetryAfterRouteRefresh);
1833    }
1834
1835    #[test]
1836    fn test_region_state_retry_hint() {
1837        let region_id = RegionId::new(1, 1);
1838        let writable = RegionRoleState::Leader(RegionLeaderState::Writable);
1839        let follower_error = RegionStateSnafu {
1840            region_id,
1841            state: RegionRoleState::Follower,
1842            expect: writable,
1843        }
1844        .build();
1845        assert_eq!(
1846            follower_error.retry_hint(),
1847            RetryHint::RetryAfterRouteRefresh
1848        );
1849        assert_eq!(follower_error.status_code(), StatusCode::RegionNotReady);
1850        let leader_error = RegionStateSnafu {
1851            region_id,
1852            state: writable,
1853            expect: RegionRoleState::Follower,
1854        }
1855        .build();
1856        assert_eq!(leader_error.retry_hint(), RetryHint::Retryable);
1857        for (error, status, hint) in [
1858            (
1859                RejectWriteSnafu { region_id }.build(),
1860                StatusCode::StorageUnavailable,
1861                RetryHint::Retryable,
1862            ),
1863            (
1864                RejectWriteInStagingSnafu { region_id }.build(),
1865                StatusCode::StorageUnavailable,
1866                RetryHint::RetryAfterRouteRefresh,
1867            ),
1868            (
1869                RegionNotFoundSnafu { region_id }.build(),
1870                StatusCode::RegionNotFound,
1871                RetryHint::RetryAfterRouteRefresh,
1872            ),
1873            (
1874                RegionClosedSnafu { region_id }.build(),
1875                StatusCode::Cancelled,
1876                RetryHint::RetryAfterRouteRefresh,
1877            ),
1878            (
1879                RegionDroppedSnafu { region_id }.build(),
1880                StatusCode::Cancelled,
1881                RetryHint::NonRetryable,
1882            ),
1883            (
1884                RegionTruncatedSnafu { region_id }.build(),
1885                StatusCode::Cancelled,
1886                RetryHint::NonRetryable,
1887            ),
1888        ] {
1889            assert_eq!(error.status_code(), status);
1890            assert_eq!(error.retry_hint(), hint);
1891        }
1892    }
1893
1894    #[test]
1895    fn test_shared_sst_metadata_preserves_error_semantics() {
1896        for source in [
1897            OpenDalSnafu {}
1898                .into_error(object_store::Error::new(ErrorKind::NotFound, "missing SST")),
1899            OpenDalSnafu {}.into_error(object_store::Error::new(
1900                ErrorKind::Unexpected,
1901                "read failed",
1902            )),
1903            RejectWriteSnafu {
1904                region_id: RegionId::new(1, 1),
1905            }
1906            .build(),
1907        ] {
1908            let expected_not_found = source.is_object_not_found();
1909            let expected_status = source.status_code();
1910            let expected_retry = source.retry_hint();
1911            let source = Arc::new(source);
1912            for wrapped in [
1913                LoadSstMetaSnafu.into_error(source.clone()),
1914                LoadRangeResultSnafu.into_error(source),
1915            ] {
1916                assert_eq!(expected_not_found, wrapped.is_object_not_found());
1917                assert_eq!(expected_status, wrapped.status_code());
1918                assert_eq!(expected_retry, wrapped.retry_hint());
1919            }
1920        }
1921    }
1922
1923    #[test]
1924    fn test_manifest_update_persistence() {
1925        let rejected_kinds = [
1926            ErrorKind::Unsupported,
1927            ErrorKind::ConfigInvalid,
1928            ErrorKind::NotFound,
1929            ErrorKind::IsADirectory,
1930            ErrorKind::NotADirectory,
1931            ErrorKind::AlreadyExists,
1932            ErrorKind::IsSameFile,
1933            ErrorKind::ConditionNotMatch,
1934            ErrorKind::RangeNotSatisfied,
1935        ];
1936        for kind in rejected_kinds {
1937            let error = OpenDalSnafu {}.into_error(object_store::Error::new(kind, "test"));
1938            assert!(
1939                !error.may_have_persisted_manifest_update(),
1940                "error kind {kind:?} should prove the manifest was not persisted"
1941            );
1942        }
1943
1944        // The last retry can fail with these kinds even though an earlier attempt was stored.
1945        for kind in [
1946            ErrorKind::Unexpected,
1947            ErrorKind::RateLimited,
1948            ErrorKind::PermissionDenied,
1949        ] {
1950            let error = OpenDalSnafu {}.into_error(object_store::Error::new(kind, "test"));
1951            assert!(
1952                error.may_have_persisted_manifest_update(),
1953                "error kind {kind:?} should not prove the manifest was not persisted"
1954            );
1955        }
1956
1957        let region_id = RegionId::new(1, 1);
1958        let error = RegionTruncatedSnafu { region_id }.build();
1959        assert!(!error.may_have_persisted_manifest_update());
1960
1961        // This can be raised while applying an edit after its manifest file was saved.
1962        let error = RegionMetadataNotFoundSnafu {}.build();
1963        assert!(error.may_have_persisted_manifest_update());
1964    }
1965}