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.
910//! 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.
1920use mz_repr::GlobalId;
21use mz_storage_types::read_holds::ReadHoldError;
22use thiserror::Error;
2324use crate::controller::{ComputeInstanceId, ReplicaId};
2526/// 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";
2930/// 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);
3435/// 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);
4041/// 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);
4546/// 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>);
5051/// 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}")]
56InstanceMissing(ComputeInstanceId),
57/// TODO(database-issues#7533): Add documentation.
58#[error("collection does not exist: {0}")]
59CollectionMissing(GlobalId),
60}
6162impl From<InstanceMissing> for CollectionLookupError {
63fn from(error: InstanceMissing) -> Self {
64Self::InstanceMissing(error.0)
65 }
66}
6768impl From<CollectionMissing> for CollectionLookupError {
69fn from(error: CollectionMissing) -> Self {
70Self::CollectionMissing(error.0)
71 }
72}
7374/// 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}")]
79InstanceMissing(ComputeInstanceId),
80/// TODO(database-issues#7533): Add documentation.
81#[error("replica exists already: {0}")]
82ReplicaExists(ReplicaId),
83}
8485impl From<InstanceMissing> for ReplicaCreationError {
86fn from(error: InstanceMissing) -> Self {
87Self::InstanceMissing(error.0)
88 }
89}
9091/// 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}")]
96InstanceMissing(ComputeInstanceId),
97/// TODO(database-issues#7533): Add documentation.
98#[error("replica does not exist: {0}")]
99ReplicaMissing(ReplicaId),
100}
101102impl From<InstanceMissing> for ReplicaDropError {
103fn from(error: InstanceMissing) -> Self {
104Self::InstanceMissing(error.0)
105 }
106}
107108/// 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}")]
113InstanceMissing(ComputeInstanceId),
114/// One of the imported collections does not exist.
115#[error("collection does not exist: {0}")]
116CollectionMissing(GlobalId),
117/// The targeted replica does not exist.
118#[error("replica does not exist: {0}")]
119ReplicaMissing(ReplicaId),
120/// The dataflow definition has doesn't have an `as_of` set.
121#[error("dataflow definition lacks an as_of value")]
122MissingAsOf,
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}")]
125SinceViolation(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")]
129EmptyAsOfForSubscribe,
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")]
133EmptyAsOfForCopyTo,
134}
135136impl From<InstanceMissing> for DataflowCreationError {
137fn from(error: InstanceMissing) -> Self {
138Self::InstanceMissing(error.0)
139 }
140}
141142impl From<CollectionMissing> for DataflowCreationError {
143fn from(error: CollectionMissing) -> Self {
144Self::CollectionMissing(error.0)
145 }
146}
147148impl From<ReadHoldError> for DataflowCreationError {
149fn from(error: ReadHoldError) -> Self {
150match error {
151 ReadHoldError::CollectionMissing(id) => Self::CollectionMissing(id),
152 ReadHoldError::SinceViolation(id) => Self::SinceViolation(id),
153 }
154 }
155}
156157/// 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}")]
162InstanceMissing(ComputeInstanceId),
163/// TODO(database-issues#7533): Add documentation.
164#[error("collection does not exist: {0}")]
165CollectionMissing(GlobalId),
166/// TODO(database-issues#7533): Add documentation.
167#[error("replica does not exist: {0}")]
168ReplicaMissing(ReplicaId),
169/// TODO(database-issues#7533): Add documentation.
170#[error("peek timestamp is not beyond the since of collection: {0}")]
171SinceViolation(GlobalId),
172}
173174impl From<InstanceMissing> for PeekError {
175fn from(error: InstanceMissing) -> Self {
176Self::InstanceMissing(error.0)
177 }
178}
179180impl From<CollectionMissing> for PeekError {
181fn from(error: CollectionMissing) -> Self {
182Self::CollectionMissing(error.0)
183 }
184}
185186impl From<ReadHoldError> for PeekError {
187fn from(error: ReadHoldError) -> Self {
188match error {
189 ReadHoldError::CollectionMissing(id) => Self::CollectionMissing(id),
190 ReadHoldError::SinceViolation(id) => Self::SinceViolation(id),
191 }
192 }
193}
194195/// 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}")]
200InstanceMissing(ComputeInstanceId),
201/// TODO(database-issues#7533): Add documentation.
202#[error("collection does not exist: {0}")]
203CollectionMissing(GlobalId),
204}
205206impl From<InstanceMissing> for CollectionUpdateError {
207fn from(error: InstanceMissing) -> Self {
208Self::InstanceMissing(error.0)
209 }
210}
211212impl From<CollectionMissing> for CollectionUpdateError {
213fn from(error: CollectionMissing) -> Self {
214Self::CollectionMissing(error.0)
215 }
216}
217218/// 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}")]
223InstanceMissing(ComputeInstanceId),
224/// TODO(database-issues#7533): Add documentation.
225#[error("collection does not exist: {0}")]
226CollectionMissing(GlobalId),
227/// TODO(database-issues#7533): Add documentation.
228#[error("collection is write-only: {0}")]
229WriteOnlyCollection(GlobalId),
230}
231232impl From<InstanceMissing> for ReadPolicyError {
233fn from(error: InstanceMissing) -> Self {
234Self::InstanceMissing(error.0)
235 }
236}
237238impl From<CollectionMissing> for ReadPolicyError {
239fn from(error: CollectionMissing) -> Self {
240Self::CollectionMissing(error.0)
241 }
242}
243244/// Errors arising during orphan removal.
245#[derive(Error, Debug)]
246pub enum RemoveOrphansError {
247/// TODO(database-issues#7533): Add documentation.
248#[error("orchestrator error: {0}")]
249OrchestratorError(anyhow::Error),
250}
251252impl From<anyhow::Error> for RemoveOrphansError {
253fn from(error: anyhow::Error) -> Self {
254Self::OrchestratorError(error)
255 }
256}