1use crate::analyticsx::error::Error as AnalyticsError;
20use crate::httpx::error::Error as HttpError;
21use crate::memdx;
22use crate::mgmtx::error::Error as MgmtError;
23use crate::queryx::error::Error as QueryError;
24use crate::retry::RetryRequest;
25use crate::searchx::error::Error as SearchError;
26use crate::service_type::ServiceType;
27use crate::tracingcomponent::MetricsName;
28use std::error::Error as StdError;
29use std::fmt::{Display, Formatter};
30use std::ops::Deref;
31use std::sync::Arc;
32
33pub type Result<T> = std::result::Result<T, Error>;
34
35#[derive(Debug, Clone)]
36pub struct Error {
37 kind: Arc<ErrorKind>,
38 retry_info: Option<RetryRequest>,
39}
40
41impl Display for Error {
42 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
43 if let Some(retry_info) = &self.retry_info {
44 return write!(f, "{}, {}", self.kind, retry_info);
45 }
46 write!(f, "{}", self.kind)
47 }
48}
49
50impl StdError for Error {
51 fn source(&self) -> Option<&(dyn StdError + 'static)> {
52 match self.kind.as_ref() {
53 ErrorKind::Memdx(err) => err.inner.source.source(),
54 ErrorKind::Query(err) => err.source(),
55 ErrorKind::Search(err) => err.source(),
56 ErrorKind::Http(err) => err.source(),
57 ErrorKind::Mgmt(err) => err.source(),
58 _ => None,
59 }
60 }
61}
62
63impl Error {
64 pub(crate) fn new(kind: ErrorKind) -> Self {
65 Self {
66 kind: Arc::new(kind),
67 retry_info: None,
68 }
69 }
70
71 pub(crate) fn new_contextual_memdx_error(e: MemdxError) -> Self {
72 Self::new(ErrorKind::Memdx(e))
73 }
74
75 pub(crate) fn new_message_error(msg: impl Into<String>) -> Self {
76 Self::new(ErrorKind::Message { msg: msg.into() })
77 }
78
79 pub(crate) fn new_invalid_argument_error(
80 msg: impl Into<String>,
81 arg: impl Into<Option<String>>,
82 ) -> Self {
83 Self::new(ErrorKind::InvalidArgument {
84 msg: msg.into(),
85 arg: arg.into(),
86 })
87 }
88
89 pub(crate) fn new_feature_not_available_error(
90 feature: impl Into<String>,
91 msg: impl Into<String>,
92 ) -> Self {
93 Self::new(ErrorKind::FeatureNotAvailable {
94 feature: feature.into(),
95 msg: msg.into(),
96 })
97 }
98
99 pub fn kind(&self) -> &ErrorKind {
100 &self.kind
101 }
102
103 pub(crate) fn is_memdx_error(&self) -> Option<&memdx::error::Error> {
104 match self.kind.as_ref() {
105 ErrorKind::Memdx(err) => Some(err),
106 _ => None,
107 }
108 }
109
110 pub(crate) fn set_retry_info(&mut self, retry_info: RetryRequest) {
111 self.retry_info = Some(retry_info);
112 }
113
114 pub fn retry_info(&self) -> Option<&RetryRequest> {
115 self.retry_info.as_ref()
116 }
117}
118
119#[derive(Debug, PartialEq)]
120#[non_exhaustive]
121pub enum ErrorKind {
122 Memdx(MemdxError),
123 Analytics(AnalyticsError),
124 Query(QueryError),
125 Search(SearchError),
126 Http(HttpError),
127 Mgmt(MgmtError),
128 VbucketMapOutdated,
129 #[non_exhaustive]
130 InvalidArgument {
131 msg: String,
132 arg: Option<String>,
133 },
134 #[non_exhaustive]
135 EndpointNotKnown {
136 endpoint: String,
137 },
138 InvalidVbucket {
139 requested_vb_id: u16,
140 num_vbuckets: usize,
141 },
142 InvalidReplica {
143 requested_replica: u32,
144 num_servers: usize,
145 },
146 NoEndpointsAvailable,
147 Shutdown,
148 NoBucket,
149 IllegalState {
150 msg: String,
151 },
152 NoVbucketMap,
153 #[non_exhaustive]
154 NoServerAssigned {
155 requested_vb_id: u16,
156 },
157 #[non_exhaustive]
158 CollectionManifestOutdated {
159 manifest_uid: u64,
160 server_manifest_uid: u64,
161 },
162 #[non_exhaustive]
163 Message {
164 msg: String,
165 },
166 #[non_exhaustive]
167 ServiceNotAvailable {
168 service: ServiceType,
169 },
170 #[non_exhaustive]
171 FeatureNotAvailable {
172 feature: String,
173 msg: String,
174 },
175 #[non_exhaustive]
176 Compression {
177 msg: String,
178 },
179 #[non_exhaustive]
180 Internal {
181 msg: String,
182 },
183}
184
185impl Display for ErrorKind {
186 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
187 match self {
188 ErrorKind::VbucketMapOutdated => write!(f, "vbucket map outdated"),
189 ErrorKind::InvalidArgument { msg, arg } => {
190 if let Some(arg) = arg {
191 write!(f, "invalid argument {arg}: {msg}")
192 } else {
193 write!(f, "invalid argument: {msg}")
194 }
195 }
196 ErrorKind::Memdx(err) => write!(f, "{err}"),
197 ErrorKind::Analytics(err) => write!(f, "{err}"),
198 ErrorKind::Query(err) => write!(f, "{err}"),
199 ErrorKind::Search(err) => write!(f, "{err}"),
200 ErrorKind::Http(err) => write!(f, "{err}"),
201 ErrorKind::Mgmt(err) => write!(f, "{err}"),
202 ErrorKind::EndpointNotKnown { endpoint } => {
203 write!(f, "endpoint not known: {endpoint}")
204 }
205 ErrorKind::NoEndpointsAvailable => write!(f, "no endpoints available"),
206 ErrorKind::Shutdown => write!(f, "shutdown"),
207 ErrorKind::NoBucket => write!(f, "no bucket selected"),
208 ErrorKind::IllegalState { msg } => write!(f, "illegal state: {msg}"),
209 ErrorKind::NoVbucketMap => write!(f, "invalid vbucket map"),
210 ErrorKind::CollectionManifestOutdated {
211 manifest_uid,
212 server_manifest_uid,
213 } => {
214 write!(
215 f,
216 "collection manifest outdated: our manifest uid: {manifest_uid}, server manifest uid: {server_manifest_uid}"
217 )
218 }
219 ErrorKind::Message { msg } => write!(f, "{msg}"),
220 ErrorKind::ServiceNotAvailable { service } => {
221 write!(f, "service not available: {service}")
222 }
223 ErrorKind::FeatureNotAvailable { feature, msg } => {
224 write!(f, "feature not available: {feature}, {msg}")
225 }
226 ErrorKind::Internal { msg } => write!(f, "internal error: {msg}"),
227 ErrorKind::NoServerAssigned { requested_vb_id } => {
228 write!(f, "no server assigned for vbucket id: {requested_vb_id}")
229 }
230 ErrorKind::InvalidVbucket {
231 requested_vb_id,
232 num_vbuckets,
233 } => write!(
234 f,
235 "invalid vbucket id: {requested_vb_id}, num vbuckets: {num_vbuckets}"
236 ),
237 ErrorKind::InvalidReplica {
238 requested_replica,
239 num_servers,
240 } => write!(
241 f,
242 "invalid replica: {requested_replica}, num servers: {num_servers}"
243 ),
244 ErrorKind::Compression { msg } => write!(f, "compression error: {msg}"),
245 }
246 }
247}
248
249impl MetricsName for Error {
250 fn metrics_name(&self) -> &'static str {
251 self.kind().metrics_name()
252 }
253}
254
255impl MetricsName for ErrorKind {
256 fn metrics_name(&self) -> &'static str {
257 match self {
258 ErrorKind::Memdx(err) => err.metrics_name(),
259 ErrorKind::Analytics(err) => err.metrics_name(),
260 ErrorKind::Query(err) => err.metrics_name(),
261 ErrorKind::Search(err) => err.metrics_name(),
262 ErrorKind::Http(err) => err.metrics_name(),
263 ErrorKind::Mgmt(err) => err.metrics_name(),
264 ErrorKind::InvalidArgument { .. } => "InvalidArgument",
265 ErrorKind::ServiceNotAvailable { .. } => "ServiceNotAvailable",
266 ErrorKind::FeatureNotAvailable { .. } => "FeatureNotAvailable",
267 ErrorKind::VbucketMapOutdated => "VBucketMapOutdated",
268 ErrorKind::EndpointNotKnown { .. } => "EndpointNotKnown",
269 ErrorKind::InvalidVbucket { .. } => "InvalidVbucket",
270 ErrorKind::InvalidReplica { .. } => "InvalidReplica",
271 ErrorKind::NoEndpointsAvailable => "NoEndpointsAvailable",
272 ErrorKind::Shutdown => "Shutdown",
273 ErrorKind::NoBucket => "NoBucket",
274 ErrorKind::IllegalState { .. } => "IllegalState",
275 ErrorKind::NoVbucketMap => "NoVbucketMap",
276 ErrorKind::NoServerAssigned { .. } => "NoServerAssigned",
277 ErrorKind::CollectionManifestOutdated { .. } => "CollectionManifestOutdated",
278 ErrorKind::Message { .. } => "_OTHER",
279 ErrorKind::Compression { .. } => "Compression",
280 ErrorKind::Internal { .. } => "_OTHER",
281 }
282 }
283}
284
285impl MetricsName for MemdxError {
286 fn metrics_name(&self) -> &'static str {
287 self.inner.source.metrics_name()
288 }
289}
290
291#[derive(Debug, PartialEq)]
292pub struct MemdxError {
293 inner: Box<InnerMemdxError>,
294}
295
296#[derive(Debug, PartialEq)]
297pub struct InnerMemdxError {
298 source: memdx::error::Error,
299 dispatched_to: Option<String>,
300 dispatched_from: Option<String>,
301 doc_id: Option<Vec<u8>>,
302 bucket_name: Option<String>,
303 scope_name: Option<String>,
304 collection_name: Option<String>,
305}
306
307impl Deref for MemdxError {
308 type Target = memdx::error::Error;
309
310 fn deref(&self) -> &Self::Target {
311 &self.inner.source
312 }
313}
314
315impl MemdxError {
316 pub(crate) fn new(source: memdx::error::Error) -> Self {
317 Self {
318 inner: Box::new(InnerMemdxError {
319 source,
320 dispatched_to: None,
321 dispatched_from: None,
322 doc_id: None,
323 bucket_name: None,
324 scope_name: None,
325 collection_name: None,
326 }),
327 }
328 }
329
330 pub(crate) fn with_dispatched_to(mut self, dispatched_to: impl Into<String>) -> Self {
331 self.inner.dispatched_to = Some(dispatched_to.into());
332 self
333 }
334
335 pub(crate) fn with_dispatched_from(mut self, dispatched_from: impl Into<String>) -> Self {
336 self.inner.dispatched_from = Some(dispatched_from.into());
337 self
338 }
339
340 pub fn dispatched_to(&self) -> Option<&String> {
341 self.inner.dispatched_to.as_ref()
342 }
343
344 pub fn dispatched_from(&self) -> Option<&String> {
345 self.inner.dispatched_from.as_ref()
346 }
347
348 pub fn doc_id(&self) -> Option<&[u8]> {
349 self.inner.doc_id.as_deref()
350 }
351
352 pub fn bucket_name(&self) -> Option<&String> {
353 self.inner.bucket_name.as_ref()
354 }
355
356 pub fn scope_name(&self) -> Option<&String> {
357 self.inner.scope_name.as_ref()
358 }
359
360 pub fn collection_name(&self) -> Option<&String> {
361 self.inner.collection_name.as_ref()
362 }
363
364 pub(crate) fn set_doc_id(mut self, doc_id: Vec<u8>) -> Self {
365 self.inner.doc_id = Some(doc_id);
366 self
367 }
368
369 pub(crate) fn set_bucket_name(mut self, bucket_name: String) -> Self {
370 self.inner.bucket_name = Some(bucket_name);
371 self
372 }
373
374 pub(crate) fn set_scope_name(mut self, scope_name: String) -> Self {
375 self.inner.scope_name = Some(scope_name);
376 self
377 }
378
379 pub(crate) fn set_collection_name(mut self, collection_name: String) -> Self {
380 self.inner.collection_name = Some(collection_name);
381 self
382 }
383}
384
385impl Display for MemdxError {
386 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
387 write!(f, "{}", self.inner.source)?;
388 if let Some(ref dispatched_to) = self.inner.dispatched_to {
389 write!(f, ", dispatched to: {dispatched_to}")?;
390 }
391 if let Some(ref dispatched_from) = self.inner.dispatched_from {
392 write!(f, ", dispatched from: {dispatched_from}")?;
393 }
394 Ok(())
395 }
396}
397
398impl<E> From<E> for Error
399where
400 ErrorKind: From<E>,
401{
402 fn from(err: E) -> Self {
403 Self {
404 kind: Arc::new(err.into()),
405 retry_info: None,
406 }
407 }
408}
409
410impl From<AnalyticsError> for Error {
411 fn from(value: AnalyticsError) -> Self {
412 Self::new(ErrorKind::Analytics(value))
413 }
414}
415
416impl From<QueryError> for Error {
417 fn from(value: QueryError) -> Self {
418 Self::new(ErrorKind::Query(value))
419 }
420}
421
422impl From<HttpError> for Error {
423 fn from(value: HttpError) -> Self {
424 Self::new(ErrorKind::Http(value))
425 }
426}
427
428impl From<SearchError> for Error {
429 fn from(value: SearchError) -> Self {
430 Self::new(ErrorKind::Search(value))
431 }
432}
433
434impl From<MgmtError> for Error {
435 fn from(value: MgmtError) -> Self {
436 Self::new(ErrorKind::Mgmt(value))
437 }
438}