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}