Skip to main content

meta_srv/
handler.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::cmp::Ordering;
16use std::collections::{BTreeMap, HashMap, HashSet};
17use std::fmt::{Debug, Display};
18use std::ops::Bound;
19use std::sync::{Arc, Mutex};
20use std::time::{Duration, Instant};
21
22use api::v1::meta::mailbox_message::Payload;
23use api::v1::meta::{
24    HeartbeatConfig, HeartbeatRequest, HeartbeatResponse, MailboxMessage, PROTOCOL_VERSION,
25    RegionLease, ResponseHeader, Role,
26};
27use check_leader_handler::CheckLeaderHandler;
28use collect_cluster_info_handler::{
29    CollectDatanodeClusterInfoHandler, CollectFlownodeClusterInfoHandler,
30    CollectFrontendClusterInfoHandler,
31};
32use collect_leader_region_handler::CollectLeaderRegionHandler;
33use collect_stats_handler::CollectStatsHandler;
34use common_base::Plugins;
35use common_meta::datanode::Stat;
36use common_meta::instruction::InstructionReply;
37use common_meta::sequence::Sequence;
38use common_telemetry::{debug, info, warn};
39use dashmap::DashMap;
40use extract_stat_handler::ExtractStatHandler;
41use failure_handler::RegionFailureHandler;
42use filter_inactive_region_stats::FilterInactiveRegionStatsHandler;
43use futures::future::join_all;
44use keep_lease_handler::{DatanodeKeepLeaseHandler, FlownodeKeepLeaseHandler};
45use mailbox_handler::MailboxHandler;
46use on_leader_start_handler::OnLeaderStartHandler;
47use publish_heartbeat_handler::PublishHeartbeatHandler;
48use region_lease_handler::RegionLeaseHandler;
49use remap_flow_peer_handler::RemapFlowPeerHandler;
50use response_header_handler::ResponseHeaderHandler;
51use snafu::{OptionExt, ResultExt};
52use store_api::storage::RegionId;
53use tokio::sync::mpsc::Sender;
54use tokio::sync::{Notify, OwnedMutexGuard, RwLock, oneshot, watch};
55
56use crate::error::{self, DeserializeFromJsonSnafu, Result, UnexpectedInstructionReplySnafu};
57use crate::handler::collect_topic_stats_handler::CollectTopicStatsHandler;
58use crate::handler::flow_state_handler::FlowStateHandler;
59use crate::handler::persist_stats_handler::PersistStatsHandler;
60use crate::metasrv::Context;
61use crate::metrics::{METRIC_META_HANDLER_EXECUTE, METRIC_META_HEARTBEAT_CONNECTION_NUM};
62use crate::pubsub::PublisherRef;
63use crate::service::mailbox::{
64    BroadcastChannel, Channel, Mailbox, MailboxReceiver, MailboxRef, MessageId,
65};
66
67pub mod check_leader_handler;
68pub mod collect_cluster_info_handler;
69pub mod collect_leader_region_handler;
70pub mod collect_stats_handler;
71pub mod collect_topic_stats_handler;
72pub mod extract_stat_handler;
73pub mod failure_handler;
74pub mod filter_inactive_region_stats;
75pub mod flow_state_handler;
76pub mod keep_lease_handler;
77pub mod mailbox_handler;
78pub mod on_leader_start_handler;
79pub mod persist_stats_handler;
80pub mod publish_heartbeat_handler;
81pub mod region_lease_handler;
82pub mod remap_flow_peer_handler;
83pub mod response_header_handler;
84mod utils;
85
86#[cfg(test)]
87pub mod test_utils;
88
89#[async_trait::async_trait]
90pub trait HeartbeatHandler: Send + Sync {
91    fn is_acceptable(&self, role: Role) -> bool;
92
93    fn name(&self) -> &'static str {
94        let type_name = std::any::type_name::<Self>();
95        // short name
96        type_name.split("::").last().unwrap_or(type_name)
97    }
98
99    async fn handle(
100        &self,
101        req: &HeartbeatRequest,
102        ctx: &mut Context,
103        acc: &mut HeartbeatAccumulator,
104    ) -> Result<HandleControl>;
105}
106
107/// HandleControl
108///
109/// Controls process of handling heartbeat request.
110#[derive(PartialEq, Debug)]
111pub enum HandleControl {
112    Continue,
113    Done,
114}
115
116#[derive(Debug, Default)]
117pub struct HeartbeatAccumulator {
118    pub header: Option<ResponseHeader>,
119    mailbox_message: Option<MailboxMessage>,
120    pub stat: Option<Stat>,
121    pub inactive_region_ids: HashSet<RegionId>,
122    pub region_lease: Option<RegionLease>,
123    /// Generic heartbeat response extensions accumulated by handlers.
124    pub extensions: HashMap<String, Vec<u8>>,
125}
126
127impl HeartbeatAccumulator {
128    pub(crate) fn take_mailbox_message(&mut self) -> Option<MailboxMessage> {
129        self.mailbox_message.take()
130    }
131
132    pub fn set_mailbox_message(&mut self, message: MailboxMessage) {
133        let _ = self.mailbox_message.insert(message);
134    }
135}
136
137#[derive(Copy, Clone)]
138pub struct PusherId {
139    pub role: Role,
140    pub id: u64,
141}
142
143impl PartialEq for PusherId {
144    fn eq(&self, other: &Self) -> bool {
145        self.role as i32 == other.role as i32 && self.id == other.id
146    }
147}
148
149impl Eq for PusherId {}
150
151impl PartialOrd for PusherId {
152    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
153        Some(self.cmp(other))
154    }
155}
156
157impl Ord for PusherId {
158    fn cmp(&self, other: &Self) -> Ordering {
159        (self.role as i32, self.id).cmp(&(other.role as i32, other.id))
160    }
161}
162
163impl Debug for PusherId {
164    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
165        write!(f, "{:?}-{}", self.role, self.id)
166    }
167}
168
169impl Display for PusherId {
170    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
171        write!(f, "{:?}-{}", self.role, self.id)
172    }
173}
174
175impl PusherId {
176    pub fn new(role: Role, id: u64) -> Self {
177        Self { role, id }
178    }
179
180    fn role_range(role: Role) -> (Bound<Self>, Bound<Self>) {
181        (
182            Bound::Included(Self::new(role, u64::MIN)),
183            Bound::Included(Self::new(role, u64::MAX)),
184        )
185    }
186}
187
188/// The receiver of the deregister signal.
189pub type DeregisterSignalReceiver = watch::Receiver<bool>;
190
191/// The pusher of the heartbeat response.
192pub struct Pusher {
193    sender: Sender<std::result::Result<HeartbeatResponse, tonic::Status>>,
194    // The sender of the deregister signal.
195    // default is false, means the pusher is not deregistered.
196    // when the pusher is deregistered, the sender will be notified.
197    deregister_signal_sender: watch::Sender<bool>,
198    deregister_signal_receiver: DeregisterSignalReceiver,
199
200    res_header: ResponseHeader,
201    /// The `node_epoch` of the datanode process that registered the pusher, or 0.
202    node_epoch: u64,
203}
204
205impl Drop for Pusher {
206    fn drop(&mut self) {
207        // Ignore the error here.
208        // if all the receivers have been dropped, means no body cares the deregister signal.
209        let _ = self.deregister_signal_sender.send(true);
210    }
211}
212
213impl Pusher {
214    pub fn new(sender: Sender<std::result::Result<HeartbeatResponse, tonic::Status>>) -> Self {
215        let res_header = ResponseHeader {
216            protocol_version: PROTOCOL_VERSION,
217            ..Default::default()
218        };
219        let (deregister_signal_sender, deregister_signal_receiver) = watch::channel(false);
220        Self {
221            sender,
222            deregister_signal_sender,
223            deregister_signal_receiver,
224            res_header,
225            node_epoch: 0,
226        }
227    }
228
229    pub(crate) fn with_node_epoch(mut self, node_epoch: u64) -> Self {
230        self.node_epoch = node_epoch;
231        self
232    }
233
234    #[inline]
235    pub fn header(&self) -> ResponseHeader {
236        self.res_header.clone()
237    }
238}
239
240/// An owned snapshot of the [`Pusher`] fields the push paths need, so a caller can drop
241/// the [`Pushers`] read guard before awaiting the send. It must not hold a [`Pusher`]:
242/// dropping one fires the deregister signal, which reads as a closed channel.
243struct PusherHandle {
244    sender: Sender<std::result::Result<HeartbeatResponse, tonic::Status>>,
245    res_header: ResponseHeader,
246    deregister_signal_receiver: DeregisterSignalReceiver,
247}
248
249impl PusherHandle {
250    /// Snapshots `pusher`, which callers read under the [`Pushers`] guard.
251    fn from_pusher(pusher: &Pusher) -> Self {
252        Self {
253            sender: pusher.sender.clone(),
254            res_header: pusher.header(),
255            deregister_signal_receiver: pusher.deregister_signal_receiver.clone(),
256        }
257    }
258
259    /// Sends one mailbox message, consuming the handle.
260    async fn push(self, mailbox_message: MailboxMessage) -> Result<()> {
261        self.sender
262            .send(Ok(HeartbeatResponse {
263                header: Some(self.res_header),
264                mailbox_message: Some(mailbox_message),
265                ..Default::default()
266            }))
267            .await
268            .map_err(|e| {
269                error::PushMessageSnafu {
270                    err_msg: e.to_string(),
271                }
272                .build()
273            })
274    }
275
276    #[inline]
277    fn deregister_signal_receiver(&self) -> DeregisterSignalReceiver {
278        self.deregister_signal_receiver.clone()
279    }
280}
281
282/// The group of heartbeat pushers.
283#[derive(Clone, Default)]
284pub struct Pushers(Arc<RwLock<BTreeMap<PusherId, Pusher>>>);
285
286impl Pushers {
287    async fn push(
288        &self,
289        pusher_id: PusherId,
290        mailbox_message: MailboxMessage,
291    ) -> Result<DeregisterSignalReceiver> {
292        // Releases the guard before the send below, which parks while the target's
293        // channel is full. `PusherNotFound` is still reported from inside the guard.
294        let handle = {
295            let pushers = self.0.read().await;
296            let pusher = pushers
297                .get(&pusher_id)
298                .with_context(|| error::PusherNotFoundSnafu {
299                    pusher_id: pusher_id.to_string(),
300                })?;
301            PusherHandle::from_pusher(pusher)
302        };
303
304        let deregister_signal_receiver = handle.deregister_signal_receiver();
305        handle.push(mailbox_message).await?;
306
307        Ok(deregister_signal_receiver)
308    }
309
310    async fn broadcast(&self, role: Role, mailbox_message: &MailboxMessage) -> Result<()> {
311        // Collects owned handles, releasing the guard before the sends below. Collecting
312        // `&Pusher` would hold it for the whole `join_all`.
313        let targets = {
314            let pushers = self.0.read().await;
315            pushers
316                .range(PusherId::role_range(role))
317                .map(|(_, pusher)| PusherHandle::from_pusher(pusher))
318                .collect::<Vec<_>>()
319        };
320
321        let mut results = Vec::with_capacity(targets.len());
322        for handle in targets {
323            let mut mailbox_message = mailbox_message.clone();
324            mailbox_message.id = 0; // one-way message
325
326            results.push(handle.push(mailbox_message));
327        }
328
329        // Checks the error out of the loop.
330        let _ = join_all(results)
331            .await
332            .into_iter()
333            .collect::<Result<Vec<_>>>()?;
334
335        Ok(())
336    }
337
338    /// Inserts the pusher unless the slot holds one with a higher node epoch, so an older
339    /// datanode process cannot take over a newer one's pusher. A pusher of the same stream
340    /// only takes the new epoch, keeping the messages waiting on it. Returns `None` if refused,
341    /// otherwise whether the slot was empty.
342    pub(crate) async fn insert(&self, pusher_id: PusherId, pusher: Pusher) -> Option<bool> {
343        let mut pushers = self.0.write().await;
344        match pushers.get_mut(&pusher_id) {
345            None => {
346                pushers.insert(pusher_id, pusher);
347                return Some(true);
348            }
349            Some(current) if current.node_epoch > pusher.node_epoch => return None,
350            Some(current) if current.sender.same_channel(&pusher.sender) => {
351                current.node_epoch = pusher.node_epoch;
352            }
353            Some(current) => *current = pusher,
354        }
355        Some(false)
356    }
357
358    /// Removes the pusher if it pushes to `sender`'s channel, keeping one that another stream
359    /// has registered since.
360    async fn remove(
361        &self,
362        pusher_id: PusherId,
363        sender: &Sender<std::result::Result<HeartbeatResponse, tonic::Status>>,
364    ) -> bool {
365        let mut pushers = self.0.write().await;
366        let own = pushers
367            .get(&pusher_id)
368            .is_some_and(|pusher| pusher.sender.same_channel(sender));
369        own && pushers.remove(&pusher_id).is_some()
370    }
371}
372
373#[derive(Clone)]
374pub struct NameCachedHandler {
375    name: &'static str,
376    handler: Arc<dyn HeartbeatHandler>,
377}
378
379impl NameCachedHandler {
380    fn new(handler: impl HeartbeatHandler + 'static) -> Self {
381        let name = handler.name();
382        let handler = Arc::new(handler);
383        Self { name, handler }
384    }
385}
386
387pub type HeartbeatHandlerGroupRef = Arc<HeartbeatHandlerGroup>;
388
389/// The group of heartbeat handlers.
390#[derive(Default, Clone)]
391pub struct HeartbeatHandlerGroup {
392    handlers: Vec<NameCachedHandler>,
393    pushers: Pushers,
394    /// One lock per datanode id seen, kept for the life of the process.
395    datanode_locks: DashMap<u64, Arc<tokio::sync::Mutex<()>>>,
396}
397
398impl HeartbeatHandlerGroup {
399    /// Registers the heartbeat response [`Pusher`] with the given key to the group, unless the
400    /// group holds one with a higher node epoch.
401    pub async fn register_pusher(&self, pusher_id: PusherId, pusher: Pusher) {
402        let Some(vacant) = self.pushers.insert(pusher_id, pusher).await else {
403            return;
404        };
405        info!("Pusher register: {}", pusher_id);
406        if vacant {
407            METRIC_META_HEARTBEAT_CONNECTION_NUM.inc();
408        }
409    }
410
411    /// Deregisters the heartbeat response [`Pusher`] with the given key from the group if
412    /// `sender` registered it.
413    pub async fn deregister_push(
414        &self,
415        pusher_id: PusherId,
416        sender: &Sender<std::result::Result<HeartbeatResponse, tonic::Status>>,
417    ) {
418        if self.pushers.remove(pusher_id, sender).await {
419            info!("Pusher unregister: {}", pusher_id);
420            METRIC_META_HEARTBEAT_CONNECTION_NUM.dec();
421        }
422    }
423
424    /// Locks the datanode with the given id until the guard is dropped, so its requests are
425    /// checked and handled one at a time.
426    pub(crate) async fn lock_datanode(&self, node_id: u64) -> OwnedMutexGuard<()> {
427        let lock = self.datanode_locks.entry(node_id).or_default().clone();
428        lock.lock_owned().await
429    }
430
431    #[cfg(test)]
432    /// Returns whether the group contains the heartbeat response [`Pusher`] with the given key.
433    pub async fn contains_pusher(&self, pusher_id: &PusherId) -> bool {
434        let pushers = self.pushers.0.read().await;
435        pushers.contains_key(pusher_id)
436    }
437
438    /// Returns the [`Pushers`] of the group.
439    pub fn pushers(&self) -> Pushers {
440        self.pushers.clone()
441    }
442
443    /// Handles the heartbeat request.
444    pub async fn handle(
445        &self,
446        req: HeartbeatRequest,
447        mut ctx: Context,
448    ) -> Result<HeartbeatResponse> {
449        let mut acc = HeartbeatAccumulator::default();
450        let role = req
451            .header
452            .as_ref()
453            .and_then(|h| Role::try_from(h.role).ok())
454            .context(error::InvalidArgumentsSnafu {
455                err_msg: format!("invalid role: {:?}", req.header),
456            })?;
457
458        let is_handshake = ctx.is_handshake;
459
460        for NameCachedHandler { name, handler } in self.handlers.iter() {
461            if !handler.is_acceptable(role) {
462                continue;
463            }
464
465            let _timer = METRIC_META_HANDLER_EXECUTE
466                .with_label_values(&[*name])
467                .start_timer();
468
469            if handler.handle(&req, &mut ctx, &mut acc).await? == HandleControl::Done {
470                break;
471            }
472        }
473        let header = std::mem::take(&mut acc.header);
474        let mailbox_message = acc.take_mailbox_message();
475
476        // Populate heartbeat_config during handshake
477        let heartbeat_config = if is_handshake {
478            let mut config: HeartbeatConfig = ctx.heartbeat_options_for(role).into();
479            config.gc_enabled = ctx.gc_enabled;
480
481            info!(
482                "Handshake with {:?} node, sending config: {:?}",
483                role, config
484            );
485
486            Some(config)
487        } else {
488            None
489        };
490
491        let res = HeartbeatResponse {
492            header,
493            region_lease: acc.region_lease,
494            mailbox_message,
495            heartbeat_config,
496            extensions: std::mem::take(&mut acc.extensions),
497        };
498        Ok(res)
499    }
500}
501
502pub struct HeartbeatMailbox {
503    pushers: Pushers,
504    sequence: Sequence,
505    senders: DashMap<MessageId, oneshot::Sender<Result<MailboxMessage>>>,
506    timeouts: DashMap<MessageId, Instant>,
507    timeout_notify: Notify,
508}
509
510impl HeartbeatMailbox {
511    pub fn json_reply(msg: &MailboxMessage) -> Result<InstructionReply> {
512        let Payload::Json(payload) =
513            msg.payload
514                .as_ref()
515                .with_context(|| UnexpectedInstructionReplySnafu {
516                    mailbox_message: msg.to_string(),
517                    reason: "empty JSON payload".to_string(),
518                })?;
519        serde_json::from_str(payload).context(DeserializeFromJsonSnafu {
520            input_len: payload.len(),
521        })
522    }
523
524    /// Parses the [Instruction] from [MailboxMessage].
525    #[cfg(test)]
526    pub(crate) fn json_instruction(
527        msg: &MailboxMessage,
528    ) -> Result<common_meta::instruction::Instruction> {
529        let Payload::Json(payload) =
530            msg.payload
531                .as_ref()
532                .with_context(|| UnexpectedInstructionReplySnafu {
533                    mailbox_message: msg.to_string(),
534                    reason: "empty JSON payload".to_string(),
535                })?;
536        serde_json::from_str(payload).context(DeserializeFromJsonSnafu {
537            input_len: payload.len(),
538        })
539    }
540
541    pub fn create(pushers: Pushers, sequence: Sequence) -> MailboxRef {
542        let mailbox = Arc::new(Self::new(pushers, sequence));
543
544        let timeout_checker = mailbox.clone();
545        let _handle = common_runtime::spawn_global(async move {
546            timeout_checker.check_timeout_bg(10).await;
547        });
548
549        mailbox
550    }
551
552    fn new(pushers: Pushers, sequence: Sequence) -> Self {
553        Self {
554            pushers,
555            sequence,
556            senders: DashMap::default(),
557            timeouts: DashMap::default(),
558            timeout_notify: Notify::new(),
559        }
560    }
561
562    async fn check_timeout_bg(&self, interval_millis: u64) {
563        let mut interval = tokio::time::interval(Duration::from_millis(interval_millis));
564
565        loop {
566            let _ = interval.tick().await;
567
568            if self.timeouts.is_empty() {
569                self.timeout_notify.notified().await;
570            }
571
572            let now = Instant::now();
573            let timeout_ids = self
574                .timeouts
575                .iter()
576                .filter_map(|entry| {
577                    let (id, deadline) = entry.pair();
578                    if deadline < &now { Some(*id) } else { None }
579                })
580                .collect::<Vec<_>>();
581
582            for id in timeout_ids {
583                let _ = self
584                    .on_recv(id, Err(error::MailboxTimeoutSnafu { id }.build()))
585                    .await;
586            }
587        }
588    }
589
590    #[inline]
591    async fn next_message_id(&self) -> Result<u64> {
592        // In this implementation, we pre-occupy the message_id of 0,
593        // and we use `message_id = 0` to mark a Message as a one-way call.
594        loop {
595            let next = self
596                .sequence
597                .next()
598                .await
599                .context(error::NextSequenceSnafu)?;
600            if next > 0 {
601                return Ok(next);
602            }
603        }
604    }
605}
606
607#[async_trait::async_trait]
608impl Mailbox for HeartbeatMailbox {
609    async fn send(
610        &self,
611        ch: &Channel,
612        mut msg: MailboxMessage,
613        timeout: Duration,
614    ) -> Result<MailboxReceiver> {
615        let message_id = self.next_message_id().await?;
616        msg.id = message_id;
617
618        let pusher_id = ch.pusher_id();
619        let payload_len = msg
620            .payload
621            .as_ref()
622            .map(|Payload::Json(payload)| payload.len())
623            .unwrap_or_default();
624        debug!(message_id, payload_len, %pusher_id, "Sending mailbox message");
625
626        let (tx, rx) = oneshot::channel();
627        let _ = self.senders.insert(message_id, tx);
628        let deadline = Instant::now() + timeout;
629        self.timeouts.insert(message_id, deadline);
630        self.timeout_notify.notify_one();
631        let deregister_signal_receiver = self.pushers.push(pusher_id, msg).await?;
632
633        Ok(MailboxReceiver::new(
634            message_id,
635            rx,
636            deregister_signal_receiver,
637            *ch,
638        ))
639    }
640
641    async fn send_oneway(&self, ch: &Channel, mut msg: MailboxMessage) -> Result<()> {
642        let message_id = 0; // one-way message, same as `broadcast`
643        msg.id = message_id;
644
645        let pusher_id = ch.pusher_id();
646        let payload_len = msg
647            .payload
648            .as_ref()
649            .map(|Payload::Json(payload)| payload.len())
650            .unwrap_or_default();
651        debug!(message_id, payload_len, %pusher_id, "Sending one-way mailbox message");
652
653        self.pushers.push(pusher_id, msg).await?;
654
655        Ok(())
656    }
657
658    async fn broadcast(&self, ch: &BroadcastChannel, msg: &MailboxMessage) -> Result<()> {
659        self.pushers.broadcast(ch.role(), msg).await
660    }
661
662    async fn on_recv(&self, id: MessageId, maybe_msg: Result<MailboxMessage>) -> Result<()> {
663        let payload_len = maybe_msg
664            .as_ref()
665            .ok()
666            .and_then(|msg| msg.payload.as_ref())
667            .map(|Payload::Json(payload)| payload.len())
668            .unwrap_or_default();
669        debug!(
670            message_id = id,
671            payload_len,
672            success = maybe_msg.is_ok(),
673            "Received mailbox message"
674        );
675
676        let _ = self.timeouts.remove(&id);
677
678        if let Some((_, tx)) = self.senders.remove(&id) {
679            tx.send(maybe_msg)
680                .map_err(|_| error::MailboxClosedSnafu { id }.build())?;
681        } else if let Ok(finally_msg) = maybe_msg {
682            let payload_len = finally_msg
683                .payload
684                .as_ref()
685                .map(|Payload::Json(payload)| payload.len())
686                .unwrap_or_default();
687            warn!(
688                message_id = id,
689                payload_len, "The mailbox response arrived too late"
690            );
691        }
692
693        Ok(())
694    }
695}
696
697/// The builder to build the group of heartbeat handlers.
698pub struct HeartbeatHandlerGroupBuilder {
699    /// The handler to handle region failure.
700    region_failure_handler: Option<RegionFailureHandler>,
701
702    /// The handler to handle region lease.
703    region_lease_handler: Option<RegionLeaseHandler>,
704
705    /// The factor that determines how often statistics should be flushed,
706    /// based on the number of received heartbeats. When the number of heartbeats
707    /// reaches this factor, a flush operation is triggered.
708    flush_stats_factor: Option<usize>,
709    /// A simple handler for flow internal state report
710    flow_state_handler: Option<FlowStateHandler>,
711
712    /// The handler to persist stats.
713    persist_stats_handler: Option<PersistStatsHandler>,
714
715    /// The plugins.
716    plugins: Option<Plugins>,
717
718    /// The heartbeat response pushers.
719    pushers: Pushers,
720
721    /// The group of heartbeat handlers.
722    handlers: Vec<NameCachedHandler>,
723}
724
725impl HeartbeatHandlerGroupBuilder {
726    pub fn new(pushers: Pushers) -> Self {
727        Self {
728            region_failure_handler: None,
729            region_lease_handler: None,
730            flush_stats_factor: None,
731            flow_state_handler: None,
732            persist_stats_handler: None,
733            plugins: None,
734            pushers,
735            handlers: vec![],
736        }
737    }
738
739    pub fn with_flow_state_handler(mut self, handler: Option<FlowStateHandler>) -> Self {
740        self.flow_state_handler = handler;
741        self
742    }
743
744    pub fn with_region_lease_handler(mut self, handler: Option<RegionLeaseHandler>) -> Self {
745        self.region_lease_handler = handler;
746        self
747    }
748
749    /// Sets the [`RegionFailureHandler`].
750    pub fn with_region_failure_handler(mut self, handler: Option<RegionFailureHandler>) -> Self {
751        self.region_failure_handler = handler;
752        self
753    }
754
755    /// Sets the flush stats factor.
756    pub fn with_flush_stats_factor(mut self, flush_stats_factor: Option<usize>) -> Self {
757        self.flush_stats_factor = flush_stats_factor;
758        self
759    }
760
761    pub fn with_persist_stats_handler(mut self, handler: Option<PersistStatsHandler>) -> Self {
762        self.persist_stats_handler = handler;
763        self
764    }
765
766    /// Sets the [`Plugins`].
767    pub fn with_plugins(mut self, plugins: Option<Plugins>) -> Self {
768        self.plugins = plugins;
769        self
770    }
771
772    /// Adds the default handlers.
773    pub fn add_default_handlers(mut self) -> Self {
774        // Extract the `PublishHeartbeatHandler` from the plugins.
775        let publish_heartbeat_handler = if let Some(plugins) = self.plugins.as_ref() {
776            plugins
777                .get::<PublisherRef>()
778                .map(|publish| PublishHeartbeatHandler::new(publish.clone()))
779        } else {
780            None
781        };
782
783        self.add_handler_last(ResponseHeaderHandler);
784        // `KeepLeaseHandler` should preferably be in front of `CheckLeaderHandler`,
785        // because even if the current meta-server node is no longer the leader it can
786        // still help the datanode to keep lease.
787        self.add_handler_last(DatanodeKeepLeaseHandler);
788        self.add_handler_last(FlownodeKeepLeaseHandler);
789        self.add_handler_last(CheckLeaderHandler);
790        self.add_handler_last(OnLeaderStartHandler);
791        self.add_handler_last(ExtractStatHandler);
792        self.add_handler_last(CollectDatanodeClusterInfoHandler);
793        self.add_handler_last(CollectFrontendClusterInfoHandler);
794        self.add_handler_last(CollectFlownodeClusterInfoHandler);
795        self.add_handler_last(MailboxHandler);
796        if let Some(region_lease_handler) = self.region_lease_handler.take() {
797            self.add_handler_last(region_lease_handler);
798        }
799        self.add_handler_last(FilterInactiveRegionStatsHandler);
800        if let Some(region_failure_handler) = self.region_failure_handler.take() {
801            self.add_handler_last(region_failure_handler);
802        }
803        if let Some(publish_heartbeat_handler) = publish_heartbeat_handler {
804            self.add_handler_last(publish_heartbeat_handler);
805        }
806        self.add_handler_last(CollectLeaderRegionHandler);
807        self.add_handler_last(CollectTopicStatsHandler);
808        // Persist stats handler should be in front of collect stats handler.
809        // Because collect stats handler will consume the stats from the accumulator.
810        if let Some(persist_stats_handler) = self.persist_stats_handler.take() {
811            self.add_handler_last(persist_stats_handler);
812        }
813        self.add_handler_last(CollectStatsHandler::new(self.flush_stats_factor));
814        self.add_handler_last(RemapFlowPeerHandler::default());
815
816        if let Some(flow_state_handler) = self.flow_state_handler.take() {
817            self.add_handler_last(flow_state_handler);
818        }
819
820        self
821    }
822
823    /// Builds the group of heartbeat handlers.
824    ///
825    /// Applies the customizer if it exists.
826    pub fn build(mut self) -> Result<HeartbeatHandlerGroup> {
827        if let Some(customizer) = self
828            .plugins
829            .as_ref()
830            .and_then(|plugins| plugins.get::<HeartbeatHandlerGroupBuilderCustomizerRef>())
831        {
832            debug!("Customizing the heartbeat handler group builder");
833            customizer.customize(&mut self)?;
834        }
835
836        Ok(HeartbeatHandlerGroup {
837            handlers: self.handlers,
838            pushers: self.pushers,
839            datanode_locks: DashMap::new(),
840        })
841    }
842
843    fn add_handler_after_inner(&mut self, target: &str, handler: NameCachedHandler) -> Result<()> {
844        if let Some(pos) = self.handlers.iter().position(|x| x.name == target) {
845            self.handlers.insert(pos + 1, handler);
846            return Ok(());
847        }
848
849        error::HandlerNotFoundSnafu { name: target }.fail()
850    }
851
852    /// Adds the handler after the specified handler.
853    pub fn add_handler_after(
854        &mut self,
855        target: &'static str,
856        handler: impl HeartbeatHandler + 'static,
857    ) -> Result<()> {
858        self.add_handler_after_inner(target, NameCachedHandler::new(handler))
859    }
860
861    fn add_handler_before_inner(&mut self, target: &str, handler: NameCachedHandler) -> Result<()> {
862        if let Some(pos) = self.handlers.iter().position(|x| x.name == target) {
863            self.handlers.insert(pos, handler);
864            return Ok(());
865        }
866
867        error::HandlerNotFoundSnafu { name: target }.fail()
868    }
869
870    /// Adds the handler before the specified handler.
871    pub fn add_handler_before(
872        &mut self,
873        target: &'static str,
874        handler: impl HeartbeatHandler + 'static,
875    ) -> Result<()> {
876        self.add_handler_before_inner(target, NameCachedHandler::new(handler))
877    }
878
879    fn replace_handler_inner(&mut self, target: &str, handler: NameCachedHandler) -> Result<()> {
880        if let Some(pos) = self.handlers.iter().position(|x| x.name == target) {
881            self.handlers[pos] = handler;
882            return Ok(());
883        }
884
885        error::HandlerNotFoundSnafu { name: target }.fail()
886    }
887
888    /// Replaces the handler with the specified name.
889    pub fn replace_handler(
890        &mut self,
891        target: &'static str,
892        handler: impl HeartbeatHandler + 'static,
893    ) -> Result<()> {
894        self.replace_handler_inner(target, NameCachedHandler::new(handler))
895    }
896
897    fn add_handler_last_inner(&mut self, handler: NameCachedHandler) {
898        self.handlers.push(handler);
899    }
900
901    fn add_handler_last(&mut self, handler: impl HeartbeatHandler + 'static) {
902        self.add_handler_last_inner(NameCachedHandler::new(handler));
903    }
904}
905
906pub type HeartbeatHandlerGroupBuilderCustomizerRef =
907    Arc<dyn HeartbeatHandlerGroupBuilderCustomizer>;
908
909pub enum CustomizeHeartbeatGroupAction {
910    AddHandlerAfter {
911        target: String,
912        handler: NameCachedHandler,
913    },
914    AddHandlerBefore {
915        target: String,
916        handler: NameCachedHandler,
917    },
918    ReplaceHandler {
919        target: String,
920        handler: NameCachedHandler,
921    },
922    AddHandlerLast {
923        handler: NameCachedHandler,
924    },
925}
926
927impl CustomizeHeartbeatGroupAction {
928    pub fn new_add_handler_after(
929        target: &'static str,
930        handler: impl HeartbeatHandler + 'static,
931    ) -> Self {
932        Self::AddHandlerAfter {
933            target: target.to_string(),
934            handler: NameCachedHandler::new(handler),
935        }
936    }
937
938    pub fn new_add_handler_before(
939        target: &'static str,
940        handler: impl HeartbeatHandler + 'static,
941    ) -> Self {
942        Self::AddHandlerBefore {
943            target: target.to_string(),
944            handler: NameCachedHandler::new(handler),
945        }
946    }
947
948    pub fn new_replace_handler(
949        target: &'static str,
950        handler: impl HeartbeatHandler + 'static,
951    ) -> Self {
952        Self::ReplaceHandler {
953            target: target.to_string(),
954            handler: NameCachedHandler::new(handler),
955        }
956    }
957
958    pub fn new_add_handler_last(handler: impl HeartbeatHandler + 'static) -> Self {
959        Self::AddHandlerLast {
960            handler: NameCachedHandler::new(handler),
961        }
962    }
963}
964
965/// The customizer of the [`HeartbeatHandlerGroupBuilder`].
966pub trait HeartbeatHandlerGroupBuilderCustomizer: Send + Sync {
967    fn customize(&self, builder: &mut HeartbeatHandlerGroupBuilder) -> Result<()>;
968
969    fn add_action(&self, action: CustomizeHeartbeatGroupAction);
970}
971
972#[derive(Default)]
973pub struct DefaultHeartbeatHandlerGroupBuilderCustomizer {
974    actions: Mutex<Vec<CustomizeHeartbeatGroupAction>>,
975}
976
977impl HeartbeatHandlerGroupBuilderCustomizer for DefaultHeartbeatHandlerGroupBuilderCustomizer {
978    fn customize(&self, builder: &mut HeartbeatHandlerGroupBuilder) -> Result<()> {
979        info!("Customizing the heartbeat handler group builder");
980        let mut actions = self.actions.lock().unwrap();
981        for action in actions.drain(..) {
982            match action {
983                CustomizeHeartbeatGroupAction::AddHandlerAfter { target, handler } => {
984                    builder.add_handler_after_inner(&target, handler)?;
985                }
986                CustomizeHeartbeatGroupAction::AddHandlerBefore { target, handler } => {
987                    builder.add_handler_before_inner(&target, handler)?;
988                }
989                CustomizeHeartbeatGroupAction::ReplaceHandler { target, handler } => {
990                    builder.replace_handler_inner(&target, handler)?;
991                }
992                CustomizeHeartbeatGroupAction::AddHandlerLast { handler } => {
993                    builder.add_handler_last_inner(handler);
994                }
995            }
996        }
997        Ok(())
998    }
999
1000    fn add_action(&self, action: CustomizeHeartbeatGroupAction) {
1001        self.actions.lock().unwrap().push(action);
1002    }
1003}
1004
1005#[cfg(test)]
1006mod tests {
1007
1008    use std::assert_matches;
1009    use std::collections::BTreeMap;
1010    use std::sync::Arc;
1011    use std::time::Duration;
1012
1013    use api::v1::meta::{HeartbeatRequest, HeartbeatResponse, MailboxMessage, RequestHeader, Role};
1014    use common_meta::kv_backend::memory::MemoryKvBackend;
1015    use common_meta::sequence::SequenceBuilder;
1016    use futures::future::poll_immediate;
1017    use tokio::sync::mpsc;
1018
1019    use super::{
1020        HandleControl, HeartbeatAccumulator, HeartbeatHandler, HeartbeatHandlerGroupBuilder,
1021        PusherHandle, PusherId, Pushers,
1022    };
1023    use crate::error;
1024    use crate::handler::collect_stats_handler::CollectStatsHandler;
1025    use crate::handler::response_header_handler::ResponseHeaderHandler;
1026    use crate::handler::test_utils::TestEnv;
1027    use crate::handler::{HeartbeatHandlerGroup, HeartbeatMailbox, Pusher};
1028    use crate::metasrv::Context;
1029    use crate::service::mailbox::{Channel, MailboxReceiver, MailboxRef};
1030
1031    #[tokio::test]
1032    async fn test_mailbox() {
1033        let (mailbox, receiver) = push_msg_via_mailbox().await;
1034        let id = receiver.message_id();
1035
1036        let resp_msg = MailboxMessage {
1037            id,
1038            subject: "resp-test".to_string(),
1039            timestamp_millis: 456,
1040            ..Default::default()
1041        };
1042
1043        mailbox.on_recv(id, Ok(resp_msg)).await.unwrap();
1044
1045        let recv_msg = receiver.await.unwrap();
1046        assert_eq!(recv_msg.id, id);
1047        assert_eq!(recv_msg.timestamp_millis, 456);
1048        assert_eq!(recv_msg.subject, "resp-test".to_string());
1049    }
1050
1051    #[tokio::test]
1052    async fn test_mailbox_timeout() {
1053        let (_, receiver) = push_msg_via_mailbox().await;
1054        let res = receiver.await;
1055        assert!(res.is_err());
1056    }
1057
1058    async fn push_msg_via_mailbox() -> (MailboxRef, MailboxReceiver) {
1059        let datanode_id = 12;
1060        let (pusher_tx, mut pusher_rx) = mpsc::channel(16);
1061        let pusher_id = PusherId::new(Role::Datanode, datanode_id);
1062        let pusher: Pusher = Pusher::new(pusher_tx);
1063        let handler_group = HeartbeatHandlerGroup::default();
1064        handler_group.register_pusher(pusher_id, pusher).await;
1065
1066        let kv_backend = Arc::new(MemoryKvBackend::new());
1067        let seq = SequenceBuilder::new("test_seq", kv_backend).build();
1068        let mailbox = HeartbeatMailbox::create(handler_group.pushers(), seq);
1069
1070        let msg = MailboxMessage {
1071            id: 0,
1072            subject: "req-test".to_string(),
1073            timestamp_millis: 123,
1074            ..Default::default()
1075        };
1076        let ch = Channel::Datanode(datanode_id);
1077
1078        let receiver = mailbox
1079            .send(&ch, msg, Duration::from_secs(1))
1080            .await
1081            .unwrap();
1082
1083        let recv_obj = pusher_rx.recv().await.unwrap().unwrap();
1084        let message = recv_obj.mailbox_message.unwrap();
1085        assert_eq!(message.timestamp_millis, 123);
1086        assert_eq!(message.subject, "req-test".to_string());
1087
1088        (mailbox, receiver)
1089    }
1090
1091    #[test]
1092    fn test_pusher_id_role_range() {
1093        let mut pushers = BTreeMap::new();
1094        pushers.insert(PusherId::new(Role::Datanode, u64::MAX), "datanode");
1095        pushers.insert(PusherId::new(Role::Frontend, u64::MIN), "frontend-min");
1096        pushers.insert(PusherId::new(Role::Frontend, u64::MAX), "frontend-max");
1097        pushers.insert(PusherId::new(Role::Flownode, u64::MIN), "flownode");
1098
1099        let frontend_pushers = pushers
1100            .range(PusherId::role_range(Role::Frontend))
1101            .map(|(_, value)| *value)
1102            .collect::<Vec<_>>();
1103
1104        assert_eq!(frontend_pushers, vec!["frontend-min", "frontend-max"]);
1105    }
1106
1107    #[tokio::test]
1108    async fn test_pushers_broadcast_by_role() {
1109        let pushers = Pushers::default();
1110        let (datanode_tx, mut datanode_rx) = mpsc::channel(1);
1111        let (frontend_tx, mut frontend_rx) = mpsc::channel(1);
1112        let (flownode_tx, mut flownode_rx) = mpsc::channel(1);
1113
1114        pushers
1115            .insert(
1116                PusherId::new(Role::Datanode, u64::MAX),
1117                Pusher::new(datanode_tx),
1118            )
1119            .await;
1120        pushers
1121            .insert(PusherId::new(Role::Frontend, 1), Pusher::new(frontend_tx))
1122            .await;
1123        pushers
1124            .insert(
1125                PusherId::new(Role::Flownode, u64::MIN),
1126                Pusher::new(flownode_tx),
1127            )
1128            .await;
1129
1130        let msg = MailboxMessage {
1131            id: 42,
1132            subject: "broadcast-test".to_string(),
1133            timestamp_millis: 123,
1134            ..Default::default()
1135        };
1136
1137        pushers.broadcast(Role::Frontend, &msg).await.unwrap();
1138
1139        let received = frontend_rx.recv().await.unwrap().unwrap();
1140        let mailbox_message = received.mailbox_message.unwrap();
1141        assert_eq!(mailbox_message.id, 0);
1142        assert_eq!(mailbox_message.subject, "broadcast-test");
1143        assert!(datanode_rx.try_recv().is_err());
1144        assert!(flownode_rx.try_recv().is_err());
1145    }
1146
1147    #[test]
1148    fn test_handler_group_builder() {
1149        let group = HeartbeatHandlerGroupBuilder::new(Pushers::default())
1150            .add_default_handlers()
1151            .build()
1152            .unwrap();
1153
1154        let handlers = group.handlers;
1155        let names = [
1156            "ResponseHeaderHandler",
1157            "DatanodeKeepLeaseHandler",
1158            "FlownodeKeepLeaseHandler",
1159            "CheckLeaderHandler",
1160            "OnLeaderStartHandler",
1161            "ExtractStatHandler",
1162            "CollectDatanodeClusterInfoHandler",
1163            "CollectFrontendClusterInfoHandler",
1164            "CollectFlownodeClusterInfoHandler",
1165            "MailboxHandler",
1166            "FilterInactiveRegionStatsHandler",
1167            "CollectLeaderRegionHandler",
1168            "CollectTopicStatsHandler",
1169            "CollectStatsHandler",
1170            "RemapFlowPeerHandler",
1171        ];
1172        assert_eq!(names.len(), handlers.len());
1173        for (handler, name) in handlers.iter().zip(names) {
1174            assert_eq!(handler.name, name);
1175        }
1176    }
1177
1178    #[test]
1179    fn test_handler_group_builder_add_before() {
1180        let mut builder =
1181            HeartbeatHandlerGroupBuilder::new(Pushers::default()).add_default_handlers();
1182        builder
1183            .add_handler_before(
1184                "FilterInactiveRegionStatsHandler",
1185                CollectStatsHandler::default(),
1186            )
1187            .unwrap();
1188
1189        let group = builder.build().unwrap();
1190        let handlers = group.handlers;
1191        let names = [
1192            "ResponseHeaderHandler",
1193            "DatanodeKeepLeaseHandler",
1194            "FlownodeKeepLeaseHandler",
1195            "CheckLeaderHandler",
1196            "OnLeaderStartHandler",
1197            "ExtractStatHandler",
1198            "CollectDatanodeClusterInfoHandler",
1199            "CollectFrontendClusterInfoHandler",
1200            "CollectFlownodeClusterInfoHandler",
1201            "MailboxHandler",
1202            "CollectStatsHandler",
1203            "FilterInactiveRegionStatsHandler",
1204            "CollectLeaderRegionHandler",
1205            "CollectTopicStatsHandler",
1206            "CollectStatsHandler",
1207            "RemapFlowPeerHandler",
1208        ];
1209        assert_eq!(names.len(), handlers.len());
1210        for (handler, name) in handlers.iter().zip(names) {
1211            assert_eq!(handler.name, name);
1212        }
1213    }
1214
1215    #[test]
1216    fn test_handler_group_builder_add_before_first() {
1217        let mut builder =
1218            HeartbeatHandlerGroupBuilder::new(Pushers::default()).add_default_handlers();
1219        builder
1220            .add_handler_before("ResponseHeaderHandler", CollectStatsHandler::default())
1221            .unwrap();
1222
1223        let group = builder.build().unwrap();
1224        let handlers = group.handlers;
1225        let names = [
1226            "CollectStatsHandler",
1227            "ResponseHeaderHandler",
1228            "DatanodeKeepLeaseHandler",
1229            "FlownodeKeepLeaseHandler",
1230            "CheckLeaderHandler",
1231            "OnLeaderStartHandler",
1232            "ExtractStatHandler",
1233            "CollectDatanodeClusterInfoHandler",
1234            "CollectFrontendClusterInfoHandler",
1235            "CollectFlownodeClusterInfoHandler",
1236            "MailboxHandler",
1237            "FilterInactiveRegionStatsHandler",
1238            "CollectLeaderRegionHandler",
1239            "CollectTopicStatsHandler",
1240            "CollectStatsHandler",
1241            "RemapFlowPeerHandler",
1242        ];
1243        assert_eq!(names.len(), handlers.len());
1244        for (handler, name) in handlers.iter().zip(names) {
1245            assert_eq!(handler.name, name);
1246        }
1247    }
1248
1249    #[test]
1250    fn test_handler_group_builder_add_after() {
1251        let mut builder =
1252            HeartbeatHandlerGroupBuilder::new(Pushers::default()).add_default_handlers();
1253        builder
1254            .add_handler_after("MailboxHandler", CollectStatsHandler::default())
1255            .unwrap();
1256
1257        let group = builder.build().unwrap();
1258        let handlers = group.handlers;
1259        let names = [
1260            "ResponseHeaderHandler",
1261            "DatanodeKeepLeaseHandler",
1262            "FlownodeKeepLeaseHandler",
1263            "CheckLeaderHandler",
1264            "OnLeaderStartHandler",
1265            "ExtractStatHandler",
1266            "CollectDatanodeClusterInfoHandler",
1267            "CollectFrontendClusterInfoHandler",
1268            "CollectFlownodeClusterInfoHandler",
1269            "MailboxHandler",
1270            "CollectStatsHandler",
1271            "FilterInactiveRegionStatsHandler",
1272            "CollectLeaderRegionHandler",
1273            "CollectTopicStatsHandler",
1274            "CollectStatsHandler",
1275            "RemapFlowPeerHandler",
1276        ];
1277        assert_eq!(names.len(), handlers.len());
1278        for (handler, name) in handlers.iter().zip(names) {
1279            assert_eq!(handler.name, name);
1280        }
1281    }
1282
1283    #[test]
1284    fn test_handler_group_builder_add_after_last() {
1285        let mut builder =
1286            HeartbeatHandlerGroupBuilder::new(Pushers::default()).add_default_handlers();
1287        builder
1288            .add_handler_after("CollectStatsHandler", ResponseHeaderHandler)
1289            .unwrap();
1290
1291        let group = builder.build().unwrap();
1292        let handlers = group.handlers;
1293        let names = [
1294            "ResponseHeaderHandler",
1295            "DatanodeKeepLeaseHandler",
1296            "FlownodeKeepLeaseHandler",
1297            "CheckLeaderHandler",
1298            "OnLeaderStartHandler",
1299            "ExtractStatHandler",
1300            "CollectDatanodeClusterInfoHandler",
1301            "CollectFrontendClusterInfoHandler",
1302            "CollectFlownodeClusterInfoHandler",
1303            "MailboxHandler",
1304            "FilterInactiveRegionStatsHandler",
1305            "CollectLeaderRegionHandler",
1306            "CollectTopicStatsHandler",
1307            "CollectStatsHandler",
1308            "ResponseHeaderHandler",
1309            "RemapFlowPeerHandler",
1310        ];
1311        assert_eq!(names.len(), handlers.len());
1312        for (handler, name) in handlers.iter().zip(names) {
1313            assert_eq!(handler.name, name);
1314        }
1315    }
1316
1317    #[test]
1318    fn test_handler_group_builder_replace() {
1319        let mut builder =
1320            HeartbeatHandlerGroupBuilder::new(Pushers::default()).add_default_handlers();
1321        builder
1322            .replace_handler("MailboxHandler", CollectStatsHandler::default())
1323            .unwrap();
1324
1325        let group = builder.build().unwrap();
1326        let handlers = group.handlers;
1327        let names = [
1328            "ResponseHeaderHandler",
1329            "DatanodeKeepLeaseHandler",
1330            "FlownodeKeepLeaseHandler",
1331            "CheckLeaderHandler",
1332            "OnLeaderStartHandler",
1333            "ExtractStatHandler",
1334            "CollectDatanodeClusterInfoHandler",
1335            "CollectFrontendClusterInfoHandler",
1336            "CollectFlownodeClusterInfoHandler",
1337            "CollectStatsHandler",
1338            "FilterInactiveRegionStatsHandler",
1339            "CollectLeaderRegionHandler",
1340            "CollectTopicStatsHandler",
1341            "CollectStatsHandler",
1342            "RemapFlowPeerHandler",
1343        ];
1344
1345        assert_eq!(names.len(), handlers.len());
1346        for (handler, name) in handlers.iter().zip(names) {
1347            assert_eq!(handler.name, name);
1348        }
1349    }
1350
1351    #[test]
1352    fn test_handler_group_builder_replace_last() {
1353        let mut builder =
1354            HeartbeatHandlerGroupBuilder::new(Pushers::default()).add_default_handlers();
1355        builder
1356            .replace_handler("CollectStatsHandler", ResponseHeaderHandler)
1357            .unwrap();
1358
1359        let group = builder.build().unwrap();
1360        let handlers = group.handlers;
1361        let names = [
1362            "ResponseHeaderHandler",
1363            "DatanodeKeepLeaseHandler",
1364            "FlownodeKeepLeaseHandler",
1365            "CheckLeaderHandler",
1366            "OnLeaderStartHandler",
1367            "ExtractStatHandler",
1368            "CollectDatanodeClusterInfoHandler",
1369            "CollectFrontendClusterInfoHandler",
1370            "CollectFlownodeClusterInfoHandler",
1371            "MailboxHandler",
1372            "FilterInactiveRegionStatsHandler",
1373            "CollectLeaderRegionHandler",
1374            "CollectTopicStatsHandler",
1375            "ResponseHeaderHandler",
1376            "RemapFlowPeerHandler",
1377        ];
1378
1379        assert_eq!(names.len(), handlers.len());
1380        for (handler, name) in handlers.iter().zip(names) {
1381            assert_eq!(handler.name, name);
1382        }
1383    }
1384
1385    #[test]
1386    fn test_handler_group_builder_replace_first() {
1387        let mut builder =
1388            HeartbeatHandlerGroupBuilder::new(Pushers::default()).add_default_handlers();
1389        builder
1390            .replace_handler("ResponseHeaderHandler", CollectStatsHandler::default())
1391            .unwrap();
1392
1393        let group = builder.build().unwrap();
1394        let handlers = group.handlers;
1395        let names = [
1396            "CollectStatsHandler",
1397            "DatanodeKeepLeaseHandler",
1398            "FlownodeKeepLeaseHandler",
1399            "CheckLeaderHandler",
1400            "OnLeaderStartHandler",
1401            "ExtractStatHandler",
1402            "CollectDatanodeClusterInfoHandler",
1403            "CollectFrontendClusterInfoHandler",
1404            "CollectFlownodeClusterInfoHandler",
1405            "MailboxHandler",
1406            "FilterInactiveRegionStatsHandler",
1407            "CollectLeaderRegionHandler",
1408            "CollectTopicStatsHandler",
1409            "CollectStatsHandler",
1410            "RemapFlowPeerHandler",
1411        ];
1412        assert_eq!(names.len(), handlers.len());
1413        for (handler, name) in handlers.iter().zip(names) {
1414            assert_eq!(handler.name, name);
1415        }
1416    }
1417
1418    #[test]
1419    fn test_handler_group_builder_handler_not_found() {
1420        let mut builder =
1421            HeartbeatHandlerGroupBuilder::new(Pushers::default()).add_default_handlers();
1422        let err = builder
1423            .add_handler_before("NotExists", CollectStatsHandler::default())
1424            .unwrap_err();
1425        assert_matches!(err, error::Error::HandlerNotFound { .. });
1426
1427        let err = builder
1428            .add_handler_after("NotExists", CollectStatsHandler::default())
1429            .unwrap_err();
1430        assert_matches!(err, error::Error::HandlerNotFound { .. });
1431
1432        let err = builder
1433            .replace_handler("NotExists", CollectStatsHandler::default())
1434            .unwrap_err();
1435        assert_matches!(err, error::Error::HandlerNotFound { .. });
1436    }
1437
1438    #[tokio::test]
1439    async fn test_pusher_drop() {
1440        let (tx, _rx) = mpsc::channel(1);
1441        let pusher = Pusher::new(tx);
1442        let mut deregister_signal_tx = pusher.deregister_signal_receiver.clone();
1443
1444        drop(pusher);
1445        deregister_signal_tx.changed().await.unwrap();
1446    }
1447
1448    #[tokio::test]
1449    async fn test_custom_handler_extension_reaches_response() {
1450        struct CustomExtensionHandler;
1451
1452        #[async_trait::async_trait]
1453        impl HeartbeatHandler for CustomExtensionHandler {
1454            fn is_acceptable(&self, role: Role) -> bool {
1455                role == Role::Frontend
1456            }
1457
1458            async fn handle(
1459                &self,
1460                _req: &HeartbeatRequest,
1461                _ctx: &mut Context,
1462                acc: &mut HeartbeatAccumulator,
1463            ) -> crate::error::Result<HandleControl> {
1464                acc.extensions
1465                    .insert("custom.key".to_string(), b"custom-value".to_vec());
1466                Ok(HandleControl::Continue)
1467            }
1468        }
1469
1470        let mut builder =
1471            HeartbeatHandlerGroupBuilder::new(Pushers::default()).add_default_handlers();
1472        builder.add_handler_last(CustomExtensionHandler);
1473
1474        let group = builder.build().unwrap();
1475
1476        let req = HeartbeatRequest {
1477            header: Some(RequestHeader::new(1, Role::Frontend, Default::default())),
1478            ..Default::default()
1479        };
1480        let ctx = TestEnv::new().ctx();
1481
1482        let res = group.handle(req, ctx).await.unwrap();
1483
1484        let extensions = res.extensions;
1485        assert_eq!(extensions.get("custom.key").unwrap(), b"custom-value");
1486    }
1487
1488    async fn full_pusher(
1489        pushers: &Pushers,
1490        id: PusherId,
1491    ) -> mpsc::Receiver<std::result::Result<HeartbeatResponse, tonic::Status>> {
1492        let (tx, rx) = mpsc::channel(1);
1493        tx.try_send(Ok(HeartbeatResponse::default())).unwrap();
1494        pushers.insert(id, Pusher::new(tx)).await;
1495        // Callers keep `rx` alive: dropping it would make the send fail instead of park.
1496        rx
1497    }
1498
1499    fn test_mailbox_message(subject: &str) -> MailboxMessage {
1500        MailboxMessage {
1501            id: 0,
1502            subject: subject.to_string(),
1503            timestamp_millis: 123,
1504            ..Default::default()
1505        }
1506    }
1507
1508    #[tokio::test]
1509    async fn test_pushers_push_does_not_fence_the_registry() {
1510        let pushers = Pushers::default();
1511
1512        let full_id = PusherId::new(Role::Datanode, 1);
1513        let _full_rx = full_pusher(&pushers, full_id).await;
1514
1515        let (healthy_tx, mut healthy_rx) = mpsc::channel(1);
1516        let healthy_id = PusherId::new(Role::Datanode, 2);
1517        pushers.insert(healthy_id, Pusher::new(healthy_tx)).await;
1518
1519        let msg = test_mailbox_message("fence-test");
1520
1521        let mut parked = Box::pin(pushers.push(full_id, msg.clone()));
1522        assert!(poll_immediate(parked.as_mut()).await.is_none());
1523
1524        let (writer_tx, _writer_rx) = mpsc::channel(1);
1525        let mut writer =
1526            Box::pin(pushers.insert(PusherId::new(Role::Datanode, 3), Pusher::new(writer_tx)));
1527        assert!(poll_immediate(writer.as_mut()).await.is_some());
1528
1529        let mut healthy = Box::pin(pushers.push(healthy_id, msg));
1530        assert!(poll_immediate(healthy.as_mut()).await.is_some());
1531        assert!(healthy_rx.try_recv().is_ok());
1532    }
1533
1534    #[tokio::test]
1535    async fn test_pusher_insert_reports_an_empty_slot() {
1536        let pushers = Pushers::default();
1537        let id = PusherId::new(Role::Datanode, 1);
1538        let (tx1, _rx1) = mpsc::channel(1);
1539        let (tx2, _rx2) = mpsc::channel(1);
1540        assert_eq!(
1541            pushers.insert(id, Pusher::new(tx1.clone())).await,
1542            Some(true)
1543        );
1544        // Taking an epoch and replacing another stream's pusher fill no slot.
1545        let in_place = Pusher::new(tx1).with_node_epoch(2);
1546        assert_eq!(pushers.insert(id, in_place).await, Some(false));
1547        let lower = Pusher::new(tx2.clone()).with_node_epoch(1);
1548        assert_eq!(pushers.insert(id, lower).await, None);
1549        let other = Pusher::new(tx2).with_node_epoch(2);
1550        assert_eq!(pushers.insert(id, other).await, Some(false));
1551    }
1552
1553    #[tokio::test]
1554    async fn test_pushers_broadcast_does_not_fence_the_registry() {
1555        let pushers = Pushers::default();
1556
1557        let _full_rx = full_pusher(&pushers, PusherId::new(Role::Datanode, 1)).await;
1558        let (healthy_tx, _healthy_rx) = mpsc::channel(1);
1559        pushers
1560            .insert(PusherId::new(Role::Datanode, 2), Pusher::new(healthy_tx))
1561            .await;
1562
1563        let msg = test_mailbox_message("broadcast-fence-test");
1564        let mut parked = Box::pin(pushers.broadcast(Role::Datanode, &msg));
1565        assert!(poll_immediate(parked.as_mut()).await.is_none());
1566
1567        let (writer_tx, _writer_rx) = mpsc::channel(1);
1568        let mut writer =
1569            Box::pin(pushers.insert(PusherId::new(Role::Flownode, 1), Pusher::new(writer_tx)));
1570        assert!(poll_immediate(writer.as_mut()).await.is_some());
1571    }
1572
1573    #[tokio::test]
1574    async fn test_pusher_handle_does_not_fire_the_deregister_signal() {
1575        let (tx, _rx) = mpsc::channel(1);
1576        let pusher = Pusher::new(tx);
1577        let mut signal = pusher.deregister_signal_receiver.clone();
1578
1579        let handle = PusherHandle::from_pusher(&pusher);
1580        drop(handle);
1581
1582        assert!(
1583            tokio::time::timeout(Duration::from_millis(100), signal.changed())
1584                .await
1585                .is_err()
1586        );
1587
1588        // The real `Pusher` still owns the signal.
1589        drop(pusher);
1590        assert!(signal.changed().await.is_ok());
1591    }
1592}