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 write parquet file"))]
202    WriteParquet {
203        #[snafu(source)]
204        error: parquet::errors::ParquetError,
205        #[snafu(implicit)]
206        location: Location,
207    },
208
209    #[snafu(display(
210        "Cannot assign a stable field id to native histogram sub-field '{}' of column id {} (unknown sub-field name or derived id overflows i32)",
211        field_name,
212        column_id
213    ))]
214    InvalidNativeHistogramSubfield {
215        column_id: i32,
216        field_name: String,
217        #[snafu(implicit)]
218        location: Location,
219    },
220
221    #[snafu(display(
222        "Native histogram column '{}' has no usable PARQUET:field_id to namespace its sub-field ids (missing, malformed, or exceeds i32::MAX)",
223        field_name
224    ))]
225    InvalidNativeHistogramFieldId {
226        field_name: String,
227        #[snafu(implicit)]
228        location: Location,
229    },
230
231    #[snafu(display("Region {} not found", region_id))]
232    RegionNotFound {
233        region_id: RegionId,
234        #[snafu(implicit)]
235        location: Location,
236    },
237
238    #[snafu(display("Object store not found: {}", object_store))]
239    ObjectStoreNotFound {
240        object_store: String,
241        #[snafu(implicit)]
242        location: Location,
243    },
244
245    #[snafu(display("Region {} is corrupted, reason: {}", region_id, reason))]
246    RegionCorrupted {
247        region_id: RegionId,
248        reason: String,
249        #[snafu(implicit)]
250        location: Location,
251    },
252
253    #[snafu(display("Invalid request to region {}, reason: {}", region_id, reason))]
254    InvalidRequest {
255        region_id: RegionId,
256        reason: String,
257        #[snafu(implicit)]
258        location: Location,
259    },
260
261    #[snafu(display(
262        "STALE_CURSOR: incremental query stale, region: {}, given_seq: {}, min_readable_seq: {}, retry_hint: FALLBACK_FULL_RECOMPUTE",
263        region_id,
264        given_seq,
265        min_readable_seq
266    ))]
267    IncrementalQueryStale {
268        region_id: RegionId,
269        given_seq: u64,
270        min_readable_seq: u64,
271        #[snafu(implicit)]
272        location: Location,
273    },
274
275    #[snafu(display(
276        "STALE_SNAPSHOT_FENCE: snapshot upper bound stale, region: {}, given_seq: {}, min_enforceable_seq: {}, retry_hint: REBIND_SNAPSHOT_FENCE",
277        region_id,
278        given_seq,
279        min_enforceable_seq
280    ))]
281    SnapshotFenceStale {
282        region_id: RegionId,
283        given_seq: u64,
284        min_enforceable_seq: u64,
285        #[snafu(implicit)]
286        location: Location,
287    },
288
289    #[snafu(display("Old manifest missing for region {}", region_id))]
290    MissingOldManifest {
291        region_id: RegionId,
292        #[snafu(implicit)]
293        location: Location,
294    },
295
296    #[snafu(display("New manifest missing for region {}", region_id))]
297    MissingNewManifest {
298        region_id: RegionId,
299        #[snafu(implicit)]
300        location: Location,
301    },
302
303    #[snafu(display("Manifest missing for region {}", region_id))]
304    MissingManifest {
305        region_id: RegionId,
306        #[snafu(implicit)]
307        location: Location,
308    },
309
310    #[snafu(display("File consistency check failed for file {}: {}", file_id, reason))]
311    InconsistentFile {
312        file_id: FileId,
313        reason: String,
314        #[snafu(implicit)]
315        location: Location,
316    },
317
318    #[snafu(display("Files lost during remapping: old={}, new={}", old_count, new_count))]
319    FilesLost {
320        old_count: usize,
321        new_count: usize,
322        #[snafu(implicit)]
323        location: Location,
324    },
325
326    #[snafu(display("No old manifests provided (need at least one for template)"))]
327    NoOldManifests {
328        #[snafu(implicit)]
329        location: Location,
330    },
331
332    #[snafu(display("Failed to fetch manifests"))]
333    FetchManifests {
334        #[snafu(implicit)]
335        location: Location,
336        source: BoxedError,
337    },
338
339    #[snafu(display("Partition expression missing for region {}", region_id))]
340    MissingPartitionExpr {
341        region_id: RegionId,
342        #[snafu(implicit)]
343        location: Location,
344    },
345
346    #[snafu(display("Failed to serialize partition expression: {}", source))]
347    SerializePartitionExpr {
348        #[snafu(source)]
349        source: PartitionError,
350        #[snafu(implicit)]
351        location: Location,
352    },
353
354    #[snafu(display(
355        "Failed to convert ConcreteDataType to ColumnDataType, reason: {}",
356        reason
357    ))]
358    ConvertColumnDataType {
359        reason: String,
360        source: api::error::Error,
361        #[snafu(implicit)]
362        location: Location,
363    },
364
365    /// An error type to indicate that schema is changed and we need
366    /// to fill default values again.
367    #[snafu(display("Need to fill default value for region {}", region_id))]
368    FillDefault {
369        region_id: RegionId,
370        // The error is for internal use so we don't need a location.
371    },
372
373    #[snafu(display(
374        "Failed to create default value for column {} of region {}",
375        column,
376        region_id
377    ))]
378    CreateDefault {
379        region_id: RegionId,
380        column: String,
381        source: datatypes::Error,
382        #[snafu(implicit)]
383        location: Location,
384    },
385
386    #[snafu(display("Failed to build entry, region_id: {}", region_id))]
387    BuildEntry {
388        region_id: RegionId,
389        #[snafu(implicit)]
390        location: Location,
391        source: BoxedError,
392    },
393
394    #[snafu(display("Failed to write WAL"))]
395    WriteWal {
396        #[snafu(implicit)]
397        location: Location,
398        source: BoxedError,
399    },
400
401    #[snafu(display("Failed to read WAL, provider: {}", provider))]
402    ReadWal {
403        provider: Provider,
404        #[snafu(implicit)]
405        location: Location,
406        source: BoxedError,
407    },
408
409    #[snafu(display("Failed to decode WAL entry, region_id: {}", region_id))]
410    DecodeWal {
411        region_id: RegionId,
412        #[snafu(implicit)]
413        location: Location,
414        #[snafu(source)]
415        error: DecodeError,
416    },
417
418    #[snafu(display("Failed to delete WAL, region_id: {}", region_id))]
419    DeleteWal {
420        region_id: RegionId,
421        #[snafu(implicit)]
422        location: Location,
423        source: BoxedError,
424    },
425
426    // Shared error for each writer in the write group.
427    #[snafu(display("Failed to write region"))]
428    WriteGroup { source: Arc<Error> },
429
430    #[snafu(display("Invalid parquet SST file {}, reason: {}", file, reason))]
431    InvalidParquet {
432        file: String,
433        reason: String,
434        #[snafu(implicit)]
435        location: Location,
436    },
437
438    #[snafu(display("Invalid batch, {}", reason))]
439    InvalidBatch {
440        reason: String,
441        #[snafu(implicit)]
442        location: Location,
443    },
444
445    #[snafu(display("Invalid arrow record batch, {}", reason))]
446    InvalidRecordBatch {
447        reason: String,
448        #[snafu(implicit)]
449        location: Location,
450    },
451
452    #[snafu(display("Invalid wal read request, {}", reason))]
453    InvalidWalReadRequest {
454        reason: String,
455        #[snafu(implicit)]
456        location: Location,
457    },
458
459    #[snafu(display("Failed to convert array to vector"))]
460    ConvertVector {
461        #[snafu(implicit)]
462        location: Location,
463        source: datatypes::error::Error,
464    },
465
466    #[snafu(display("Failed to compute arrow arrays"))]
467    ComputeArrow {
468        #[snafu(implicit)]
469        location: Location,
470        #[snafu(source)]
471        error: datatypes::arrow::error::ArrowError,
472    },
473
474    #[snafu(display("Failed to evaluate partition filter"))]
475    EvalPartitionFilter {
476        #[snafu(implicit)]
477        location: Location,
478        #[snafu(source)]
479        error: datafusion::error::DataFusionError,
480    },
481
482    #[snafu(display("Failed to merge candidate series"))]
483    MergeCandidateSeries {
484        #[snafu(implicit)]
485        location: Location,
486        #[snafu(source)]
487        error: datafusion::error::DataFusionError,
488    },
489
490    #[snafu(display("Failed to compute vector"))]
491    ComputeVector {
492        #[snafu(implicit)]
493        location: Location,
494        source: datatypes::error::Error,
495    },
496
497    #[snafu(display("Primary key length mismatch, expect: {}, actual: {}", expect, actual))]
498    PrimaryKeyLengthMismatch {
499        expect: usize,
500        actual: usize,
501        #[snafu(implicit)]
502        location: Location,
503    },
504
505    #[snafu(display("Invalid sender",))]
506    InvalidSender {
507        #[snafu(implicit)]
508        location: Location,
509    },
510
511    #[snafu(display("Invalid scheduler state"))]
512    InvalidSchedulerState {
513        #[snafu(implicit)]
514        location: Location,
515    },
516
517    #[snafu(display("Failed to stop scheduler"))]
518    StopScheduler {
519        #[snafu(source)]
520        error: JoinError,
521        #[snafu(implicit)]
522        location: Location,
523    },
524
525    #[snafu(display(
526        "Failed to batch delete SST files, region id: {}, file ids: {:?}",
527        region_id,
528        file_ids
529    ))]
530    DeleteSsts {
531        region_id: RegionId,
532        file_ids: Vec<FileId>,
533        #[snafu(source)]
534        error: object_store::Error,
535        #[snafu(implicit)]
536        location: Location,
537    },
538
539    #[snafu(display("Failed to delete index file, file id: {}", file_id))]
540    DeleteIndex {
541        file_id: FileId,
542        #[snafu(source)]
543        error: object_store::Error,
544        #[snafu(implicit)]
545        location: Location,
546    },
547
548    #[snafu(display("Failed to batch delete index files, file ids: {:?}", file_ids))]
549    DeleteIndexes {
550        file_ids: Vec<FileId>,
551        #[snafu(source)]
552        error: object_store::Error,
553        #[snafu(implicit)]
554        location: Location,
555    },
556
557    #[snafu(display("Failed to flush region {}", region_id))]
558    FlushRegion {
559        region_id: RegionId,
560        source: Arc<Error>,
561        #[snafu(implicit)]
562        location: Location,
563    },
564
565    #[snafu(display("Region {} is dropped", region_id))]
566    RegionDropped {
567        region_id: RegionId,
568        #[snafu(implicit)]
569        location: Location,
570    },
571
572    #[snafu(display("Region {} is closed", region_id))]
573    RegionClosed {
574        region_id: RegionId,
575        #[snafu(implicit)]
576        location: Location,
577    },
578
579    #[snafu(display(
580        "Stale compaction execution for region {}, the region may have been reopened, truncated or the compaction was superseded",
581        region_id
582    ))]
583    StaleCompactionExecution {
584        region_id: RegionId,
585        #[snafu(implicit)]
586        location: Location,
587    },
588
589    #[snafu(display("Region {} is truncated", region_id))]
590    RegionTruncated {
591        region_id: RegionId,
592        #[snafu(implicit)]
593        location: Location,
594    },
595
596    #[snafu(display(
597        "Engine write buffer is full, rejecting write requests of region {}",
598        region_id,
599    ))]
600    RejectWrite {
601        region_id: RegionId,
602        #[snafu(implicit)]
603        location: Location,
604    },
605
606    #[snafu(display("Failed to compact region {}", region_id))]
607    CompactRegion {
608        region_id: RegionId,
609        source: Arc<Error>,
610        #[snafu(implicit)]
611        location: Location,
612    },
613
614    #[snafu(display("Failed to edit region {}", region_id))]
615    EditRegion {
616        region_id: RegionId,
617        source: Arc<Error>,
618        #[snafu(implicit)]
619        location: Location,
620    },
621
622    #[snafu(display(
623        "Failed to compat readers for region {}, reason: {}",
624        region_id,
625        reason,
626    ))]
627    CompatReader {
628        region_id: RegionId,
629        reason: String,
630        #[snafu(implicit)]
631        location: Location,
632    },
633
634    #[snafu(display("Invalue region req"))]
635    InvalidRegionRequest {
636        source: store_api::metadata::MetadataError,
637        #[snafu(implicit)]
638        location: Location,
639    },
640
641    #[snafu(display(
642        "Region {} is in {:?} state, which does not permit manifest updates.",
643        region_id,
644        state
645    ))]
646    UpdateManifest {
647        region_id: RegionId,
648        state: RegionRoleState,
649        #[snafu(implicit)]
650        location: Location,
651    },
652
653    #[snafu(display("Region {} is in {:?} state, expect: {:?}", region_id, state, expect))]
654    RegionState {
655        region_id: RegionId,
656        state: RegionRoleState,
657        expect: RegionRoleState,
658        #[snafu(implicit)]
659        location: Location,
660    },
661
662    #[snafu(display(
663        "Partition expr version mismatch for region {}: request {}, expected {}",
664        region_id,
665        request_version,
666        expected_version
667    ))]
668    PartitionExprVersionMismatch {
669        region_id: RegionId,
670        request_version: u64,
671        expected_version: u64,
672        #[snafu(implicit)]
673        location: Location,
674    },
675
676    #[snafu(display("Invalid options"))]
677    JsonOptions {
678        #[snafu(source)]
679        error: serde_json::Error,
680        #[snafu(implicit)]
681        location: Location,
682    },
683
684    #[snafu(display(
685        "Empty region directory, region_id: {}, region_dir: {}",
686        region_id,
687        region_dir,
688    ))]
689    EmptyRegionDir {
690        region_id: RegionId,
691        region_dir: String,
692        #[snafu(implicit)]
693        location: Location,
694    },
695
696    #[snafu(display("Empty manifest directory, manifest_dir: {}", manifest_dir,))]
697    EmptyManifestDir {
698        manifest_dir: String,
699        #[snafu(implicit)]
700        location: Location,
701    },
702
703    #[snafu(display("Column not found, column: {column}"))]
704    ColumnNotFound {
705        column: String,
706        #[snafu(implicit)]
707        location: Location,
708    },
709
710    #[snafu(display("Failed to build index applier"))]
711    BuildIndexApplier {
712        source: index::inverted_index::error::Error,
713        #[snafu(implicit)]
714        location: Location,
715    },
716
717    #[snafu(display("Failed to build index asynchronously in region {}", region_id))]
718    BuildIndexAsync {
719        region_id: RegionId,
720        source: Arc<Error>,
721        #[snafu(implicit)]
722        location: Location,
723    },
724
725    #[snafu(display("Failed to convert value"))]
726    ConvertValue {
727        source: datatypes::error::Error,
728        #[snafu(implicit)]
729        location: Location,
730    },
731
732    #[snafu(display("Failed to apply inverted index"))]
733    ApplyInvertedIndex {
734        source: index::inverted_index::error::Error,
735        #[snafu(implicit)]
736        location: Location,
737    },
738
739    #[snafu(display("Failed to apply bloom filter index"))]
740    ApplyBloomFilterIndex {
741        source: index::bloom_filter::error::Error,
742        #[snafu(implicit)]
743        location: Location,
744    },
745
746    #[cfg(feature = "vector_index")]
747    #[snafu(display("Failed to apply vector index: {}", reason))]
748    ApplyVectorIndex {
749        reason: String,
750        #[snafu(implicit)]
751        location: Location,
752    },
753
754    #[snafu(display("Failed to push index value"))]
755    PushIndexValue {
756        source: index::inverted_index::error::Error,
757        #[snafu(implicit)]
758        location: Location,
759    },
760
761    #[snafu(display("Failed to write index completely"))]
762    IndexFinish {
763        source: index::inverted_index::error::Error,
764        #[snafu(implicit)]
765        location: Location,
766    },
767
768    #[snafu(display("Operate on aborted index"))]
769    OperateAbortedIndex {
770        #[snafu(implicit)]
771        location: Location,
772    },
773
774    #[snafu(display("Failed to read puffin blob"))]
775    PuffinReadBlob {
776        source: puffin::error::Error,
777        #[snafu(implicit)]
778        location: Location,
779    },
780
781    #[snafu(display("Failed to add blob to puffin file"))]
782    PuffinAddBlob {
783        source: puffin::error::Error,
784        #[snafu(implicit)]
785        location: Location,
786    },
787
788    #[snafu(display("Failed to clean dir {dir}"))]
789    CleanDir {
790        dir: String,
791        #[snafu(source)]
792        error: std::io::Error,
793        #[snafu(implicit)]
794        location: Location,
795    },
796
797    #[snafu(display("Invalid config, {reason}"))]
798    InvalidConfig {
799        reason: String,
800        #[snafu(implicit)]
801        location: Location,
802    },
803
804    #[snafu(display(
805        "Stale log entry found during replay, region: {}, flushed: {}, replayed: {}",
806        region_id,
807        flushed_entry_id,
808        unexpected_entry_id
809    ))]
810    StaleLogEntry {
811        region_id: RegionId,
812        flushed_entry_id: u64,
813        unexpected_entry_id: u64,
814    },
815
816    #[snafu(display(
817        "Failed to download file, region_id: {}, file_id: {}, file_type: {:?}",
818        region_id,
819        file_id,
820        file_type,
821    ))]
822    Download {
823        region_id: RegionId,
824        file_id: FileId,
825        file_type: FileType,
826        #[snafu(source)]
827        error: std::io::Error,
828        #[snafu(implicit)]
829        location: Location,
830    },
831
832    #[snafu(display(
833        "Failed to upload file, region_id: {}, file_id: {}, file_type: {:?}",
834        region_id,
835        file_id,
836        file_type,
837    ))]
838    Upload {
839        region_id: RegionId,
840        file_id: FileId,
841        file_type: FileType,
842        #[snafu(source)]
843        error: std::io::Error,
844        #[snafu(implicit)]
845        location: Location,
846    },
847
848    #[snafu(display("Failed to create directory {}", dir))]
849    CreateDir {
850        dir: String,
851        #[snafu(source)]
852        error: std::io::Error,
853    },
854
855    #[snafu(display("Record batch error"))]
856    RecordBatch {
857        source: common_recordbatch::error::Error,
858        #[snafu(implicit)]
859        location: Location,
860    },
861
862    #[snafu(display("BiErrors, first: {first}, second: {second}"))]
863    BiErrors {
864        first: Box<Error>,
865        second: Box<Error>,
866        #[snafu(implicit)]
867        location: Location,
868    },
869
870    #[snafu(display("Encode null value"))]
871    IndexEncodeNull {
872        #[snafu(implicit)]
873        location: Location,
874    },
875
876    #[snafu(display("Failed to encode memtable to Parquet bytes"))]
877    EncodeMemtable {
878        #[snafu(source)]
879        error: parquet::errors::ParquetError,
880        #[snafu(implicit)]
881        location: Location,
882    },
883
884    #[snafu(display("Partition {} out of range, {} in total", given, all))]
885    PartitionOutOfRange {
886        given: usize,
887        all: usize,
888        #[snafu(implicit)]
889        location: Location,
890    },
891
892    #[snafu(display("Failed to iter data part"))]
893    ReadDataPart {
894        #[snafu(implicit)]
895        location: Location,
896        #[snafu(source)]
897        error: parquet::errors::ParquetError,
898    },
899
900    #[snafu(display("Failed to read row group in memtable"))]
901    DecodeArrowRowGroup {
902        #[snafu(source)]
903        error: ArrowError,
904        #[snafu(implicit)]
905        location: Location,
906    },
907
908    #[snafu(display("Invalid region options, {}", reason))]
909    InvalidRegionOptions {
910        reason: String,
911        #[snafu(implicit)]
912        location: Location,
913    },
914
915    #[snafu(display("checksum mismatch (actual: {}, expected: {})", actual, expected))]
916    ChecksumMismatch { actual: u32, expected: u32 },
917
918    #[snafu(display(
919        "No checkpoint found, region: {}, last_version: {}",
920        region_id,
921        last_version
922    ))]
923    NoCheckpoint {
924        region_id: RegionId,
925        last_version: ManifestVersion,
926        #[snafu(implicit)]
927        location: Location,
928    },
929
930    #[snafu(display(
931        "No manifests found in range: [{}..{}), region: {}, last_version: {}",
932        start_version,
933        end_version,
934        region_id,
935        last_version
936    ))]
937    NoManifests {
938        region_id: RegionId,
939        start_version: ManifestVersion,
940        end_version: ManifestVersion,
941        last_version: ManifestVersion,
942        #[snafu(implicit)]
943        location: Location,
944    },
945
946    #[snafu(display(
947        "Failed to install manifest to {}, region: {}, available manifest version: {}, last version: {}",
948        target_version,
949        region_id,
950        available_version,
951        last_version
952    ))]
953    InstallManifestTo {
954        region_id: RegionId,
955        target_version: ManifestVersion,
956        available_version: ManifestVersion,
957        #[snafu(implicit)]
958        location: Location,
959        last_version: ManifestVersion,
960    },
961
962    #[snafu(display("Region {} is stopped", region_id))]
963    RegionStopped {
964        region_id: RegionId,
965        #[snafu(implicit)]
966        location: Location,
967    },
968
969    #[snafu(display(
970        "Time range predicate overflows, timestamp: {:?}, target unit: {}",
971        timestamp,
972        unit
973    ))]
974    TimeRangePredicateOverflow {
975        timestamp: Timestamp,
976        unit: TimeUnit,
977        #[snafu(implicit)]
978        location: Location,
979    },
980
981    #[snafu(display("Failed to open region"))]
982    OpenRegion {
983        #[snafu(implicit)]
984        location: Location,
985        source: Arc<Error>,
986    },
987
988    #[snafu(display(
989        "Region {} does not satisfy requirement '{}': {}",
990        region_id,
991        requirement,
992        reason
993    ))]
994    RegionRequirement {
995        region_id: RegionId,
996        requirement: &'static str,
997        reason: &'static str,
998        #[snafu(implicit)]
999        location: Location,
1000    },
1001
1002    #[snafu(display("Failed to parse job id"))]
1003    ParseJobId {
1004        #[snafu(implicit)]
1005        location: Location,
1006        #[snafu(source)]
1007        error: uuid::Error,
1008    },
1009
1010    #[snafu(display("Operation is not supported: {}", err_msg))]
1011    UnsupportedOperation {
1012        err_msg: String,
1013        #[snafu(implicit)]
1014        location: Location,
1015    },
1016
1017    #[snafu(display(
1018        "Failed to remotely compact region {} by job {:?} due to {}",
1019        region_id,
1020        job_id,
1021        reason
1022    ))]
1023    RemoteCompaction {
1024        region_id: RegionId,
1025        job_id: Option<JobId>,
1026        reason: String,
1027        #[snafu(implicit)]
1028        location: Location,
1029    },
1030
1031    #[snafu(display("Failed to initialize puffin stager"))]
1032    PuffinInitStager {
1033        source: puffin::error::Error,
1034        #[snafu(implicit)]
1035        location: Location,
1036    },
1037
1038    #[snafu(display("Failed to purge puffin stager"))]
1039    PuffinPurgeStager {
1040        source: puffin::error::Error,
1041        #[snafu(implicit)]
1042        location: Location,
1043    },
1044
1045    #[snafu(display("Failed to build puffin reader"))]
1046    PuffinBuildReader {
1047        source: puffin::error::Error,
1048        #[snafu(implicit)]
1049        location: Location,
1050    },
1051
1052    #[snafu(display("Failed to retrieve index options from column metadata"))]
1053    IndexOptions {
1054        #[snafu(implicit)]
1055        location: Location,
1056        source: datatypes::error::Error,
1057        column_name: String,
1058    },
1059
1060    #[snafu(display("Failed to create fulltext index creator"))]
1061    CreateFulltextCreator {
1062        source: index::fulltext_index::error::Error,
1063        #[snafu(implicit)]
1064        location: Location,
1065    },
1066
1067    #[snafu(display("Failed to cast vector of {from} to {to}"))]
1068    CastVector {
1069        #[snafu(implicit)]
1070        location: Location,
1071        from: ConcreteDataType,
1072        to: ConcreteDataType,
1073        source: datatypes::error::Error,
1074    },
1075
1076    #[snafu(display("Failed to push text to fulltext index"))]
1077    FulltextPushText {
1078        source: index::fulltext_index::error::Error,
1079        #[snafu(implicit)]
1080        location: Location,
1081    },
1082
1083    #[snafu(display("Failed to finalize fulltext index creator"))]
1084    FulltextFinish {
1085        source: index::fulltext_index::error::Error,
1086        #[snafu(implicit)]
1087        location: Location,
1088    },
1089
1090    #[snafu(display("Failed to apply fulltext index"))]
1091    ApplyFulltextIndex {
1092        source: index::fulltext_index::error::Error,
1093        #[snafu(implicit)]
1094        location: Location,
1095    },
1096
1097    #[snafu(display("SST file {} does not contain valid stats info", file_path))]
1098    StatsNotPresent {
1099        file_path: String,
1100        #[snafu(implicit)]
1101        location: Location,
1102    },
1103
1104    #[snafu(display("Failed to decode stats of file {}", file_path))]
1105    DecodeStats {
1106        file_path: String,
1107        #[snafu(implicit)]
1108        location: Location,
1109    },
1110
1111    #[snafu(display("Region {} is busy", region_id))]
1112    RegionBusy {
1113        region_id: RegionId,
1114        #[snafu(implicit)]
1115        location: Location,
1116    },
1117
1118    #[snafu(display("Failed to get schema metadata"))]
1119    GetSchemaMetadata {
1120        source: common_meta::error::Error,
1121        #[snafu(implicit)]
1122        location: Location,
1123    },
1124
1125    #[snafu(display("Timeout"))]
1126    Timeout {
1127        #[snafu(source)]
1128        error: Elapsed,
1129        #[snafu(implicit)]
1130        location: Location,
1131    },
1132
1133    #[snafu(display("Failed to read file metadata"))]
1134    Metadata {
1135        #[snafu(source)]
1136        error: std::io::Error,
1137        #[snafu(implicit)]
1138        location: Location,
1139    },
1140
1141    #[snafu(display("Failed to push value to bloom filter"))]
1142    PushBloomFilterValue {
1143        source: index::bloom_filter::error::Error,
1144        #[snafu(implicit)]
1145        location: Location,
1146    },
1147
1148    #[snafu(display("Failed to finish bloom filter"))]
1149    BloomFilterFinish {
1150        source: index::bloom_filter::error::Error,
1151        #[snafu(implicit)]
1152        location: Location,
1153    },
1154
1155    #[cfg(feature = "vector_index")]
1156    #[snafu(display("Failed to build vector index: {}", reason))]
1157    VectorIndexBuild {
1158        reason: String,
1159        #[snafu(implicit)]
1160        location: Location,
1161    },
1162
1163    #[cfg(feature = "vector_index")]
1164    #[snafu(display("Failed to finish vector index: {}", reason))]
1165    VectorIndexFinish {
1166        reason: String,
1167        #[snafu(implicit)]
1168        location: Location,
1169    },
1170
1171    #[snafu(display("Manual compaction is override by following operations."))]
1172    ManualCompactionOverride {},
1173
1174    #[snafu(display("Manual compaction is already running for region {region_id}."))]
1175    ManualCompactionAlreadyRunning { region_id: RegionId },
1176
1177    #[snafu(display("Compaction is cancelled."))]
1178    CompactionCancelled {},
1179
1180    #[snafu(display("Flush is cancelled."))]
1181    FlushCancelled {},
1182
1183    #[snafu(display("Compaction memory exhausted for region {region_id} (policy: {policy})",))]
1184    CompactionMemoryExhausted {
1185        region_id: RegionId,
1186        policy: String,
1187        #[snafu(source)]
1188        source: common_memory_manager::Error,
1189        #[snafu(implicit)]
1190        location: Location,
1191    },
1192
1193    #[snafu(display(
1194        "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: {}",
1195        global,
1196        region
1197    ))]
1198    IncompatibleWalProviderChange { global: String, region: String },
1199
1200    #[snafu(display("Expected mito manifest info"))]
1201    MitoManifestInfo {
1202        #[snafu(implicit)]
1203        location: Location,
1204    },
1205
1206    #[snafu(display("Failed to scan series"))]
1207    ScanSeries {
1208        #[snafu(implicit)]
1209        location: Location,
1210        source: Arc<Error>,
1211    },
1212
1213    #[snafu(display("Partition {} scan multiple times", partition))]
1214    ScanMultiTimes {
1215        partition: usize,
1216        #[snafu(implicit)]
1217        location: Location,
1218    },
1219
1220    #[snafu(display("Invalid partition expression: {}", expr))]
1221    InvalidPartitionExpr {
1222        expr: String,
1223        #[snafu(implicit)]
1224        location: Location,
1225        source: partition::error::Error,
1226    },
1227
1228    #[snafu(display("Failed to decode bulk wal entry"))]
1229    ConvertBulkWalEntry {
1230        #[snafu(implicit)]
1231        location: Location,
1232        source: common_grpc::Error,
1233    },
1234
1235    #[snafu(display("Failed to encode"))]
1236    Encode {
1237        #[snafu(implicit)]
1238        location: Location,
1239        source: mito_codec::error::Error,
1240    },
1241
1242    #[snafu(display("Failed to decode"))]
1243    Decode {
1244        #[snafu(implicit)]
1245        location: Location,
1246        source: mito_codec::error::Error,
1247    },
1248
1249    #[snafu(display("Unexpected: {reason}"))]
1250    Unexpected {
1251        reason: String,
1252        #[snafu(implicit)]
1253        location: Location,
1254    },
1255
1256    #[cfg(feature = "enterprise")]
1257    #[snafu(display("Failed to scan external range"))]
1258    ScanExternalRange {
1259        source: BoxedError,
1260        #[snafu(implicit)]
1261        location: Location,
1262    },
1263
1264    #[snafu(display(
1265        "Inconsistent timestamp column length, expect: {}, actual: {}",
1266        expected,
1267        actual
1268    ))]
1269    InconsistentTimestampLength {
1270        expected: usize,
1271        actual: usize,
1272        #[snafu(implicit)]
1273        location: Location,
1274    },
1275
1276    #[snafu(display(
1277        "Too many files to read concurrently: {}, max allowed: {}",
1278        actual,
1279        max
1280    ))]
1281    TooManyFilesToRead {
1282        actual: usize,
1283        max: usize,
1284        #[snafu(implicit)]
1285        location: Location,
1286    },
1287
1288    #[snafu(display("Duration out of range: {input:?}"))]
1289    DurationOutOfRange {
1290        input: std::time::Duration,
1291        #[snafu(source)]
1292        error: chrono::OutOfRangeError,
1293        #[snafu(implicit)]
1294        location: Location,
1295    },
1296
1297    #[snafu(display("GC job permit exhausted"))]
1298    TooManyGcJobs {
1299        #[snafu(implicit)]
1300        location: Location,
1301    },
1302
1303    #[snafu(display(
1304        "Staging partition expr mismatch, manifest: {:?}, request: {}",
1305        manifest_expr,
1306        request_expr
1307    ))]
1308    StagingPartitionExprMismatch {
1309        manifest_expr: Option<String>,
1310        request_expr: String,
1311        #[snafu(implicit)]
1312        location: Location,
1313    },
1314
1315    #[snafu(display(
1316        "Invalid source and target region, source: {}, target: {}",
1317        source_region_id,
1318        target_region_id
1319    ))]
1320    InvalidSourceAndTargetRegion {
1321        source_region_id: RegionId,
1322        target_region_id: RegionId,
1323        #[snafu(implicit)]
1324        location: Location,
1325    },
1326
1327    #[snafu(display("Failed to prune file"))]
1328    PruneFile {
1329        source: Arc<Error>,
1330        #[snafu(implicit)]
1331        location: Location,
1332    },
1333
1334    #[snafu(display("Failed to cast column"))]
1335    CastColumn {
1336        #[snafu(source)]
1337        error: datafusion::error::DataFusionError,
1338        #[snafu(implicit)]
1339        location: Location,
1340    },
1341
1342    #[snafu(display("Failed to generate Arrow schema from Parquet file: {}", file))]
1343    ParquetToArrowSchema {
1344        file: String,
1345        #[snafu(source)]
1346        error: parquet::errors::ParquetError,
1347        #[snafu(implicit)]
1348        location: Location,
1349    },
1350
1351    #[snafu(display(
1352        "Region {} is in {:?} state, expect: Writable, Staging or Downgrading",
1353        region_id,
1354        state
1355    ))]
1356    FlushableRegionState {
1357        region_id: RegionId,
1358        state: RegionRoleState,
1359        #[snafu(implicit)]
1360        location: Location,
1361    },
1362}
1363
1364pub type Result<T, E = Error> = std::result::Result<T, E>;
1365
1366impl Error {
1367    /// Returns true if we need to fill default value for a region.
1368    pub(crate) fn is_fill_default(&self) -> bool {
1369        matches!(self, Error::FillDefault { .. })
1370    }
1371
1372    /// Returns true if the file is not found on the object store.
1373    pub(crate) fn is_object_not_found(&self) -> bool {
1374        match self {
1375            Error::OpenDal { error, .. } => error.kind() == ErrorKind::NotFound,
1376            Error::ManifestDeltaNotFound { .. } => true,
1377            _ => false,
1378        }
1379    }
1380
1381    /// Returns whether a failed manifest update may have been persisted.
1382    ///
1383    /// Unknown errors are treated conservatively because deleting output SSTs after an ambiguous
1384    /// manifest write could leave the manifest referencing missing files.
1385    pub(crate) fn may_have_persisted_manifest_update(&self) -> bool {
1386        match self {
1387            Error::UpdateManifest { .. }
1388            | Error::RegionState { .. }
1389            | Error::RegionTruncated { .. }
1390            | Error::RegionStopped { .. }
1391            | Error::SerdeJson { .. }
1392            | Error::CompressObject { .. } => false,
1393            Error::OpenDal { error, .. } => !matches!(
1394                error.kind(),
1395                ErrorKind::Unsupported
1396                    | ErrorKind::ConfigInvalid
1397                    | ErrorKind::NotFound
1398                    | ErrorKind::PermissionDenied
1399                    | ErrorKind::IsADirectory
1400                    | ErrorKind::NotADirectory
1401                    | ErrorKind::AlreadyExists
1402                    | ErrorKind::RateLimited
1403                    | ErrorKind::IsSameFile
1404                    | ErrorKind::ConditionNotMatch
1405                    | ErrorKind::RangeNotSatisfied
1406            ),
1407            _ => true,
1408        }
1409    }
1410}
1411
1412impl ErrorExt for Error {
1413    fn status_code(&self) -> StatusCode {
1414        use Error::*;
1415
1416        match self {
1417            DataTypeMismatch { source, .. } => source.status_code(),
1418            OpenDal { .. } | ManifestDeltaNotFound { .. } | ReadParquet { .. } => {
1419                StatusCode::StorageUnavailable
1420            }
1421            WriteWal { source, .. } | ReadWal { source, .. } | DeleteWal { source, .. } => {
1422                source.status_code()
1423            }
1424            CompressObject { .. }
1425            | DecompressObject { .. }
1426            | SerdeJson { .. }
1427            | Utf8 { .. }
1428            | NewRecordBatch { .. }
1429            | RegionCorrupted { .. }
1430            | InconsistentFile { .. }
1431            | CreateDefault { .. }
1432            | InvalidParquet { .. }
1433            | OperateAbortedIndex { .. }
1434            | IndexEncodeNull { .. }
1435            | NoCheckpoint { .. }
1436            | NoManifests { .. }
1437            | FilesLost { .. }
1438            | InstallManifestTo { .. }
1439            | Unexpected { .. }
1440            | SerializeColumnMetadata { .. }
1441            | SerializeManifest { .. }
1442            | StagingPartitionExprMismatch { .. } => StatusCode::Unexpected,
1443
1444            RegionNotFound { .. } => StatusCode::RegionNotFound,
1445            ObjectStoreNotFound { .. }
1446            | InvalidScanIndex { .. }
1447            | InvalidMeta { .. }
1448            | InvalidRequest { .. }
1449            | PartitionExprVersionMismatch { .. }
1450            | FillDefault { .. }
1451            | ConvertColumnDataType { .. }
1452            | ColumnNotFound { .. }
1453            | InvalidMetadata { .. }
1454            | InvalidRegionOptions { .. }
1455            | InvalidWalReadRequest { .. }
1456            | PartitionOutOfRange { .. }
1457            | ParseJobId { .. }
1458            | DurationOutOfRange { .. }
1459            | MissingOldManifest { .. }
1460            | MissingNewManifest { .. }
1461            | MissingManifest { .. }
1462            | NoOldManifests { .. }
1463            | MissingPartitionExpr { .. }
1464            | SerializePartitionExpr { .. }
1465            | InvalidSourceAndTargetRegion { .. } => StatusCode::InvalidArguments,
1466
1467            IncrementalQueryStale { .. } | SnapshotFenceStale { .. } => StatusCode::RequestOutdated,
1468
1469            RegionMetadataNotFound { .. }
1470            | Join { .. }
1471            | WorkerStopped { .. }
1472            | Recv { .. }
1473            | DecodeWal { .. }
1474            | ComputeArrow { .. }
1475            | EvalPartitionFilter { .. }
1476            | MergeCandidateSeries { .. }
1477            | BiErrors { .. }
1478            | StopScheduler { .. }
1479            | ComputeVector { .. }
1480            | EncodeMemtable { .. }
1481            | CreateDir { .. }
1482            | ReadDataPart { .. }
1483            | BuildEntry { .. }
1484            | Metadata { .. }
1485            | CastColumn { .. }
1486            | MitoManifestInfo { .. }
1487            | ParquetToArrowSchema { .. } => StatusCode::Internal,
1488
1489            FetchManifests { source, .. } => source.status_code(),
1490
1491            OpenRegion { source, .. } => source.status_code(),
1492
1493            WriteParquet { .. } => StatusCode::StorageUnavailable,
1494            WriteGroup { source, .. } => source.status_code(),
1495            InvalidBatch { .. } => StatusCode::InvalidArguments,
1496            InvalidRecordBatch { .. } => StatusCode::InvalidArguments,
1497            ConvertVector { source, .. } => source.status_code(),
1498
1499            PrimaryKeyLengthMismatch { .. } => StatusCode::InvalidArguments,
1500            InvalidSender { .. } => StatusCode::InvalidArguments,
1501            InvalidSchedulerState { .. } => StatusCode::InvalidArguments,
1502            RegionRequirement { .. } => StatusCode::InvalidArguments,
1503            DeleteSsts { .. } | DeleteIndex { .. } | DeleteIndexes { .. } => {
1504                StatusCode::StorageUnavailable
1505            }
1506            FlushRegion { source, .. } | BuildIndexAsync { source, .. } => source.status_code(),
1507            RegionDropped { .. } => StatusCode::Cancelled,
1508            RegionClosed { .. } => StatusCode::Cancelled,
1509            StaleCompactionExecution { .. } => StatusCode::Cancelled,
1510            RegionTruncated { .. } => StatusCode::Cancelled,
1511            RejectWrite { .. } => StatusCode::StorageUnavailable,
1512            CompactRegion { source, .. } => source.status_code(),
1513            EditRegion { source, .. } => source.status_code(),
1514            CompatReader { .. } => StatusCode::Unexpected,
1515            InvalidRegionRequest { source, .. } => source.status_code(),
1516            RegionState { .. } | UpdateManifest { .. } => StatusCode::RegionNotReady,
1517            JsonOptions { .. } => StatusCode::InvalidArguments,
1518            EmptyRegionDir { .. } | EmptyManifestDir { .. } => StatusCode::RegionNotFound,
1519            ConvertValue { source, .. } => source.status_code(),
1520            ApplyBloomFilterIndex { source, .. } => source.status_code(),
1521            InvalidPartitionExpr { source, .. } => source.status_code(),
1522            BuildIndexApplier { source, .. }
1523            | PushIndexValue { source, .. }
1524            | ApplyInvertedIndex { source, .. }
1525            | IndexFinish { source, .. } => source.status_code(),
1526            #[cfg(feature = "vector_index")]
1527            ApplyVectorIndex { .. } => StatusCode::Internal,
1528            PuffinReadBlob { source, .. }
1529            | PuffinAddBlob { source, .. }
1530            | PuffinInitStager { source, .. }
1531            | PuffinBuildReader { source, .. }
1532            | PuffinPurgeStager { source, .. } => source.status_code(),
1533            CleanDir { .. } => StatusCode::Unexpected,
1534            InvalidConfig { .. } => StatusCode::InvalidArguments,
1535            StaleLogEntry { .. }
1536            | InvalidNativeHistogramSubfield { .. }
1537            | InvalidNativeHistogramFieldId { .. } => StatusCode::Unexpected,
1538
1539            External { source, .. } => source.status_code(),
1540
1541            RecordBatch { source, .. } => source.status_code(),
1542
1543            Download { .. } | Upload { .. } => StatusCode::StorageUnavailable,
1544            ChecksumMismatch { .. } => StatusCode::Unexpected,
1545            RegionStopped { .. } => StatusCode::RegionNotReady,
1546            TimeRangePredicateOverflow { .. } => StatusCode::InvalidArguments,
1547            UnsupportedOperation { .. } => StatusCode::Unsupported,
1548            RemoteCompaction { .. } => StatusCode::Unexpected,
1549
1550            IndexOptions { source, .. } => source.status_code(),
1551            CreateFulltextCreator { source, .. } => source.status_code(),
1552            CastVector { source, .. } => source.status_code(),
1553            FulltextPushText { source, .. }
1554            | FulltextFinish { source, .. }
1555            | ApplyFulltextIndex { source, .. } => source.status_code(),
1556            DecodeStats { .. } | StatsNotPresent { .. } => StatusCode::Internal,
1557            RegionBusy { .. } => StatusCode::RegionBusy,
1558            GetSchemaMetadata { source, .. } => source.status_code(),
1559            Timeout { .. } => StatusCode::Cancelled,
1560
1561            DecodeArrowRowGroup { .. } => StatusCode::Internal,
1562
1563            PushBloomFilterValue { source, .. } | BloomFilterFinish { source, .. } => {
1564                source.status_code()
1565            }
1566
1567            #[cfg(feature = "vector_index")]
1568            VectorIndexBuild { .. } | VectorIndexFinish { .. } => StatusCode::Internal,
1569
1570            ManualCompactionOverride {} | CompactionCancelled {} | FlushCancelled {} => {
1571                StatusCode::Cancelled
1572            }
1573
1574            // A concurrent manual compaction fails fast instead of being queued;
1575            // the conflict is reported to the caller, which decides whether to
1576            // issue a new request after the running one finishes.
1577            ManualCompactionAlreadyRunning { .. } => StatusCode::RegionBusy,
1578
1579            CompactionMemoryExhausted { source, .. } => source.status_code(),
1580
1581            IncompatibleWalProviderChange { .. } => StatusCode::InvalidArguments,
1582
1583            ScanSeries { source, .. } => source.status_code(),
1584
1585            ScanMultiTimes { .. } => StatusCode::InvalidArguments,
1586            ConvertBulkWalEntry { source, .. } => source.status_code(),
1587
1588            Encode { source, .. } | Decode { source, .. } => source.status_code(),
1589
1590            #[cfg(feature = "enterprise")]
1591            ScanExternalRange { source, .. } => source.status_code(),
1592
1593            InconsistentTimestampLength { .. } => StatusCode::InvalidArguments,
1594
1595            TooManyFilesToRead { .. } | TooManyGcJobs { .. } => StatusCode::RateLimited,
1596
1597            PruneFile { source, .. } => source.status_code(),
1598
1599            FlushableRegionState { .. } => StatusCode::RegionNotReady,
1600        }
1601    }
1602
1603    fn as_any(&self) -> &dyn Any {
1604        self
1605    }
1606
1607    fn retry_hint(&self) -> RetryHint {
1608        use Error::*;
1609
1610        match self {
1611            ReadParquet { .. }
1612            | WriteParquet { .. }
1613            | RejectWrite { .. }
1614            | Download { .. }
1615            | Upload { .. }
1616            | RegionState { .. }
1617            | UpdateManifest { .. }
1618            | RegionStopped { .. }
1619            | RegionBusy { .. }
1620            | ManualCompactionAlreadyRunning { .. }
1621            | FlushableRegionState { .. }
1622            | ManifestDeltaNotFound { .. } => RetryHint::Retryable,
1623
1624            OpenDal { error, .. }
1625            | DeleteSsts { error, .. }
1626            | DeleteIndex { error, .. }
1627            | DeleteIndexes { error, .. } => retry_hint_from_opendal_error(error),
1628
1629            WriteWal { source, .. }
1630            | ReadWal { source, .. }
1631            | DeleteWal { source, .. }
1632            | FetchManifests { source, .. }
1633            | External { source, .. } => source.retry_hint(),
1634
1635            OpenRegion { source, .. }
1636            | WriteGroup { source, .. }
1637            | FlushRegion { source, .. }
1638            | BuildIndexAsync { source, .. }
1639            | CompactRegion { source, .. }
1640            | EditRegion { source, .. }
1641            | ScanSeries { source, .. }
1642            | PruneFile { source, .. } => source.retry_hint(),
1643
1644            DataTypeMismatch { source, .. }
1645            | ConvertVector { source, .. }
1646            | ConvertValue { source, .. }
1647            | IndexOptions { source, .. }
1648            | CastVector { source, .. } => source.retry_hint(),
1649
1650            BuildIndexApplier { source, .. }
1651            | PushIndexValue { source, .. }
1652            | ApplyInvertedIndex { source, .. }
1653            | IndexFinish { source, .. } => source.retry_hint(),
1654
1655            ApplyBloomFilterIndex { source, .. }
1656            | PushBloomFilterValue { source, .. }
1657            | BloomFilterFinish { source, .. } => source.retry_hint(),
1658
1659            PuffinReadBlob { source, .. }
1660            | PuffinAddBlob { source, .. }
1661            | PuffinInitStager { source, .. }
1662            | PuffinBuildReader { source, .. }
1663            | PuffinPurgeStager { source, .. } => source.retry_hint(),
1664
1665            CreateFulltextCreator { source, .. }
1666            | FulltextPushText { source, .. }
1667            | FulltextFinish { source, .. }
1668            | ApplyFulltextIndex { source, .. } => source.retry_hint(),
1669
1670            InvalidRegionRequest { source, .. } => source.retry_hint(),
1671            InvalidPartitionExpr { source, .. } => source.retry_hint(),
1672            RecordBatch { source, .. } => source.retry_hint(),
1673            GetSchemaMetadata { source, .. } => source.retry_hint(),
1674            CompactionMemoryExhausted { source, .. } => source.retry_hint(),
1675            ConvertBulkWalEntry { source, .. } => source.retry_hint(),
1676            Encode { source, .. } | Decode { source, .. } => source.retry_hint(),
1677
1678            #[cfg(feature = "enterprise")]
1679            ScanExternalRange { source, .. } => source.retry_hint(),
1680
1681            _ => RetryHint::NonRetryable,
1682        }
1683    }
1684}
1685
1686#[cfg(test)]
1687mod tests {
1688    use snafu::IntoError;
1689
1690    use super::*;
1691
1692    #[test]
1693    fn test_manifest_update_persistence() {
1694        let rejected_kinds = [
1695            ErrorKind::Unsupported,
1696            ErrorKind::ConfigInvalid,
1697            ErrorKind::NotFound,
1698            ErrorKind::PermissionDenied,
1699            ErrorKind::IsADirectory,
1700            ErrorKind::NotADirectory,
1701            ErrorKind::AlreadyExists,
1702            ErrorKind::RateLimited,
1703            ErrorKind::IsSameFile,
1704            ErrorKind::ConditionNotMatch,
1705            ErrorKind::RangeNotSatisfied,
1706        ];
1707        for kind in rejected_kinds {
1708            let error = OpenDalSnafu {}.into_error(object_store::Error::new(kind, "test"));
1709            assert!(
1710                !error.may_have_persisted_manifest_update(),
1711                "error kind {kind:?} should prove the manifest was not persisted"
1712            );
1713        }
1714
1715        let error =
1716            OpenDalSnafu {}.into_error(object_store::Error::new(ErrorKind::Unexpected, "test"));
1717        assert!(error.may_have_persisted_manifest_update());
1718
1719        let region_id = RegionId::new(1, 1);
1720        let error = RegionTruncatedSnafu { region_id }.build();
1721        assert!(!error.may_have_persisted_manifest_update());
1722
1723        // This can be raised while applying an edit after its manifest file was saved.
1724        let error = RegionMetadataNotFoundSnafu {}.build();
1725        assert!(error.may_have_persisted_manifest_update());
1726    }
1727}