Skip to main content

nexir_mvcc_core/
error.rs

1use thiserror::Error;
2
3use crate::types::{Timestamp, TxnId};
4
5/// Error during a read operation.
6#[derive(Error, Debug, Clone, PartialEq, Eq)]
7pub enum ReadError {
8    /// An error returned by the backend storage.
9    #[error("backend error: {0}")]
10    Backend(String),
11}
12
13/// Error during a single-key prewrite operation.
14#[derive(Error, Debug, Clone, PartialEq, Eq)]
15pub enum PrewriteError {
16    /// The key is locked by another active transaction.
17    #[error("key is locked by another transaction: txn_id={txn_id}")]
18    KeyLocked {
19        /// The transaction ID currently holding the lock.
20        txn_id: TxnId,
21    },
22    /// A committed version exists that is newer than the transaction's start_ts.
23    #[error("write conflict: committed version after start_ts")]
24    WriteConflict,
25    /// An error returned by the backend storage.
26    #[error("backend error: {0}")]
27    Backend(String),
28    /// An intent already exists for the same transaction but with different parameters.
29    #[error("intent already exists with different parameters")]
30    IntentAlreadyExists,
31}
32
33/// Error during a single-key commit operation.
34#[derive(Error, Debug, Clone, PartialEq, Eq)]
35pub enum CommitError {
36    /// The intent to be committed was not found.
37    #[error("intent not found")]
38    IntentNotFound,
39    /// The transaction ID on the intent does not match the commit request.
40    #[error("txn_id mismatch")]
41    TxnIdMismatch,
42    /// The start timestamp on the intent does not match the commit request.
43    #[error("start_ts mismatch")]
44    StartTsMismatch,
45    /// The commit timestamp is less than or equal to the start timestamp.
46    #[error("invalid commit timestamp: commit_ts {commit_ts} <= start_ts {start_ts}")]
47    InvalidCommitTimestamp {
48        /// The start timestamp of the transaction.
49        start_ts: Timestamp,
50        /// The invalid commit timestamp.
51        commit_ts: Timestamp,
52    },
53    /// A committed version already exists exactly at this commit timestamp.
54    #[error("duplicate commit timestamp: {commit_ts}")]
55    DuplicateCommitTimestamp {
56        /// The duplicate commit timestamp.
57        commit_ts: Timestamp,
58    },
59    /// The commit timestamp is older than the latest committed version for a key.
60    #[error("commit timestamp too old: commit_ts {commit_ts}, latest is {latest_commit_ts}")]
61    CommitTsTooOld {
62        /// The requested commit timestamp.
63        commit_ts: Timestamp,
64        /// The latest committed version's timestamp.
65        latest_commit_ts: Timestamp,
66    },
67    /// The commit timestamp is earlier than the intent's required minimum commit timestamp.
68    #[error("commit_ts {commit_ts} is before required minimum {min_commit_ts}")]
69    CommitTsTooEarly {
70        /// The requested commit timestamp.
71        commit_ts: Timestamp,
72        /// The minimum allowed commit timestamp.
73        min_commit_ts: Timestamp,
74    },
75    /// An error returned by the backend storage.
76    #[error("backend error: {0}")]
77    Backend(String),
78}
79
80/// Error during a single-key abort operation.
81#[derive(Error, Debug, Clone, PartialEq, Eq)]
82pub enum AbortError {
83    /// An error returned by the backend storage.
84    #[error("backend error: {0}")]
85    Backend(String),
86}
87
88/// Error during garbage collection.
89#[derive(Error, Debug, Clone, PartialEq, Eq)]
90pub enum GcError {
91    /// An error returned by the backend storage.
92    #[error("backend error: {0}")]
93    Backend(String),
94    /// The provided GC budget is invalid (e.g., max_keys or max_versions is 0).
95    #[error("invalid gc budget: max_keys and max_versions must be > 0")]
96    InvalidGcBudget,
97}
98
99/// Error during codec operations.
100#[derive(Error, Debug, Clone, PartialEq, Eq)]
101pub enum CodecError {
102    /// An error occurred during encoding.
103    #[error("encode error: {0}")]
104    Encode(String),
105    /// An error occurred during decoding.
106    #[error("decode error: {0}")]
107    Decode(String),
108}
109
110/// Error during a direct or guarded batch.
111#[derive(Error, Debug, Clone, PartialEq, Eq)]
112pub enum BatchError {
113    /// The batch contained no write operations.
114    #[error("batch is empty")]
115    EmptyBatch,
116    /// The commit timestamp is less than or equal to a guard's read timestamp.
117    #[error("invalid commit timestamp: commit_ts {commit_ts} <= read_ts {read_ts}")]
118    InvalidCommitTimestamp {
119        /// The read timestamp of the guard.
120        read_ts: Timestamp,
121        /// The invalid commit timestamp.
122        commit_ts: Timestamp,
123    },
124    /// The commit timestamp is older than the latest committed version for a key.
125    #[error("commit timestamp too old: key {key:?} at {commit_ts}, latest is {latest_commit_ts}")]
126    CommitTsTooOld {
127        /// The key that caused the error.
128        key: Vec<u8>,
129        /// The requested commit timestamp.
130        commit_ts: Timestamp,
131        /// The latest committed version's timestamp.
132        latest_commit_ts: Timestamp,
133    },
134    /// A guarded batch was submitted without any read guards.
135    #[error("guarded batch requires at least one read guard")]
136    NoReadGuards,
137    /// The batch contains multiple physical writes for the same key.
138    #[error("duplicate key in batch: {key:?}")]
139    DuplicateKeyInBatch {
140        /// The duplicate key.
141        key: Vec<u8>,
142    },
143    /// A key in the batch is currently locked by an active intent.
144    #[error("key is locked by an active intent: key {key:?}, txn_id {txn_id}")]
145    KeyLocked {
146        /// The locked key.
147        key: Vec<u8>,
148        /// The transaction ID holding the lock.
149        txn_id: TxnId,
150    },
151    /// A read guard failed because a newer version exists after the `read_ts`.
152    #[error("read guard failed: newer version exists after read_ts {read_ts} for key {key:?} (actual_commit_ts: {actual_commit_ts})")]
153    GuardFailedNewerVersion {
154        /// The key that failed the guard.
155        key: Vec<u8>,
156        /// The read timestamp of the guard.
157        read_ts: Timestamp,
158        /// The timestamp of the newer version.
159        actual_commit_ts: Timestamp,
160    },
161    /// A read guard failed because the actual version did not match the expected version.
162    #[error(
163        "read guard failed: expected commit_ts {expected:?} but found {actual:?} for key {key:?}"
164    )]
165    GuardFailedVersionMismatch {
166        /// The key that failed the guard.
167        key: Vec<u8>,
168        /// The expected commit timestamp (or None if expected absent).
169        expected: Option<Timestamp>,
170        /// The actual commit timestamp found (or None if actually absent).
171        actual: Option<Timestamp>,
172    },
173    /// A read guard failed because the actual logical value did not match the expected value.
174    #[error("read guard failed: expected value mismatch for key {key:?}")]
175    GuardFailedValueMismatch {
176        /// The key that failed the guard.
177        key: Vec<u8>,
178    },
179    /// An error returned by the backend storage.
180    #[error("backend error: {0}")]
181    Backend(String),
182}
183
184/// Error during a prewrite batch.
185#[derive(Error, Debug, Clone, PartialEq, Eq)]
186pub enum BatchPrewriteError {
187    /// The batch contained no write operations.
188    #[error("batch is empty")]
189    EmptyBatch,
190    /// The batch contains multiple writes for the same key.
191    #[error("duplicate key in batch: {key:?}")]
192    DuplicateKeyInBatch {
193        /// The duplicate key.
194        key: Vec<u8>,
195    },
196    /// A key in the batch is currently locked by another active transaction.
197    #[error("key is locked by another transaction: key {key:?}, txn_id {txn_id}")]
198    KeyLocked {
199        /// The locked key.
200        key: Vec<u8>,
201        /// The transaction ID holding the lock.
202        txn_id: TxnId,
203    },
204    /// A committed version exists that is newer than the transaction's start_ts.
205    #[error("write conflict: committed version after start_ts for key {key:?}")]
206    WriteConflict {
207        /// The key that caused the conflict.
208        key: Vec<u8>,
209    },
210    /// An intent already exists for the same transaction but with different parameters.
211    #[error("intent already exists with different parameters for key {key:?}")]
212    IntentAlreadyExists {
213        /// The key with the conflicting intent.
214        key: Vec<u8>,
215    },
216    /// The batch is a partial replay, meaning some intents exist while others do not.
217    #[error("partial batch replay detected: some keys have intents, others are missing")]
218    PartialBatchReplay,
219    /// An error returned by the backend storage.
220    #[error("backend error: {0}")]
221    Backend(String),
222}
223
224/// Error during a commit batch.
225#[derive(Error, Debug, Clone, PartialEq, Eq)]
226pub enum BatchCommitError {
227    /// The batch contained no commit operations.
228    #[error("batch is empty")]
229    EmptyBatch,
230    /// The batch contains multiple commits for the same key.
231    #[error("duplicate key in batch: {key:?}")]
232    DuplicateKeyInBatch {
233        /// The duplicate key.
234        key: Vec<u8>,
235    },
236    /// The intent to be committed was not found.
237    #[error("intent not found for key {key:?}")]
238    IntentNotFound {
239        /// The key whose intent is missing.
240        key: Vec<u8>,
241    },
242    /// The transaction ID on the intent does not match the commit request.
243    #[error("txn_id mismatch for key {key:?}")]
244    TxnIdMismatch {
245        /// The key with the mismatched transaction ID.
246        key: Vec<u8>,
247    },
248    /// The start timestamp on the intent does not match the commit request.
249    #[error("start_ts mismatch for key {key:?}")]
250    StartTsMismatch {
251        /// The key with the mismatched start timestamp.
252        key: Vec<u8>,
253    },
254    /// The commit timestamp is less than or equal to the start timestamp.
255    #[error("invalid commit timestamp: commit_ts {commit_ts} <= start_ts {start_ts}")]
256    InvalidCommitTimestamp {
257        /// The start timestamp of the transaction.
258        start_ts: Timestamp,
259        /// The invalid commit timestamp.
260        commit_ts: Timestamp,
261    },
262    /// The commit timestamp is earlier than the intent's required minimum commit timestamp.
263    #[error("commit_ts {commit_ts} is before required minimum {min_commit_ts} for key {key:?}")]
264    CommitTsTooEarly {
265        /// The key failing the minimum commit timestamp check.
266        key: Vec<u8>,
267        /// The requested commit timestamp.
268        commit_ts: Timestamp,
269        /// The minimum allowed commit timestamp.
270        min_commit_ts: Timestamp,
271    },
272    /// The commit timestamp is older than the latest committed version for a key.
273    #[error("commit timestamp too old: key {key:?} at {commit_ts}, latest is {latest_commit_ts}")]
274    CommitTsTooOld {
275        /// The key that caused the error.
276        key: Vec<u8>,
277        /// The requested commit timestamp.
278        commit_ts: Timestamp,
279        /// The latest committed version's timestamp.
280        latest_commit_ts: Timestamp,
281    },
282    /// An error returned by the backend storage.
283    #[error("backend error: {0}")]
284    Backend(String),
285}
286
287/// Error during a batch abort operation.
288#[derive(Error, Debug, Clone, PartialEq, Eq)]
289pub enum BatchAbortError {
290    /// The batch contains multiple aborts for the same key.
291    #[error("duplicate key in batch: {key:?}")]
292    DuplicateKeyInBatch {
293        /// The duplicate key.
294        key: Vec<u8>,
295    },
296    /// An error returned by the backend storage.
297    #[error("backend error: {0}")]
298    Backend(String),
299}