1use std::cmp::Ordering;
16use std::io::ErrorKind;
17use std::sync::Arc;
18use std::sync::atomic::AtomicU64;
19use std::time::Duration;
20
21use api::v1::meta::{
22 AskLeaderRequest, AskLeaderResponse, Error, HeartbeatRequest, HeartbeatResponse,
23 PROTOCOL_VERSION, Peer, RequestHeader, ResponseHeader, Role, heartbeat_server,
24};
25use common_meta::election::LeaderChangeMessage;
26use common_meta::key::MetadataValue;
27use common_meta::key::datanode_epoch::{DatanodeEpochKey, DatanodeEpochValue};
28use common_meta::kv_backend::KvBackend;
29use common_meta::rpc::store::CompareAndPutRequest;
30use common_telemetry::{debug, error, info, warn};
31use common_time::util::current_time_millis;
32use futures::StreamExt;
33use once_cell::sync::OnceCell;
34use snafu::{OptionExt, ResultExt};
35use tokio::sync::broadcast::error::RecvError;
36use tokio::sync::mpsc;
37use tokio::sync::mpsc::Sender;
38use tokio_stream::wrappers::ReceiverStream;
39use tonic::{Request, Response, Status, Streaming};
40
41use crate::error::{self, Result};
42use crate::handler::{HeartbeatHandlerGroup, Pusher, PusherId};
43use crate::metasrv::{Context, ElectionRef, Metasrv};
44use crate::metrics::METRIC_META_HEARTBEAT_RECV;
45use crate::service::{GrpcResult, GrpcStream};
46
47type HeartbeatResponseResult = std::result::Result<HeartbeatResponse, Status>;
48
49const MAX_NODE_EPOCH_AHEAD: Duration = Duration::from_secs(5 * 60);
51
52#[async_trait::async_trait]
53trait HeartbeatRequestStream {
54 async fn next(&mut self) -> Option<std::result::Result<HeartbeatRequest, Status>>;
55}
56
57struct TonicHeartbeatRequestStream {
58 inner: Streaming<HeartbeatRequest>,
59}
60
61impl TonicHeartbeatRequestStream {
62 fn new(inner: Streaming<HeartbeatRequest>) -> Self {
63 Self { inner }
64 }
65}
66
67#[async_trait::async_trait]
68impl HeartbeatRequestStream for TonicHeartbeatRequestStream {
69 async fn next(&mut self) -> Option<std::result::Result<HeartbeatRequest, Status>> {
70 self.inner.next().await
71 }
72}
73
74enum LeaderStepDownEvent {
75 StepDown,
76 Closed,
77}
78
79#[async_trait::async_trait]
80trait LeaderStepDown {
81 async fn wait(&mut self) -> LeaderStepDownEvent;
82}
83
84struct ElectionLeaderStepDown {
85 rx: tokio::sync::broadcast::Receiver<LeaderChangeMessage>,
86}
87
88impl ElectionLeaderStepDown {
89 fn new(election: ElectionRef) -> Self {
90 Self {
91 rx: election.subscribe_leader_change(),
92 }
93 }
94}
95
96#[async_trait::async_trait]
97impl LeaderStepDown for ElectionLeaderStepDown {
98 async fn wait(&mut self) -> LeaderStepDownEvent {
99 loop {
100 match self.rx.recv().await {
101 Ok(LeaderChangeMessage::StepDown(_)) => return LeaderStepDownEvent::StepDown,
102 Ok(LeaderChangeMessage::Elected(_)) => {}
103 Err(RecvError::Lagged(skipped)) => {
104 warn!(
105 "Leader step-down watcher lagged, skipped {} leader change events",
106 skipped
107 );
108 }
109 Err(RecvError::Closed) => return LeaderStepDownEvent::Closed,
110 }
111 }
112 }
113}
114
115struct HeartbeatSession<R, L> {
116 requests: R,
117 tx: Sender<HeartbeatResponseResult>,
118 leader_step_down: Option<L>,
119 handler_group: Arc<HeartbeatHandlerGroup>,
120 ctx: Context,
121 sender_id: PusherId,
122 pusher_epoch: Option<u64>,
124}
125
126impl<R, L> HeartbeatSession<R, L>
127where
128 R: HeartbeatRequestStream,
129 L: LeaderStepDown,
130{
131 async fn init(
134 mut requests: R,
135 tx: Sender<HeartbeatResponseResult>,
136 leader_step_down: Option<L>,
137 handler_group: Arc<HeartbeatHandlerGroup>,
138 ctx: Context,
139 ) -> Option<Self> {
140 let msg = requests.next().await?;
141
142 let req = match msg {
143 Ok(req) => req,
144 Err(err) => {
145 error!("Failed to receive the first heartbeat request, error: {err}");
146 let _ = handle_request_stream_error(None, &tx, err).await;
147 return None;
148 }
149 };
150
151 let Some(header) = req.header.as_ref() else {
152 error!("Exit on malformed request: MissingRequestHeader");
153 let _ = tx
154 .send(Err(error::MissingRequestHeaderSnafu {}.build().into()))
155 .await;
156 return None;
157 };
158
159 let sender_id = PusherId::new(header.role(), get_node_id(header));
160 if sender_id.role != Role::Datanode {
162 let pusher = Pusher::new(tx.clone());
163 handler_group.register_pusher(sender_id, pusher).await;
164 }
165 let mut session = Self {
166 requests,
167 tx,
168 leader_step_down,
169 handler_group,
170 ctx,
171 sender_id,
172 pusher_epoch: None,
173 };
174
175 if session.handle_request(req, true).await {
176 Some(session)
177 } else {
178 session.cleanup().await;
179 None
180 }
181 }
182
183 async fn run(mut self) {
185 let mut leader_step_down = self.leader_step_down.take();
186
187 loop {
188 tokio::select! {
189 msg = self.requests.next() => {
190 let Some(msg) = msg else {
191 break;
192 };
193
194 if !self.handle_message(msg).await {
195 break;
196 }
197 }
198 event = wait_leader_step_down(leader_step_down.as_mut()), if leader_step_down.is_some() => {
199 match event {
200 LeaderStepDownEvent::StepDown => {
201 self.send_not_leader_error().await;
202 break;
203 }
204 LeaderStepDownEvent::Closed => {
205 warn!("Leader step-down watcher closed");
206 self.send_election_unavailable_error().await;
207 break;
208 }
209 }
210 }
211 }
212 }
213
214 self.cleanup().await;
215 }
216
217 async fn handle_message(&mut self, msg: std::result::Result<HeartbeatRequest, Status>) -> bool {
219 match msg {
220 Ok(req) => self.handle_request(req, false).await,
221 Err(err) => handle_request_stream_error(Some(self.sender_id), &self.tx, err).await,
222 }
223 }
224
225 async fn handle_request(&mut self, req: HeartbeatRequest, is_handshake: bool) -> bool {
227 let mailbox_message_id = req.mailbox_message.as_ref().map(|msg| msg.id);
228 debug!(
229 sender_id = %self.sender_id,
230 ?mailbox_message_id,
231 is_handshake,
232 "Receiving heartbeat request"
233 );
234
235 let sender_id = self.sender_id.to_string();
236 METRIC_META_HEARTBEAT_RECV
237 .with_label_values(&[sender_id.as_str()])
238 .inc();
239
240 let datanode_lock = if self.sender_id.role == Role::Datanode && req.node_epoch != 0 {
243 Some(self.handler_group.lock_datanode(self.sender_id.id).await)
244 } else {
245 None
246 };
247 let res = match self.check_node_epoch(&req, is_handshake).await {
248 Some(res) => res,
249 None => {
250 self.handler_group
251 .handle(req, self.ctx.clone().with_handshake(is_handshake))
252 .await
253 }
254 };
255 drop(datanode_lock);
256 let res = res
257 .inspect_err(
258 |e| warn!(e; "Failed to handle heartbeat request, sender: {}", self.sender_id),
259 )
260 .map_err(|e| e.into());
261
262 let is_not_leader = res.as_ref().is_ok_and(|r| r.is_not_leader());
263
264 debug!(
265 sender_id = %self.sender_id,
266 success = res.is_ok(),
267 is_not_leader,
268 "Sending heartbeat response"
269 );
270
271 if self.tx.send(res).await.is_err() {
272 info!(
273 "ReceiverStream was dropped; shutting down, sender: {}",
274 self.sender_id
275 );
276 return false;
277 }
278
279 if is_not_leader {
280 warn!(
281 "Quit because it is no longer the leader, sender: {}",
282 self.sender_id
283 );
284 self.send_not_leader_error().await;
285 return false;
286 }
287
288 true
289 }
290
291 async fn check_node_epoch(
294 &mut self,
295 req: &HeartbeatRequest,
296 is_handshake: bool,
297 ) -> Option<Result<HeartbeatResponse>> {
298 let node_epoch = req.node_epoch;
299 if self.sender_id.role != Role::Datanode || (node_epoch == 0 && is_handshake) {
300 return None;
301 }
302 if node_epoch != 0 {
304 if let Some(election) = &self.ctx.election
305 && !election.is_leader()
306 {
307 return Some(Ok(header_only(Some(Error::is_not_leader()))));
308 }
309 let kv_backend = &*self.ctx.leader_cached_kv_backend;
310 match accept_node_epoch(kv_backend, self.sender_id.id, node_epoch).await {
311 Ok(true) => {}
312 Ok(false) => {
314 self.handler_group
315 .deregister_push(self.sender_id, &self.tx)
316 .await;
317 return Some(Ok(header_only(None)));
318 }
319 Err(e) => return Some(Err(e)),
320 }
321 }
322 if self.pusher_epoch.is_none_or(|epoch| node_epoch > epoch) {
324 self.pusher_epoch = Some(node_epoch);
325 let pusher = Pusher::new(self.tx.clone()).with_node_epoch(node_epoch);
326 self.handler_group
327 .register_pusher(self.sender_id, pusher)
328 .await;
329 }
330 None
331 }
332
333 async fn send_not_leader_error(&mut self) {
334 let _ = self
335 .tx
336 .send(Err(Status::aborted(format!(
337 "The requested metasrv node is not leader, node addr: {}",
338 self.ctx.server_addr
339 ))))
340 .await;
341 }
342
343 async fn send_election_unavailable_error(&mut self) {
344 let _ = self
345 .tx
346 .send(Err(Status::unavailable(format!(
347 "The requested metasrv node is shutting down, node addr: {}",
348 self.ctx.server_addr
349 ))))
350 .await;
351 }
352
353 async fn cleanup(&self) {
354 info!("Heartbeat stream closed, sender: {}", self.sender_id);
355 self.handler_group
356 .deregister_push(self.sender_id, &self.tx)
357 .await;
358 }
359}
360
361async fn wait_leader_step_down<L>(leader_step_down: Option<&mut L>) -> LeaderStepDownEvent
362where
363 L: LeaderStepDown,
364{
365 match leader_step_down {
366 Some(leader_step_down) => leader_step_down.wait().await,
367 None => std::future::pending().await,
368 }
369}
370
371async fn handle_request_stream_error(
375 sender_id: Option<PusherId>,
376 tx: &Sender<HeartbeatResponseResult>,
377 err: Status,
378) -> bool {
379 if let Some(io_err) = error::match_for_io_error(&err)
380 && io_err.kind() == ErrorKind::BrokenPipe
381 {
382 error!("Client disconnected: broken pipe, sender: {:?}", sender_id);
383 return false;
384 }
385 error!(err; "Error while receiving heartbeat request, sender: {:?}", sender_id);
386
387 if tx.send(Err(err)).await.is_err() {
388 info!(
389 "Failed to forward heartbeat request stream error; response stream was dropped, sender: {:?}",
390 sender_id
391 );
392 return false;
393 }
394
395 true
396}
397
398#[async_trait::async_trait]
399impl heartbeat_server::Heartbeat for Metasrv {
400 type HeartbeatStream = GrpcStream<HeartbeatResponse>;
401
402 async fn heartbeat(
403 &self,
404 req: Request<Streaming<HeartbeatRequest>>,
405 ) -> GrpcResult<Self::HeartbeatStream> {
406 let (tx, rx) = mpsc::channel(128);
407 let handler_group = self.handler_group().context(error::UnexpectedSnafu {
408 violated: "expected heartbeat handlers",
409 })?;
410
411 let ctx = self.new_ctx();
412 let requests = TonicHeartbeatRequestStream::new(req.into_inner());
413 let _handle = common_runtime::spawn_global(async move {
414 if let Some(session) = HeartbeatSession::init(
415 requests,
416 tx,
417 ctx.election
418 .as_ref()
419 .map(|r| ElectionLeaderStepDown::new(r.clone())),
420 handler_group,
421 ctx,
422 )
423 .await
424 {
425 session.run().await;
426 }
427 });
428
429 let out_stream = ReceiverStream::new(rx);
430
431 Ok(Response::new(Box::pin(out_stream)))
432 }
433
434 async fn ask_leader(&self, req: Request<AskLeaderRequest>) -> GrpcResult<AskLeaderResponse> {
435 let req = req.into_inner();
436 let ctx = self.new_ctx();
437 let res = handle_ask_leader(req, ctx).await?;
438
439 Ok(Response::new(res))
440 }
441}
442
443async fn handle_ask_leader(_req: AskLeaderRequest, ctx: Context) -> Result<AskLeaderResponse> {
444 let addr = match ctx.election {
445 Some(election) => {
446 if election.is_leader() {
447 ctx.server_addr
448 } else {
449 election.leader().await.context(error::KvBackendSnafu)?.0
450 }
451 }
452 None => ctx.server_addr,
453 };
454
455 let leader = Some(Peer {
456 id: 0, addr,
458 });
459
460 let header = Some(ResponseHeader::success());
461 Ok(AskLeaderResponse { header, leader })
462}
463
464fn get_node_id(header: &RequestHeader) -> u64 {
465 static ID: OnceCell<Arc<AtomicU64>> = OnceCell::new();
466
467 fn next_id() -> u64 {
468 let id = ID.get_or_init(|| Arc::new(AtomicU64::new(0))).clone();
469 id.fetch_add(1, std::sync::atomic::Ordering::Relaxed)
470 }
471
472 match header.role() {
473 Role::Frontend => next_id(),
474 Role::Datanode | Role::Flownode => header.member_id,
475 }
476}
477
478async fn accept_node_epoch(
482 kv_backend: &dyn KvBackend<Error = common_meta::error::Error>,
483 node_id: u64,
484 node_epoch: u64,
485) -> Result<bool> {
486 let key = DatanodeEpochKey::new(node_id).to_bytes();
487 let mut current = kv_backend.get(&key).await.context(error::KvBackendSnafu)?;
488 let limit = current_time_millis().max(0) as u64 + MAX_NODE_EPOCH_AHEAD.as_millis() as u64;
489 loop {
490 let (expect, highest) = match current {
491 Some(kv) => {
492 let value = DatanodeEpochValue::try_from_raw_value(&kv.value)
493 .context(error::KvBackendSnafu)?;
494 (kv.value, value.node_epoch)
495 }
496 None => (vec![], 0),
497 };
498 match node_epoch.cmp(&highest) {
499 Ordering::Equal => return Ok(true),
500 Ordering::Greater if node_epoch <= limit => {}
501 _ => {
502 warn!("Fenced datanode {node_id} with epoch {node_epoch}, recorded {highest}");
503 return Ok(false);
504 }
505 }
506 let value = DatanodeEpochValue { node_epoch }
507 .try_as_raw_value()
508 .context(error::KvBackendSnafu)?;
509 let req = CompareAndPutRequest {
510 key: key.clone(),
511 expect,
512 value,
513 };
514 let resp = kv_backend
515 .compare_and_put(req)
516 .await
517 .context(error::KvBackendSnafu)?;
518 if resp.success {
519 info!("Recorded epoch {node_epoch} of datanode {node_id}");
520 return Ok(true);
521 }
522 current = resp.prev_kv;
523 }
524}
525
526fn header_only(error: Option<Error>) -> HeartbeatResponse {
527 HeartbeatResponse {
528 header: Some(ResponseHeader {
529 protocol_version: PROTOCOL_VERSION,
530 error,
531 }),
532 ..Default::default()
533 }
534}
535
536#[cfg(test)]
537mod tests {
538 use std::collections::VecDeque;
539 use std::sync::Arc;
540
541 use api::v1::meta::heartbeat_server::Heartbeat;
542 use common_meta::kv_backend::memory::MemoryKvBackend;
543 use common_telemetry::tracing_context::W3cTrace;
544 use servers::grpc::GrpcOptions;
545 use tokio::sync::mpsc;
546 use tonic::{Code, IntoRequest};
547
548 use super::*;
549 use crate::handler::test_utils::TestEnv;
550 use crate::metasrv::MetasrvOptions;
551 use crate::metasrv::builder::MetasrvBuilder;
552
553 struct MockHeartbeatRequestStream {
554 messages: VecDeque<std::result::Result<HeartbeatRequest, Status>>,
555 pending_when_empty: bool,
556 }
557
558 impl MockHeartbeatRequestStream {
559 fn new(messages: Vec<std::result::Result<HeartbeatRequest, Status>>) -> Self {
560 Self {
561 messages: messages.into(),
562 pending_when_empty: false,
563 }
564 }
565
566 fn pending_after(messages: Vec<std::result::Result<HeartbeatRequest, Status>>) -> Self {
567 Self {
568 messages: messages.into(),
569 pending_when_empty: true,
570 }
571 }
572 }
573
574 #[async_trait::async_trait]
575 impl HeartbeatRequestStream for MockHeartbeatRequestStream {
576 async fn next(&mut self) -> Option<std::result::Result<HeartbeatRequest, Status>> {
577 if let Some(message) = self.messages.pop_front() {
578 return Some(message);
579 }
580
581 if self.pending_when_empty {
582 std::future::pending().await
583 } else {
584 None
585 }
586 }
587 }
588
589 struct MockLeaderStepDown {
590 event: Option<LeaderStepDownEvent>,
591 }
592
593 impl MockLeaderStepDown {
594 fn new(event: LeaderStepDownEvent) -> Self {
595 Self { event: Some(event) }
596 }
597 }
598
599 #[async_trait::async_trait]
600 impl LeaderStepDown for MockLeaderStepDown {
601 async fn wait(&mut self) -> LeaderStepDownEvent {
602 self.event.take().unwrap()
603 }
604 }
605
606 fn heartbeat_request(role: Role, member_id: u64) -> HeartbeatRequest {
607 HeartbeatRequest {
608 header: Some(RequestHeader {
609 role: role.into(),
610 member_id,
611 ..Default::default()
612 }),
613 ..Default::default()
614 }
615 }
616
617 fn sender_id(role: Role, member_id: u64) -> PusherId {
618 PusherId::new(role, member_id)
619 }
620
621 fn test_context() -> Context {
622 TestEnv::new().ctx()
623 }
624
625 fn test_handler_group() -> Arc<HeartbeatHandlerGroup> {
626 Arc::new(HeartbeatHandlerGroup::default())
627 }
628
629 async fn init_session<L>(
630 requests: MockHeartbeatRequestStream,
631 tx: Sender<HeartbeatResponseResult>,
632 leader_step_down: Option<L>,
633 handler_group: Arc<HeartbeatHandlerGroup>,
634 ) -> Option<HeartbeatSession<MockHeartbeatRequestStream, L>>
635 where
636 L: LeaderStepDown,
637 {
638 HeartbeatSession::init(
639 requests,
640 tx,
641 leader_step_down,
642 handler_group,
643 test_context(),
644 )
645 .await
646 }
647
648 async fn recv_response(
649 rx: &mut mpsc::Receiver<HeartbeatResponseResult>,
650 ) -> HeartbeatResponseResult {
651 rx.recv().await.unwrap()
652 }
653
654 #[tokio::test]
655 async fn test_heartbeat_session_init_returns_none_on_empty_stream() {
656 let (tx, _rx) = mpsc::channel(8);
657 let handler_group = test_handler_group();
658 let requests = MockHeartbeatRequestStream::new(vec![]);
659
660 let session = init_session(
661 requests,
662 tx,
663 None::<MockLeaderStepDown>,
664 handler_group.clone(),
665 )
666 .await;
667
668 assert!(session.is_none());
669 assert!(
670 !handler_group
671 .contains_pusher(&sender_id(Role::Datanode, 42))
672 .await
673 );
674 }
675
676 #[tokio::test]
677 async fn test_heartbeat_session_init_forwards_first_stream_error() {
678 let (tx, mut rx) = mpsc::channel(8);
679 let handler_group = test_handler_group();
680 let requests = MockHeartbeatRequestStream::new(vec![Err(Status::internal("boom"))]);
681
682 let session = init_session(requests, tx, None::<MockLeaderStepDown>, handler_group).await;
683
684 assert!(session.is_none());
685 let status = recv_response(&mut rx).await.unwrap_err();
686 assert_eq!(Code::Internal, status.code());
687 assert_eq!("boom", status.message());
688 }
689
690 #[tokio::test]
691 async fn test_heartbeat_session_init_sends_error_on_missing_header() {
692 let (tx, mut rx) = mpsc::channel(8);
693 let handler_group = test_handler_group();
694 let requests = MockHeartbeatRequestStream::new(vec![Ok(HeartbeatRequest::default())]);
695
696 let session = init_session(
697 requests,
698 tx,
699 None::<MockLeaderStepDown>,
700 handler_group.clone(),
701 )
702 .await;
703
704 assert!(session.is_none());
705 assert!(
706 !handler_group
707 .contains_pusher(&sender_id(Role::Datanode, 42))
708 .await
709 );
710
711 let status = recv_response(&mut rx).await.unwrap_err();
712 assert_eq!(Code::InvalidArgument, status.code());
713 }
714
715 #[tokio::test]
716 async fn test_heartbeat_session_init_registers_sender() {
717 let (tx, mut rx) = mpsc::channel(8);
718 let handler_group = test_handler_group();
719 let sender_id = sender_id(Role::Flownode, 42);
720 let requests =
721 MockHeartbeatRequestStream::new(vec![Ok(heartbeat_request(Role::Flownode, 42))]);
722
723 let session = init_session(
724 requests,
725 tx,
726 None::<MockLeaderStepDown>,
727 handler_group.clone(),
728 )
729 .await;
730
731 assert!(session.is_some());
732 assert!(handler_group.contains_pusher(&sender_id).await);
733
734 let response = recv_response(&mut rx).await.unwrap();
735 assert!(response.heartbeat_config.is_some());
736 }
737
738 #[tokio::test]
739 async fn test_heartbeat_session_run_deregisters_sender_on_stream_close() {
740 let (tx, mut rx) = mpsc::channel(8);
741 let handler_group = test_handler_group();
742 let sender_id = sender_id(Role::Flownode, 42);
743 let requests =
744 MockHeartbeatRequestStream::new(vec![Ok(heartbeat_request(Role::Flownode, 42))]);
745 let session = init_session(
746 requests,
747 tx,
748 None::<MockLeaderStepDown>,
749 handler_group.clone(),
750 )
751 .await
752 .unwrap();
753 let _ = recv_response(&mut rx).await.unwrap();
754
755 session.run().await;
756
757 assert!(!handler_group.contains_pusher(&sender_id).await);
758 }
759
760 #[tokio::test]
761 async fn test_heartbeat_session_run_forwards_stream_error_after_init() {
762 let (tx, mut rx) = mpsc::channel(8);
763 let handler_group = test_handler_group();
764 let sender_id = sender_id(Role::Flownode, 42);
765 let requests = MockHeartbeatRequestStream::new(vec![
766 Ok(heartbeat_request(Role::Flownode, 42)),
767 Err(Status::unavailable("temporary")),
768 ]);
769 let session = init_session(
770 requests,
771 tx,
772 None::<MockLeaderStepDown>,
773 handler_group.clone(),
774 )
775 .await
776 .unwrap();
777 let _ = recv_response(&mut rx).await.unwrap();
778
779 session.run().await;
780
781 let status = recv_response(&mut rx).await.unwrap_err();
782 assert_eq!(Code::Unavailable, status.code());
783 assert_eq!("temporary", status.message());
784 assert!(!handler_group.contains_pusher(&sender_id).await);
785 }
786
787 #[tokio::test]
788 async fn test_heartbeat_session_leader_step_down_sends_aborted_and_deregisters() {
789 let (tx, mut rx) = mpsc::channel(8);
790 let handler_group = test_handler_group();
791 let sender_id = sender_id(Role::Flownode, 42);
792 let requests = MockHeartbeatRequestStream::pending_after(vec![Ok(heartbeat_request(
793 Role::Flownode,
794 42,
795 ))]);
796 let session = init_session(
797 requests,
798 tx,
799 Some(MockLeaderStepDown::new(LeaderStepDownEvent::StepDown)),
800 handler_group.clone(),
801 )
802 .await
803 .unwrap();
804 let _ = recv_response(&mut rx).await.unwrap();
805
806 session.run().await;
807
808 let status = recv_response(&mut rx).await.unwrap_err();
809 assert_eq!(Code::Aborted, status.code());
810 assert!(!handler_group.contains_pusher(&sender_id).await);
811 }
812
813 #[tokio::test]
814 async fn test_heartbeat_session_leader_watcher_closed_sends_unavailable_and_deregisters() {
815 let (tx, mut rx) = mpsc::channel(8);
816 let handler_group = test_handler_group();
817 let sender_id = sender_id(Role::Flownode, 42);
818 let requests = MockHeartbeatRequestStream::pending_after(vec![Ok(heartbeat_request(
819 Role::Flownode,
820 42,
821 ))]);
822 let session = init_session(
823 requests,
824 tx,
825 Some(MockLeaderStepDown::new(LeaderStepDownEvent::Closed)),
826 handler_group.clone(),
827 )
828 .await
829 .unwrap();
830 let _ = recv_response(&mut rx).await.unwrap();
831
832 session.run().await;
833
834 let status = recv_response(&mut rx).await.unwrap_err();
835 assert_eq!(Code::Unavailable, status.code());
836 assert!(!handler_group.contains_pusher(&sender_id).await);
837 }
838
839 #[tokio::test]
840 async fn test_ask_leader() {
841 let kv_backend = Arc::new(MemoryKvBackend::new());
842
843 let metasrv = MetasrvBuilder::new()
844 .kv_backend(kv_backend)
845 .options(MetasrvOptions {
846 grpc: GrpcOptions {
847 server_addr: "127.0.0.1:3002".to_string(),
848 ..Default::default()
849 },
850 ..Default::default()
851 })
852 .build()
853 .await
854 .unwrap();
855
856 let req = AskLeaderRequest {
857 header: Some(RequestHeader::new(1, Role::Datanode, W3cTrace::new())),
858 };
859
860 let res = metasrv.ask_leader(req.into_request()).await.unwrap();
861 let res = res.into_inner();
862 assert_eq!(metasrv.options().grpc.server_addr, res.leader.unwrap().addr);
863 }
864
865 #[test]
866 fn test_get_node_id() {
867 let header = RequestHeader {
868 role: Role::Datanode.into(),
869 member_id: 11,
870 ..Default::default()
871 };
872 assert_eq!(11, get_node_id(&header));
873
874 let header = RequestHeader {
875 role: Role::Frontend.into(),
876 ..Default::default()
877 };
878 for i in 0..10 {
879 assert_eq!(i, get_node_id(&header));
880 }
881
882 let header = RequestHeader {
883 role: Role::Frontend.into(),
884 member_id: 11,
885 ..Default::default()
886 };
887 for i in 10..20 {
888 assert_eq!(i, get_node_id(&header));
889 }
890 }
891
892 mod node_epoch {
893 use std::sync::Arc;
894 use std::time::Duration;
895
896 use api::v1::meta::{HeartbeatRequest, HeartbeatResponse, MailboxMessage, Peer, Role};
897 use common_meta::error::UnexpectedSnafu;
898 use common_meta::key::datanode_epoch::{DatanodeEpochKey, DatanodeEpochValue};
899 use common_meta::key::{MetadataValue, TableMetadataManager};
900 use common_meta::kv_backend::memory::MemoryKvBackend;
901 use common_meta::kv_backend::test_util::MockKvBackendBuilder;
902 use common_meta::kv_backend::{KvBackend, KvBackendRef, ResettableKvBackend};
903 use common_meta::region_keeper::MemoryRegionKeeper;
904 use common_meta::rpc::store::{PutRequest, RangeResponse};
905 use common_meta::sequence::SequenceBuilder;
906 use common_time::util::current_time_millis;
907 use tokio::sync::{Notify, mpsc};
908
909 use super::{MockHeartbeatRequestStream, MockLeaderStepDown, heartbeat_request};
910 use crate::discovery::utils::find_datanode_lease_value;
911 use crate::handler::region_lease_handler::RegionLeaseHandler;
912 use crate::handler::test_utils::TestEnv;
913 use crate::handler::{
914 HandleControl, HeartbeatAccumulator, HeartbeatHandler, HeartbeatHandlerGroup,
915 HeartbeatHandlerGroupBuilder, HeartbeatMailbox, Pusher, PusherId, Pushers,
916 };
917 use crate::metasrv::Context;
918 use crate::service::heartbeat::{
919 HeartbeatResponseResult, HeartbeatSession, accept_node_epoch,
920 };
921 use crate::service::mailbox::{BroadcastChannel, Channel, MailboxRef};
922 use crate::service::store::cached_kv::LeaderCachedKvBackend;
923
924 const NODE_ID: u64 = 1;
925
926 struct Stream {
928 session: HeartbeatSession<MockHeartbeatRequestStream, MockLeaderStepDown>,
929 rx: mpsc::Receiver<HeartbeatResponseResult>,
930 }
931
932 impl Stream {
933 async fn open(group: &Arc<HeartbeatHandlerGroup>, ctx: &Context) -> Self {
934 let (tx, mut rx) = mpsc::channel(8);
935 let handshake = heartbeat_request(Role::Datanode, NODE_ID);
936 let session = HeartbeatSession::init(
937 MockHeartbeatRequestStream::new(vec![Ok(handshake)]),
938 tx,
939 None,
940 group.clone(),
941 ctx.clone(),
942 )
943 .await
944 .unwrap();
945 rx.recv().await.unwrap().unwrap();
946 Self { session, rx }
947 }
948
949 async fn send(&mut self, req: HeartbeatRequest) -> HeartbeatResponse {
950 assert!(self.session.handle_request(req, false).await);
951 self.rx.recv().await.unwrap().unwrap()
952 }
953
954 fn received_push(&mut self) -> bool {
956 self.rx.try_recv().is_ok()
957 }
958 }
959
960 fn group_builder() -> HeartbeatHandlerGroupBuilder {
961 let lease_handler = RegionLeaseHandler::new(
962 10,
963 Arc::new(TableMetadataManager::new(Arc::new(MemoryKvBackend::new()))),
964 Arc::new(MemoryRegionKeeper::default()),
965 None,
966 );
967 let mut builder = HeartbeatHandlerGroupBuilder::new(Pushers::default())
968 .with_region_lease_handler(Some(lease_handler))
969 .add_default_handlers();
970 builder
971 .add_handler_after("ResponseHeaderHandler", BroadcastHandler)
972 .unwrap();
973 builder
974 }
975
976 fn new_group() -> Arc<HeartbeatHandlerGroup> {
977 Arc::new(group_builder().build().unwrap())
978 }
979
980 struct PauseHandler {
982 entered: Arc<Notify>,
983 release: Arc<Notify>,
984 }
985
986 #[async_trait::async_trait]
987 impl HeartbeatHandler for PauseHandler {
988 fn is_acceptable(&self, role: Role) -> bool {
989 role == Role::Datanode
990 }
991
992 async fn handle(
993 &self,
994 req: &HeartbeatRequest,
995 _: &mut Context,
996 _: &mut HeartbeatAccumulator,
997 ) -> crate::error::Result<HandleControl> {
998 if req.peer.as_ref().is_some_and(|peer| peer.addr == "pause") {
999 self.entered.notify_one();
1000 self.release.notified().await;
1001 }
1002 Ok(HandleControl::Continue)
1003 }
1004 }
1005
1006 struct BroadcastHandler;
1008
1009 #[async_trait::async_trait]
1010 impl HeartbeatHandler for BroadcastHandler {
1011 fn is_acceptable(&self, role: Role) -> bool {
1012 role == Role::Datanode
1013 }
1014
1015 async fn handle(
1016 &self,
1017 req: &HeartbeatRequest,
1018 ctx: &mut Context,
1019 _: &mut HeartbeatAccumulator,
1020 ) -> crate::error::Result<HandleControl> {
1021 if req
1022 .peer
1023 .as_ref()
1024 .is_some_and(|peer| peer.addr == "broadcast")
1025 {
1026 let msg = MailboxMessage::default();
1027 ctx.mailbox
1028 .broadcast(&BroadcastChannel::Datanode, &msg)
1029 .await?;
1030 }
1031 Ok(HandleControl::Continue)
1032 }
1033 }
1034
1035 fn heartbeat(node_epoch: u64, addr: &str) -> HeartbeatRequest {
1036 HeartbeatRequest {
1037 peer: Some(Peer::new(NODE_ID, addr)),
1038 node_epoch,
1039 ..heartbeat_request(Role::Datanode, NODE_ID)
1040 }
1041 }
1042
1043 fn mailbox(pushers: Pushers) -> MailboxRef {
1044 let seq = SequenceBuilder::new("test_seq", Arc::new(MemoryKvBackend::new())).build();
1045 HeartbeatMailbox::create(pushers, seq)
1046 }
1047
1048 async fn push(group: &HeartbeatHandlerGroup) {
1049 mailbox(group.pushers())
1050 .send_oneway(&Channel::Datanode(NODE_ID), MailboxMessage::default())
1051 .await
1052 .unwrap();
1053 }
1054
1055 async fn lease_addr(ctx: &Context) -> Option<String> {
1056 let in_memory = ctx.in_memory.clone() as KvBackendRef;
1057 find_datanode_lease_value(&in_memory, NODE_ID)
1058 .await
1059 .unwrap()
1060 .map(|lease| lease.node_addr)
1061 }
1062
1063 async fn record(ctx: &Context, node_epoch: u64) {
1065 let key = DatanodeEpochKey::new(NODE_ID).to_bytes();
1066 let value = DatanodeEpochValue { node_epoch }
1067 .try_as_raw_value()
1068 .unwrap();
1069 let req = PutRequest::new().with_key(key).with_value(value);
1070 ctx.leader_cached_kv_backend.put(req).await.unwrap();
1071 }
1072
1073 fn epochs() -> (u64, u64) {
1074 let now = current_time_millis() as u64;
1075 (now - 1000, now)
1076 }
1077
1078 #[tokio::test]
1079 async fn test_newer_process_fences_the_older_one() {
1080 let group = new_group();
1081 let mut ctx = TestEnv::new().ctx();
1082 let pushers = Pushers::default();
1084 let (tx, _rx) = mpsc::channel(8);
1085 pushers
1086 .insert(PusherId::new(Role::Datanode, NODE_ID), Pusher::new(tx))
1087 .await;
1088 ctx.mailbox = mailbox(pushers);
1089 let wait_for_reply = || {
1090 ctx.mailbox.send(
1091 &Channel::Datanode(NODE_ID),
1092 MailboxMessage::default(),
1093 Duration::from_millis(500),
1094 )
1095 };
1096 let (e1, e2) = epochs();
1097 let mut a1 = Stream::open(&group, &ctx).await;
1098 let mut a2 = Stream::open(&group, &ctx).await;
1099
1100 let res = a1.send(heartbeat(e1, "a1")).await;
1101 assert!(res.region_lease.is_some());
1102 let res = a2.send(heartbeat(e2, "a2")).await;
1104 assert!(res.region_lease.is_some());
1105
1106 let res = a1.send(heartbeat(e1, "a1")).await;
1108 assert!(res.region_lease.is_none());
1109 assert!(res.header.unwrap().error.is_none());
1110 assert_eq!(lease_addr(&ctx).await.as_deref(), Some("a2"));
1111
1112 let a1_reply = wait_for_reply().await.unwrap();
1114 let a2_reply = wait_for_reply().await.unwrap();
1115 for (stream, reply, epoch) in [(&mut a1, &a1_reply, e1), (&mut a2, &a2_reply, e2)] {
1116 let mut req = heartbeat(epoch, "a");
1117 req.mailbox_message = Some(MailboxMessage {
1118 id: reply.message_id(),
1119 ..Default::default()
1120 });
1121 stream.send(req).await;
1122 }
1123 assert!(a1_reply.await.is_err());
1124 assert!(a2_reply.await.is_ok());
1125 }
1126
1127 #[tokio::test]
1128 async fn test_pusher_follows_the_newer_process() {
1129 let group = new_group();
1130 let mut ctx = TestEnv::new().ctx();
1131 ctx.mailbox = mailbox(group.pushers());
1132 let (e1, e2) = epochs();
1133 let mut a1 = Stream::open(&group, &ctx).await;
1134 a1.send(heartbeat(e1, "a1")).await;
1135 let mut a2 = Stream::open(&group, &ctx).await;
1138 assert!(
1139 a2.session
1140 .handle_request(heartbeat(e2, "broadcast"), false)
1141 .await
1142 );
1143 let broadcast = a2.rx.recv().await.unwrap().unwrap();
1144 assert!(broadcast.mailbox_message.is_some());
1145 let res = a2.rx.recv().await.unwrap().unwrap();
1146 assert!(res.region_lease.is_some());
1147 assert!(!a1.received_push());
1148 push(&group).await;
1149 assert!(a2.received_push());
1150
1151 let mut a1_again = Stream::open(&group, &ctx).await;
1153 a1_again.send(heartbeat(e1, "a1")).await;
1154 push(&group).await;
1155 assert!(a2.received_push());
1156
1157 a1.session.run().await;
1159 a1_again.session.run().await;
1160 push(&group).await;
1161 assert!(a2.received_push());
1162 let mut a2_again = Stream::open(&group, &ctx).await;
1165 a2_again.send(heartbeat(e2, "a2")).await;
1166 a2.session.run().await;
1167 push(&group).await;
1168 assert!(a2_again.received_push());
1169
1170 record(&ctx, e2 + 1).await;
1172 a2_again.send(heartbeat(e2, "a2")).await;
1173 let pusher_id = PusherId::new(Role::Datanode, NODE_ID);
1174 assert!(!group.contains_pusher(&pusher_id).await);
1175 let _a1_reconnected = Stream::open(&group, &ctx).await;
1176 assert!(!group.contains_pusher(&pusher_id).await);
1177 }
1178
1179 #[tokio::test]
1180 async fn test_newer_process_waits_for_an_older_request() {
1181 let (entered, release) = (Arc::new(Notify::new()), Arc::new(Notify::new()));
1182 let mut builder = group_builder();
1183 let pause = PauseHandler {
1184 entered: entered.clone(),
1185 release: release.clone(),
1186 };
1187 builder
1188 .add_handler_before("DatanodeKeepLeaseHandler", pause)
1189 .unwrap();
1190 let group = Arc::new(builder.build().unwrap());
1191 let ctx = TestEnv::new().ctx();
1192 let (e1, e2) = epochs();
1193 let mut a1 = Stream::open(&group, &ctx).await;
1194 let mut a2 = Stream::open(&group, &ctx).await;
1195
1196 let a1_req = a1.session.handle_request(heartbeat(e1, "pause"), false);
1199 let a2_req = async {
1200 entered.notified().await;
1201 let mut a2_req = std::pin::pin!(a2.send(heartbeat(e2, "a2")));
1202 let waiting = tokio::time::timeout(Duration::from_millis(100), &mut a2_req).await;
1203 assert!(waiting.is_err());
1204 release.notify_one();
1205 a2_req.await
1206 };
1207 let (open, res) = tokio::join!(a1_req, a2_req);
1208 assert!(open);
1209 assert!(res.region_lease.is_some());
1210 assert_eq!(lease_addr(&ctx).await.as_deref(), Some("a2"));
1211
1212 a1.rx.recv().await.unwrap().unwrap();
1214 let res = a1.send(heartbeat(e1, "a1")).await;
1215 assert!(res.region_lease.is_none());
1216 assert_eq!(lease_addr(&ctx).await.as_deref(), Some("a2"));
1217 }
1218
1219 #[tokio::test]
1220 async fn test_kv_error_fails_the_request() {
1221 let group = new_group();
1222 let mut ctx = TestEnv::new().ctx();
1223 let kv_backend = MockKvBackendBuilder::default()
1224 .range_fn(Arc::new(|_| {
1225 Ok(RangeResponse {
1226 kvs: vec![],
1227 more: false,
1228 })
1229 }))
1230 .txn(Arc::new(|_| {
1231 UnexpectedSnafu {
1232 err_msg: "injected",
1233 }
1234 .fail()
1235 }))
1236 .build()
1237 .unwrap();
1238 let cached = LeaderCachedKvBackend::with_always_leader(Arc::new(kv_backend));
1239 ctx.leader_cached_kv_backend = Arc::new(cached);
1240 let (e1, _) = epochs();
1241 let mut a1 = Stream::open(&group, &ctx).await;
1242
1243 let req = HeartbeatRequest {
1244 node_epoch: e1,
1245 ..heartbeat_request(Role::Datanode, NODE_ID)
1246 };
1247 assert!(a1.session.handle_request(req, false).await);
1248 assert!(a1.rx.recv().await.unwrap().is_err());
1249 }
1250
1251 #[tokio::test]
1252 async fn test_first_epoch_keeps_waiting_messages() {
1253 let group = new_group();
1254 let mut ctx = TestEnv::new().ctx();
1255 ctx.mailbox = mailbox(group.pushers());
1256 let (e1, _) = epochs();
1257 let mut a1 = Stream::open(&group, &ctx).await;
1258 a1.send(heartbeat(0, "a1")).await;
1260 let reply = ctx
1261 .mailbox
1262 .send(
1263 &Channel::Datanode(NODE_ID),
1264 MailboxMessage::default(),
1265 Duration::from_secs(10),
1266 )
1267 .await
1268 .unwrap();
1269 let id = a1
1270 .rx
1271 .recv()
1272 .await
1273 .unwrap()
1274 .unwrap()
1275 .mailbox_message
1276 .unwrap()
1277 .id;
1278 tokio::pin!(reply);
1279
1280 a1.send(heartbeat(e1, "a1")).await;
1283 assert!(futures::poll!(reply.as_mut()).is_pending());
1284 let mut req = heartbeat(e1, "a1");
1285 req.mailbox_message = Some(MailboxMessage {
1286 id,
1287 ..Default::default()
1288 });
1289 a1.send(req).await;
1290 assert!(reply.await.is_ok());
1291 }
1292
1293 #[tokio::test]
1294 async fn test_record_is_reloaded_on_leader_change() {
1295 let store: KvBackendRef = Arc::new(MemoryKvBackend::new());
1296 let cached = LeaderCachedKvBackend::with_always_leader(store.clone());
1297 let now = current_time_millis() as u64;
1298 let (e1, e2) = (now - 1000, now);
1299 assert!(accept_node_epoch(&cached, 1, e1).await.unwrap());
1300 assert!(accept_node_epoch(&cached, 1, e2).await.unwrap());
1301
1302 cached.reset();
1305 cached.load().await.unwrap();
1306 store
1307 .delete(&DatanodeEpochKey::new(1).to_bytes(), false)
1308 .await
1309 .unwrap();
1310 assert!(!accept_node_epoch(&cached, 1, e1).await.unwrap());
1311 assert!(accept_node_epoch(&cached, 1, e2).await.unwrap());
1312 }
1313
1314 #[tokio::test]
1315 async fn test_epoch_above_a_record_ahead_of_the_clock_is_accepted() {
1316 let group = new_group();
1317 let ctx = TestEnv::new().ctx();
1318 let recorded = current_time_millis() as u64 + 60_000;
1320 record(&ctx, recorded).await;
1321
1322 let mut restarted = Stream::open(&group, &ctx).await;
1323 let res = restarted.send(heartbeat(recorded + 1, "a2")).await;
1324 assert!(res.region_lease.is_some());
1325 assert_eq!(lease_addr(&ctx).await.as_deref(), Some("a2"));
1326 }
1327
1328 #[tokio::test]
1329 async fn test_epoch_far_ahead_is_not_recorded() {
1330 let kv_backend = MemoryKvBackend::new();
1331 let now = current_time_millis() as u64;
1332 let ahead = now + Duration::from_secs(10 * 60).as_millis() as u64;
1333 assert!(!accept_node_epoch(&kv_backend, 1, ahead).await.unwrap());
1334 let key = DatanodeEpochKey::new(1).to_bytes();
1335 assert!(kv_backend.get(&key).await.unwrap().is_none());
1336
1337 let slightly_ahead = now + Duration::from_secs(60).as_millis() as u64;
1338 assert!(
1339 accept_node_epoch(&kv_backend, 1, slightly_ahead)
1340 .await
1341 .unwrap()
1342 );
1343 }
1344
1345 #[tokio::test]
1346 async fn test_datanode_without_epoch_is_not_checked() {
1347 let group = new_group();
1348 let ctx = TestEnv::new().ctx();
1349 let (_, e2) = epochs();
1351 record(&ctx, e2).await;
1352 let mut a1 = Stream::open(&group, &ctx).await;
1353
1354 let res = a1.send(heartbeat(0, "a1")).await;
1355 assert!(res.region_lease.is_some());
1356 push(&group).await;
1357 assert!(a1.received_push());
1358 }
1359 }
1360}