1use std::io::ErrorKind;
16use std::sync::Arc;
17use std::sync::atomic::AtomicU64;
18
19use api::v1::meta::{
20 AskLeaderRequest, AskLeaderResponse, HeartbeatRequest, HeartbeatResponse, Peer, RequestHeader,
21 ResponseHeader, Role, heartbeat_server,
22};
23use common_meta::election::LeaderChangeMessage;
24use common_telemetry::{debug, error, info, warn};
25use futures::StreamExt;
26use once_cell::sync::OnceCell;
27use snafu::{OptionExt, ResultExt};
28use tokio::sync::broadcast::error::RecvError;
29use tokio::sync::mpsc;
30use tokio::sync::mpsc::Sender;
31use tokio_stream::wrappers::ReceiverStream;
32use tonic::{Request, Response, Status, Streaming};
33
34use crate::error::{self, Result};
35use crate::handler::{HeartbeatHandlerGroup, Pusher, PusherId};
36use crate::metasrv::{Context, ElectionRef, Metasrv};
37use crate::metrics::METRIC_META_HEARTBEAT_RECV;
38use crate::service::{GrpcResult, GrpcStream};
39
40type HeartbeatResponseResult = std::result::Result<HeartbeatResponse, Status>;
41
42#[async_trait::async_trait]
43trait HeartbeatRequestStream {
44 async fn next(&mut self) -> Option<std::result::Result<HeartbeatRequest, Status>>;
45}
46
47struct TonicHeartbeatRequestStream {
48 inner: Streaming<HeartbeatRequest>,
49}
50
51impl TonicHeartbeatRequestStream {
52 fn new(inner: Streaming<HeartbeatRequest>) -> Self {
53 Self { inner }
54 }
55}
56
57#[async_trait::async_trait]
58impl HeartbeatRequestStream for TonicHeartbeatRequestStream {
59 async fn next(&mut self) -> Option<std::result::Result<HeartbeatRequest, Status>> {
60 self.inner.next().await
61 }
62}
63
64enum LeaderStepDownEvent {
65 StepDown,
66 Closed,
67}
68
69#[async_trait::async_trait]
70trait LeaderStepDown {
71 async fn wait(&mut self) -> LeaderStepDownEvent;
72}
73
74struct ElectionLeaderStepDown {
75 rx: tokio::sync::broadcast::Receiver<LeaderChangeMessage>,
76}
77
78impl ElectionLeaderStepDown {
79 fn new(election: ElectionRef) -> Self {
80 Self {
81 rx: election.subscribe_leader_change(),
82 }
83 }
84}
85
86#[async_trait::async_trait]
87impl LeaderStepDown for ElectionLeaderStepDown {
88 async fn wait(&mut self) -> LeaderStepDownEvent {
89 loop {
90 match self.rx.recv().await {
91 Ok(LeaderChangeMessage::StepDown(_)) => return LeaderStepDownEvent::StepDown,
92 Ok(LeaderChangeMessage::Elected(_)) => {}
93 Err(RecvError::Lagged(skipped)) => {
94 warn!(
95 "Leader step-down watcher lagged, skipped {} leader change events",
96 skipped
97 );
98 }
99 Err(RecvError::Closed) => return LeaderStepDownEvent::Closed,
100 }
101 }
102 }
103}
104
105struct HeartbeatSession<R, L> {
106 requests: R,
107 tx: Sender<HeartbeatResponseResult>,
108 leader_step_down: Option<L>,
109 handler_group: Arc<HeartbeatHandlerGroup>,
110 ctx: Context,
111 sender_id: PusherId,
112}
113
114impl<R, L> HeartbeatSession<R, L>
115where
116 R: HeartbeatRequestStream,
117 L: LeaderStepDown,
118{
119 async fn init(
122 mut requests: R,
123 tx: Sender<HeartbeatResponseResult>,
124 leader_step_down: Option<L>,
125 handler_group: Arc<HeartbeatHandlerGroup>,
126 ctx: Context,
127 ) -> Option<Self> {
128 let msg = requests.next().await?;
129
130 let req = match msg {
131 Ok(req) => req,
132 Err(err) => {
133 error!("Failed to receive the first heartbeat request, error: {err}");
134 let _ = handle_request_stream_error(None, &tx, err).await;
135 return None;
136 }
137 };
138
139 let Some(header) = req.header.as_ref() else {
140 error!("Exit on malformed request: MissingRequestHeader");
141 let _ = tx
142 .send(Err(error::MissingRequestHeaderSnafu {}.build().into()))
143 .await;
144 return None;
145 };
146
147 let sender_id = register_pusher(&handler_group, header, tx.clone()).await;
148 let mut session = Self {
149 requests,
150 tx,
151 leader_step_down,
152 handler_group,
153 ctx,
154 sender_id,
155 };
156
157 if session.handle_request(req, true).await {
158 Some(session)
159 } else {
160 session.cleanup().await;
161 None
162 }
163 }
164
165 async fn run(mut self) {
167 let mut leader_step_down = self.leader_step_down.take();
168
169 loop {
170 tokio::select! {
171 msg = self.requests.next() => {
172 let Some(msg) = msg else {
173 break;
174 };
175
176 if !self.handle_message(msg).await {
177 break;
178 }
179 }
180 event = wait_leader_step_down(leader_step_down.as_mut()), if leader_step_down.is_some() => {
181 match event {
182 LeaderStepDownEvent::StepDown => {
183 self.send_not_leader_error().await;
184 break;
185 }
186 LeaderStepDownEvent::Closed => {
187 warn!("Leader step-down watcher closed");
188 self.send_election_unavailable_error().await;
189 break;
190 }
191 }
192 }
193 }
194 }
195
196 self.cleanup().await;
197 }
198
199 async fn handle_message(&mut self, msg: std::result::Result<HeartbeatRequest, Status>) -> bool {
201 match msg {
202 Ok(req) => self.handle_request(req, false).await,
203 Err(err) => handle_request_stream_error(Some(self.sender_id), &self.tx, err).await,
204 }
205 }
206
207 async fn handle_request(&mut self, req: HeartbeatRequest, is_handshake: bool) -> bool {
209 let mailbox_message_id = req.mailbox_message.as_ref().map(|msg| msg.id);
210 debug!(
211 sender_id = %self.sender_id,
212 ?mailbox_message_id,
213 is_handshake,
214 "Receiving heartbeat request"
215 );
216
217 let sender_id = self.sender_id.to_string();
218 METRIC_META_HEARTBEAT_RECV
219 .with_label_values(&[sender_id.as_str()])
220 .inc();
221
222 let res = self
223 .handler_group
224 .handle(req, self.ctx.clone().with_handshake(is_handshake))
225 .await
226 .inspect_err(
227 |e| warn!(e; "Failed to handle heartbeat request, sender: {}", self.sender_id),
228 )
229 .map_err(|e| e.into());
230
231 let is_not_leader = res.as_ref().is_ok_and(|r| r.is_not_leader());
232
233 debug!(
234 sender_id = %self.sender_id,
235 success = res.is_ok(),
236 is_not_leader,
237 "Sending heartbeat response"
238 );
239
240 if self.tx.send(res).await.is_err() {
241 info!(
242 "ReceiverStream was dropped; shutting down, sender: {}",
243 self.sender_id
244 );
245 return false;
246 }
247
248 if is_not_leader {
249 warn!(
250 "Quit because it is no longer the leader, sender: {}",
251 self.sender_id
252 );
253 self.send_not_leader_error().await;
254 return false;
255 }
256
257 true
258 }
259
260 async fn send_not_leader_error(&mut self) {
261 let _ = self
262 .tx
263 .send(Err(Status::aborted(format!(
264 "The requested metasrv node is not leader, node addr: {}",
265 self.ctx.server_addr
266 ))))
267 .await;
268 }
269
270 async fn send_election_unavailable_error(&mut self) {
271 let _ = self
272 .tx
273 .send(Err(Status::unavailable(format!(
274 "The requested metasrv node is shutting down, node addr: {}",
275 self.ctx.server_addr
276 ))))
277 .await;
278 }
279
280 async fn cleanup(&self) {
281 info!("Heartbeat stream closed, sender: {}", self.sender_id);
282 let _ = self.handler_group.deregister_push(self.sender_id).await;
283 }
284}
285
286async fn wait_leader_step_down<L>(leader_step_down: Option<&mut L>) -> LeaderStepDownEvent
287where
288 L: LeaderStepDown,
289{
290 match leader_step_down {
291 Some(leader_step_down) => leader_step_down.wait().await,
292 None => std::future::pending().await,
293 }
294}
295
296async fn handle_request_stream_error(
300 sender_id: Option<PusherId>,
301 tx: &Sender<HeartbeatResponseResult>,
302 err: Status,
303) -> bool {
304 if let Some(io_err) = error::match_for_io_error(&err)
305 && io_err.kind() == ErrorKind::BrokenPipe
306 {
307 error!("Client disconnected: broken pipe, sender: {:?}", sender_id);
308 return false;
309 }
310 error!(err; "Error while receiving heartbeat request, sender: {:?}", sender_id);
311
312 if tx.send(Err(err)).await.is_err() {
313 info!(
314 "Failed to forward heartbeat request stream error; response stream was dropped, sender: {:?}",
315 sender_id
316 );
317 return false;
318 }
319
320 true
321}
322
323#[async_trait::async_trait]
324impl heartbeat_server::Heartbeat for Metasrv {
325 type HeartbeatStream = GrpcStream<HeartbeatResponse>;
326
327 async fn heartbeat(
328 &self,
329 req: Request<Streaming<HeartbeatRequest>>,
330 ) -> GrpcResult<Self::HeartbeatStream> {
331 let (tx, rx) = mpsc::channel(128);
332 let handler_group = self.handler_group().context(error::UnexpectedSnafu {
333 violated: "expected heartbeat handlers",
334 })?;
335
336 let ctx = self.new_ctx();
337 let requests = TonicHeartbeatRequestStream::new(req.into_inner());
338 let _handle = common_runtime::spawn_global(async move {
339 if let Some(session) = HeartbeatSession::init(
340 requests,
341 tx,
342 ctx.election
343 .as_ref()
344 .map(|r| ElectionLeaderStepDown::new(r.clone())),
345 handler_group,
346 ctx,
347 )
348 .await
349 {
350 session.run().await;
351 }
352 });
353
354 let out_stream = ReceiverStream::new(rx);
355
356 Ok(Response::new(Box::pin(out_stream)))
357 }
358
359 async fn ask_leader(&self, req: Request<AskLeaderRequest>) -> GrpcResult<AskLeaderResponse> {
360 let req = req.into_inner();
361 let ctx = self.new_ctx();
362 let res = handle_ask_leader(req, ctx).await?;
363
364 Ok(Response::new(res))
365 }
366}
367
368async fn handle_ask_leader(_req: AskLeaderRequest, ctx: Context) -> Result<AskLeaderResponse> {
369 let addr = match ctx.election {
370 Some(election) => {
371 if election.is_leader() {
372 ctx.server_addr
373 } else {
374 election.leader().await.context(error::KvBackendSnafu)?.0
375 }
376 }
377 None => ctx.server_addr,
378 };
379
380 let leader = Some(Peer {
381 id: 0, addr,
383 });
384
385 let header = Some(ResponseHeader::success());
386 Ok(AskLeaderResponse { header, leader })
387}
388
389fn get_node_id(header: &RequestHeader) -> u64 {
390 static ID: OnceCell<Arc<AtomicU64>> = OnceCell::new();
391
392 fn next_id() -> u64 {
393 let id = ID.get_or_init(|| Arc::new(AtomicU64::new(0))).clone();
394 id.fetch_add(1, std::sync::atomic::Ordering::Relaxed)
395 }
396
397 match header.role() {
398 Role::Frontend => next_id(),
399 Role::Datanode | Role::Flownode => header.member_id,
400 }
401}
402
403async fn register_pusher(
404 handler_group: &HeartbeatHandlerGroup,
405 header: &RequestHeader,
406 sender: Sender<std::result::Result<HeartbeatResponse, tonic::Status>>,
407) -> PusherId {
408 let role = header.role();
409 let id = get_node_id(header);
410 let pusher_id = PusherId::new(role, id);
411 let pusher = Pusher::new(sender);
412 handler_group.register_pusher(pusher_id, pusher).await;
413 pusher_id
414}
415
416#[cfg(test)]
417mod tests {
418 use std::collections::VecDeque;
419 use std::sync::Arc;
420
421 use api::v1::meta::heartbeat_server::Heartbeat;
422 use api::v1::meta::*;
423 use common_meta::kv_backend::memory::MemoryKvBackend;
424 use common_telemetry::tracing_context::W3cTrace;
425 use servers::grpc::GrpcOptions;
426 use tokio::sync::mpsc;
427 use tonic::{Code, IntoRequest};
428
429 use super::*;
430 use crate::handler::test_utils::TestEnv;
431 use crate::metasrv::MetasrvOptions;
432 use crate::metasrv::builder::MetasrvBuilder;
433
434 struct MockHeartbeatRequestStream {
435 messages: VecDeque<std::result::Result<HeartbeatRequest, Status>>,
436 pending_when_empty: bool,
437 }
438
439 impl MockHeartbeatRequestStream {
440 fn new(messages: Vec<std::result::Result<HeartbeatRequest, Status>>) -> Self {
441 Self {
442 messages: messages.into(),
443 pending_when_empty: false,
444 }
445 }
446
447 fn pending_after(messages: Vec<std::result::Result<HeartbeatRequest, Status>>) -> Self {
448 Self {
449 messages: messages.into(),
450 pending_when_empty: true,
451 }
452 }
453 }
454
455 #[async_trait::async_trait]
456 impl HeartbeatRequestStream for MockHeartbeatRequestStream {
457 async fn next(&mut self) -> Option<std::result::Result<HeartbeatRequest, Status>> {
458 if let Some(message) = self.messages.pop_front() {
459 return Some(message);
460 }
461
462 if self.pending_when_empty {
463 std::future::pending().await
464 } else {
465 None
466 }
467 }
468 }
469
470 struct MockLeaderStepDown {
471 event: Option<LeaderStepDownEvent>,
472 }
473
474 impl MockLeaderStepDown {
475 fn new(event: LeaderStepDownEvent) -> Self {
476 Self { event: Some(event) }
477 }
478 }
479
480 #[async_trait::async_trait]
481 impl LeaderStepDown for MockLeaderStepDown {
482 async fn wait(&mut self) -> LeaderStepDownEvent {
483 self.event.take().unwrap()
484 }
485 }
486
487 fn heartbeat_request(role: Role, member_id: u64) -> HeartbeatRequest {
488 HeartbeatRequest {
489 header: Some(RequestHeader {
490 role: role.into(),
491 member_id,
492 ..Default::default()
493 }),
494 ..Default::default()
495 }
496 }
497
498 fn sender_id(role: Role, member_id: u64) -> PusherId {
499 PusherId::new(role, member_id)
500 }
501
502 fn test_context() -> Context {
503 TestEnv::new().ctx()
504 }
505
506 fn test_handler_group() -> Arc<HeartbeatHandlerGroup> {
507 Arc::new(HeartbeatHandlerGroup::default())
508 }
509
510 async fn init_session<L>(
511 requests: MockHeartbeatRequestStream,
512 tx: Sender<HeartbeatResponseResult>,
513 leader_step_down: Option<L>,
514 handler_group: Arc<HeartbeatHandlerGroup>,
515 ) -> Option<HeartbeatSession<MockHeartbeatRequestStream, L>>
516 where
517 L: LeaderStepDown,
518 {
519 HeartbeatSession::init(
520 requests,
521 tx,
522 leader_step_down,
523 handler_group,
524 test_context(),
525 )
526 .await
527 }
528
529 async fn recv_response(
530 rx: &mut mpsc::Receiver<HeartbeatResponseResult>,
531 ) -> HeartbeatResponseResult {
532 rx.recv().await.unwrap()
533 }
534
535 #[tokio::test]
536 async fn test_heartbeat_session_init_returns_none_on_empty_stream() {
537 let (tx, _rx) = mpsc::channel(8);
538 let handler_group = test_handler_group();
539 let requests = MockHeartbeatRequestStream::new(vec![]);
540
541 let session = init_session(
542 requests,
543 tx,
544 None::<MockLeaderStepDown>,
545 handler_group.clone(),
546 )
547 .await;
548
549 assert!(session.is_none());
550 assert!(
551 !handler_group
552 .contains_pusher(&sender_id(Role::Datanode, 42))
553 .await
554 );
555 }
556
557 #[tokio::test]
558 async fn test_heartbeat_session_init_forwards_first_stream_error() {
559 let (tx, mut rx) = mpsc::channel(8);
560 let handler_group = test_handler_group();
561 let requests = MockHeartbeatRequestStream::new(vec![Err(Status::internal("boom"))]);
562
563 let session = init_session(requests, tx, None::<MockLeaderStepDown>, handler_group).await;
564
565 assert!(session.is_none());
566 let status = recv_response(&mut rx).await.unwrap_err();
567 assert_eq!(Code::Internal, status.code());
568 assert_eq!("boom", status.message());
569 }
570
571 #[tokio::test]
572 async fn test_heartbeat_session_init_sends_error_on_missing_header() {
573 let (tx, mut rx) = mpsc::channel(8);
574 let handler_group = test_handler_group();
575 let requests = MockHeartbeatRequestStream::new(vec![Ok(HeartbeatRequest::default())]);
576
577 let session = init_session(
578 requests,
579 tx,
580 None::<MockLeaderStepDown>,
581 handler_group.clone(),
582 )
583 .await;
584
585 assert!(session.is_none());
586 assert!(
587 !handler_group
588 .contains_pusher(&sender_id(Role::Datanode, 42))
589 .await
590 );
591
592 let status = recv_response(&mut rx).await.unwrap_err();
593 assert_eq!(Code::InvalidArgument, status.code());
594 }
595
596 #[tokio::test]
597 async fn test_heartbeat_session_init_registers_sender() {
598 let (tx, mut rx) = mpsc::channel(8);
599 let handler_group = test_handler_group();
600 let sender_id = sender_id(Role::Datanode, 42);
601 let requests =
602 MockHeartbeatRequestStream::new(vec![Ok(heartbeat_request(Role::Datanode, 42))]);
603
604 let session = init_session(
605 requests,
606 tx,
607 None::<MockLeaderStepDown>,
608 handler_group.clone(),
609 )
610 .await;
611
612 assert!(session.is_some());
613 assert!(handler_group.contains_pusher(&sender_id).await);
614
615 let response = recv_response(&mut rx).await.unwrap();
616 assert!(response.heartbeat_config.is_some());
617 }
618
619 #[tokio::test]
620 async fn test_heartbeat_session_run_deregisters_sender_on_stream_close() {
621 let (tx, mut rx) = mpsc::channel(8);
622 let handler_group = test_handler_group();
623 let sender_id = sender_id(Role::Datanode, 42);
624 let requests =
625 MockHeartbeatRequestStream::new(vec![Ok(heartbeat_request(Role::Datanode, 42))]);
626 let session = init_session(
627 requests,
628 tx,
629 None::<MockLeaderStepDown>,
630 handler_group.clone(),
631 )
632 .await
633 .unwrap();
634 let _ = recv_response(&mut rx).await.unwrap();
635
636 session.run().await;
637
638 assert!(!handler_group.contains_pusher(&sender_id).await);
639 }
640
641 #[tokio::test]
642 async fn test_heartbeat_session_run_forwards_stream_error_after_init() {
643 let (tx, mut rx) = mpsc::channel(8);
644 let handler_group = test_handler_group();
645 let sender_id = sender_id(Role::Datanode, 42);
646 let requests = MockHeartbeatRequestStream::new(vec![
647 Ok(heartbeat_request(Role::Datanode, 42)),
648 Err(Status::unavailable("temporary")),
649 ]);
650 let session = init_session(
651 requests,
652 tx,
653 None::<MockLeaderStepDown>,
654 handler_group.clone(),
655 )
656 .await
657 .unwrap();
658 let _ = recv_response(&mut rx).await.unwrap();
659
660 session.run().await;
661
662 let status = recv_response(&mut rx).await.unwrap_err();
663 assert_eq!(Code::Unavailable, status.code());
664 assert_eq!("temporary", status.message());
665 assert!(!handler_group.contains_pusher(&sender_id).await);
666 }
667
668 #[tokio::test]
669 async fn test_heartbeat_session_leader_step_down_sends_aborted_and_deregisters() {
670 let (tx, mut rx) = mpsc::channel(8);
671 let handler_group = test_handler_group();
672 let sender_id = sender_id(Role::Datanode, 42);
673 let requests = MockHeartbeatRequestStream::pending_after(vec![Ok(heartbeat_request(
674 Role::Datanode,
675 42,
676 ))]);
677 let session = init_session(
678 requests,
679 tx,
680 Some(MockLeaderStepDown::new(LeaderStepDownEvent::StepDown)),
681 handler_group.clone(),
682 )
683 .await
684 .unwrap();
685 let _ = recv_response(&mut rx).await.unwrap();
686
687 session.run().await;
688
689 let status = recv_response(&mut rx).await.unwrap_err();
690 assert_eq!(Code::Aborted, status.code());
691 assert!(!handler_group.contains_pusher(&sender_id).await);
692 }
693
694 #[tokio::test]
695 async fn test_heartbeat_session_leader_watcher_closed_sends_unavailable_and_deregisters() {
696 let (tx, mut rx) = mpsc::channel(8);
697 let handler_group = test_handler_group();
698 let sender_id = sender_id(Role::Datanode, 42);
699 let requests = MockHeartbeatRequestStream::pending_after(vec![Ok(heartbeat_request(
700 Role::Datanode,
701 42,
702 ))]);
703 let session = init_session(
704 requests,
705 tx,
706 Some(MockLeaderStepDown::new(LeaderStepDownEvent::Closed)),
707 handler_group.clone(),
708 )
709 .await
710 .unwrap();
711 let _ = recv_response(&mut rx).await.unwrap();
712
713 session.run().await;
714
715 let status = recv_response(&mut rx).await.unwrap_err();
716 assert_eq!(Code::Unavailable, status.code());
717 assert!(!handler_group.contains_pusher(&sender_id).await);
718 }
719
720 #[tokio::test]
721 async fn test_ask_leader() {
722 let kv_backend = Arc::new(MemoryKvBackend::new());
723
724 let metasrv = MetasrvBuilder::new()
725 .kv_backend(kv_backend)
726 .options(MetasrvOptions {
727 grpc: GrpcOptions {
728 server_addr: "127.0.0.1:3002".to_string(),
729 ..Default::default()
730 },
731 ..Default::default()
732 })
733 .build()
734 .await
735 .unwrap();
736
737 let req = AskLeaderRequest {
738 header: Some(RequestHeader::new(1, Role::Datanode, W3cTrace::new())),
739 };
740
741 let res = metasrv.ask_leader(req.into_request()).await.unwrap();
742 let res = res.into_inner();
743 assert_eq!(metasrv.options().grpc.server_addr, res.leader.unwrap().addr);
744 }
745
746 #[test]
747 fn test_get_node_id() {
748 let header = RequestHeader {
749 role: Role::Datanode.into(),
750 member_id: 11,
751 ..Default::default()
752 };
753 assert_eq!(11, get_node_id(&header));
754
755 let header = RequestHeader {
756 role: Role::Frontend.into(),
757 ..Default::default()
758 };
759 for i in 0..10 {
760 assert_eq!(i, get_node_id(&header));
761 }
762
763 let header = RequestHeader {
764 role: Role::Frontend.into(),
765 member_id: 11,
766 ..Default::default()
767 };
768 for i in 10..20 {
769 assert_eq!(i, get_node_id(&header));
770 }
771 }
772}