Skip to main content

dynomite/msg/
message.rs

1//! In-memory representation of a single Dynomite message.
2//!
3//! [`Msg`] is the unit that flows through the engine: a request from
4//! a client connection, a response from the upstream datastore, or
5//! an internal control packet. It carries the parsed metadata, the
6//! mbuf chain holding the on-the-wire bytes, the parser state used
7//! by the protocol decoders, and the bookkeeping flags every layer
8//! sets and reads.
9//!
10//! This module builds the message data shape and exposes the
11//! field-level accessors. The connection-coupled lifecycle paths
12//! (timeout tracking, queue threading, parser dispatch) live in
13//! [`crate::net`].
14
15use crate::core::types::MsgId;
16
17use super::keypos::{ArgPos, KeyPos};
18use super::msg_type::MsgType;
19use super::response_mgr::ResponseMgr;
20use crate::io::mbuf::MbufQueue;
21use crate::proto::dnode::{Dmsg, DynParseState};
22
23/// Stable connection identifier carried by [`Msg::owner`].
24///
25/// A unique 64-bit tag the connection layer stamps on every message
26/// it produces.
27pub type ConnId = u64;
28
29/// Parser outcome reported by datastore protocol decoders.
30///
31/// The variants name the possible parse outcomes
32/// so downstream callers can dispatch on the same semantics.
33#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
34pub enum MsgParseResult {
35    /// Parsing completed for this message.
36    #[default]
37    Ok,
38    /// Parser detected unrecoverable framing error.
39    Error,
40    /// Parser consumed valid bytes but expects to be re-driven on
41    /// the trailing bytes after a buffer split.
42    Repair,
43    /// Multi-key request needs to be fragmented before forwarding.
44    Fragment,
45    /// Need more bytes; caller must read more before retrying.
46    Again,
47    /// Parsing succeeded; downstream layer should take no action.
48    Noop,
49    /// Message was a Dynomite configuration directive.
50    DynoConfig,
51    /// Out-of-memory while parsing.
52    OomError,
53}
54
55/// Routing override applied to a request.
56///
57/// The message routing mode. The default
58/// (`Normal`) honors the configured key-hash routing; the other
59/// variants short-circuit it for diagnostic and special-purpose
60/// paths.
61#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
62#[repr(u8)]
63pub enum MsgRouting {
64    /// Apply the standard key-hash routing.
65    #[default]
66    Normal = 0,
67    /// Send to the local node only, ignoring the key hash.
68    LocalNodeOnly = 1,
69    /// Apply the key hash but stay within the local rack.
70    TokenOwnerLocalRackOnly = 2,
71    /// Send to every node in the local rack, ignoring the key hash.
72    AllNodesLocalRackOnly = 3,
73    /// Send to every node in every rack of every datacenter.
74    AllNodesAllRacksAllDcs = 4,
75}
76
77impl MsgRouting {
78    /// Stable string name for diagnostic output.
79    ///
80    /// # Examples
81    ///
82    /// ```
83    /// use dynomite::msg::MsgRouting;
84    /// assert_eq!(MsgRouting::Normal.name(), "ROUTING_NORMAL");
85    /// ```
86    #[must_use]
87    pub fn name(self) -> &'static str {
88        match self {
89            MsgRouting::Normal => "ROUTING_NORMAL",
90            MsgRouting::LocalNodeOnly => "ROUTING_LOCAL_NODE_ONLY",
91            MsgRouting::TokenOwnerLocalRackOnly => "ROUTING_TOKEN_OWNER_LOCAL_RACK_ONLY",
92            MsgRouting::AllNodesLocalRackOnly => "ROUTING_ALL_NODES_LOCAL_RACK_ONLY",
93            MsgRouting::AllNodesAllRacksAllDcs => "ROUTING_ALL_NODES_ALL_RACKS_ALL_DCS",
94        }
95    }
96}
97
98/// Bag of boolean lifecycle flags used by the request and response
99/// pipelines.
100#[allow(clippy::struct_excessive_bools)]
101#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
102pub struct MsgFlags {
103    /// Message is currently in the error state.
104    pub is_error: bool,
105    /// At least one fragment of this multi-message vector errored.
106    pub is_ferror: bool,
107    /// Caller issued a `quit` request.
108    pub quit: bool,
109    /// Caller expects the datastore to produce a reply.
110    pub expect_datastore_reply: bool,
111    /// Reply has been routed to the caller.
112    pub done: bool,
113    /// Every fragment of this vector finished.
114    pub fdone: bool,
115    /// Discard the corresponding response on arrival.
116    pub swallow: bool,
117    /// A DNODE header has already been prepended to the mbuf chain.
118    pub dnode_header_prepended: bool,
119    /// Response for this request has been written to the wire.
120    pub rsp_sent: bool,
121    /// Read request (vs write).
122    pub is_read: bool,
123    /// Marked by the dispatcher that a repair must be issued.
124    pub needs_repair: bool,
125    /// Request body can be safely rewritten with a timestamp.
126    pub rewrite_with_ts_possible: bool,
127    /// Response managers have been initialised.
128    pub rspmgrs_inited: bool,
129}
130
131impl MsgFlags {
132    /// Construct flags with the same default state the reference
133    /// engine sets in `_msg_get`.
134    #[must_use]
135    fn default_for_msg() -> Self {
136        Self {
137            expect_datastore_reply: true,
138            is_read: true,
139            rewrite_with_ts_possible: true,
140            ..Self::default()
141        }
142    }
143}
144
145/// One Dynomite message: the in-memory representation of a request
146/// or a response on its way through the engine.
147#[derive(Debug)]
148pub struct Msg {
149    id: MsgId,
150    parent_id: MsgId,
151    ty: MsgType,
152    orig_type: MsgType,
153    is_request: bool,
154    mbufs: MbufQueue,
155    mlen: u32,
156    parse_result: MsgParseResult,
157    dyn_parse_state: DynParseState,
158    dmsg: Option<Dmsg>,
159    routing: MsgRouting,
160    consistency: super::ConsistencyLevel,
161    timestamp_us: u64,
162    error_code: i32,
163    dyn_error_code: super::DynErrorCode,
164    awaiting_rsps: u32,
165    fragment_ids: Vec<MsgId>,
166    response_ids: Vec<MsgId>,
167    selected_rsp: Option<MsgId>,
168    owner: Option<ConnId>,
169    flags: MsgFlags,
170    rspmgr: Option<ResponseMgr>,
171    additional_rspmgrs: Vec<ResponseMgr>,
172    parser_state: u32,
173    parser_pos: usize,
174    parser_token: Option<usize>,
175    rlen: u32,
176    rntokens: u32,
177    ntokens: u32,
178    nkeys: u32,
179    vlen: u32,
180    integer: i64,
181    keys: Vec<KeyPos>,
182    args: Vec<ArgPos>,
183    end_marker: Option<usize>,
184    ntoken_start: Option<usize>,
185    ntoken_end: Option<usize>,
186    frag_id: u64,
187}
188
189impl Msg {
190    /// Construct a new message with `id`, type tag `ty`, and the
191    /// request/response orientation `is_request`. The mbuf chain
192    /// starts empty and the parser is reset to `DynParseState::Start`.
193    ///
194    /// # Examples
195    ///
196    /// ```
197    /// use dynomite::msg::{Msg, MsgType};
198    /// let m = Msg::new(1, MsgType::ReqRedisGet, true);
199    /// assert_eq!(m.id(), 1);
200    /// assert!(m.is_request());
201    /// ```
202    #[must_use]
203    pub fn new(id: MsgId, ty: MsgType, is_request: bool) -> Self {
204        Self {
205            id,
206            parent_id: 0,
207            ty,
208            orig_type: MsgType::Unknown,
209            is_request,
210            mbufs: MbufQueue::new(),
211            mlen: 0,
212            parse_result: MsgParseResult::default(),
213            dyn_parse_state: DynParseState::Start,
214            dmsg: None,
215            routing: MsgRouting::Normal,
216            consistency: super::ConsistencyLevel::DcOne,
217            timestamp_us: 0,
218            error_code: 0,
219            dyn_error_code: super::DynErrorCode::Ok,
220            awaiting_rsps: 0,
221            fragment_ids: Vec::new(),
222            response_ids: Vec::new(),
223            selected_rsp: None,
224            owner: None,
225            flags: MsgFlags::default_for_msg(),
226            rspmgr: None,
227            additional_rspmgrs: Vec::new(),
228            parser_state: 0,
229            parser_pos: 0,
230            parser_token: None,
231            rlen: 0,
232            rntokens: 0,
233            ntokens: 0,
234            nkeys: 0,
235            vlen: 0,
236            integer: 0,
237            keys: Vec::new(),
238            args: Vec::new(),
239            end_marker: None,
240            ntoken_start: None,
241            ntoken_end: None,
242            frag_id: 0,
243        }
244    }
245
246    /// Borrow the parsed key list. Populated by the protocol parsers.
247    ///
248    /// # Examples
249    /// ```
250    /// use dynomite::msg::{Msg, MsgType};
251    /// assert!(Msg::new(1, MsgType::Unknown, true).keys().is_empty());
252    /// ```
253    #[must_use]
254    pub fn keys(&self) -> &[KeyPos] {
255        &self.keys
256    }
257
258    /// Mutably borrow the parsed key list.
259    pub fn keys_mut(&mut self) -> &mut Vec<KeyPos> {
260        &mut self.keys
261    }
262
263    /// Append a parsed key. Used by the protocol parsers.
264    pub fn push_key(&mut self, k: KeyPos) {
265        self.keys.push(k);
266    }
267
268    /// Borrow the parsed argument list.
269    #[must_use]
270    pub fn args(&self) -> &[ArgPos] {
271        &self.args
272    }
273
274    /// Mutably borrow the parsed argument list.
275    pub fn args_mut(&mut self) -> &mut Vec<ArgPos> {
276        &mut self.args
277    }
278
279    /// Append a parsed argument.
280    pub fn push_arg(&mut self, a: ArgPos) {
281        self.args.push(a);
282    }
283
284    /// Protocol-specific parser state index. Each parser defines
285    /// its own state alphabet keyed on this `u32`.
286    #[must_use]
287    pub fn parser_state(&self) -> u32 {
288        self.parser_state
289    }
290
291    /// Set the protocol parser state index.
292    pub fn set_parser_state(&mut self, s: u32) {
293        self.parser_state = s;
294    }
295
296    /// Cursor offset into the input buffer where the next byte
297    /// should be read.
298    #[must_use]
299    pub fn parser_pos(&self) -> usize {
300        self.parser_pos
301    }
302
303    /// Set the parser cursor offset.
304    pub fn set_parser_pos(&mut self, p: usize) {
305        self.parser_pos = p;
306    }
307
308    /// Optional token marker offset.
309    #[must_use]
310    pub fn parser_token(&self) -> Option<usize> {
311        self.parser_token
312    }
313
314    /// Set the optional token marker offset.
315    pub fn set_parser_token(&mut self, t: Option<usize>) {
316        self.parser_token = t;
317    }
318
319    /// Remaining length of the bulk argument the parser is currently
320    /// consuming.
321    #[must_use]
322    pub fn rlen(&self) -> u32 {
323        self.rlen
324    }
325
326    /// Set the bulk-argument remaining length.
327    pub fn set_rlen(&mut self, n: u32) {
328        self.rlen = n;
329    }
330
331    /// Remaining unprocessed token count for the current parse.
332    #[must_use]
333    pub fn rntokens(&self) -> u32 {
334        self.rntokens
335    }
336
337    /// Set the remaining-token counter.
338    pub fn set_rntokens(&mut self, n: u32) {
339        self.rntokens = n;
340    }
341
342    /// Total parsed token count for the current message.
343    #[must_use]
344    pub fn ntokens(&self) -> u32 {
345        self.ntokens
346    }
347
348    /// Set the total parsed token count.
349    pub fn set_ntokens(&mut self, n: u32) {
350        self.ntokens = n;
351    }
352
353    /// Number of keys the script (EVAL/EVALSHA) declared.
354    #[must_use]
355    pub fn nkeys(&self) -> u32 {
356        self.nkeys
357    }
358
359    /// Set the script-key count.
360    pub fn set_nkeys(&mut self, n: u32) {
361        self.nkeys = n;
362    }
363
364    /// Storage-command value length.
365    #[must_use]
366    pub fn vlen(&self) -> u32 {
367        self.vlen
368    }
369
370    /// Set the storage-command value length.
371    pub fn set_vlen(&mut self, n: u32) {
372        self.vlen = n;
373    }
374
375    /// Integer value carried by the response (`:n\r\n`).
376    #[must_use]
377    pub fn integer(&self) -> i64 {
378        self.integer
379    }
380
381    /// Set the integer response value.
382    pub fn set_integer(&mut self, v: i64) {
383        self.integer = v;
384    }
385
386    /// Offset of the multi-bulk `END` marker in the response, if any.
387    #[must_use]
388    pub fn end_marker(&self) -> Option<usize> {
389        self.end_marker
390    }
391
392    /// Set the response `END` marker offset.
393    pub fn set_end_marker(&mut self, m: Option<usize>) {
394        self.end_marker = m;
395    }
396
397    /// Start offset of the multi-bulk argument count token.
398    #[must_use]
399    pub fn ntoken_start(&self) -> Option<usize> {
400        self.ntoken_start
401    }
402
403    /// End offset (exclusive) of the multi-bulk argument count token.
404    #[must_use]
405    pub fn ntoken_end(&self) -> Option<usize> {
406        self.ntoken_end
407    }
408
409    /// Set the multi-bulk argument count span.
410    pub fn set_ntoken_span(&mut self, start: Option<usize>, end: Option<usize>) {
411        self.ntoken_start = start;
412        self.ntoken_end = end;
413    }
414
415    /// Fragment id grouping all sub-messages produced from a
416    /// multi-key request.
417    #[must_use]
418    pub fn frag_id(&self) -> u64 {
419        self.frag_id
420    }
421
422    /// Set the fragment id.
423    pub fn set_frag_id(&mut self, id: u64) {
424        self.frag_id = id;
425    }
426
427    /// Message id.
428    ///
429    /// # Examples
430    /// ```
431    /// use dynomite::msg::{Msg, MsgType};
432    /// assert_eq!(Msg::new(99, MsgType::Unknown, true).id(), 99);
433    /// ```
434    #[must_use]
435    pub fn id(&self) -> MsgId {
436        self.id
437    }
438
439    /// Parent id (zero when not a fragment).
440    ///
441    /// # Examples
442    /// ```
443    /// use dynomite::msg::{Msg, MsgType};
444    /// assert_eq!(Msg::new(1, MsgType::Unknown, true).parent_id(), 0);
445    /// ```
446    #[must_use]
447    pub fn parent_id(&self) -> MsgId {
448        self.parent_id
449    }
450
451    /// Set the parent id.
452    ///
453    /// # Examples
454    /// ```
455    /// use dynomite::msg::{Msg, MsgType};
456    /// let mut m = Msg::new(2, MsgType::Unknown, true);
457    /// m.set_parent_id(1);
458    /// assert_eq!(m.parent_id(), 1);
459    /// ```
460    pub fn set_parent_id(&mut self, parent: MsgId) {
461        self.parent_id = parent;
462    }
463
464    /// Message type tag.
465    ///
466    /// # Examples
467    /// ```
468    /// use dynomite::msg::{Msg, MsgType};
469    /// assert_eq!(Msg::new(1, MsgType::ReqMcGet, true).ty(), MsgType::ReqMcGet);
470    /// ```
471    #[must_use]
472    pub fn ty(&self) -> MsgType {
473        self.ty
474    }
475
476    /// Override the message type. The previous value is preserved as
477    /// the original type so query rewriters can recover it.
478    ///
479    /// # Examples
480    /// ```
481    /// use dynomite::msg::{Msg, MsgType};
482    /// let mut m = Msg::new(1, MsgType::ReqRedisGet, true);
483    /// m.set_type(MsgType::ReqRedisSet);
484    /// assert_eq!(m.ty(), MsgType::ReqRedisSet);
485    /// assert_eq!(m.orig_type(), MsgType::ReqRedisGet);
486    /// ```
487    pub fn set_type(&mut self, ty: MsgType) {
488        self.orig_type = self.ty;
489        self.ty = ty;
490    }
491
492    /// Original message type before any rewrite.
493    ///
494    /// # Examples
495    /// ```
496    /// use dynomite::msg::{Msg, MsgType};
497    /// assert_eq!(
498    ///     Msg::new(1, MsgType::ReqRedisGet, true).orig_type(),
499    ///     MsgType::Unknown,
500    /// );
501    /// ```
502    #[must_use]
503    pub fn orig_type(&self) -> MsgType {
504        self.orig_type
505    }
506
507    /// True for requests.
508    ///
509    /// # Examples
510    /// ```
511    /// use dynomite::msg::{Msg, MsgType};
512    /// assert!(Msg::new(1, MsgType::ReqMcGet, true).is_request());
513    /// assert!(!Msg::new(1, MsgType::RspMcStored, false).is_request());
514    /// ```
515    #[must_use]
516    pub fn is_request(&self) -> bool {
517        self.is_request
518    }
519
520    /// Borrow the underlying mbuf chain.
521    ///
522    /// # Examples
523    /// ```
524    /// use dynomite::msg::{Msg, MsgType};
525    /// let m = Msg::new(1, MsgType::Unknown, true);
526    /// assert!(m.mbufs().is_empty());
527    /// ```
528    #[must_use]
529    pub fn mbufs(&self) -> &MbufQueue {
530        &self.mbufs
531    }
532
533    /// Mutably borrow the mbuf chain.
534    ///
535    /// # Examples
536    /// ```
537    /// use dynomite::io::mbuf::MbufPool;
538    /// use dynomite::msg::{Msg, MsgType};
539    ///
540    /// let pool = MbufPool::default();
541    /// let mut m = Msg::new(1, MsgType::Unknown, true);
542    /// m.mbufs_mut().push_back(pool.get());
543    /// assert_eq!(m.mbufs().len(), 1);
544    /// ```
545    pub fn mbufs_mut(&mut self) -> &mut MbufQueue {
546        &mut self.mbufs
547    }
548
549    /// Cumulative readable byte count of the chain (`mlen`).
550    ///
551    /// # Examples
552    /// ```
553    /// use dynomite::msg::{Msg, MsgType};
554    /// assert_eq!(Msg::new(1, MsgType::Unknown, true).mlen(), 0);
555    /// ```
556    #[must_use]
557    pub fn mlen(&self) -> u32 {
558        self.mlen
559    }
560
561    /// Refresh `mlen` from the current chain.
562    ///
563    /// The parser updates the length as it consumes bytes; callers
564    /// that mutate the chain directly call this to keep the cached
565    /// length consistent with the actual chain content.
566    ///
567    /// # Examples
568    /// ```
569    /// use dynomite::io::mbuf::MbufPool;
570    /// use dynomite::msg::{Msg, MsgType};
571    ///
572    /// let pool = MbufPool::default();
573    /// let mut m = Msg::new(1, MsgType::Unknown, true);
574    /// let mut buf = pool.get();
575    /// buf.recv(b"hi");
576    /// m.mbufs_mut().push_back(buf);
577    /// m.recompute_mlen();
578    /// assert_eq!(m.mlen(), 2);
579    /// ```
580    pub fn recompute_mlen(&mut self) {
581        let total: usize = self.mbufs.iter().map(crate::io::mbuf::Mbuf::len).sum();
582        self.mlen = u32::try_from(total).unwrap_or(u32::MAX);
583    }
584
585    /// Direct setter for `mlen`. Use [`Msg::recompute_mlen`] when the
586    /// chain has been mutated; this entry point exists for parsers
587    /// that adjust the value as they consume bytes.
588    ///
589    /// # Examples
590    /// ```
591    /// use dynomite::msg::{Msg, MsgType};
592    /// let mut m = Msg::new(1, MsgType::Unknown, true);
593    /// m.set_mlen(123);
594    /// assert_eq!(m.mlen(), 123);
595    /// ```
596    pub fn set_mlen(&mut self, mlen: u32) {
597        self.mlen = mlen;
598    }
599
600    /// Last parse outcome.
601    ///
602    /// # Examples
603    /// ```
604    /// use dynomite::msg::{Msg, MsgParseResult, MsgType};
605    /// assert_eq!(
606    ///     Msg::new(1, MsgType::Unknown, true).parse_result(),
607    ///     MsgParseResult::Ok,
608    /// );
609    /// ```
610    #[must_use]
611    pub fn parse_result(&self) -> MsgParseResult {
612        self.parse_result
613    }
614
615    /// Set the parse outcome.
616    ///
617    /// # Examples
618    /// ```
619    /// use dynomite::msg::{Msg, MsgParseResult, MsgType};
620    /// let mut m = Msg::new(1, MsgType::Unknown, true);
621    /// m.set_parse_result(MsgParseResult::Again);
622    /// assert_eq!(m.parse_result(), MsgParseResult::Again);
623    /// ```
624    pub fn set_parse_result(&mut self, r: MsgParseResult) {
625        self.parse_result = r;
626    }
627
628    /// Current DNODE parser state.
629    ///
630    /// # Examples
631    /// ```
632    /// use dynomite::msg::{Msg, MsgType};
633    /// use dynomite::proto::dnode::DynParseState;
634    /// assert_eq!(
635    ///     Msg::new(1, MsgType::Unknown, true).dyn_parse_state(),
636    ///     DynParseState::Start,
637    /// );
638    /// ```
639    #[must_use]
640    pub fn dyn_parse_state(&self) -> DynParseState {
641        self.dyn_parse_state
642    }
643
644    /// Set the DNODE parser state.
645    pub fn set_dyn_parse_state(&mut self, state: DynParseState) {
646        self.dyn_parse_state = state;
647    }
648
649    /// Borrow the parsed DNODE header, if any.
650    ///
651    /// # Examples
652    /// ```
653    /// use dynomite::msg::{Msg, MsgType};
654    /// assert!(Msg::new(1, MsgType::Unknown, true).dmsg().is_none());
655    /// ```
656    #[must_use]
657    pub fn dmsg(&self) -> Option<&Dmsg> {
658        self.dmsg.as_ref()
659    }
660
661    /// Mutably borrow the parsed DNODE header.
662    pub fn dmsg_mut(&mut self) -> Option<&mut Dmsg> {
663        self.dmsg.as_mut()
664    }
665
666    /// Attach a parsed DNODE header.
667    pub fn set_dmsg(&mut self, dmsg: Dmsg) {
668        self.dmsg = Some(dmsg);
669    }
670
671    /// Routing override.
672    #[must_use]
673    pub fn routing(&self) -> MsgRouting {
674        self.routing
675    }
676
677    /// Set the routing override.
678    pub fn set_routing(&mut self, routing: MsgRouting) {
679        self.routing = routing;
680    }
681
682    /// Consistency level for this message.
683    #[must_use]
684    pub fn consistency(&self) -> super::ConsistencyLevel {
685        self.consistency
686    }
687
688    /// Set the consistency level.
689    pub fn set_consistency(&mut self, level: super::ConsistencyLevel) {
690        self.consistency = level;
691    }
692
693    /// Microsecond timestamp recorded at request creation.
694    #[must_use]
695    pub fn timestamp_us(&self) -> u64 {
696        self.timestamp_us
697    }
698
699    /// Update the request timestamp.
700    pub fn set_timestamp_us(&mut self, ts: u64) {
701        self.timestamp_us = ts;
702    }
703
704    /// Datastore-level error code (`errno`-shaped).
705    #[must_use]
706    pub fn error_code(&self) -> i32 {
707        self.error_code
708    }
709
710    /// Set the datastore error code.
711    pub fn set_error_code(&mut self, e: i32) {
712        self.error_code = e;
713    }
714
715    /// Dynomite-level error code.
716    #[must_use]
717    pub fn dyn_error_code(&self) -> super::DynErrorCode {
718        self.dyn_error_code
719    }
720
721    /// Set the Dynomite error code.
722    pub fn set_dyn_error_code(&mut self, e: super::DynErrorCode) {
723        self.dyn_error_code = e;
724    }
725
726    /// Number of replies the request is still waiting on.
727    #[must_use]
728    pub fn awaiting_rsps(&self) -> u32 {
729        self.awaiting_rsps
730    }
731
732    /// Increment `awaiting_rsps`.
733    pub fn incr_awaiting_rsps(&mut self) {
734        self.awaiting_rsps = self.awaiting_rsps.saturating_add(1);
735    }
736
737    /// Decrement `awaiting_rsps`.
738    pub fn decr_awaiting_rsps(&mut self) {
739        self.awaiting_rsps = self.awaiting_rsps.saturating_sub(1);
740    }
741
742    /// Set `awaiting_rsps` directly. Used by the response manager
743    /// initialiser to seed the per-DC count.
744    pub fn set_awaiting_rsps(&mut self, n: u32) {
745        self.awaiting_rsps = n;
746    }
747
748    /// Borrow the fragment-id list.
749    #[must_use]
750    pub fn fragment_ids(&self) -> &[MsgId] {
751        &self.fragment_ids
752    }
753
754    /// Append `id` to the fragment-id list.
755    pub fn push_fragment_id(&mut self, id: MsgId) {
756        self.fragment_ids.push(id);
757    }
758
759    /// Borrow the response-id list.
760    #[must_use]
761    pub fn response_ids(&self) -> &[MsgId] {
762        &self.response_ids
763    }
764
765    /// Append `id` to the response-id list.
766    pub fn push_response_id(&mut self, id: MsgId) {
767        self.response_ids.push(id);
768    }
769
770    /// Currently-selected response id.
771    #[must_use]
772    pub fn selected_rsp(&self) -> Option<MsgId> {
773        self.selected_rsp
774    }
775
776    /// Set the currently-selected response id.
777    pub fn set_selected_rsp(&mut self, id: Option<MsgId>) {
778        self.selected_rsp = id;
779    }
780
781    /// Owner connection id, when the message is bound to one.
782    #[must_use]
783    pub fn owner(&self) -> Option<ConnId> {
784        self.owner
785    }
786
787    /// Set the owner connection id.
788    pub fn set_owner(&mut self, owner: Option<ConnId>) {
789        self.owner = owner;
790    }
791
792    /// Borrow the lifecycle flags.
793    #[must_use]
794    pub fn flags(&self) -> &MsgFlags {
795        &self.flags
796    }
797
798    /// Mutably borrow the lifecycle flags.
799    pub fn flags_mut(&mut self) -> &mut MsgFlags {
800        &mut self.flags
801    }
802
803    /// Set the `swallow` flag.
804    pub fn set_swallow(&mut self, on: bool) {
805        self.flags.swallow = on;
806    }
807
808    /// Set the `done` flag.
809    pub fn set_done(&mut self, on: bool) {
810        self.flags.done = on;
811    }
812
813    /// Set the `is_error` flag.
814    pub fn set_is_error(&mut self, on: bool) {
815        self.flags.is_error = on;
816    }
817
818    /// Borrow the local-DC response manager.
819    #[must_use]
820    pub fn rspmgr(&self) -> Option<&ResponseMgr> {
821        self.rspmgr.as_ref()
822    }
823
824    /// Mutably borrow the local-DC response manager.
825    pub fn rspmgr_mut(&mut self) -> Option<&mut ResponseMgr> {
826        self.rspmgr.as_mut()
827    }
828
829    /// Install a fresh response manager for the local DC.
830    pub fn set_rspmgr(&mut self, mgr: ResponseMgr) {
831        self.flags.rspmgrs_inited = true;
832        self.set_awaiting_rsps(u32::from(mgr.max_responses()));
833        self.rspmgr = Some(mgr);
834    }
835
836    /// Borrow the per-remote-DC response managers.
837    #[must_use]
838    pub fn additional_rspmgrs(&self) -> &[ResponseMgr] {
839        &self.additional_rspmgrs
840    }
841
842    /// Mutably borrow the per-remote-DC response managers.
843    pub fn additional_rspmgrs_mut(&mut self) -> &mut Vec<ResponseMgr> {
844        &mut self.additional_rspmgrs
845    }
846}
847
848#[cfg(test)]
849mod tests {
850    use super::*;
851
852    #[test]
853    fn defaults_match_reference() {
854        let m = Msg::new(1, MsgType::ReqRedisGet, true);
855        assert!(m.flags().expect_datastore_reply);
856        assert!(m.flags().is_read);
857        assert!(m.flags().rewrite_with_ts_possible);
858        assert!(!m.flags().is_error);
859        assert!(!m.flags().rspmgrs_inited);
860        assert_eq!(m.consistency(), super::super::ConsistencyLevel::DcOne);
861        assert_eq!(m.routing(), MsgRouting::Normal);
862        assert_eq!(m.dyn_parse_state(), DynParseState::Start);
863    }
864
865    #[test]
866    fn set_type_preserves_original() {
867        let mut m = Msg::new(1, MsgType::ReqRedisGet, true);
868        assert_eq!(m.orig_type(), MsgType::Unknown);
869        m.set_type(MsgType::ReqRedisSet);
870        assert_eq!(m.ty(), MsgType::ReqRedisSet);
871        assert_eq!(m.orig_type(), MsgType::ReqRedisGet);
872    }
873
874    #[test]
875    fn awaiting_saturates() {
876        let mut m = Msg::new(1, MsgType::ReqRedisGet, true);
877        m.decr_awaiting_rsps();
878        assert_eq!(m.awaiting_rsps(), 0);
879        m.incr_awaiting_rsps();
880        m.incr_awaiting_rsps();
881        assert_eq!(m.awaiting_rsps(), 2);
882        m.decr_awaiting_rsps();
883        assert_eq!(m.awaiting_rsps(), 1);
884    }
885
886    #[test]
887    fn routing_name_covers_every_variant() {
888        // Each MsgRouting variant has a stable diagnostic name.
889        assert_eq!(MsgRouting::Normal.name(), "ROUTING_NORMAL");
890        assert_eq!(MsgRouting::LocalNodeOnly.name(), "ROUTING_LOCAL_NODE_ONLY");
891        assert_eq!(
892            MsgRouting::TokenOwnerLocalRackOnly.name(),
893            "ROUTING_TOKEN_OWNER_LOCAL_RACK_ONLY"
894        );
895        assert_eq!(
896            MsgRouting::AllNodesLocalRackOnly.name(),
897            "ROUTING_ALL_NODES_LOCAL_RACK_ONLY"
898        );
899        assert_eq!(
900            MsgRouting::AllNodesAllRacksAllDcs.name(),
901            "ROUTING_ALL_NODES_ALL_RACKS_ALL_DCS"
902        );
903    }
904
905    #[test]
906    fn key_and_arg_lists_mutate_through_accessors() {
907        // keys_mut / push_key and args expose the parsed lists.
908        use crate::msg::keypos::KeyPos;
909        let mut m = Msg::new(1, MsgType::ReqRedisGet, true);
910        m.push_key(KeyPos::new(b"k".to_vec(), 0..1));
911        assert_eq!(m.keys().len(), 1);
912        m.keys_mut().clear();
913        assert!(m.keys().is_empty());
914        assert!(m.args().is_empty());
915    }
916
917    #[test]
918    fn scalar_setters_round_trip() {
919        // The plain setter/getter pairs round-trip their values.
920        use crate::msg::{ConsistencyLevel, DynErrorCode};
921        let mut m = Msg::new(1, MsgType::ReqRedisGet, true);
922        m.set_mlen(123);
923        assert_eq!(m.mlen(), 123);
924        m.set_parse_result(MsgParseResult::Again);
925        assert_eq!(m.parse_result(), MsgParseResult::Again);
926        m.set_dyn_parse_state(DynParseState::Start);
927        assert_eq!(m.dyn_parse_state(), DynParseState::Start);
928        m.set_routing(MsgRouting::LocalNodeOnly);
929        assert_eq!(m.routing(), MsgRouting::LocalNodeOnly);
930        m.set_consistency(ConsistencyLevel::DcQuorum);
931        assert_eq!(m.consistency(), ConsistencyLevel::DcQuorum);
932        m.set_timestamp_us(9_999);
933        assert_eq!(m.timestamp_us(), 9_999);
934        m.set_error_code(13);
935        assert_eq!(m.error_code(), 13);
936        m.set_dyn_error_code(DynErrorCode::PeerHostDown);
937        assert_eq!(m.dyn_error_code(), DynErrorCode::PeerHostDown);
938        m.set_awaiting_rsps(4);
939        assert_eq!(m.awaiting_rsps(), 4);
940        m.set_owner(Some(77));
941        assert_eq!(m.owner(), Some(77));
942        m.set_selected_rsp(Some(5));
943        assert_eq!(m.selected_rsp(), Some(5));
944    }
945
946    #[test]
947    fn flag_setters_and_id_lists() {
948        // swallow / done / is_error setters plus the fragment and
949        // response id lists and their accessors.
950        let mut m = Msg::new(1, MsgType::ReqRedisMget, true);
951        m.set_swallow(true);
952        assert!(m.flags().swallow);
953        m.set_done(true);
954        assert!(m.flags().done);
955        m.set_is_error(true);
956        assert!(m.flags().is_error);
957        m.push_fragment_id(2);
958        assert_eq!(m.fragment_ids(), &[2]);
959        m.push_response_id(3);
960        assert_eq!(m.response_ids(), &[3]);
961    }
962
963    #[test]
964    fn dmsg_attach_and_borrow() {
965        // set_dmsg / dmsg / dmsg_mut attach and expose the DNODE
966        // header.
967        use crate::proto::dnode::Dmsg;
968        let mut m = Msg::new(1, MsgType::Unknown, true);
969        assert!(m.dmsg().is_none());
970        m.set_dmsg(Dmsg::default());
971        assert!(m.dmsg().is_some());
972        assert!(m.dmsg_mut().is_some());
973    }
974
975    #[test]
976    fn rspmgr_install_seeds_awaiting_and_borrows() {
977        // set_rspmgr marks rspmgrs_inited, seeds awaiting_rsps from
978        // the manager's max, and exposes mutable borrows of both the
979        // local and the additional managers.
980        use crate::msg::response_mgr::ResponseMgr;
981        let mut m = Msg::new(1, MsgType::ReqRedisGet, true);
982        let probe = Msg::new(2, MsgType::ReqRedisGet, true);
983        let mgr = ResponseMgr::new(&probe, 3, None);
984        m.set_rspmgr(mgr);
985        assert!(m.flags().rspmgrs_inited);
986        assert_eq!(m.awaiting_rsps(), 3);
987        assert!(m.rspmgr().is_some());
988        assert!(m.rspmgr_mut().is_some());
989        assert!(m.additional_rspmgrs().is_empty());
990        let extra = ResponseMgr::new(&probe, 1, Some("dc2".to_string()));
991        m.additional_rspmgrs_mut().push(extra);
992        assert_eq!(m.additional_rspmgrs().len(), 1);
993    }
994}