1use crate::tree_store::{FILE_FORMAT_VERSION2, MAX_VALUE_LENGTH};
2use crate::{ReadTransaction, TypeName};
3use std::fmt::{Display, Formatter};
4use std::sync::PoisonError;
5use std::{io, panic};
6
7#[derive(Debug)]
9#[non_exhaustive]
10pub enum StorageError {
11 Corrupted(String),
13 ValueTooLarge(usize),
15 Io(io::Error),
16 PreviousIo,
17 LockPoisoned(&'static panic::Location<'static>),
18}
19
20impl<T> From<PoisonError<T>> for StorageError {
21 fn from(_: PoisonError<T>) -> StorageError {
22 StorageError::LockPoisoned(panic::Location::caller())
23 }
24}
25
26impl From<io::Error> for StorageError {
27 fn from(err: io::Error) -> StorageError {
28 StorageError::Io(err)
29 }
30}
31
32impl From<StorageError> for Error {
33 fn from(err: StorageError) -> Error {
34 match err {
35 StorageError::Corrupted(msg) => Error::Corrupted(msg),
36 StorageError::ValueTooLarge(x) => Error::ValueTooLarge(x),
37 StorageError::Io(x) => Error::Io(x),
38 StorageError::PreviousIo => Error::PreviousIo,
39 StorageError::LockPoisoned(location) => Error::LockPoisoned(location),
40 }
41 }
42}
43
44impl Display for StorageError {
45 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
46 match self {
47 StorageError::Corrupted(msg) => {
48 write!(f, "DB corrupted: {msg}")
49 }
50 StorageError::ValueTooLarge(len) => {
51 write!(
52 f,
53 "The value (length={len}) being inserted exceeds the maximum of {}GiB",
54 MAX_VALUE_LENGTH / 1024 / 1024 / 1024
55 )
56 }
57 StorageError::Io(err) => {
58 write!(f, "I/O error: {err}")
59 }
60 StorageError::PreviousIo => {
61 write!(
62 f,
63 "Previous I/O error occurred. Please close and re-open the database."
64 )
65 }
66 StorageError::LockPoisoned(location) => {
67 write!(f, "Poisoned internal lock: {location}")
68 }
69 }
70 }
71}
72
73impl std::error::Error for StorageError {}
74
75#[derive(Debug)]
77#[non_exhaustive]
78pub enum TableError {
79 TableTypeMismatch {
81 table: String,
82 key: TypeName,
83 value: TypeName,
84 },
85 TableIsMultimap(String),
87 TableIsNotMultimap(String),
89 TypeDefinitionChanged {
90 name: TypeName,
91 alignment: usize,
92 width: Option<usize>,
93 },
94 TableDoesNotExist(String),
96 TableAlreadyOpen(String, &'static panic::Location<'static>),
99 Storage(StorageError),
101}
102
103impl TableError {
104 pub(crate) fn into_storage_error_or_corrupted(self, msg: &str) -> StorageError {
105 match self {
106 TableError::TableTypeMismatch { .. }
107 | TableError::TableIsMultimap(_)
108 | TableError::TableIsNotMultimap(_)
109 | TableError::TypeDefinitionChanged { .. }
110 | TableError::TableDoesNotExist(_)
111 | TableError::TableAlreadyOpen(_, _) => {
112 StorageError::Corrupted(format!("{msg}: {self}"))
113 }
114 TableError::Storage(storage) => storage,
115 }
116 }
117}
118
119impl From<TableError> for Error {
120 fn from(err: TableError) -> Error {
121 match err {
122 TableError::TypeDefinitionChanged {
123 name,
124 alignment,
125 width,
126 } => Error::TypeDefinitionChanged {
127 name,
128 alignment,
129 width,
130 },
131 TableError::TableTypeMismatch { table, key, value } => {
132 Error::TableTypeMismatch { table, key, value }
133 }
134 TableError::TableIsMultimap(table) => Error::TableIsMultimap(table),
135 TableError::TableIsNotMultimap(table) => Error::TableIsNotMultimap(table),
136 TableError::TableDoesNotExist(table) => Error::TableDoesNotExist(table),
137 TableError::TableAlreadyOpen(name, location) => Error::TableAlreadyOpen(name, location),
138 TableError::Storage(storage) => storage.into(),
139 }
140 }
141}
142
143impl From<StorageError> for TableError {
144 fn from(err: StorageError) -> TableError {
145 TableError::Storage(err)
146 }
147}
148
149impl Display for TableError {
150 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
151 match self {
152 TableError::TypeDefinitionChanged {
153 name,
154 alignment,
155 width,
156 } => {
157 write!(
158 f,
159 "Current definition of {} does not match stored definition (width={:?}, alignment={})",
160 name.name(),
161 width,
162 alignment,
163 )
164 }
165 TableError::TableTypeMismatch { table, key, value } => {
166 write!(
167 f,
168 "{table} is of type Table<{}, {}>",
169 key.name(),
170 value.name(),
171 )
172 }
173 TableError::TableIsMultimap(table) => {
174 write!(f, "{table} is a multimap table")
175 }
176 TableError::TableIsNotMultimap(table) => {
177 write!(f, "{table} is not a multimap table")
178 }
179 TableError::TableDoesNotExist(table) => {
180 write!(f, "Table '{table}' does not exist")
181 }
182 TableError::TableAlreadyOpen(name, location) => {
183 write!(f, "Table '{name}' already opened at: {location}")
184 }
185 TableError::Storage(storage) => storage.fmt(f),
186 }
187 }
188}
189
190impl std::error::Error for TableError {}
191
192#[derive(Debug)]
194#[non_exhaustive]
195pub enum DatabaseError {
196 DatabaseAlreadyOpen,
198 RepairAborted,
200 UpgradeRequired(u8),
202 Storage(StorageError),
204}
205
206impl From<DatabaseError> for Error {
207 fn from(err: DatabaseError) -> Error {
208 match err {
209 DatabaseError::DatabaseAlreadyOpen => Error::DatabaseAlreadyOpen,
210 DatabaseError::RepairAborted => Error::RepairAborted,
211 DatabaseError::UpgradeRequired(x) => Error::UpgradeRequired(x),
212 DatabaseError::Storage(storage) => storage.into(),
213 }
214 }
215}
216
217impl From<io::Error> for DatabaseError {
218 fn from(err: io::Error) -> DatabaseError {
219 DatabaseError::Storage(StorageError::Io(err))
220 }
221}
222
223impl From<StorageError> for DatabaseError {
224 fn from(err: StorageError) -> DatabaseError {
225 DatabaseError::Storage(err)
226 }
227}
228
229impl Display for DatabaseError {
230 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
231 match self {
232 DatabaseError::UpgradeRequired(actual) => {
233 write!(f, "Manual upgrade required. Expected file format version {FILE_FORMAT_VERSION2}, but file is version {actual}")
234 }
235 DatabaseError::RepairAborted => {
236 write!(f, "Database repair aborted.")
237 }
238 DatabaseError::DatabaseAlreadyOpen => {
239 write!(f, "Database already open. Cannot acquire lock.")
240 }
241 DatabaseError::Storage(storage) => storage.fmt(f),
242 }
243 }
244}
245
246impl std::error::Error for DatabaseError {}
247
248#[derive(Debug)]
250#[non_exhaustive]
251pub enum SavepointError {
252 InvalidSavepoint,
257 Storage(StorageError),
259}
260
261impl From<SavepointError> for Error {
262 fn from(err: SavepointError) -> Error {
263 match err {
264 SavepointError::InvalidSavepoint => Error::InvalidSavepoint,
265 SavepointError::Storage(storage) => storage.into(),
266 }
267 }
268}
269
270impl From<StorageError> for SavepointError {
271 fn from(err: StorageError) -> SavepointError {
272 SavepointError::Storage(err)
273 }
274}
275
276impl Display for SavepointError {
277 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
278 match self {
279 SavepointError::InvalidSavepoint => {
280 write!(f, "Savepoint is invalid or cannot be created.")
281 }
282 SavepointError::Storage(storage) => storage.fmt(f),
283 }
284 }
285}
286
287impl std::error::Error for SavepointError {}
288
289#[derive(Debug)]
291#[non_exhaustive]
292pub enum CompactionError {
293 PersistentSavepointExists,
295 EphemeralSavepointExists,
297 TransactionInProgress,
299 Storage(StorageError),
301}
302
303impl From<CompactionError> for Error {
304 fn from(err: CompactionError) -> Error {
305 match err {
306 CompactionError::PersistentSavepointExists => Error::PersistentSavepointExists,
307 CompactionError::EphemeralSavepointExists => Error::EphemeralSavepointExists,
308 CompactionError::TransactionInProgress => Error::TransactionInProgress,
309 CompactionError::Storage(storage) => storage.into(),
310 }
311 }
312}
313
314impl From<StorageError> for CompactionError {
315 fn from(err: StorageError) -> CompactionError {
316 CompactionError::Storage(err)
317 }
318}
319
320impl Display for CompactionError {
321 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
322 match self {
323 CompactionError::PersistentSavepointExists => {
324 write!(
325 f,
326 "Persistent savepoint exists. Operation cannot be performed."
327 )
328 }
329 CompactionError::EphemeralSavepointExists => {
330 write!(
331 f,
332 "Ephemeral savepoint exists. Operation cannot be performed."
333 )
334 }
335 CompactionError::TransactionInProgress => {
336 write!(
337 f,
338 "A transaction is still in progress. Operation cannot be performed."
339 )
340 }
341 CompactionError::Storage(storage) => storage.fmt(f),
342 }
343 }
344}
345
346impl std::error::Error for CompactionError {}
347
348#[derive(Debug)]
350#[non_exhaustive]
351pub enum TransactionError {
352 Storage(StorageError),
354 ReadTransactionStillInUse(ReadTransaction),
356}
357
358impl TransactionError {
359 pub(crate) fn into_storage_error(self) -> StorageError {
360 match self {
361 TransactionError::Storage(storage) => storage,
362 _ => unreachable!(),
363 }
364 }
365}
366
367impl From<TransactionError> for Error {
368 fn from(err: TransactionError) -> Error {
369 match err {
370 TransactionError::Storage(storage) => storage.into(),
371 TransactionError::ReadTransactionStillInUse(txn) => {
372 Error::ReadTransactionStillInUse(txn)
373 }
374 }
375 }
376}
377
378impl From<StorageError> for TransactionError {
379 fn from(err: StorageError) -> TransactionError {
380 TransactionError::Storage(err)
381 }
382}
383
384impl Display for TransactionError {
385 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
386 match self {
387 TransactionError::Storage(storage) => storage.fmt(f),
388 TransactionError::ReadTransactionStillInUse(_) => {
389 write!(f, "Transaction still in use")
390 }
391 }
392 }
393}
394
395impl std::error::Error for TransactionError {}
396
397#[derive(Debug)]
399#[non_exhaustive]
400pub enum CommitError {
401 Storage(StorageError),
403}
404
405impl CommitError {
406 pub(crate) fn into_storage_error(self) -> StorageError {
407 match self {
408 CommitError::Storage(storage) => storage,
409 }
410 }
411}
412
413impl From<CommitError> for Error {
414 fn from(err: CommitError) -> Error {
415 match err {
416 CommitError::Storage(storage) => storage.into(),
417 }
418 }
419}
420
421impl From<StorageError> for CommitError {
422 fn from(err: StorageError) -> CommitError {
423 CommitError::Storage(err)
424 }
425}
426
427impl Display for CommitError {
428 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
429 match self {
430 CommitError::Storage(storage) => storage.fmt(f),
431 }
432 }
433}
434
435impl std::error::Error for CommitError {}
436
437#[derive(Debug)]
439#[non_exhaustive]
440pub enum Error {
441 DatabaseAlreadyOpen,
443 InvalidSavepoint,
448 RepairAborted,
450 PersistentSavepointExists,
452 EphemeralSavepointExists,
454 TransactionInProgress,
456 Corrupted(String),
458 UpgradeRequired(u8),
460 ValueTooLarge(usize),
462 TableTypeMismatch {
464 table: String,
465 key: TypeName,
466 value: TypeName,
467 },
468 TableIsMultimap(String),
470 TableIsNotMultimap(String),
472 TypeDefinitionChanged {
473 name: TypeName,
474 alignment: usize,
475 width: Option<usize>,
476 },
477 TableDoesNotExist(String),
479 TableAlreadyOpen(String, &'static panic::Location<'static>),
482 Io(io::Error),
483 PreviousIo,
485 LockPoisoned(&'static panic::Location<'static>),
486 ReadTransactionStillInUse(ReadTransaction),
488}
489
490impl<T> From<PoisonError<T>> for Error {
491 fn from(_: PoisonError<T>) -> Error {
492 Error::LockPoisoned(panic::Location::caller())
493 }
494}
495
496impl From<io::Error> for Error {
497 fn from(err: io::Error) -> Error {
498 Error::Io(err)
499 }
500}
501
502impl Display for Error {
503 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
504 match self {
505 Error::Corrupted(msg) => {
506 write!(f, "DB corrupted: {msg}")
507 }
508 Error::UpgradeRequired(actual) => {
509 write!(f, "Manual upgrade required. Expected file format version {FILE_FORMAT_VERSION2}, but file is version {actual}")
510 }
511 Error::ValueTooLarge(len) => {
512 write!(
513 f,
514 "The value (length={len}) being inserted exceeds the maximum of {}GiB",
515 MAX_VALUE_LENGTH / 1024 / 1024 / 1024
516 )
517 }
518 Error::TypeDefinitionChanged {
519 name,
520 alignment,
521 width,
522 } => {
523 write!(
524 f,
525 "Current definition of {} does not match stored definition (width={:?}, alignment={})",
526 name.name(),
527 width,
528 alignment,
529 )
530 }
531 Error::TableTypeMismatch { table, key, value } => {
532 write!(
533 f,
534 "{table} is of type Table<{}, {}>",
535 key.name(),
536 value.name(),
537 )
538 }
539 Error::TableIsMultimap(table) => {
540 write!(f, "{table} is a multimap table")
541 }
542 Error::TableIsNotMultimap(table) => {
543 write!(f, "{table} is not a multimap table")
544 }
545 Error::TableDoesNotExist(table) => {
546 write!(f, "Table '{table}' does not exist")
547 }
548 Error::TableAlreadyOpen(name, location) => {
549 write!(f, "Table '{name}' already opened at: {location}")
550 }
551 Error::Io(err) => {
552 write!(f, "I/O error: {err}")
553 }
554 Error::PreviousIo => {
555 write!(
556 f,
557 "Previous I/O error occurred. Please close and re-open the database."
558 )
559 }
560 Error::LockPoisoned(location) => {
561 write!(f, "Poisoned internal lock: {location}")
562 }
563 Error::DatabaseAlreadyOpen => {
564 write!(f, "Database already open. Cannot acquire lock.")
565 }
566 Error::RepairAborted => {
567 write!(f, "Database repair aborted.")
568 }
569 Error::PersistentSavepointExists => {
570 write!(
571 f,
572 "Persistent savepoint exists. Operation cannot be performed."
573 )
574 }
575 Error::EphemeralSavepointExists => {
576 write!(
577 f,
578 "Ephemeral savepoint exists. Operation cannot be performed."
579 )
580 }
581 Error::TransactionInProgress => {
582 write!(
583 f,
584 "A transaction is still in progress. Operation cannot be performed."
585 )
586 }
587 Error::InvalidSavepoint => {
588 write!(f, "Savepoint is invalid or cannot be created.")
589 }
590 Error::ReadTransactionStillInUse(_) => {
591 write!(f, "Transaction still in use")
592 }
593 }
594 }
595}
596
597impl std::error::Error for Error {}