surrealdb_core/kvs/
err.rs1use thiserror::Error;
2
3pub type Result<T> = std::result::Result<T, Error>;
5
6#[allow(dead_code, reason = "Some variants are only used by specific KV stores")]
11#[derive(Error, Debug)]
12pub enum Error {
13 #[error("There was a problem with the datastore: {0}")]
15 Datastore(String),
16
17 #[error("Connection to storage backend failed: {0}")]
19 ConnectionFailed(String),
20
21 #[error(
23 "The datastore is in read-and-deletion-only mode due to disk space limitations. Only read and delete operations are allowed. Deleting data will free up space and automatically restore normal operations when usage drops below the threshold"
24 )]
25 ReadAndDeleteOnly,
26
27 #[error("There was a problem with a transaction: {0}")]
29 Transaction(String),
30
31 #[error("The transaction is too large")]
33 TransactionTooLarge,
34
35 #[error("The key being inserted is too large")]
37 TransactionKeyTooLarge,
38
39 #[error("Transaction conflict: {0}. This transaction can be retried")]
41 TransactionConflict(String),
42
43 #[error("Couldn't update a finished transaction")]
45 TransactionFinished,
46
47 #[error("Couldn't write to a read only transaction")]
49 TransactionReadonly,
50
51 #[error("Value being checked was not correct")]
53 TransactionConditionNotMet,
54
55 #[error("The key being inserted already exists")]
57 TransactionKeyAlreadyExists,
58
59 #[error("The underlying datastore does not support versioned queries")]
61 UnsupportedVersionedQueries,
62
63 #[error("The specified timestamp is not valid for the underlying datastore: {0}")]
65 TimestampInvalid(String),
66
67 #[error("There was an internal error: {0}")]
69 Internal(String),
70
71 #[error("The storage layer does not support compaction requests.")]
72 CompactionNotSupported,
73}
74
75impl Error {
76 pub fn is_retryable(&self) -> bool {
78 matches!(self, Error::TransactionConflict(_))
79 }
80}
81
82impl From<std::num::TryFromIntError> for Error {
83 fn from(e: std::num::TryFromIntError) -> Error {
84 Error::TimestampInvalid(e.to_string())
85 }
86}
87
88#[cfg(feature = "kv-mem")]
89impl From<surrealmx::Error> for Error {
90 fn from(e: surrealmx::Error) -> Error {
91 match e {
92 surrealmx::Error::TxNotWritable => Error::TransactionReadonly,
93 surrealmx::Error::ValNotExpectedValue => Error::TransactionConditionNotMet,
94 surrealmx::Error::TxClosed => Error::TransactionFinished,
95 surrealmx::Error::KeyAlreadyExists => Error::TransactionKeyAlreadyExists,
96 surrealmx::Error::KeyReadConflict => Error::TransactionConflict(e.to_string()),
97 surrealmx::Error::KeyWriteConflict => Error::TransactionConflict(e.to_string()),
98 _ => Error::Transaction(e.to_string()),
99 }
100 }
101}
102
103#[cfg(feature = "kv-surrealkv")]
104impl From<surrealkv::Error> for Error {
105 fn from(e: surrealkv::Error) -> Error {
106 match e {
107 surrealkv::Error::TransactionWriteConflict => Error::TransactionConflict(e.to_string()),
108 surrealkv::Error::TransactionReadOnly => Error::TransactionReadonly,
109 surrealkv::Error::TransactionClosed => Error::TransactionFinished,
110 _ => Error::Transaction(e.to_string()),
111 }
112 }
113}
114
115#[cfg(feature = "kv-rocksdb")]
116impl From<rocksdb::Error> for Error {
117 fn from(e: rocksdb::Error) -> Error {
118 match e.kind() {
119 rocksdb::ErrorKind::Busy => Error::TransactionConflict(e.to_string()),
120 rocksdb::ErrorKind::TryAgain => Error::TransactionConflict(e.to_string()),
121 _ => Error::Transaction(e.to_string()),
122 }
123 }
124}
125
126#[cfg(feature = "kv-indxdb")]
127impl From<indxdb::Error> for Error {
128 fn from(e: indxdb::Error) -> Error {
129 match e {
130 indxdb::Error::DbError => Error::Datastore(e.to_string()),
131 indxdb::Error::TxError => Error::Transaction(e.to_string()),
132 indxdb::Error::TxClosed => Error::TransactionFinished,
133 indxdb::Error::TxNotWritable => Error::TransactionReadonly,
134 indxdb::Error::KeyAlreadyExists => Error::TransactionKeyAlreadyExists,
135 indxdb::Error::ValNotExpectedValue => Error::TransactionConditionNotMet,
136 _ => Error::Transaction(e.to_string()),
137 }
138 }
139}
140
141#[cfg(feature = "kv-tikv")]
142impl From<tikv::Error> for Error {
143 fn from(e: tikv::Error) -> Error {
144 match e {
145 tikv::Error::DuplicateKeyInsertion => Error::TransactionKeyAlreadyExists,
146 tikv::Error::Grpc(_) => Error::ConnectionFailed(e.to_string()),
147 tikv::Error::KeyError(ref ke) => {
148 if let Some(conflict) = &ke.conflict {
149 use crate::key::debug::Sprintable;
150 Error::TransactionConflict(conflict.key.sprint())
151 } else if ke.already_exist.is_some() {
152 Error::TransactionKeyAlreadyExists
153 } else if ke.abort.contains("KeyTooLarge") {
154 Error::TransactionKeyTooLarge
155 } else {
156 Error::Transaction(e.to_string())
157 }
158 }
159 tikv::Error::RegionError(ref re) if re.raft_entry_too_large.is_some() => {
160 Error::TransactionTooLarge
161 }
162 _ => Error::Transaction(e.to_string()),
163 }
164 }
165}
166
167impl From<anyhow::Error> for Error {
169 fn from(e: anyhow::Error) -> Self {
170 match e.downcast::<Error>() {
172 Ok(e) => e,
173 Err(e) => Error::Internal(e.to_string()),
174 }
175 }
176}