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(
58 "incompatible persist version {found_version}, current: {catalog_version}, \
59 make sure to upgrade the catalog one major version forward at a time"
60 )]
61 IncompatiblePersistVersion {
62 found_version: semver::Version,
63 catalog_version: semver::Version,
64 },
65 #[error("uninitialized")]
67 Uninitialized,
68 #[error("{0}")]
70 NotWritable(String),
71 #[error("cannot commit a dry-run catalog transaction")]
73 DryRunTransaction,
74 #[error("proto: {0}")]
76 Proto(TryFromProtoError),
77 #[error("duplicate key")]
79 DuplicateKey,
80 #[error("uniqueness violation")]
82 UniquenessViolation,
83 #[error(transparent)]
85 Storage(StorageError),
86 #[error("durable catalog advanced to {upper} with {update_count} unapplied updates")]
92 CatalogOutOfSync {
93 update_count: usize,
94 upper: Timestamp,
95 },
96 #[error("Internal catalog error: {0}")]
98 Internal(String),
99}
100
101impl DurableCatalogError {
102 pub fn can_recover_with_write_mode(&self) -> bool {
104 match self {
105 DurableCatalogError::NotWritable(_) => true,
106 _ => false,
107 }
108 }
109}
110
111impl From<StorageError> for DurableCatalogError {
112 fn from(e: StorageError) -> Self {
113 DurableCatalogError::Storage(e)
114 }
115}
116
117impl From<TryFromProtoError> for DurableCatalogError {
118 fn from(e: TryFromProtoError) -> Self {
119 DurableCatalogError::Proto(e)
120 }
121}
122
123#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, thiserror::Error)]
127pub enum FenceError {
128 #[error(
132 "current catalog deployment generation {current_generation} fenced by new catalog epoch {fence_generation}"
133 )]
134 DeployGeneration {
135 current_generation: u64,
136 fence_generation: u64,
137 },
138 #[error("current catalog epoch {current_epoch} fenced by new catalog epoch {fence_epoch}")]
141 Epoch {
142 current_epoch: Epoch,
143 fence_epoch: Epoch,
144 },
145 #[error(
148 "builtin table migration shard upper {expected_upper:?} fenced by new builtin table migration shard upper {actual_upper:?}"
149 )]
150 MigrationUpper {
151 expected_upper: Timestamp,
152 actual_upper: Timestamp,
153 },
154}
155
156impl FenceError {
157 pub fn migration(err: UpperMismatch<Timestamp>) -> Self {
158 Self::MigrationUpper {
159 expected_upper: antichain_to_timestamp(err.expected),
160 actual_upper: antichain_to_timestamp(err.current),
161 }
162 }
163}
164
165#[cfg(test)]
166mod tests {
167 use crate::durable::{Epoch, FenceError};
168
169 #[mz_ore::test]
170 fn test_fence_err_ord() {
171 let deploy_generation = FenceError::DeployGeneration {
172 current_generation: 90,
173 fence_generation: 91,
174 };
175 let epoch = FenceError::Epoch {
176 current_epoch: Epoch::new(80).expect("non zero"),
177 fence_epoch: Epoch::new(81).expect("non zero"),
178 };
179 assert!(deploy_generation < epoch);
180
181 let migration = FenceError::MigrationUpper {
182 expected_upper: 60.into(),
183 actual_upper: 61.into(),
184 };
185 assert!(epoch < migration);
186 }
187}