mz_catalog/durable/
error.rs1use std::fmt::Debug;
11
12use mz_persist_client::error::UpperMismatch;
13use mz_proto::TryFromProtoError;
14use mz_repr::Timestamp;
15use mz_sql::catalog::CatalogError as SqlCatalogError;
16use mz_storage_types::controller::StorageError;
17
18use crate::durable::Epoch;
19use crate::durable::persist::antichain_to_timestamp;
20
21#[derive(Debug, thiserror::Error)]
22pub enum CatalogError {
23 #[error(transparent)]
24 Catalog(#[from] SqlCatalogError),
25 #[error(transparent)]
26 Durable(#[from] DurableCatalogError),
27}
28
29impl From<TryFromProtoError> for CatalogError {
30 fn from(e: TryFromProtoError) -> Self {
31 Self::Durable(e.into())
32 }
33}
34
35impl From<FenceError> for CatalogError {
36 fn from(err: FenceError) -> Self {
37 let err: DurableCatalogError = err.into();
38 err.into()
39 }
40}
41
42#[derive(Debug, thiserror::Error)]
44pub enum DurableCatalogError {
45 #[error(transparent)]
47 Fence(#[from] FenceError),
48 #[error(
50 "incompatible Catalog version {found_version}, minimum: {min_catalog_version}, current: {catalog_version}"
51 )]
52 IncompatibleDataVersion {
53 found_version: u64,
54 min_catalog_version: u64,
55 catalog_version: u64,
56 },
57 #[error(
60 "incompatible persist version {found_version}, current: {catalog_version}, make sure to upgrade the catalog one version forward at a time"
61 )]
62 IncompatiblePersistVersion {
63 found_version: semver::Version,
64 catalog_version: semver::Version,
65 },
66 #[error("uninitialized")]
68 Uninitialized,
69 #[error("{0}")]
71 NotWritable(String),
72 #[error("proto: {0}")]
74 Proto(TryFromProtoError),
75 #[error("duplicate key")]
77 DuplicateKey,
78 #[error("uniqueness violation")]
80 UniquenessViolation,
81 #[error(transparent)]
83 Storage(StorageError<Timestamp>),
84 #[error("Internal catalog error: {0}")]
86 Internal(String),
87}
88
89impl DurableCatalogError {
90 pub fn can_recover_with_write_mode(&self) -> bool {
92 match self {
93 DurableCatalogError::NotWritable(_) => true,
94 _ => false,
95 }
96 }
97}
98
99impl From<StorageError<Timestamp>> for DurableCatalogError {
100 fn from(e: StorageError<Timestamp>) -> Self {
101 DurableCatalogError::Storage(e)
102 }
103}
104
105impl From<TryFromProtoError> for DurableCatalogError {
106 fn from(e: TryFromProtoError) -> Self {
107 DurableCatalogError::Proto(e)
108 }
109}
110
111#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, thiserror::Error)]
115pub enum FenceError {
116 #[error(
120 "current catalog deployment generation {current_generation} fenced by new catalog epoch {fence_generation}"
121 )]
122 DeployGeneration {
123 current_generation: u64,
124 fence_generation: u64,
125 },
126 #[error("current catalog epoch {current_epoch} fenced by new catalog epoch {fence_epoch}")]
129 Epoch {
130 current_epoch: Epoch,
131 fence_epoch: Epoch,
132 },
133 #[error(
136 "builtin table migration shard upper {expected_upper:?} fenced by new builtin table migration shard upper {actual_upper:?}"
137 )]
138 MigrationUpper {
139 expected_upper: Timestamp,
140 actual_upper: Timestamp,
141 },
142}
143
144impl FenceError {
145 pub fn migration(err: UpperMismatch<Timestamp>) -> Self {
146 Self::MigrationUpper {
147 expected_upper: antichain_to_timestamp(err.expected),
148 actual_upper: antichain_to_timestamp(err.current),
149 }
150 }
151}
152
153#[cfg(test)]
154mod tests {
155 use crate::durable::{Epoch, FenceError};
156
157 #[mz_ore::test]
158 fn test_fence_err_ord() {
159 let deploy_generation = FenceError::DeployGeneration {
160 current_generation: 90,
161 fence_generation: 91,
162 };
163 let epoch = FenceError::Epoch {
164 current_epoch: Epoch::new(80).expect("non zero"),
165 fence_epoch: Epoch::new(81).expect("non zero"),
166 };
167 assert!(deploy_generation < epoch);
168
169 let migration = FenceError::MigrationUpper {
170 expected_upper: 60.into(),
171 actual_upper: 61.into(),
172 };
173 assert!(epoch < migration);
174 }
175}