mz_compute_client/controller/
error.rs

1// Copyright Materialize, Inc. and contributors. All rights reserved.
2//
3// Use of this software is governed by the Business Source License
4// included in the LICENSE file.
5//
6// As of the Change Date specified in that file, in accordance with
7// the Business Source License, use of this software will be governed
8// by the Apache License, Version 2.0.
9
10//! Errors returned by the compute controller.
11//!
12//! The guiding principle for error handling in the compute controller is that each public method
13//! should return an error type that defines exactly the error variants the method can return, and
14//! no additional ones. This precludes the usage of a single `ComputeControllerError` enum that
15//! simply includes the union of all error variants the compute controller can ever return (and
16//! possibly some internal ones that are never returned to external callers). Instead, compute
17//! controller methods return bespoke error types that serve as documentation for the failure modes
18//! of each method and make it easy for callers to ensure that all possible errors are handled.
19
20use mz_repr::GlobalId;
21use mz_storage_types::read_holds::ReadHoldError;
22use thiserror::Error;
23
24use crate::controller::{ComputeInstanceId, ReplicaId};
25
26/// The error returned by replica-targeted peeks and subscribes when the target replica
27/// disconnects.
28pub const ERROR_TARGET_REPLICA_FAILED: &str = "target replica failed or was dropped";
29
30/// Error returned in response to a reference to an unknown compute instance.
31#[derive(Error, Debug)]
32#[error("instance does not exist: {0}")]
33pub struct InstanceMissing(pub ComputeInstanceId);
34
35/// Error returned in response to a request to create a compute instance with an ID of an existing
36/// compute instance.
37#[derive(Error, Debug)]
38#[error("instance exists already: {0}")]
39pub struct InstanceExists(pub ComputeInstanceId);
40
41/// Error returned in response to a reference to an unknown compute collection.
42#[derive(Error, Debug)]
43#[error("collection does not exist: {0}")]
44pub struct CollectionMissing(pub GlobalId);
45
46/// Error returned in response to a reference to an unknown compute collection.
47#[derive(Error, Debug)]
48#[error("No replicas found in cluster for target list.")]
49pub struct HydrationCheckBadTarget(pub Vec<ReplicaId>);
50
51/// Errors arising during compute collection lookup.
52#[derive(Error, Debug)]
53pub enum CollectionLookupError {
54    /// TODO(database-issues#7533): Add documentation.
55    #[error("instance does not exist: {0}")]
56    InstanceMissing(ComputeInstanceId),
57    /// TODO(database-issues#7533): Add documentation.
58    #[error("collection does not exist: {0}")]
59    CollectionMissing(GlobalId),
60}
61
62impl From<InstanceMissing> for CollectionLookupError {
63    fn from(error: InstanceMissing) -> Self {
64        Self::InstanceMissing(error.0)
65    }
66}
67
68impl From<CollectionMissing> for CollectionLookupError {
69    fn from(error: CollectionMissing) -> Self {
70        Self::CollectionMissing(error.0)
71    }
72}
73
74/// Errors arising during compute replica creation.
75#[derive(Error, Debug)]
76pub enum ReplicaCreationError {
77    /// TODO(database-issues#7533): Add documentation.
78    #[error("instance does not exist: {0}")]
79    InstanceMissing(ComputeInstanceId),
80    /// TODO(database-issues#7533): Add documentation.
81    #[error("replica exists already: {0}")]
82    ReplicaExists(ReplicaId),
83}
84
85impl From<InstanceMissing> for ReplicaCreationError {
86    fn from(error: InstanceMissing) -> Self {
87        Self::InstanceMissing(error.0)
88    }
89}
90
91/// Errors arising during compute replica removal.
92#[derive(Error, Debug)]
93pub enum ReplicaDropError {
94    /// TODO(database-issues#7533): Add documentation.
95    #[error("instance does not exist: {0}")]
96    InstanceMissing(ComputeInstanceId),
97    /// TODO(database-issues#7533): Add documentation.
98    #[error("replica does not exist: {0}")]
99    ReplicaMissing(ReplicaId),
100}
101
102impl From<InstanceMissing> for ReplicaDropError {
103    fn from(error: InstanceMissing) -> Self {
104        Self::InstanceMissing(error.0)
105    }
106}
107
108/// Errors arising during dataflow creation.
109#[derive(Error, Debug)]
110pub enum DataflowCreationError {
111    /// The given instance does not exist.
112    #[error("instance does not exist: {0}")]
113    InstanceMissing(ComputeInstanceId),
114    /// One of the imported collections does not exist.
115    #[error("collection does not exist: {0}")]
116    CollectionMissing(GlobalId),
117    /// The targeted replica does not exist.
118    #[error("replica does not exist: {0}")]
119    ReplicaMissing(ReplicaId),
120    /// The dataflow definition has doesn't have an `as_of` set.
121    #[error("dataflow definition lacks an as_of value")]
122    MissingAsOf,
123    /// One of the imported collections has a read frontier greater than the dataflow `as_of`.
124    #[error("dataflow has an as_of not beyond the since of collection: {0}")]
125    SinceViolation(GlobalId),
126    /// We skip dataflow creation for empty `as_of`s, which would be a problem for a SUBSCRIBE,
127    /// because an initial response is expected.
128    #[error("subscribe dataflow has an empty as_of")]
129    EmptyAsOfForSubscribe,
130    /// We skip dataflow creation for empty `as_of`s, which would be a problem for a COPY TO,
131    /// because it should always have an external side effect.
132    #[error("copy to dataflow has an empty as_of")]
133    EmptyAsOfForCopyTo,
134}
135
136impl From<InstanceMissing> for DataflowCreationError {
137    fn from(error: InstanceMissing) -> Self {
138        Self::InstanceMissing(error.0)
139    }
140}
141
142impl From<CollectionMissing> for DataflowCreationError {
143    fn from(error: CollectionMissing) -> Self {
144        Self::CollectionMissing(error.0)
145    }
146}
147
148impl From<ReadHoldError> for DataflowCreationError {
149    fn from(error: ReadHoldError) -> Self {
150        match error {
151            ReadHoldError::CollectionMissing(id) => Self::CollectionMissing(id),
152            ReadHoldError::SinceViolation(id) => Self::SinceViolation(id),
153        }
154    }
155}
156
157/// Errors arising during peek processing.
158#[derive(Error, Debug)]
159pub enum PeekError {
160    /// TODO(database-issues#7533): Add documentation.
161    #[error("instance does not exist: {0}")]
162    InstanceMissing(ComputeInstanceId),
163    /// TODO(database-issues#7533): Add documentation.
164    #[error("collection does not exist: {0}")]
165    CollectionMissing(GlobalId),
166    /// TODO(database-issues#7533): Add documentation.
167    #[error("replica does not exist: {0}")]
168    ReplicaMissing(ReplicaId),
169    /// TODO(database-issues#7533): Add documentation.
170    #[error("peek timestamp is not beyond the since of collection: {0}")]
171    SinceViolation(GlobalId),
172}
173
174impl From<InstanceMissing> for PeekError {
175    fn from(error: InstanceMissing) -> Self {
176        Self::InstanceMissing(error.0)
177    }
178}
179
180impl From<CollectionMissing> for PeekError {
181    fn from(error: CollectionMissing) -> Self {
182        Self::CollectionMissing(error.0)
183    }
184}
185
186impl From<ReadHoldError> for PeekError {
187    fn from(error: ReadHoldError) -> Self {
188        match error {
189            ReadHoldError::CollectionMissing(id) => Self::CollectionMissing(id),
190            ReadHoldError::SinceViolation(id) => Self::SinceViolation(id),
191        }
192    }
193}
194
195/// Errors arising during collection updates.
196#[derive(Error, Debug)]
197pub enum CollectionUpdateError {
198    /// TODO(database-issues#7533): Add documentation.
199    #[error("instance does not exist: {0}")]
200    InstanceMissing(ComputeInstanceId),
201    /// TODO(database-issues#7533): Add documentation.
202    #[error("collection does not exist: {0}")]
203    CollectionMissing(GlobalId),
204}
205
206impl From<InstanceMissing> for CollectionUpdateError {
207    fn from(error: InstanceMissing) -> Self {
208        Self::InstanceMissing(error.0)
209    }
210}
211
212impl From<CollectionMissing> for CollectionUpdateError {
213    fn from(error: CollectionMissing) -> Self {
214        Self::CollectionMissing(error.0)
215    }
216}
217
218/// Errors arising during collection read policy assignment.
219#[derive(Error, Debug)]
220pub enum ReadPolicyError {
221    /// TODO(database-issues#7533): Add documentation.
222    #[error("instance does not exist: {0}")]
223    InstanceMissing(ComputeInstanceId),
224    /// TODO(database-issues#7533): Add documentation.
225    #[error("collection does not exist: {0}")]
226    CollectionMissing(GlobalId),
227    /// TODO(database-issues#7533): Add documentation.
228    #[error("collection is write-only: {0}")]
229    WriteOnlyCollection(GlobalId),
230}
231
232impl From<InstanceMissing> for ReadPolicyError {
233    fn from(error: InstanceMissing) -> Self {
234        Self::InstanceMissing(error.0)
235    }
236}
237
238impl From<CollectionMissing> for ReadPolicyError {
239    fn from(error: CollectionMissing) -> Self {
240        Self::CollectionMissing(error.0)
241    }
242}
243
244/// Errors arising during orphan removal.
245#[derive(Error, Debug)]
246pub enum RemoveOrphansError {
247    /// TODO(database-issues#7533): Add documentation.
248    #[error("orchestrator error: {0}")]
249    OrchestratorError(anyhow::Error),
250}
251
252impl From<anyhow::Error> for RemoveOrphansError {
253    fn from(error: anyhow::Error) -> Self {
254        Self::OrchestratorError(error)
255    }
256}