Skip to main content

meta_srv/service/
heartbeat.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::cmp::Ordering;
16use std::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
49/// How far ahead of the leader's clock a datanode epoch can be recorded.
50const 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    /// The node epoch the stream's pusher was registered with, if any.
123    pusher_epoch: Option<u64>,
124}
125
126impl<R, L> HeartbeatSession<R, L>
127where
128    R: HeartbeatRequestStream,
129    L: LeaderStepDown,
130{
131    /// Initializes the heartbeat session by receiving the first request,
132    /// and returns `None` if the stream is closed or an error occurs.
133    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        // A datanode stream registers its pusher on its first request that passes the check.
161        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    /// Runs the heartbeat session until the stream is closed or an error occurs.
184    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    /// Handles the incoming message, and returns whether to continue the session.
218    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    /// Handles the incoming heartbeat request, and returns whether to continue the session.
226    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        // A datanode's requests that carry an epoch are checked and handled one at a time, so
241        // an older process's request cannot run its handlers after a newer process is admitted.
242        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    /// Checks the node epoch of a datanode request, and registers the stream's pusher once
292    /// the request passes. Returns the response to send instead of running the handlers, if any.
293    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        // Datanodes that do not report their epoch are not checked.
303        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                // No error, so the datanode does not reconnect.
313                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        // Before the handlers run, so the stream receives what they broadcast.
323        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
371/// Handles request stream error by logging and forwarding the error to the client if possible.
372///
373/// Returns `false` if the stream should be terminated.
374async 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, // TODO(jiachun): meta node should have a Id
457        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
478/// Returns whether `node_epoch` is not lower than the highest epoch recorded for the datanode,
479/// raising the record when it is higher. An epoch too far ahead of this metasrv's clock is
480/// refused, since recording it would fence every later process.
481async 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        /// A datanode stream that has sent its handshake, which carries no epoch.
927        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            /// Returns whether the stream has received a pushed message.
955            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        /// Holds a request from the address "pause": notifies `entered`, then waits for `release`.
981        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        /// Broadcasts to datanodes while handling a request from the address "broadcast".
1007        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        /// Records `node_epoch` as the highest epoch of the node, through the leader cache.
1064        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            // A mailbox waiting for replies from the datanode.
1083            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            // A2 replaces A1 and records its epoch.
1103            let res = a2.send(heartbeat(e2, "a2")).await;
1104            assert!(res.region_lease.is_some());
1105
1106            // A1 is fenced: no lease, no keep-alive, no error that would make it reconnect.
1107            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            // A1's mailbox reply is dropped, A2's is delivered.
1113            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            // A2 takes over before the handlers of its first heartbeat run, so it receives
1136            // what they broadcast ahead of the response.
1137            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            // A1's new stream does not take the pusher back.
1152            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            // A stream ending removes only its own pusher.
1158            a1.session.run().await;
1159            a1_again.session.run().await;
1160            push(&group).await;
1161            assert!(a2.received_push());
1162            // A2's new stream takes over with the same epoch, and A2's old stream ending
1163            // keeps it.
1164            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            // A fenced stream removes its own pusher, and a handshake does not take the slot.
1171            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            // A1's request passes the check and is held before the keep-alive handler, and
1197            // A2's request waits for it.
1198            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 can no longer overwrite the address or get a lease.
1213            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            // A request without an epoch registers the pusher first.
1259            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            // The stream's pusher takes the epoch of its first heartbeat without cancelling
1281            // the message, which a later heartbeat answers.
1282            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            // The cache is reset and loaded again when this metasrv becomes the leader. The record
1303            // is then served from the loaded cache, even without the store.
1304            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            // The previous process of the node ran on a faster clock.
1319            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            // Even after another process of the node has recorded its epoch.
1350            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}