1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
// Copyright Materialize, Inc. and contributors. All rights reserved.
//
// Use of this software is governed by the Business Source License
// included in the LICENSE file.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0.

//! Errors for the crate

use std::fmt::Debug;

use timely::progress::{Antichain, Timestamp};

use crate::ShardId;

/// An error resulting from invalid usage of the API.
#[derive(Debug)]
#[cfg_attr(any(test, debug_assertions), derive(PartialEq))]
pub enum InvalidUsage<T> {
    /// Append bounds were invalid
    InvalidBounds {
        /// The given lower bound
        lower: Antichain<T>,
        /// The given upper bound
        upper: Antichain<T>,
    },
    /// An update was sent at an empty interval of times.
    InvalidEmptyTimeInterval {
        /// The given lower bound
        lower: Antichain<T>,
        /// The given upper bound
        upper: Antichain<T>,
        /// Set of keys containing updates.
        keys: Vec<String>,
    },
    /// Bounds of a [crate::batch::Batch] are not valid for the attempted append call
    InvalidBatchBounds {
        /// The lower of the batch
        batch_lower: Antichain<T>,
        /// The upper of the batch
        batch_upper: Antichain<T>,
        /// The lower bound given to the append call
        append_lower: Antichain<T>,
        /// The upper bound given to the append call
        append_upper: Antichain<T>,
    },
    /// An update was not beyond the expected lower of the batch
    UpdateNotBeyondLower {
        /// Timestamp of the update
        ts: T,
        /// The given lower bound
        lower: Antichain<T>,
    },
    /// An update in the batch was beyond the expected upper
    UpdateBeyondUpper {
        /// The timestamp of the update
        ts: T,
        /// The expected upper of the batch
        expected_upper: Antichain<T>,
    },
    /// A [crate::batch::Batch] or [crate::fetch::LeasedBatchPart] was
    /// given to a [crate::write::WriteHandle] from a different shard
    BatchNotFromThisShard {
        /// The shard of the batch
        batch_shard: ShardId,
        /// The shard of the handle
        handle_shard: ShardId,
    },
    /// Attempted to finalize a shard without advancing frontiers.
    FinalizationError {
        /// The current since of the shard.
        since: Antichain<T>,
        /// The current upper of the shard.
        upper: Antichain<T>,
    },
    /// The requested codecs don't match the actual ones in durable storage.
    CodecMismatch(Box<CodecMismatch>),
    /// An invalid usage of [crate::batch::Batch::rewrite_ts].
    InvalidRewrite(String),
}

impl<T: Debug> std::fmt::Display for InvalidUsage<T> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            InvalidUsage::InvalidBounds { lower, upper } => {
                write!(f, "invalid bounds [{:?}, {:?})", lower, upper)
            }
            InvalidUsage::InvalidEmptyTimeInterval { lower, upper, keys } => {
                write!(
                    f,
                    "invalid empty time interval [{:?}, {:?} {:?})",
                    lower, upper, keys
                )
            }
            InvalidUsage::InvalidBatchBounds {
                batch_lower,
                batch_upper,
                append_lower,
                append_upper,
            } => {
                write!(
                    f,
                    "invalid batch bounds [{:?}, {:?}) for append call with [{:?}, {:?})",
                    batch_lower, batch_upper, append_lower, append_upper
                )
            }
            InvalidUsage::UpdateNotBeyondLower { ts, lower } => {
                write!(f, "timestamp {:?} not beyond batch lower {:?}", ts, lower)
            }
            InvalidUsage::UpdateBeyondUpper { ts, expected_upper } => write!(
                f,
                "timestamp {:?} is beyond the expected batch upper: {:?}",
                ts, expected_upper
            ),
            InvalidUsage::BatchNotFromThisShard {
                batch_shard,
                handle_shard,
            } => write!(f, "batch was from {} not {}", batch_shard, handle_shard),
            InvalidUsage::FinalizationError { since, upper } => {
                write!(
                    f,
                    "finalized without fully advancing since {since:?} and upper {upper:?}"
                )
            }
            InvalidUsage::CodecMismatch(err) => std::fmt::Display::fmt(err, f),
            InvalidUsage::InvalidRewrite(err) => write!(f, "invalid rewrite: {err}"),
        }
    }
}

impl<T: Debug> std::error::Error for InvalidUsage<T> {}

/// The requested codecs don't match the actual ones in durable storage.
#[derive(Debug)]
#[cfg_attr(any(test, debug_assertions), derive(PartialEq))]
pub struct CodecMismatch {
    /// The requested (K, V, T, D) codecs.
    ///
    /// The last element in the tuple is Some when the name of the codecs match,
    /// but the concrete types don't: e.g. mz_repr::Timestamp and u64.
    pub(crate) requested: (String, String, String, String, Option<CodecConcreteType>),
    /// The actual (K, V, T, D) codecs in durable storage.
    ///
    /// The last element in the tuple is Some when the name of the codecs match,
    /// but the concrete types don't: e.g. mz_repr::Timestamp and u64.
    pub(crate) actual: (String, String, String, String, Option<CodecConcreteType>),
}

impl std::error::Error for CodecMismatch {}

impl std::fmt::Display for CodecMismatch {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "requested codecs {:?} did not match ones in durable storage {:?}",
            self.requested, self.actual
        )
    }
}

/// The concrete type of a [mz_persist_types::Codec] or
/// [mz_persist_types::Codec64] impl.
#[derive(Debug)]
#[cfg_attr(any(test, debug_assertions), derive(PartialEq))]
pub struct CodecConcreteType(#[allow(dead_code)] pub(crate) &'static str);

impl<T> From<CodecMismatch> for InvalidUsage<T> {
    fn from(x: CodecMismatch) -> Self {
        InvalidUsage::CodecMismatch(Box::new(x))
    }
}

impl<T> From<Box<CodecMismatch>> for InvalidUsage<T> {
    fn from(x: Box<CodecMismatch>) -> Self {
        InvalidUsage::CodecMismatch(x)
    }
}

#[derive(Debug)]
pub(crate) struct CodecMismatchT {
    /// The requested T codec.
    pub(crate) requested: String,
    /// The actual T codec in durable storage.
    pub(crate) actual: String,
}

impl std::error::Error for CodecMismatchT {}

impl std::fmt::Display for CodecMismatchT {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "requested ts codec {:?} did not match one in durable storage {:?}",
            self.requested, self.actual
        )
    }
}

/// An error returned from [crate::write::WriteHandle::compare_and_append] (and
/// variants) when the expected upper didn't match the actual current upper of
/// the shard.
#[derive(Debug, PartialEq)]
pub struct UpperMismatch<T> {
    /// The expected upper given by the caller.
    pub expected: Antichain<T>,
    /// The actual upper of the shard at the time compare_and_append evaluated.
    pub current: Antichain<T>,
}

impl<T: Timestamp> std::fmt::Display for UpperMismatch<T> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "expected upper {:?} did not match current upper {:?}",
            self.expected, self.current,
        )
    }
}