Skip to main content

couchbase_core/memdx/
error.rs

1/*
2 *
3 *  * Copyright (c) 2025 Couchbase, Inc.
4 *  *
5 *  * Licensed under the Apache License, Version 2.0 (the "License");
6 *  * you may not use this file except in compliance with the License.
7 *  * You may obtain a copy of the License at
8 *  *
9 *  *    http://www.apache.org/licenses/LICENSE-2.0
10 *  *
11 *  * Unless required by applicable law or agreed to in writing, software
12 *  * distributed under the License is distributed on an "AS IS" BASIS,
13 *  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  * See the License for the specific language governing permissions and
15 *  * limitations under the License.
16 *
17 */
18
19use serde::Deserialize;
20use std::error::Error as StdError;
21use std::fmt::{Display, Formatter, Pointer};
22use std::io;
23
24use crate::memdx::opcode::OpCode;
25use crate::memdx::status::Status;
26use crate::tracingcomponent::MetricsName;
27
28pub type Result<T> = std::result::Result<T, Error>;
29
30#[derive(Debug, PartialEq)]
31pub struct Error {
32    inner: ErrorImpl,
33}
34
35impl Error {
36    pub(crate) fn new_protocol_error(msg: impl Into<String>) -> Self {
37        Self {
38            inner: ErrorImpl {
39                kind: Box::new(ErrorKind::Protocol { msg: msg.into() }),
40                source: None,
41            },
42        }
43    }
44
45    pub(crate) fn new_decompression_error() -> Self {
46        Self {
47            inner: ErrorImpl {
48                kind: Box::new(ErrorKind::Decompression {}),
49                source: None,
50            },
51        }
52    }
53
54    pub(crate) fn new_message_error(msg: impl Into<String>) -> Self {
55        Self {
56            inner: ErrorImpl {
57                kind: Box::new(ErrorKind::Message(msg.into())),
58                source: None,
59            },
60        }
61    }
62
63    pub(crate) fn new_cancelled_error(cancellation_kind: CancellationErrorKind) -> Self {
64        Self {
65            inner: ErrorImpl {
66                kind: Box::new(ErrorKind::Cancelled(cancellation_kind)),
67                source: None,
68            },
69        }
70    }
71
72    pub(crate) fn new_invalid_argument_error(
73        msg: impl Into<String>,
74        arg: impl Into<Option<String>>,
75    ) -> Self {
76        Self {
77            inner: ErrorImpl {
78                kind: Box::new(ErrorKind::InvalidArgument {
79                    msg: msg.into(),
80                    arg: arg.into(),
81                }),
82                source: None,
83            },
84        }
85    }
86
87    pub(crate) fn new_connection_failed_error(
88        reason: impl Into<String>,
89        source: Box<io::Error>,
90    ) -> Self {
91        Self {
92            inner: ErrorImpl {
93                kind: Box::new(ErrorKind::ConnectionFailed { msg: reason.into() }),
94                source: Some(source),
95            },
96        }
97    }
98
99    pub(crate) fn new_dispatch_error(opaque: u32, op_code: OpCode, source: Box<Error>) -> Self {
100        Self {
101            inner: ErrorImpl {
102                kind: Box::new(ErrorKind::Dispatch { opaque, op_code }),
103                source: Some(source),
104            },
105        }
106    }
107
108    pub(crate) fn new_close_error(msg: String, source: Box<Error>) -> Self {
109        Self {
110            inner: ErrorImpl {
111                kind: Box::new(ErrorKind::Close { msg }),
112                source: Some(source),
113            },
114        }
115    }
116
117    pub fn has_server_config(&self) -> Option<&Vec<u8>> {
118        if let ErrorKind::Server(ServerError { config, .. }) = self.inner.kind.as_ref() {
119            config.as_ref()
120        } else {
121            None
122        }
123    }
124
125    pub fn has_server_error_context(&self) -> Option<&Vec<u8>> {
126        if let ErrorKind::Server(ServerError { context, .. }) = self.inner.kind.as_ref() {
127            context.as_ref()
128        } else if let ErrorKind::Resource(ResourceError { cause, .. }) = self.inner.kind.as_ref() {
129            cause.context.as_ref()
130        } else {
131            None
132        }
133    }
134
135    pub fn has_opaque(&self) -> Option<u32> {
136        let inner_kind = self.inner.kind.as_ref();
137        if let ErrorKind::Server(ServerError { opaque, .. }) = inner_kind {
138            Some(*opaque)
139        } else if let ErrorKind::Resource(e) = inner_kind {
140            Some(e.cause.opaque)
141        } else if let ErrorKind::Dispatch { opaque, .. } = inner_kind {
142            Some(*opaque)
143        } else {
144            None
145        }
146    }
147
148    pub fn is_cancellation_error(&self) -> bool {
149        matches!(self.inner.kind.as_ref(), ErrorKind::Cancelled { .. })
150    }
151
152    pub fn is_dispatch_error(&self) -> bool {
153        matches!(self.inner.kind.as_ref(), ErrorKind::Dispatch { .. })
154    }
155
156    pub fn is_server_error_kind(&self, kind: ServerErrorKind) -> bool {
157        match self.inner.kind.as_ref() {
158            ErrorKind::Server(e) => e.kind == kind,
159            ErrorKind::Resource(e) => e.cause.kind == kind,
160            _ => false,
161        }
162    }
163
164    pub fn kind(&self) -> &ErrorKind {
165        &self.inner.kind
166    }
167
168    pub(crate) fn with<C: Into<Source>>(mut self, source: C) -> Error {
169        self.inner.source = Some(source.into());
170        self
171    }
172}
173
174type Source = Box<dyn StdError + Send + Sync>;
175
176#[derive(Debug)]
177struct ErrorImpl {
178    kind: Box<ErrorKind>,
179    source: Option<Source>,
180}
181
182impl PartialEq for ErrorImpl {
183    fn eq(&self, other: &Self) -> bool {
184        self.kind == other.kind
185    }
186}
187
188impl Display for Error {
189    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
190        write!(f, "{}", self.inner.kind)
191    }
192}
193
194impl StdError for Error {
195    fn source(&self) -> Option<&(dyn StdError + 'static)> {
196        self.inner
197            .source
198            .as_ref()
199            .map(|cause| &**cause as &(dyn StdError + 'static))
200    }
201}
202
203#[derive(Debug, Clone, PartialEq)]
204#[non_exhaustive]
205pub enum ErrorKind {
206    Server(ServerError),
207    Resource(ResourceError),
208    #[non_exhaustive]
209    Dispatch {
210        opaque: u32,
211        op_code: OpCode,
212    },
213    #[non_exhaustive]
214    Close {
215        msg: String,
216    },
217    #[non_exhaustive]
218    Protocol {
219        msg: String,
220    },
221    Cancelled(CancellationErrorKind),
222    #[non_exhaustive]
223    ConnectionFailed {
224        msg: String,
225    },
226    Io,
227    #[non_exhaustive]
228    InvalidArgument {
229        msg: String,
230        arg: Option<String>,
231    },
232    Decompression,
233    Message(String),
234}
235
236impl Display for ErrorKind {
237    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
238        match self {
239            ErrorKind::Server(e) => write!(f, "{e}"),
240            ErrorKind::Resource(e) => write!(f, "{e}"),
241            ErrorKind::Dispatch { opaque, op_code } => {
242                write!(f, "dispatch failed: opaque: {opaque}, op_code: {op_code}")
243            }
244            ErrorKind::Close { msg } => {
245                write!(f, "close error {msg}")
246            }
247            ErrorKind::Protocol { msg } => {
248                write!(f, "{msg}")
249            }
250            ErrorKind::Cancelled(kind) => {
251                write!(f, "request cancelled: {kind}")
252            }
253            ErrorKind::ConnectionFailed { msg } => {
254                write!(f, "connection failed {msg}")
255            }
256            ErrorKind::Io => {
257                write!(f, "connection error")
258            }
259            ErrorKind::InvalidArgument { msg, arg } => {
260                let base_msg = format!("invalid argument: {msg}");
261                if let Some(arg) = arg {
262                    write!(f, "{base_msg}, arg: {arg}")
263                } else {
264                    write!(f, "{base_msg}")
265                }
266            }
267            ErrorKind::Decompression => write!(f, "decompression error"),
268            ErrorKind::Message(msg) => write!(f, "{msg}"),
269        }
270    }
271}
272
273#[derive(Clone, Debug, PartialEq, Eq)]
274#[non_exhaustive]
275pub struct ResourceError {
276    cause: ServerError,
277    scope_name: String,
278    collection_name: String,
279}
280
281impl StdError for ResourceError {}
282
283impl ResourceError {
284    pub(crate) fn new(
285        cause: ServerError,
286        scope_name: impl Into<String>,
287        collection_name: impl Into<String>,
288    ) -> Self {
289        Self {
290            cause,
291            scope_name: scope_name.into(),
292            collection_name: collection_name.into(),
293        }
294    }
295
296    pub fn cause(&self) -> &ServerError {
297        &self.cause
298    }
299
300    pub fn scope_name(&self) -> &str {
301        &self.scope_name
302    }
303
304    pub fn collection_name(&self) -> &str {
305        &self.collection_name
306    }
307}
308
309impl Display for ResourceError {
310    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
311        write!(
312            f,
313            "Resource error: {}, scope: {}, collection: {}",
314            self.cause, self.scope_name, self.collection_name
315        )
316    }
317}
318
319#[derive(Clone, Debug, PartialEq, Eq)]
320#[non_exhaustive]
321pub struct ServerError {
322    kind: ServerErrorKind,
323    config: Option<Vec<u8>>,
324    context: Option<Vec<u8>>,
325    op_code: OpCode,
326    status: Status,
327    opaque: u32,
328}
329
330impl StdError for ServerError {}
331
332impl Display for ServerError {
333    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
334        let mut base_msg = format!(
335            "Server error: {}, status: 0x{:02x}, opcode: {}, opaque: {}",
336            self.kind,
337            u16::from(self.status),
338            self.op_code,
339            self.opaque
340        );
341
342        if let Some(context) = &self.context {
343            if let Some(parsed) = Self::parse_context(context) {
344                base_msg.push_str(" (");
345                if let Some(text) = &parsed.text {
346                    base_msg.push_str(&format!("context: {text}, "));
347                }
348
349                if let Some(error_ref) = &parsed.error_ref {
350                    base_msg.push_str(&format!("error_ref: {error_ref}"));
351                }
352                base_msg.push(')');
353            }
354        }
355
356        write!(f, "{base_msg}")
357    }
358}
359
360impl ServerError {
361    pub(crate) fn new(kind: ServerErrorKind, op_code: OpCode, status: Status, opaque: u32) -> Self {
362        Self {
363            kind,
364            config: None,
365            context: None,
366            op_code,
367            status,
368            opaque,
369        }
370    }
371
372    pub(crate) fn with_context(mut self, context: Vec<u8>) -> Self {
373        self.context = Some(context);
374        self
375    }
376
377    pub(crate) fn with_config(mut self, config: Vec<u8>) -> Self {
378        self.config = Some(config);
379        self
380    }
381
382    pub fn kind(&self) -> &ServerErrorKind {
383        &self.kind
384    }
385
386    pub fn config(&self) -> Option<&Vec<u8>> {
387        self.config.as_ref()
388    }
389
390    pub fn context(&self) -> Option<&Vec<u8>> {
391        self.context.as_ref()
392    }
393
394    pub fn op_code(&self) -> OpCode {
395        self.op_code
396    }
397
398    pub fn status(&self) -> Status {
399        self.status
400    }
401
402    pub fn opaque(&self) -> u32 {
403        self.opaque
404    }
405
406    pub fn parse_context(context: &[u8]) -> Option<ServerErrorContext> {
407        if context.is_empty() {
408            return None;
409        }
410
411        let context_json: ServerErrorContextJson = match serde_json::from_slice(context) {
412            Ok(c) => c,
413            Err(_) => {
414                return None;
415            }
416        };
417
418        let text = context_json.error.context;
419
420        let error_ref = context_json.error.error_ref;
421
422        let manifest_rev = context_json
423            .manifest_rev
424            .map(|manifest_rev| u64::from_str_radix(&manifest_rev, 16).unwrap_or_default());
425
426        Some(ServerErrorContext {
427            text,
428            error_ref,
429            manifest_rev,
430        })
431    }
432}
433
434#[derive(Clone, Debug, PartialEq, Eq)]
435#[non_exhaustive]
436pub struct ServerErrorContext {
437    pub text: Option<String>,
438    pub error_ref: Option<String>,
439    pub manifest_rev: Option<u64>,
440}
441
442#[derive(Clone, Debug, Eq, Hash, PartialEq)]
443#[non_exhaustive]
444pub enum ServerErrorKind {
445    KeyNotFound,
446    KeyExists,
447    TooBig,
448    NotStored,
449    BadDelta,
450    NotMyVbucket,
451    NoBucket,
452    Locked,
453    NotLocked,
454    Auth { msg: String },
455    RangeError,
456    Access,
457    RateLimitedNetworkIngress,
458    RateLimitedNetworkEgress,
459    RateLimitedMaxConnections,
460    RateLimitedMaxCommands,
461    RateLimitedScopeSizeLimitExceeded,
462    UnknownCommand,
463    NotSupported,
464    InternalError,
465    Busy,
466    TmpFail,
467    UnknownCollectionID,
468    UnknownScopeName,
469    UnknownCollectionName,
470    DurabilityInvalid,
471    DurabilityImpossible,
472    SyncWriteInProgress,
473    SyncWriteAmbiguous,
474    SyncWriteRecommitInProgress,
475    RangeScanCancelled,
476    RangeScanVBUUIDNotEqual,
477    InvalidArgs,
478    AuthStale,
479
480    ConfigNotSet,
481    UnknownBucketName,
482    CasMismatch,
483
484    Subdoc { error: SubdocError },
485
486    UnknownStatus { status: Status },
487}
488
489impl Display for ServerErrorKind {
490    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
491        match self {
492            ServerErrorKind::NotMyVbucket => write!(f, "not my vbucket"),
493            ServerErrorKind::KeyExists => write!(f, "key exists"),
494            ServerErrorKind::NotStored => write!(f, "key not stored"),
495            ServerErrorKind::KeyNotFound => write!(f, "key not found"),
496            ServerErrorKind::TmpFail => write!(f, "temporary failure"),
497            ServerErrorKind::CasMismatch => write!(f, "cas mismatch"),
498            ServerErrorKind::Locked => write!(f, "locked"),
499            ServerErrorKind::NotLocked => write!(f, "not locked"),
500            ServerErrorKind::TooBig => write!(f, "too big"),
501            ServerErrorKind::UnknownCollectionID => write!(f, "unknown collection id"),
502            ServerErrorKind::NoBucket => write!(f, "no bucket selected"),
503            ServerErrorKind::UnknownBucketName => write!(f, "unknown bucket name"),
504            ServerErrorKind::Access => write!(f, "access error"),
505            ServerErrorKind::Auth { msg } => write!(f, "auth error {msg}"),
506            ServerErrorKind::ConfigNotSet => write!(f, "config not set"),
507            ServerErrorKind::UnknownScopeName => write!(f, "scope name unknown"),
508            ServerErrorKind::UnknownCollectionName => write!(f, "collection name unknown"),
509            ServerErrorKind::Subdoc { error } => write!(f, "{error}"),
510            ServerErrorKind::UnknownStatus { status } => {
511                write!(f, "server status unexpected for operation: {status}")
512            }
513            ServerErrorKind::BadDelta => write!(f, "bad delta"),
514            ServerErrorKind::UnknownCommand => write!(f, "unknown command"),
515            ServerErrorKind::RangeError => write!(f, "range error"),
516            ServerErrorKind::RateLimitedNetworkIngress => {
517                write!(f, "rate limited: network ingress")
518            }
519            ServerErrorKind::RateLimitedNetworkEgress => write!(f, "rate limited: network egress"),
520            ServerErrorKind::RateLimitedMaxConnections => {
521                write!(f, "rate limited: max connections")
522            }
523            ServerErrorKind::RateLimitedMaxCommands => write!(f, "rate limited: max commands"),
524            ServerErrorKind::RateLimitedScopeSizeLimitExceeded => {
525                write!(f, "rate limited: scope size limit exceeded")
526            }
527            ServerErrorKind::NotSupported => write!(f, "not supported"),
528            ServerErrorKind::InternalError => write!(f, "internal error"),
529            ServerErrorKind::Busy => write!(f, "busy"),
530            ServerErrorKind::DurabilityInvalid => write!(f, "durability invalid"),
531            ServerErrorKind::DurabilityImpossible => write!(f, "durability impossible"),
532            ServerErrorKind::SyncWriteInProgress => write!(f, "sync write in progress"),
533            ServerErrorKind::SyncWriteAmbiguous => write!(f, "sync write ambiguous"),
534            ServerErrorKind::SyncWriteRecommitInProgress => {
535                write!(f, "sync write recommit in progress")
536            }
537            ServerErrorKind::RangeScanCancelled => write!(f, "range scan cancelled"),
538            ServerErrorKind::RangeScanVBUUIDNotEqual => write!(f, "range scan vbUUID not equal"),
539            ServerErrorKind::InvalidArgs => write!(f, "invalid args"),
540            ServerErrorKind::AuthStale => write!(f, "auth stale"),
541        }
542    }
543}
544
545#[derive(Clone, Debug, PartialEq, Eq, Hash)]
546#[non_exhaustive]
547pub struct SubdocError {
548    kind: SubdocErrorKind,
549    op_index: Option<u8>,
550}
551
552impl StdError for SubdocError {}
553
554impl SubdocError {
555    pub(crate) fn new(kind: SubdocErrorKind, op_index: impl Into<Option<u8>>) -> Self {
556        Self {
557            kind,
558            op_index: op_index.into(),
559        }
560    }
561
562    pub fn is_error_kind(&self, kind: SubdocErrorKind) -> bool {
563        self.kind == kind
564    }
565
566    pub fn kind(&self) -> &SubdocErrorKind {
567        &self.kind
568    }
569
570    pub fn op_index(&self) -> Option<u8> {
571        self.op_index
572    }
573}
574
575impl Display for SubdocError {
576    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
577        if let Some(op_index) = self.op_index {
578            let base_msg = format!("Subdoc error: {}, op_index: {}", self.kind, op_index);
579            write!(f, "{base_msg}")
580        } else {
581            let base_msg = format!("Subdoc error: {}", self.kind);
582            write!(f, "{base_msg}")
583        }
584    }
585}
586
587#[derive(Clone, Debug, Eq, Hash, PartialEq)]
588#[non_exhaustive]
589pub enum SubdocErrorKind {
590    PathNotFound,
591    PathMismatch,
592    PathInvalid,
593    PathTooBig,
594    DocTooDeep,
595    CantInsert,
596    NotJSON,
597    BadRange,
598    BadDelta,
599    PathExists,
600    ValueTooDeep,
601    InvalidCombo,
602    XattrInvalidFlagCombo,
603    XattrInvalidKeyCombo,
604    XattrUnknownMacro,
605    XattrUnknownVAttr,
606    XattrCannotModifyVAttr,
607    InvalidXattrOrder,
608    XattrUnknownVattrMacro,
609    CanOnlyReviveDeletedDocuments,
610    DeletedDocumentCantHaveValue,
611    UnknownStatus { status: Status },
612}
613
614impl Display for SubdocErrorKind {
615    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
616        match self {
617            SubdocErrorKind::PathNotFound => write!(f, "subdoc path not found"),
618            SubdocErrorKind::PathMismatch => write!(f, "subdoc path mismatch"),
619            SubdocErrorKind::PathInvalid => write!(f, "subdoc path invalid"),
620            SubdocErrorKind::PathTooBig => write!(f, "subdoc path too big"),
621            SubdocErrorKind::DocTooDeep => write!(f, "subdoc doc too deep"),
622            SubdocErrorKind::CantInsert => write!(f, "subdoc can't insert"),
623            SubdocErrorKind::NotJSON => write!(f, "subdoc not JSON"),
624            SubdocErrorKind::BadRange => write!(f, "subdoc bad range"),
625            SubdocErrorKind::BadDelta => write!(f, "subdoc bad delta"),
626            SubdocErrorKind::PathExists => write!(f, "subdoc path exists"),
627            SubdocErrorKind::ValueTooDeep => write!(f, "subdoc value too deep"),
628            SubdocErrorKind::InvalidCombo => write!(f, "subdoc invalid combo"),
629            SubdocErrorKind::XattrInvalidFlagCombo => write!(f, "subdoc xattr invalid flag combo"),
630            SubdocErrorKind::XattrInvalidKeyCombo => write!(f, "subdoc xattr invalid key combo"),
631            SubdocErrorKind::XattrUnknownMacro => write!(f, "subdoc xattr unknown macro"),
632            SubdocErrorKind::XattrUnknownVAttr => write!(f, "subdoc xattr unknown vattr"),
633            SubdocErrorKind::XattrCannotModifyVAttr => {
634                write!(f, "subdoc xattr cannot modify vattr")
635            }
636            SubdocErrorKind::InvalidXattrOrder => write!(f, "subdoc invalid xattr order"),
637            SubdocErrorKind::XattrUnknownVattrMacro => {
638                write!(f, "subdoc xattr unknown vattr macro")
639            }
640            SubdocErrorKind::CanOnlyReviveDeletedDocuments => {
641                write!(f, "subdoc can only revive deleted documents")
642            }
643            SubdocErrorKind::DeletedDocumentCantHaveValue => {
644                write!(f, "subdoc deleted document can't have value")
645            }
646            SubdocErrorKind::UnknownStatus { status } => write!(
647                f,
648                "subdoc unknown status unexpected for operation: {status}"
649            ),
650        }
651    }
652}
653
654#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
655#[non_exhaustive]
656pub enum CancellationErrorKind {
657    Timeout,
658    RequestCancelled,
659    ClosedInFlight,
660}
661
662impl Display for CancellationErrorKind {
663    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
664        let txt = match self {
665            CancellationErrorKind::Timeout => "Timeout",
666            CancellationErrorKind::RequestCancelled => "Request cancelled",
667            CancellationErrorKind::ClosedInFlight => "Closed in flight",
668        };
669
670        write!(f, "{txt}")
671    }
672}
673
674impl<E> From<E> for Error
675where
676    ErrorKind: From<E>,
677{
678    fn from(err: E) -> Self {
679        Self {
680            inner: ErrorImpl {
681                kind: Box::new(ErrorKind::from(err)),
682                source: None,
683            },
684        }
685    }
686}
687
688impl From<ServerError> for Error {
689    fn from(value: ServerError) -> Self {
690        Self {
691            inner: ErrorImpl {
692                kind: Box::new(ErrorKind::Server(value)),
693                source: None,
694            },
695        }
696    }
697}
698
699impl From<ResourceError> for Error {
700    fn from(value: ResourceError) -> Self {
701        Self {
702            inner: ErrorImpl {
703                kind: Box::new(ErrorKind::Resource(value)),
704                source: None,
705            },
706        }
707    }
708}
709
710impl From<io::Error> for Error {
711    fn from(value: io::Error) -> Self {
712        Self {
713            inner: ErrorImpl {
714                kind: Box::new(ErrorKind::Io),
715                source: Some(Box::new(value)),
716            },
717        }
718    }
719}
720
721#[derive(Deserialize, Clone, Debug, PartialEq, Eq, Default)]
722struct ServerErrorContextJsonContext {
723    #[serde(alias = "context")]
724    context: Option<String>,
725    #[serde(alias = "ref")]
726    pub error_ref: Option<String>,
727}
728
729#[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
730struct ServerErrorContextJson {
731    #[serde(alias = "error", default)]
732    error: ServerErrorContextJsonContext,
733    #[serde(alias = "manifest_uid")]
734    pub manifest_rev: Option<String>,
735}
736
737impl MetricsName for Error {
738    fn metrics_name(&self) -> &'static str {
739        self.kind().metrics_name()
740    }
741}
742
743impl MetricsName for ErrorKind {
744    fn metrics_name(&self) -> &'static str {
745        match self {
746            ErrorKind::Server(err) => err.kind().metrics_name(),
747            ErrorKind::Resource(err) => err.cause().kind().metrics_name(),
748            ErrorKind::Dispatch { .. } => "memdx.Dispatch",
749            ErrorKind::Close { .. } => "memdx.Close",
750            ErrorKind::Protocol { .. } => "memdx.Protocol",
751            ErrorKind::Cancelled(_) => "memdx.Cancelled",
752            ErrorKind::ConnectionFailed { .. } => "memdx.ConnectionFailed",
753            ErrorKind::Io => "memdx.Io",
754            ErrorKind::InvalidArgument { .. } => "memdx.InvalidArgument",
755            ErrorKind::Decompression => "memdx.Decompression",
756            ErrorKind::Message(_) => "memdx._OTHER",
757        }
758    }
759}
760
761impl MetricsName for ServerErrorKind {
762    fn metrics_name(&self) -> &'static str {
763        match self {
764            ServerErrorKind::KeyNotFound => "memdx.KeyNotFound",
765            ServerErrorKind::KeyExists => "memdx.KeyExists",
766            ServerErrorKind::TooBig => "memdx.TooBig",
767            ServerErrorKind::NotStored => "memdx.NotStored",
768            ServerErrorKind::BadDelta => "memdx.BadDelta",
769            ServerErrorKind::NotMyVbucket => "memdx.NotMyVbucket",
770            ServerErrorKind::NoBucket => "memdx.NoBucket",
771            ServerErrorKind::Locked => "memdx.Locked",
772            ServerErrorKind::NotLocked => "memdx.NotLocked",
773            ServerErrorKind::Auth { .. } => "memdx.Auth",
774            ServerErrorKind::RangeError => "memdx.RangeError",
775            ServerErrorKind::Access => "memdx.Access",
776            ServerErrorKind::RateLimitedNetworkIngress => "memdx.RateLimitedNetworkIngress",
777            ServerErrorKind::RateLimitedNetworkEgress => "memdx.RateLimitedNetworkEgress",
778            ServerErrorKind::RateLimitedMaxConnections => "memdx.RateLimitedMaxConnections",
779            ServerErrorKind::RateLimitedMaxCommands => "memdx.RateLimitedMaxCommands",
780            ServerErrorKind::RateLimitedScopeSizeLimitExceeded => {
781                "memdx.RateLimitedScopeSizeLimitExceeded"
782            }
783            ServerErrorKind::UnknownCommand => "memdx.UnknownCommand",
784            ServerErrorKind::NotSupported => "memdx.NotSupported",
785            ServerErrorKind::InternalError => "memdx.InternalError",
786            ServerErrorKind::Busy => "memdx.Busy",
787            ServerErrorKind::TmpFail => "memdx.TmpFail",
788            ServerErrorKind::UnknownCollectionID => "memdx.UnknownCollectionID",
789            ServerErrorKind::UnknownScopeName => "memdx.UnknownScopeName",
790            ServerErrorKind::UnknownCollectionName => "memdx.UnknownCollectionName",
791            ServerErrorKind::DurabilityInvalid => "memdx.DurabilityInvalid",
792            ServerErrorKind::DurabilityImpossible => "memdx.DurabilityImpossible",
793            ServerErrorKind::SyncWriteInProgress => "memdx.SyncWriteInProgress",
794            ServerErrorKind::SyncWriteAmbiguous => "memdx.SyncWriteAmbiguous",
795            ServerErrorKind::SyncWriteRecommitInProgress => "memdx.SyncWriteRecommitInProgress",
796            ServerErrorKind::RangeScanCancelled => "memdx.RangeScanCancelled",
797            ServerErrorKind::RangeScanVBUUIDNotEqual => "memdx.RangeScanVBUUIDNotEqual",
798            ServerErrorKind::InvalidArgs => "memdx.InvalidArgs",
799            ServerErrorKind::AuthStale => "memdx.AuthStale",
800            ServerErrorKind::ConfigNotSet => "memdx.ConfigNotSet",
801            ServerErrorKind::UnknownBucketName => "memdx.UnknownBucketName",
802            ServerErrorKind::CasMismatch => "memdx.CasMismatch",
803            ServerErrorKind::Subdoc { error } => error.kind().metrics_name(),
804            ServerErrorKind::UnknownStatus { .. } => "memdx._OTHER",
805        }
806    }
807}
808
809impl MetricsName for SubdocErrorKind {
810    fn metrics_name(&self) -> &'static str {
811        match self {
812            SubdocErrorKind::PathNotFound => "memdx.subdoc.PathNotFound",
813            SubdocErrorKind::PathMismatch => "memdx.subdoc.PathMismatch",
814            SubdocErrorKind::PathInvalid => "memdx.subdoc.PathInvalid",
815            SubdocErrorKind::PathTooBig => "memdx.subdoc.PathTooBig",
816            SubdocErrorKind::DocTooDeep => "memdx.subdoc.DocTooDeep",
817            SubdocErrorKind::CantInsert => "memdx.subdoc.CantInsert",
818            SubdocErrorKind::NotJSON => "memdx.subdoc.NotJSON",
819            SubdocErrorKind::BadRange => "memdx.subdoc.BadRange",
820            SubdocErrorKind::BadDelta => "memdx.subdoc.BadDelta",
821            SubdocErrorKind::PathExists => "memdx.subdoc.PathExists",
822            SubdocErrorKind::ValueTooDeep => "memdx.subdoc.ValueTooDeep",
823            SubdocErrorKind::InvalidCombo => "memdx.subdoc.InvalidCombo",
824            SubdocErrorKind::XattrInvalidFlagCombo => "memdx.subdoc.XattrInvalidFlagCombo",
825            SubdocErrorKind::XattrInvalidKeyCombo => "memdx.subdoc.XattrInvalidKeyCombo",
826            SubdocErrorKind::XattrUnknownMacro => "memdx.subdoc.XattrUnknownMacro",
827            SubdocErrorKind::XattrUnknownVAttr => "memdx.subdoc.XattrUnknownVAttr",
828            SubdocErrorKind::XattrCannotModifyVAttr => "memdx.subdoc.XattrCannotModifyVAttr",
829            SubdocErrorKind::InvalidXattrOrder => "memdx.subdoc.InvalidXattrOrder",
830            SubdocErrorKind::XattrUnknownVattrMacro => "memdx.subdoc.XattrUnknownVattrMacro",
831            SubdocErrorKind::CanOnlyReviveDeletedDocuments => {
832                "memdx.subdoc.CanOnlyReviveDeletedDocuments"
833            }
834            SubdocErrorKind::DeletedDocumentCantHaveValue => {
835                "memdx.subdoc.DeletedDocumentCantHaveValue"
836            }
837            SubdocErrorKind::UnknownStatus { .. } => "memdx.subdoc._OTHER",
838        }
839    }
840}