1use 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, 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;
84
85#[cfg(test)]
86pub mod test_utils;
87
88#[async_trait::async_trait]
89pub trait HeartbeatHandler: Send + Sync {
90 fn is_acceptable(&self, role: Role) -> bool;
91
92 fn name(&self) -> &'static str {
93 let type_name = std::any::type_name::<Self>();
94 type_name.split("::").last().unwrap_or(type_name)
96 }
97
98 async fn handle(
99 &self,
100 req: &HeartbeatRequest,
101 ctx: &mut Context,
102 acc: &mut HeartbeatAccumulator,
103 ) -> Result<HandleControl>;
104}
105
106#[derive(PartialEq, Debug)]
110pub enum HandleControl {
111 Continue,
112 Done,
113}
114
115#[derive(Debug, Default)]
116pub struct HeartbeatAccumulator {
117 pub header: Option<ResponseHeader>,
118 mailbox_message: Option<MailboxMessage>,
119 pub stat: Option<Stat>,
120 pub inactive_region_ids: HashSet<RegionId>,
121 pub region_lease: Option<RegionLease>,
122 pub extensions: HashMap<String, Vec<u8>>,
124}
125
126impl HeartbeatAccumulator {
127 pub(crate) fn take_mailbox_message(&mut self) -> Option<MailboxMessage> {
128 self.mailbox_message.take()
129 }
130
131 pub fn set_mailbox_message(&mut self, message: MailboxMessage) {
132 let _ = self.mailbox_message.insert(message);
133 }
134}
135
136#[derive(Copy, Clone)]
137pub struct PusherId {
138 pub role: Role,
139 pub id: u64,
140}
141
142impl PartialEq for PusherId {
143 fn eq(&self, other: &Self) -> bool {
144 self.role as i32 == other.role as i32 && self.id == other.id
145 }
146}
147
148impl Eq for PusherId {}
149
150impl PartialOrd for PusherId {
151 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
152 Some(self.cmp(other))
153 }
154}
155
156impl Ord for PusherId {
157 fn cmp(&self, other: &Self) -> Ordering {
158 (self.role as i32, self.id).cmp(&(other.role as i32, other.id))
159 }
160}
161
162impl Debug for PusherId {
163 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
164 write!(f, "{:?}-{}", self.role, self.id)
165 }
166}
167
168impl Display for PusherId {
169 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
170 write!(f, "{:?}-{}", self.role, self.id)
171 }
172}
173
174impl PusherId {
175 pub fn new(role: Role, id: u64) -> Self {
176 Self { role, id }
177 }
178
179 fn role_range(role: Role) -> (Bound<Self>, Bound<Self>) {
180 (
181 Bound::Included(Self::new(role, u64::MIN)),
182 Bound::Included(Self::new(role, u64::MAX)),
183 )
184 }
185}
186
187pub type DeregisterSignalReceiver = watch::Receiver<bool>;
189
190pub struct Pusher {
192 sender: Sender<std::result::Result<HeartbeatResponse, tonic::Status>>,
193 deregister_signal_sender: watch::Sender<bool>,
197 deregister_signal_receiver: DeregisterSignalReceiver,
198
199 res_header: ResponseHeader,
200}
201
202impl Drop for Pusher {
203 fn drop(&mut self) {
204 let _ = self.deregister_signal_sender.send(true);
207 }
208}
209
210impl Pusher {
211 pub fn new(sender: Sender<std::result::Result<HeartbeatResponse, tonic::Status>>) -> Self {
212 let res_header = ResponseHeader {
213 protocol_version: PROTOCOL_VERSION,
214 ..Default::default()
215 };
216 let (deregister_signal_sender, deregister_signal_receiver) = watch::channel(false);
217 Self {
218 sender,
219 deregister_signal_sender,
220 deregister_signal_receiver,
221 res_header,
222 }
223 }
224
225 #[inline]
226 pub async fn push(&self, res: HeartbeatResponse) -> Result<()> {
227 self.sender.send(Ok(res)).await.map_err(|e| {
228 error::PushMessageSnafu {
229 err_msg: e.to_string(),
230 }
231 .build()
232 })
233 }
234
235 #[inline]
236 pub fn header(&self) -> ResponseHeader {
237 self.res_header.clone()
238 }
239}
240
241#[derive(Clone, Default)]
243pub struct Pushers(Arc<RwLock<BTreeMap<PusherId, Pusher>>>);
244
245impl Pushers {
246 async fn push(
247 &self,
248 pusher_id: PusherId,
249 mailbox_message: MailboxMessage,
250 ) -> Result<DeregisterSignalReceiver> {
251 let pushers = self.0.read().await;
252 let pusher = pushers
253 .get(&pusher_id)
254 .with_context(|| error::PusherNotFoundSnafu {
255 pusher_id: pusher_id.to_string(),
256 })?;
257
258 pusher
259 .push(HeartbeatResponse {
260 header: Some(pusher.header()),
261 mailbox_message: Some(mailbox_message),
262 ..Default::default()
263 })
264 .await?;
265
266 Ok(pusher.deregister_signal_receiver.clone())
267 }
268
269 async fn broadcast(&self, role: Role, mailbox_message: &MailboxMessage) -> Result<()> {
270 let pushers = self.0.read().await;
271 let pushers = pushers
272 .range(PusherId::role_range(role))
273 .map(|(_, value)| value)
274 .collect::<Vec<_>>();
275 let mut results = Vec::with_capacity(pushers.len());
276
277 for pusher in pushers {
278 let mut mailbox_message = mailbox_message.clone();
279 mailbox_message.id = 0; results.push(pusher.push(HeartbeatResponse {
282 header: Some(pusher.header()),
283 mailbox_message: Some(mailbox_message),
284 ..Default::default()
285 }))
286 }
287
288 let _ = join_all(results)
290 .await
291 .into_iter()
292 .collect::<Result<Vec<_>>>()?;
293
294 Ok(())
295 }
296
297 pub(crate) async fn insert(&self, pusher_id: PusherId, pusher: Pusher) -> Option<Pusher> {
298 self.0.write().await.insert(pusher_id, pusher)
299 }
300
301 async fn remove(&self, pusher_id: PusherId) -> Option<Pusher> {
302 self.0.write().await.remove(&pusher_id)
303 }
304}
305
306#[derive(Clone)]
307pub struct NameCachedHandler {
308 name: &'static str,
309 handler: Arc<dyn HeartbeatHandler>,
310}
311
312impl NameCachedHandler {
313 fn new(handler: impl HeartbeatHandler + 'static) -> Self {
314 let name = handler.name();
315 let handler = Arc::new(handler);
316 Self { name, handler }
317 }
318}
319
320pub type HeartbeatHandlerGroupRef = Arc<HeartbeatHandlerGroup>;
321
322#[derive(Default, Clone)]
324pub struct HeartbeatHandlerGroup {
325 handlers: Vec<NameCachedHandler>,
326 pushers: Pushers,
327}
328
329impl HeartbeatHandlerGroup {
330 pub async fn register_pusher(&self, pusher_id: PusherId, pusher: Pusher) {
332 METRIC_META_HEARTBEAT_CONNECTION_NUM.inc();
333 info!("Pusher register: {}", pusher_id);
334 let _ = self.pushers.insert(pusher_id, pusher).await;
335 }
336
337 pub async fn deregister_push(&self, pusher_id: PusherId) {
339 if self.pushers.remove(pusher_id).await.is_some() {
340 info!("Pusher unregister: {}", pusher_id);
341 METRIC_META_HEARTBEAT_CONNECTION_NUM.dec();
342 }
343 }
344
345 #[cfg(test)]
346 pub async fn contains_pusher(&self, pusher_id: &PusherId) -> bool {
348 let pushers = self.pushers.0.read().await;
349 pushers.contains_key(pusher_id)
350 }
351
352 pub fn pushers(&self) -> Pushers {
354 self.pushers.clone()
355 }
356
357 pub async fn handle(
359 &self,
360 req: HeartbeatRequest,
361 mut ctx: Context,
362 ) -> Result<HeartbeatResponse> {
363 let mut acc = HeartbeatAccumulator::default();
364 let role = req
365 .header
366 .as_ref()
367 .and_then(|h| Role::try_from(h.role).ok())
368 .context(error::InvalidArgumentsSnafu {
369 err_msg: format!("invalid role: {:?}", req.header),
370 })?;
371
372 let is_handshake = ctx.is_handshake;
373
374 for NameCachedHandler { name, handler } in self.handlers.iter() {
375 if !handler.is_acceptable(role) {
376 continue;
377 }
378
379 let _timer = METRIC_META_HANDLER_EXECUTE
380 .with_label_values(&[*name])
381 .start_timer();
382
383 if handler.handle(&req, &mut ctx, &mut acc).await? == HandleControl::Done {
384 break;
385 }
386 }
387 let header = std::mem::take(&mut acc.header);
388 let mailbox_message = acc.take_mailbox_message();
389
390 let heartbeat_config = if is_handshake {
392 let mut config: HeartbeatConfig = ctx.heartbeat_options_for(role).into();
393 config.gc_enabled = ctx.gc_enabled;
394
395 info!(
396 "Handshake with {:?} node, sending config: {:?}",
397 role, config
398 );
399
400 Some(config)
401 } else {
402 None
403 };
404
405 let res = HeartbeatResponse {
406 header,
407 region_lease: acc.region_lease,
408 mailbox_message,
409 heartbeat_config,
410 extensions: std::mem::take(&mut acc.extensions),
411 };
412 Ok(res)
413 }
414}
415
416pub struct HeartbeatMailbox {
417 pushers: Pushers,
418 sequence: Sequence,
419 senders: DashMap<MessageId, oneshot::Sender<Result<MailboxMessage>>>,
420 timeouts: DashMap<MessageId, Instant>,
421 timeout_notify: Notify,
422}
423
424impl HeartbeatMailbox {
425 pub fn json_reply(msg: &MailboxMessage) -> Result<InstructionReply> {
426 let Payload::Json(payload) =
427 msg.payload
428 .as_ref()
429 .with_context(|| UnexpectedInstructionReplySnafu {
430 mailbox_message: msg.to_string(),
431 reason: "empty JSON payload".to_string(),
432 })?;
433 serde_json::from_str(payload).context(DeserializeFromJsonSnafu {
434 input_len: payload.len(),
435 })
436 }
437
438 #[cfg(test)]
440 pub(crate) fn json_instruction(
441 msg: &MailboxMessage,
442 ) -> Result<common_meta::instruction::Instruction> {
443 let Payload::Json(payload) =
444 msg.payload
445 .as_ref()
446 .with_context(|| UnexpectedInstructionReplySnafu {
447 mailbox_message: msg.to_string(),
448 reason: "empty JSON payload".to_string(),
449 })?;
450 serde_json::from_str(payload).context(DeserializeFromJsonSnafu {
451 input_len: payload.len(),
452 })
453 }
454
455 pub fn create(pushers: Pushers, sequence: Sequence) -> MailboxRef {
456 let mailbox = Arc::new(Self::new(pushers, sequence));
457
458 let timeout_checker = mailbox.clone();
459 let _handle = common_runtime::spawn_global(async move {
460 timeout_checker.check_timeout_bg(10).await;
461 });
462
463 mailbox
464 }
465
466 fn new(pushers: Pushers, sequence: Sequence) -> Self {
467 Self {
468 pushers,
469 sequence,
470 senders: DashMap::default(),
471 timeouts: DashMap::default(),
472 timeout_notify: Notify::new(),
473 }
474 }
475
476 async fn check_timeout_bg(&self, interval_millis: u64) {
477 let mut interval = tokio::time::interval(Duration::from_millis(interval_millis));
478
479 loop {
480 let _ = interval.tick().await;
481
482 if self.timeouts.is_empty() {
483 self.timeout_notify.notified().await;
484 }
485
486 let now = Instant::now();
487 let timeout_ids = self
488 .timeouts
489 .iter()
490 .filter_map(|entry| {
491 let (id, deadline) = entry.pair();
492 if deadline < &now { Some(*id) } else { None }
493 })
494 .collect::<Vec<_>>();
495
496 for id in timeout_ids {
497 let _ = self
498 .on_recv(id, Err(error::MailboxTimeoutSnafu { id }.build()))
499 .await;
500 }
501 }
502 }
503
504 #[inline]
505 async fn next_message_id(&self) -> Result<u64> {
506 loop {
509 let next = self
510 .sequence
511 .next()
512 .await
513 .context(error::NextSequenceSnafu)?;
514 if next > 0 {
515 return Ok(next);
516 }
517 }
518 }
519}
520
521#[async_trait::async_trait]
522impl Mailbox for HeartbeatMailbox {
523 async fn send(
524 &self,
525 ch: &Channel,
526 mut msg: MailboxMessage,
527 timeout: Duration,
528 ) -> Result<MailboxReceiver> {
529 let message_id = self.next_message_id().await?;
530 msg.id = message_id;
531
532 let pusher_id = ch.pusher_id();
533 let payload_len = msg
534 .payload
535 .as_ref()
536 .map(|Payload::Json(payload)| payload.len())
537 .unwrap_or_default();
538 debug!(message_id, payload_len, %pusher_id, "Sending mailbox message");
539
540 let (tx, rx) = oneshot::channel();
541 let _ = self.senders.insert(message_id, tx);
542 let deadline = Instant::now() + timeout;
543 self.timeouts.insert(message_id, deadline);
544 self.timeout_notify.notify_one();
545 let deregister_signal_receiver = self.pushers.push(pusher_id, msg).await?;
546
547 Ok(MailboxReceiver::new(
548 message_id,
549 rx,
550 deregister_signal_receiver,
551 *ch,
552 ))
553 }
554
555 async fn send_oneway(&self, ch: &Channel, mut msg: MailboxMessage) -> Result<()> {
556 let message_id = 0; msg.id = message_id;
558
559 let pusher_id = ch.pusher_id();
560 let payload_len = msg
561 .payload
562 .as_ref()
563 .map(|Payload::Json(payload)| payload.len())
564 .unwrap_or_default();
565 debug!(message_id, payload_len, %pusher_id, "Sending one-way mailbox message");
566
567 self.pushers.push(pusher_id, msg).await?;
568
569 Ok(())
570 }
571
572 async fn broadcast(&self, ch: &BroadcastChannel, msg: &MailboxMessage) -> Result<()> {
573 self.pushers.broadcast(ch.role(), msg).await
574 }
575
576 async fn on_recv(&self, id: MessageId, maybe_msg: Result<MailboxMessage>) -> Result<()> {
577 let payload_len = maybe_msg
578 .as_ref()
579 .ok()
580 .and_then(|msg| msg.payload.as_ref())
581 .map(|Payload::Json(payload)| payload.len())
582 .unwrap_or_default();
583 debug!(
584 message_id = id,
585 payload_len,
586 success = maybe_msg.is_ok(),
587 "Received mailbox message"
588 );
589
590 let _ = self.timeouts.remove(&id);
591
592 if let Some((_, tx)) = self.senders.remove(&id) {
593 tx.send(maybe_msg)
594 .map_err(|_| error::MailboxClosedSnafu { id }.build())?;
595 } else if let Ok(finally_msg) = maybe_msg {
596 let payload_len = finally_msg
597 .payload
598 .as_ref()
599 .map(|Payload::Json(payload)| payload.len())
600 .unwrap_or_default();
601 warn!(
602 message_id = id,
603 payload_len, "The mailbox response arrived too late"
604 );
605 }
606
607 Ok(())
608 }
609}
610
611pub struct HeartbeatHandlerGroupBuilder {
613 region_failure_handler: Option<RegionFailureHandler>,
615
616 region_lease_handler: Option<RegionLeaseHandler>,
618
619 flush_stats_factor: Option<usize>,
623 flow_state_handler: Option<FlowStateHandler>,
625
626 persist_stats_handler: Option<PersistStatsHandler>,
628
629 plugins: Option<Plugins>,
631
632 pushers: Pushers,
634
635 handlers: Vec<NameCachedHandler>,
637}
638
639impl HeartbeatHandlerGroupBuilder {
640 pub fn new(pushers: Pushers) -> Self {
641 Self {
642 region_failure_handler: None,
643 region_lease_handler: None,
644 flush_stats_factor: None,
645 flow_state_handler: None,
646 persist_stats_handler: None,
647 plugins: None,
648 pushers,
649 handlers: vec![],
650 }
651 }
652
653 pub fn with_flow_state_handler(mut self, handler: Option<FlowStateHandler>) -> Self {
654 self.flow_state_handler = handler;
655 self
656 }
657
658 pub fn with_region_lease_handler(mut self, handler: Option<RegionLeaseHandler>) -> Self {
659 self.region_lease_handler = handler;
660 self
661 }
662
663 pub fn with_region_failure_handler(mut self, handler: Option<RegionFailureHandler>) -> Self {
665 self.region_failure_handler = handler;
666 self
667 }
668
669 pub fn with_flush_stats_factor(mut self, flush_stats_factor: Option<usize>) -> Self {
671 self.flush_stats_factor = flush_stats_factor;
672 self
673 }
674
675 pub fn with_persist_stats_handler(mut self, handler: Option<PersistStatsHandler>) -> Self {
676 self.persist_stats_handler = handler;
677 self
678 }
679
680 pub fn with_plugins(mut self, plugins: Option<Plugins>) -> Self {
682 self.plugins = plugins;
683 self
684 }
685
686 pub fn add_default_handlers(mut self) -> Self {
688 let publish_heartbeat_handler = if let Some(plugins) = self.plugins.as_ref() {
690 plugins
691 .get::<PublisherRef>()
692 .map(|publish| PublishHeartbeatHandler::new(publish.clone()))
693 } else {
694 None
695 };
696
697 self.add_handler_last(ResponseHeaderHandler);
698 self.add_handler_last(DatanodeKeepLeaseHandler);
702 self.add_handler_last(FlownodeKeepLeaseHandler);
703 self.add_handler_last(CheckLeaderHandler);
704 self.add_handler_last(OnLeaderStartHandler);
705 self.add_handler_last(ExtractStatHandler);
706 self.add_handler_last(CollectDatanodeClusterInfoHandler);
707 self.add_handler_last(CollectFrontendClusterInfoHandler);
708 self.add_handler_last(CollectFlownodeClusterInfoHandler);
709 self.add_handler_last(MailboxHandler);
710 if let Some(region_lease_handler) = self.region_lease_handler.take() {
711 self.add_handler_last(region_lease_handler);
712 }
713 self.add_handler_last(FilterInactiveRegionStatsHandler);
714 if let Some(region_failure_handler) = self.region_failure_handler.take() {
715 self.add_handler_last(region_failure_handler);
716 }
717 if let Some(publish_heartbeat_handler) = publish_heartbeat_handler {
718 self.add_handler_last(publish_heartbeat_handler);
719 }
720 self.add_handler_last(CollectLeaderRegionHandler);
721 self.add_handler_last(CollectTopicStatsHandler);
722 if let Some(persist_stats_handler) = self.persist_stats_handler.take() {
725 self.add_handler_last(persist_stats_handler);
726 }
727 self.add_handler_last(CollectStatsHandler::new(self.flush_stats_factor));
728 self.add_handler_last(RemapFlowPeerHandler::default());
729
730 if let Some(flow_state_handler) = self.flow_state_handler.take() {
731 self.add_handler_last(flow_state_handler);
732 }
733
734 self
735 }
736
737 pub fn build(mut self) -> Result<HeartbeatHandlerGroup> {
741 if let Some(customizer) = self
742 .plugins
743 .as_ref()
744 .and_then(|plugins| plugins.get::<HeartbeatHandlerGroupBuilderCustomizerRef>())
745 {
746 debug!("Customizing the heartbeat handler group builder");
747 customizer.customize(&mut self)?;
748 }
749
750 Ok(HeartbeatHandlerGroup {
751 handlers: self.handlers,
752 pushers: self.pushers,
753 })
754 }
755
756 fn add_handler_after_inner(&mut self, target: &str, handler: NameCachedHandler) -> Result<()> {
757 if let Some(pos) = self.handlers.iter().position(|x| x.name == target) {
758 self.handlers.insert(pos + 1, handler);
759 return Ok(());
760 }
761
762 error::HandlerNotFoundSnafu { name: target }.fail()
763 }
764
765 pub fn add_handler_after(
767 &mut self,
768 target: &'static str,
769 handler: impl HeartbeatHandler + 'static,
770 ) -> Result<()> {
771 self.add_handler_after_inner(target, NameCachedHandler::new(handler))
772 }
773
774 fn add_handler_before_inner(&mut self, target: &str, handler: NameCachedHandler) -> Result<()> {
775 if let Some(pos) = self.handlers.iter().position(|x| x.name == target) {
776 self.handlers.insert(pos, handler);
777 return Ok(());
778 }
779
780 error::HandlerNotFoundSnafu { name: target }.fail()
781 }
782
783 pub fn add_handler_before(
785 &mut self,
786 target: &'static str,
787 handler: impl HeartbeatHandler + 'static,
788 ) -> Result<()> {
789 self.add_handler_before_inner(target, NameCachedHandler::new(handler))
790 }
791
792 fn replace_handler_inner(&mut self, target: &str, handler: NameCachedHandler) -> Result<()> {
793 if let Some(pos) = self.handlers.iter().position(|x| x.name == target) {
794 self.handlers[pos] = handler;
795 return Ok(());
796 }
797
798 error::HandlerNotFoundSnafu { name: target }.fail()
799 }
800
801 pub fn replace_handler(
803 &mut self,
804 target: &'static str,
805 handler: impl HeartbeatHandler + 'static,
806 ) -> Result<()> {
807 self.replace_handler_inner(target, NameCachedHandler::new(handler))
808 }
809
810 fn add_handler_last_inner(&mut self, handler: NameCachedHandler) {
811 self.handlers.push(handler);
812 }
813
814 fn add_handler_last(&mut self, handler: impl HeartbeatHandler + 'static) {
815 self.add_handler_last_inner(NameCachedHandler::new(handler));
816 }
817}
818
819pub type HeartbeatHandlerGroupBuilderCustomizerRef =
820 Arc<dyn HeartbeatHandlerGroupBuilderCustomizer>;
821
822pub enum CustomizeHeartbeatGroupAction {
823 AddHandlerAfter {
824 target: String,
825 handler: NameCachedHandler,
826 },
827 AddHandlerBefore {
828 target: String,
829 handler: NameCachedHandler,
830 },
831 ReplaceHandler {
832 target: String,
833 handler: NameCachedHandler,
834 },
835 AddHandlerLast {
836 handler: NameCachedHandler,
837 },
838}
839
840impl CustomizeHeartbeatGroupAction {
841 pub fn new_add_handler_after(
842 target: &'static str,
843 handler: impl HeartbeatHandler + 'static,
844 ) -> Self {
845 Self::AddHandlerAfter {
846 target: target.to_string(),
847 handler: NameCachedHandler::new(handler),
848 }
849 }
850
851 pub fn new_add_handler_before(
852 target: &'static str,
853 handler: impl HeartbeatHandler + 'static,
854 ) -> Self {
855 Self::AddHandlerBefore {
856 target: target.to_string(),
857 handler: NameCachedHandler::new(handler),
858 }
859 }
860
861 pub fn new_replace_handler(
862 target: &'static str,
863 handler: impl HeartbeatHandler + 'static,
864 ) -> Self {
865 Self::ReplaceHandler {
866 target: target.to_string(),
867 handler: NameCachedHandler::new(handler),
868 }
869 }
870
871 pub fn new_add_handler_last(handler: impl HeartbeatHandler + 'static) -> Self {
872 Self::AddHandlerLast {
873 handler: NameCachedHandler::new(handler),
874 }
875 }
876}
877
878pub trait HeartbeatHandlerGroupBuilderCustomizer: Send + Sync {
880 fn customize(&self, builder: &mut HeartbeatHandlerGroupBuilder) -> Result<()>;
881
882 fn add_action(&self, action: CustomizeHeartbeatGroupAction);
883}
884
885#[derive(Default)]
886pub struct DefaultHeartbeatHandlerGroupBuilderCustomizer {
887 actions: Mutex<Vec<CustomizeHeartbeatGroupAction>>,
888}
889
890impl HeartbeatHandlerGroupBuilderCustomizer for DefaultHeartbeatHandlerGroupBuilderCustomizer {
891 fn customize(&self, builder: &mut HeartbeatHandlerGroupBuilder) -> Result<()> {
892 info!("Customizing the heartbeat handler group builder");
893 let mut actions = self.actions.lock().unwrap();
894 for action in actions.drain(..) {
895 match action {
896 CustomizeHeartbeatGroupAction::AddHandlerAfter { target, handler } => {
897 builder.add_handler_after_inner(&target, handler)?;
898 }
899 CustomizeHeartbeatGroupAction::AddHandlerBefore { target, handler } => {
900 builder.add_handler_before_inner(&target, handler)?;
901 }
902 CustomizeHeartbeatGroupAction::ReplaceHandler { target, handler } => {
903 builder.replace_handler_inner(&target, handler)?;
904 }
905 CustomizeHeartbeatGroupAction::AddHandlerLast { handler } => {
906 builder.add_handler_last_inner(handler);
907 }
908 }
909 }
910 Ok(())
911 }
912
913 fn add_action(&self, action: CustomizeHeartbeatGroupAction) {
914 self.actions.lock().unwrap().push(action);
915 }
916}
917
918#[cfg(test)]
919mod tests {
920
921 use std::assert_matches;
922 use std::collections::BTreeMap;
923 use std::sync::Arc;
924 use std::time::Duration;
925
926 use api::v1::meta::{HeartbeatRequest, MailboxMessage, RequestHeader, Role};
927 use common_meta::kv_backend::memory::MemoryKvBackend;
928 use common_meta::sequence::SequenceBuilder;
929 use tokio::sync::mpsc;
930
931 use super::{
932 HandleControl, HeartbeatAccumulator, HeartbeatHandler, HeartbeatHandlerGroupBuilder,
933 PusherId, Pushers,
934 };
935 use crate::error;
936 use crate::handler::collect_stats_handler::CollectStatsHandler;
937 use crate::handler::response_header_handler::ResponseHeaderHandler;
938 use crate::handler::test_utils::TestEnv;
939 use crate::handler::{HeartbeatHandlerGroup, HeartbeatMailbox, Pusher};
940 use crate::metasrv::Context;
941 use crate::service::mailbox::{Channel, MailboxReceiver, MailboxRef};
942
943 #[tokio::test]
944 async fn test_mailbox() {
945 let (mailbox, receiver) = push_msg_via_mailbox().await;
946 let id = receiver.message_id();
947
948 let resp_msg = MailboxMessage {
949 id,
950 subject: "resp-test".to_string(),
951 timestamp_millis: 456,
952 ..Default::default()
953 };
954
955 mailbox.on_recv(id, Ok(resp_msg)).await.unwrap();
956
957 let recv_msg = receiver.await.unwrap();
958 assert_eq!(recv_msg.id, id);
959 assert_eq!(recv_msg.timestamp_millis, 456);
960 assert_eq!(recv_msg.subject, "resp-test".to_string());
961 }
962
963 #[tokio::test]
964 async fn test_mailbox_timeout() {
965 let (_, receiver) = push_msg_via_mailbox().await;
966 let res = receiver.await;
967 assert!(res.is_err());
968 }
969
970 async fn push_msg_via_mailbox() -> (MailboxRef, MailboxReceiver) {
971 let datanode_id = 12;
972 let (pusher_tx, mut pusher_rx) = mpsc::channel(16);
973 let pusher_id = PusherId::new(Role::Datanode, datanode_id);
974 let pusher: Pusher = Pusher::new(pusher_tx);
975 let handler_group = HeartbeatHandlerGroup::default();
976 handler_group.register_pusher(pusher_id, pusher).await;
977
978 let kv_backend = Arc::new(MemoryKvBackend::new());
979 let seq = SequenceBuilder::new("test_seq", kv_backend).build();
980 let mailbox = HeartbeatMailbox::create(handler_group.pushers(), seq);
981
982 let msg = MailboxMessage {
983 id: 0,
984 subject: "req-test".to_string(),
985 timestamp_millis: 123,
986 ..Default::default()
987 };
988 let ch = Channel::Datanode(datanode_id);
989
990 let receiver = mailbox
991 .send(&ch, msg, Duration::from_secs(1))
992 .await
993 .unwrap();
994
995 let recv_obj = pusher_rx.recv().await.unwrap().unwrap();
996 let message = recv_obj.mailbox_message.unwrap();
997 assert_eq!(message.timestamp_millis, 123);
998 assert_eq!(message.subject, "req-test".to_string());
999
1000 (mailbox, receiver)
1001 }
1002
1003 #[test]
1004 fn test_pusher_id_role_range() {
1005 let mut pushers = BTreeMap::new();
1006 pushers.insert(PusherId::new(Role::Datanode, u64::MAX), "datanode");
1007 pushers.insert(PusherId::new(Role::Frontend, u64::MIN), "frontend-min");
1008 pushers.insert(PusherId::new(Role::Frontend, u64::MAX), "frontend-max");
1009 pushers.insert(PusherId::new(Role::Flownode, u64::MIN), "flownode");
1010
1011 let frontend_pushers = pushers
1012 .range(PusherId::role_range(Role::Frontend))
1013 .map(|(_, value)| *value)
1014 .collect::<Vec<_>>();
1015
1016 assert_eq!(frontend_pushers, vec!["frontend-min", "frontend-max"]);
1017 }
1018
1019 #[tokio::test]
1020 async fn test_pushers_broadcast_by_role() {
1021 let pushers = Pushers::default();
1022 let (datanode_tx, mut datanode_rx) = mpsc::channel(1);
1023 let (frontend_tx, mut frontend_rx) = mpsc::channel(1);
1024 let (flownode_tx, mut flownode_rx) = mpsc::channel(1);
1025
1026 pushers
1027 .insert(
1028 PusherId::new(Role::Datanode, u64::MAX),
1029 Pusher::new(datanode_tx),
1030 )
1031 .await;
1032 pushers
1033 .insert(PusherId::new(Role::Frontend, 1), Pusher::new(frontend_tx))
1034 .await;
1035 pushers
1036 .insert(
1037 PusherId::new(Role::Flownode, u64::MIN),
1038 Pusher::new(flownode_tx),
1039 )
1040 .await;
1041
1042 let msg = MailboxMessage {
1043 id: 42,
1044 subject: "broadcast-test".to_string(),
1045 timestamp_millis: 123,
1046 ..Default::default()
1047 };
1048
1049 pushers.broadcast(Role::Frontend, &msg).await.unwrap();
1050
1051 let received = frontend_rx.recv().await.unwrap().unwrap();
1052 let mailbox_message = received.mailbox_message.unwrap();
1053 assert_eq!(mailbox_message.id, 0);
1054 assert_eq!(mailbox_message.subject, "broadcast-test");
1055 assert!(datanode_rx.try_recv().is_err());
1056 assert!(flownode_rx.try_recv().is_err());
1057 }
1058
1059 #[test]
1060 fn test_handler_group_builder() {
1061 let group = HeartbeatHandlerGroupBuilder::new(Pushers::default())
1062 .add_default_handlers()
1063 .build()
1064 .unwrap();
1065
1066 let handlers = group.handlers;
1067 let names = [
1068 "ResponseHeaderHandler",
1069 "DatanodeKeepLeaseHandler",
1070 "FlownodeKeepLeaseHandler",
1071 "CheckLeaderHandler",
1072 "OnLeaderStartHandler",
1073 "ExtractStatHandler",
1074 "CollectDatanodeClusterInfoHandler",
1075 "CollectFrontendClusterInfoHandler",
1076 "CollectFlownodeClusterInfoHandler",
1077 "MailboxHandler",
1078 "FilterInactiveRegionStatsHandler",
1079 "CollectLeaderRegionHandler",
1080 "CollectTopicStatsHandler",
1081 "CollectStatsHandler",
1082 "RemapFlowPeerHandler",
1083 ];
1084 assert_eq!(names.len(), handlers.len());
1085 for (handler, name) in handlers.iter().zip(names) {
1086 assert_eq!(handler.name, name);
1087 }
1088 }
1089
1090 #[test]
1091 fn test_handler_group_builder_add_before() {
1092 let mut builder =
1093 HeartbeatHandlerGroupBuilder::new(Pushers::default()).add_default_handlers();
1094 builder
1095 .add_handler_before(
1096 "FilterInactiveRegionStatsHandler",
1097 CollectStatsHandler::default(),
1098 )
1099 .unwrap();
1100
1101 let group = builder.build().unwrap();
1102 let handlers = group.handlers;
1103 let names = [
1104 "ResponseHeaderHandler",
1105 "DatanodeKeepLeaseHandler",
1106 "FlownodeKeepLeaseHandler",
1107 "CheckLeaderHandler",
1108 "OnLeaderStartHandler",
1109 "ExtractStatHandler",
1110 "CollectDatanodeClusterInfoHandler",
1111 "CollectFrontendClusterInfoHandler",
1112 "CollectFlownodeClusterInfoHandler",
1113 "MailboxHandler",
1114 "CollectStatsHandler",
1115 "FilterInactiveRegionStatsHandler",
1116 "CollectLeaderRegionHandler",
1117 "CollectTopicStatsHandler",
1118 "CollectStatsHandler",
1119 "RemapFlowPeerHandler",
1120 ];
1121 assert_eq!(names.len(), handlers.len());
1122 for (handler, name) in handlers.iter().zip(names) {
1123 assert_eq!(handler.name, name);
1124 }
1125 }
1126
1127 #[test]
1128 fn test_handler_group_builder_add_before_first() {
1129 let mut builder =
1130 HeartbeatHandlerGroupBuilder::new(Pushers::default()).add_default_handlers();
1131 builder
1132 .add_handler_before("ResponseHeaderHandler", CollectStatsHandler::default())
1133 .unwrap();
1134
1135 let group = builder.build().unwrap();
1136 let handlers = group.handlers;
1137 let names = [
1138 "CollectStatsHandler",
1139 "ResponseHeaderHandler",
1140 "DatanodeKeepLeaseHandler",
1141 "FlownodeKeepLeaseHandler",
1142 "CheckLeaderHandler",
1143 "OnLeaderStartHandler",
1144 "ExtractStatHandler",
1145 "CollectDatanodeClusterInfoHandler",
1146 "CollectFrontendClusterInfoHandler",
1147 "CollectFlownodeClusterInfoHandler",
1148 "MailboxHandler",
1149 "FilterInactiveRegionStatsHandler",
1150 "CollectLeaderRegionHandler",
1151 "CollectTopicStatsHandler",
1152 "CollectStatsHandler",
1153 "RemapFlowPeerHandler",
1154 ];
1155 assert_eq!(names.len(), handlers.len());
1156 for (handler, name) in handlers.iter().zip(names) {
1157 assert_eq!(handler.name, name);
1158 }
1159 }
1160
1161 #[test]
1162 fn test_handler_group_builder_add_after() {
1163 let mut builder =
1164 HeartbeatHandlerGroupBuilder::new(Pushers::default()).add_default_handlers();
1165 builder
1166 .add_handler_after("MailboxHandler", CollectStatsHandler::default())
1167 .unwrap();
1168
1169 let group = builder.build().unwrap();
1170 let handlers = group.handlers;
1171 let names = [
1172 "ResponseHeaderHandler",
1173 "DatanodeKeepLeaseHandler",
1174 "FlownodeKeepLeaseHandler",
1175 "CheckLeaderHandler",
1176 "OnLeaderStartHandler",
1177 "ExtractStatHandler",
1178 "CollectDatanodeClusterInfoHandler",
1179 "CollectFrontendClusterInfoHandler",
1180 "CollectFlownodeClusterInfoHandler",
1181 "MailboxHandler",
1182 "CollectStatsHandler",
1183 "FilterInactiveRegionStatsHandler",
1184 "CollectLeaderRegionHandler",
1185 "CollectTopicStatsHandler",
1186 "CollectStatsHandler",
1187 "RemapFlowPeerHandler",
1188 ];
1189 assert_eq!(names.len(), handlers.len());
1190 for (handler, name) in handlers.iter().zip(names) {
1191 assert_eq!(handler.name, name);
1192 }
1193 }
1194
1195 #[test]
1196 fn test_handler_group_builder_add_after_last() {
1197 let mut builder =
1198 HeartbeatHandlerGroupBuilder::new(Pushers::default()).add_default_handlers();
1199 builder
1200 .add_handler_after("CollectStatsHandler", ResponseHeaderHandler)
1201 .unwrap();
1202
1203 let group = builder.build().unwrap();
1204 let handlers = group.handlers;
1205 let names = [
1206 "ResponseHeaderHandler",
1207 "DatanodeKeepLeaseHandler",
1208 "FlownodeKeepLeaseHandler",
1209 "CheckLeaderHandler",
1210 "OnLeaderStartHandler",
1211 "ExtractStatHandler",
1212 "CollectDatanodeClusterInfoHandler",
1213 "CollectFrontendClusterInfoHandler",
1214 "CollectFlownodeClusterInfoHandler",
1215 "MailboxHandler",
1216 "FilterInactiveRegionStatsHandler",
1217 "CollectLeaderRegionHandler",
1218 "CollectTopicStatsHandler",
1219 "CollectStatsHandler",
1220 "ResponseHeaderHandler",
1221 "RemapFlowPeerHandler",
1222 ];
1223 assert_eq!(names.len(), handlers.len());
1224 for (handler, name) in handlers.iter().zip(names) {
1225 assert_eq!(handler.name, name);
1226 }
1227 }
1228
1229 #[test]
1230 fn test_handler_group_builder_replace() {
1231 let mut builder =
1232 HeartbeatHandlerGroupBuilder::new(Pushers::default()).add_default_handlers();
1233 builder
1234 .replace_handler("MailboxHandler", CollectStatsHandler::default())
1235 .unwrap();
1236
1237 let group = builder.build().unwrap();
1238 let handlers = group.handlers;
1239 let names = [
1240 "ResponseHeaderHandler",
1241 "DatanodeKeepLeaseHandler",
1242 "FlownodeKeepLeaseHandler",
1243 "CheckLeaderHandler",
1244 "OnLeaderStartHandler",
1245 "ExtractStatHandler",
1246 "CollectDatanodeClusterInfoHandler",
1247 "CollectFrontendClusterInfoHandler",
1248 "CollectFlownodeClusterInfoHandler",
1249 "CollectStatsHandler",
1250 "FilterInactiveRegionStatsHandler",
1251 "CollectLeaderRegionHandler",
1252 "CollectTopicStatsHandler",
1253 "CollectStatsHandler",
1254 "RemapFlowPeerHandler",
1255 ];
1256
1257 assert_eq!(names.len(), handlers.len());
1258 for (handler, name) in handlers.iter().zip(names) {
1259 assert_eq!(handler.name, name);
1260 }
1261 }
1262
1263 #[test]
1264 fn test_handler_group_builder_replace_last() {
1265 let mut builder =
1266 HeartbeatHandlerGroupBuilder::new(Pushers::default()).add_default_handlers();
1267 builder
1268 .replace_handler("CollectStatsHandler", ResponseHeaderHandler)
1269 .unwrap();
1270
1271 let group = builder.build().unwrap();
1272 let handlers = group.handlers;
1273 let names = [
1274 "ResponseHeaderHandler",
1275 "DatanodeKeepLeaseHandler",
1276 "FlownodeKeepLeaseHandler",
1277 "CheckLeaderHandler",
1278 "OnLeaderStartHandler",
1279 "ExtractStatHandler",
1280 "CollectDatanodeClusterInfoHandler",
1281 "CollectFrontendClusterInfoHandler",
1282 "CollectFlownodeClusterInfoHandler",
1283 "MailboxHandler",
1284 "FilterInactiveRegionStatsHandler",
1285 "CollectLeaderRegionHandler",
1286 "CollectTopicStatsHandler",
1287 "ResponseHeaderHandler",
1288 "RemapFlowPeerHandler",
1289 ];
1290
1291 assert_eq!(names.len(), handlers.len());
1292 for (handler, name) in handlers.iter().zip(names) {
1293 assert_eq!(handler.name, name);
1294 }
1295 }
1296
1297 #[test]
1298 fn test_handler_group_builder_replace_first() {
1299 let mut builder =
1300 HeartbeatHandlerGroupBuilder::new(Pushers::default()).add_default_handlers();
1301 builder
1302 .replace_handler("ResponseHeaderHandler", CollectStatsHandler::default())
1303 .unwrap();
1304
1305 let group = builder.build().unwrap();
1306 let handlers = group.handlers;
1307 let names = [
1308 "CollectStatsHandler",
1309 "DatanodeKeepLeaseHandler",
1310 "FlownodeKeepLeaseHandler",
1311 "CheckLeaderHandler",
1312 "OnLeaderStartHandler",
1313 "ExtractStatHandler",
1314 "CollectDatanodeClusterInfoHandler",
1315 "CollectFrontendClusterInfoHandler",
1316 "CollectFlownodeClusterInfoHandler",
1317 "MailboxHandler",
1318 "FilterInactiveRegionStatsHandler",
1319 "CollectLeaderRegionHandler",
1320 "CollectTopicStatsHandler",
1321 "CollectStatsHandler",
1322 "RemapFlowPeerHandler",
1323 ];
1324 assert_eq!(names.len(), handlers.len());
1325 for (handler, name) in handlers.iter().zip(names) {
1326 assert_eq!(handler.name, name);
1327 }
1328 }
1329
1330 #[test]
1331 fn test_handler_group_builder_handler_not_found() {
1332 let mut builder =
1333 HeartbeatHandlerGroupBuilder::new(Pushers::default()).add_default_handlers();
1334 let err = builder
1335 .add_handler_before("NotExists", CollectStatsHandler::default())
1336 .unwrap_err();
1337 assert_matches!(err, error::Error::HandlerNotFound { .. });
1338
1339 let err = builder
1340 .add_handler_after("NotExists", CollectStatsHandler::default())
1341 .unwrap_err();
1342 assert_matches!(err, error::Error::HandlerNotFound { .. });
1343
1344 let err = builder
1345 .replace_handler("NotExists", CollectStatsHandler::default())
1346 .unwrap_err();
1347 assert_matches!(err, error::Error::HandlerNotFound { .. });
1348 }
1349
1350 #[tokio::test]
1351 async fn test_pusher_drop() {
1352 let (tx, _rx) = mpsc::channel(1);
1353 let pusher = Pusher::new(tx);
1354 let mut deregister_signal_tx = pusher.deregister_signal_receiver.clone();
1355
1356 drop(pusher);
1357 deregister_signal_tx.changed().await.unwrap();
1358 }
1359
1360 #[tokio::test]
1361 async fn test_custom_handler_extension_reaches_response() {
1362 struct CustomExtensionHandler;
1363
1364 #[async_trait::async_trait]
1365 impl HeartbeatHandler for CustomExtensionHandler {
1366 fn is_acceptable(&self, role: Role) -> bool {
1367 role == Role::Frontend
1368 }
1369
1370 async fn handle(
1371 &self,
1372 _req: &HeartbeatRequest,
1373 _ctx: &mut Context,
1374 acc: &mut HeartbeatAccumulator,
1375 ) -> crate::error::Result<HandleControl> {
1376 acc.extensions
1377 .insert("custom.key".to_string(), b"custom-value".to_vec());
1378 Ok(HandleControl::Continue)
1379 }
1380 }
1381
1382 let mut builder =
1383 HeartbeatHandlerGroupBuilder::new(Pushers::default()).add_default_handlers();
1384 builder.add_handler_last(CustomExtensionHandler);
1385
1386 let group = builder.build().unwrap();
1387
1388 let req = HeartbeatRequest {
1389 header: Some(RequestHeader::new(1, Role::Frontend, Default::default())),
1390 ..Default::default()
1391 };
1392 let ctx = TestEnv::new().ctx();
1393
1394 let res = group.handle(req, ctx).await.unwrap();
1395
1396 let extensions = res.extensions;
1397 assert_eq!(extensions.get("custom.key").unwrap(), b"custom-value");
1398 }
1399}