1use std::collections::HashMap;
16use std::sync::Arc;
17use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
18
19use api::v1::meta::GrantedRegion;
20use async_trait::async_trait;
21use common_error::ext::ErrorExt;
22use common_error::status_code::StatusCode;
23use common_meta::error::InvalidProtoMsgSnafu;
24use common_meta::heartbeat::handler::{
25 HandleControl, HeartbeatResponseHandler, HeartbeatResponseHandlerContext,
26};
27use common_telemetry::{debug, error, info, trace, warn};
28use snafu::OptionExt;
29use store_api::region_engine::{RegionRole, SettableRegionRoleState};
30use store_api::region_request::{RegionCloseRequest, RegionRequest};
31use store_api::storage::RegionId;
32#[cfg(test)]
33use tokio::sync::oneshot;
34use tokio::sync::{Mutex, mpsc};
35use tokio::task::JoinHandle;
36use tokio::time::{Duration, Instant};
37
38use crate::error::{self, Result};
39use crate::event_listener::{RegionServerEvent, RegionServerEventReceiver};
40use crate::region_server::RegionServer;
41
42pub struct RegionAliveKeeper {
51 region_server: RegionServer,
52 tasks: Arc<Mutex<HashMap<RegionId, Arc<CountdownTaskHandle>>>>,
53 heartbeat_interval_millis: Arc<AtomicU64>,
54 started: Arc<AtomicBool>,
55
56 epoch: Instant,
61
62 countdown_task_handler_ext: Option<CountdownTaskHandlerExtRef>,
63}
64
65impl RegionAliveKeeper {
66 pub fn new(
68 region_server: RegionServer,
69 countdown_task_handler_ext: Option<CountdownTaskHandlerExtRef>,
70 heartbeat_interval: Duration,
71 ) -> Self {
72 Self {
73 region_server,
74 tasks: Arc::new(Mutex::new(HashMap::new())),
75 heartbeat_interval_millis: Arc::new(AtomicU64::new(
76 heartbeat_interval.as_millis() as u64
77 )),
78 started: Arc::new(AtomicBool::new(false)),
79 epoch: Instant::now(),
80 countdown_task_handler_ext,
81 }
82 }
83
84 pub fn update_heartbeat_interval(&self, heartbeat_interval_millis: u64) {
86 self.heartbeat_interval_millis
87 .store(heartbeat_interval_millis, Ordering::Relaxed);
88 }
89
90 async fn find_handle(&self, region_id: RegionId) -> Option<Arc<CountdownTaskHandle>> {
91 self.tasks.lock().await.get(®ion_id).cloned()
92 }
93
94 pub async fn register_region(&self, region_id: RegionId) {
97 let handle = Arc::new(CountdownTaskHandle::new(
98 self.region_server.clone(),
99 self.countdown_task_handler_ext.clone(),
100 region_id,
101 ));
102
103 let should_start = {
104 let mut handles = self.tasks.lock().await;
105
106 if handles.contains_key(®ion_id) {
108 return;
109 }
110
111 handles.insert(region_id, handle.clone());
113
114 self.started.load(Ordering::Relaxed)
116 };
117
118 if should_start {
119 handle
120 .start(self.heartbeat_interval_millis.load(Ordering::Relaxed))
121 .await;
122 info!("Region alive countdown for region {region_id} is started!");
123 } else {
124 info!(
125 "Region alive countdown for region {region_id} is registered but not started yet!"
126 );
127 }
128 }
129
130 pub async fn deregister_region(&self, region_id: RegionId) {
132 if self.tasks.lock().await.remove(®ion_id).is_some() {
133 info!("Deregister alive countdown for region {region_id}")
134 }
135 }
136
137 async fn renew_region_leases(&self, regions: &[GrantedRegion], deadline: Instant) {
139 for region in regions {
140 let (role, region_id) = (region.role().into(), RegionId::from(region.region_id));
141 if let Some(handle) = self.find_handle(region_id).await {
142 handle
143 .reset_deadline(role, deadline, region.extensions.clone())
144 .await;
145 } else {
146 warn!(
147 "Trying to renew the lease for region {region_id}, the keeper handler is not found!"
148 );
149 }
151 }
152 }
153
154 async fn close_staled_region(&self, region_id: RegionId) {
155 info!("Closing staled region: {region_id}");
156 let request = RegionRequest::Close(RegionCloseRequest::default());
157 if let Err(e) = self.region_server.handle_request(region_id, request).await
158 && e.status_code() != StatusCode::RegionNotFound
159 {
160 let _ = self
161 .region_server
162 .set_region_role(region_id, RegionRole::Follower);
163 error!(e; "Failed to close staled region {}, convert region to follower.", region_id);
164 }
165 }
166
167 async fn close_staled_regions(&self, regions: &[u64]) {
169 for region_id in regions {
170 self.close_staled_region(RegionId::from_u64(*region_id))
171 .await;
172 }
173 }
174
175 #[cfg(test)]
176 async fn deadline(&self, region_id: RegionId) -> Option<Instant> {
177 let mut deadline = None;
178 if let Some(handle) = self.find_handle(region_id).await {
179 let (s, r) = oneshot::channel();
180 if handle.tx.send(CountdownCommand::Deadline(s)).await.is_ok() {
181 deadline = r.await.ok()
182 }
183 }
184 deadline
185 }
186
187 pub async fn start(
188 self: &Arc<Self>,
189 event_receiver: Option<RegionServerEventReceiver>,
190 ) -> Result<()> {
191 self.started.store(true, Ordering::Relaxed);
192
193 if let Some(mut event_receiver) = event_receiver {
194 let keeper = self.clone();
195 loop {
198 match event_receiver.0.try_recv() {
199 Ok(RegionServerEvent::Registered(region_id)) => {
200 keeper.register_region(region_id).await;
201 }
202 Ok(RegionServerEvent::Deregistered(region_id)) => {
203 keeper.deregister_region(region_id).await;
204 }
205 Err(mpsc::error::TryRecvError::Disconnected) => {
206 return error::UnexpectedSnafu {
207 violated: "RegionServerEventSender closed",
208 }
209 .fail();
210 }
211 Err(mpsc::error::TryRecvError::Empty) => {
212 break;
213 }
214 }
215 }
216 let running = self.started.clone();
217
218 common_runtime::spawn_global(async move {
220 loop {
221 if !running.load(Ordering::Relaxed) {
222 info!("RegionAliveKeeper stopped! Quits the watch loop!");
223 break;
224 }
225
226 match event_receiver.0.recv().await {
227 Some(RegionServerEvent::Registered(region_id)) => {
228 keeper.register_region(region_id).await;
229 }
230 Some(RegionServerEvent::Deregistered(region_id)) => {
231 keeper.deregister_region(region_id).await;
232 }
233 None => {
234 info!("RegionServerEventSender closed! Quits the watch loop!");
235 break;
236 }
237 }
238 }
239 });
240 }
241
242 let tasks = self.tasks.lock().await;
243 let interval = self.heartbeat_interval_millis.load(Ordering::Relaxed);
244 for task in tasks.values() {
245 task.start(interval).await;
246 }
247
248 info!(
249 "RegionAliveKeeper is started with region {:?}",
250 tasks.keys().map(|x| x.to_string()).collect::<Vec<_>>(),
251 );
252
253 Ok(())
254 }
255
256 pub fn epoch(&self) -> Instant {
257 self.epoch
258 }
259}
260
261#[async_trait]
262impl HeartbeatResponseHandler for RegionAliveKeeper {
263 fn is_acceptable(&self, ctx: &HeartbeatResponseHandlerContext) -> bool {
264 ctx.response.region_lease.is_some()
265 }
266
267 async fn handle(
268 &self,
269 ctx: &mut HeartbeatResponseHandlerContext,
270 ) -> common_meta::error::Result<HandleControl> {
271 let region_lease = ctx
272 .response
273 .region_lease
274 .as_ref()
275 .context(InvalidProtoMsgSnafu {
276 err_msg: "'region_lease' is missing in heartbeat response",
277 })?;
278 let start_instant = self.epoch + Duration::from_millis(region_lease.duration_since_epoch);
279 let deadline = start_instant + Duration::from_secs(region_lease.lease_seconds);
280
281 if let Some(mito) = self.region_server.mito_engine() {
282 mito.renew_node_lease(deadline.into_std());
283 }
284 self.renew_region_leases(®ion_lease.regions, deadline)
285 .await;
286 self.close_staled_regions(®ion_lease.closeable_region_ids)
287 .await;
288
289 Ok(HandleControl::Continue)
290 }
291}
292
293#[derive(Debug)]
294enum CountdownCommand {
295 Start(u64),
298 Reset((RegionRole, Instant, HashMap<String, Vec<u8>>)),
301 #[cfg(test)]
303 Deadline(oneshot::Sender<Instant>),
304}
305
306pub type CountdownTaskHandlerExtRef = Arc<dyn CountdownTaskHandlerExt>;
307
308#[async_trait]
310pub trait CountdownTaskHandlerExt: Send + Sync {
311 async fn reset_deadline(
312 &self,
313 region_server: &RegionServer,
314 region_id: RegionId,
315 role: RegionRole,
316 deadline: Instant,
317 extension_info: HashMap<String, Vec<u8>>,
318 );
319}
320
321struct CountdownTaskHandle {
322 tx: mpsc::Sender<CountdownCommand>,
323 handler: JoinHandle<()>,
324 region_id: RegionId,
325}
326
327impl CountdownTaskHandle {
328 fn new(
330 region_server: RegionServer,
331 handler_ext: Option<CountdownTaskHandlerExtRef>,
332 region_id: RegionId,
333 ) -> Self {
334 let (tx, rx) = mpsc::channel(1024);
335
336 let mut countdown_task = CountdownTask {
337 region_server,
338 handler_ext,
339 region_id,
340 rx,
341 };
342 let handler = common_runtime::spawn_hb(async move {
343 countdown_task.run().await;
344 });
345
346 Self {
347 tx,
348 handler,
349 region_id,
350 }
351 }
352
353 async fn start(&self, heartbeat_interval_millis: u64) {
356 if let Err(e) = self
357 .tx
358 .send(CountdownCommand::Start(heartbeat_interval_millis))
359 .await
360 {
361 warn!(
362 "Failed to start region alive keeper countdown: {e}. \
363 Maybe the task is stopped due to region been closed."
364 );
365 }
366 }
367
368 #[cfg(test)]
369 async fn deadline(&self) -> Option<Instant> {
370 let (tx, rx) = oneshot::channel();
371 if self.tx.send(CountdownCommand::Deadline(tx)).await.is_ok() {
372 return rx.await.ok();
373 }
374 None
375 }
376
377 async fn reset_deadline(
378 &self,
379 role: RegionRole,
380 deadline: Instant,
381 extension_info: HashMap<String, Vec<u8>>,
382 ) {
383 if let Err(e) = self
384 .tx
385 .send(CountdownCommand::Reset((role, deadline, extension_info)))
386 .await
387 {
388 warn!(
389 "Failed to reset region alive keeper deadline: {e}. \
390 Maybe the task is stopped due to region been closed."
391 );
392 }
393 }
394}
395
396impl Drop for CountdownTaskHandle {
397 fn drop(&mut self) {
398 debug!(
399 "Aborting region alive countdown task for region {}",
400 self.region_id
401 );
402 self.handler.abort();
403 }
404}
405
406struct CountdownTask {
407 region_server: RegionServer,
408 region_id: RegionId,
409 handler_ext: Option<CountdownTaskHandlerExtRef>,
410 rx: mpsc::Receiver<CountdownCommand>,
411}
412
413impl CountdownTask {
414 async fn run(&mut self) {
415 let far_future = Instant::now() + Duration::from_secs(86400 * 365 * 30);
417
418 let countdown = tokio::time::sleep_until(far_future);
421 tokio::pin!(countdown);
422 let region_id = self.region_id;
423
424 let mut started = false;
425 loop {
426 tokio::select! {
427 command = self.rx.recv() => {
428 match command {
429 Some(CountdownCommand::Start(heartbeat_interval_millis)) => {
430 if !started {
431 let first_deadline = Instant::now() + Duration::from_millis(heartbeat_interval_millis) * 4;
435 countdown.set(tokio::time::sleep_until(first_deadline));
436 started = true;
437 }
438 },
439 Some(CountdownCommand::Reset((role, deadline, extension_info))) => {
440 let prev_role_leader = self.region_server.is_region_leader(self.region_id).unwrap_or(false);
441 if let Err(err) = self.region_server.set_region_role_with_lease(self.region_id, role, deadline.into_std()) {
442 if err.status_code() == StatusCode::RegionNotFound {
443 warn!(err; "Failed to set region role to {role} for region {region_id}");
447 } else {
448 error!(err; "Failed to set region role to {role} for region {region_id}");
449 }
450
451 } else if !prev_role_leader && role == RegionRole::Leader
453 && let Err(err) = self
454 .region_server
455 .set_region_role_state_gracefully(self.region_id, SettableRegionRoleState::Leader)
456 .await
457 {
458 error!(err; "Failed to set region role state gracefully to {role} for region {region_id}");
459 }
460
461 if let Some(ext_handler) = self.handler_ext.as_ref() {
462 ext_handler.reset_deadline(
463 &self.region_server,
464 self.region_id,
465 role,
466 deadline,
467 extension_info,
468 ).await;
469 }
470 trace!(
471 "Reset deadline of region {region_id} to approximately {} seconds later.",
472 (deadline - Instant::now()).as_secs_f32(),
473 );
474 countdown.set(tokio::time::sleep_until(deadline));
475 },
476 None => {
477 info!(
478 "The handle of countdown task for region {region_id}\
479 is dropped, RegionAliveKeeper out."
480 );
481 break;
482 },
483 #[cfg(test)]
484 Some(CountdownCommand::Deadline(tx)) => {
485 let _ = tx.send(countdown.deadline());
486 }
487 }
488 }
489 () = &mut countdown => {
490 warn!("The region {region_id} lease is expired, convert region to follower.");
491 if let Err(err) = self.region_server.set_region_role(self.region_id, RegionRole::Follower) {
492 error!(err; "Failed to set region role to follower for region {region_id}");
493 }
494 let far_future = Instant::now() + Duration::from_secs(86400 * 365 * 30);
496 countdown.as_mut().reset(far_future);
497 }
498 }
499 }
500 }
501}
502
503#[cfg(test)]
504mod test {
505
506 use api::v1::Rows;
507 use api::v1::meta::{HeartbeatResponse, RegionLease};
508 use common_meta::heartbeat::mailbox::HeartbeatMailbox;
509 use mito2::config::MitoConfig;
510 use mito2::test_util::{CreateRequestBuilder, TestEnv, build_rows, rows_schema};
511 use store_api::region_engine::RegionEngine;
512 use store_api::region_request::{
513 EnterStagingRequest, RegionPutRequest, StagingPartitionDirective,
514 };
515
516 use super::*;
517 use crate::tests::mock_region_server;
518
519 async fn handle_lease_response(alive_keeper: &RegionAliveKeeper, regions: Vec<GrantedRegion>) {
521 let (tx, _rx) = mpsc::channel(1);
522 let response = HeartbeatResponse {
523 region_lease: Some(RegionLease {
524 regions,
525 duration_since_epoch: alive_keeper.epoch().elapsed().as_millis() as u64,
526 lease_seconds: 86400,
528 closeable_region_ids: vec![],
529 }),
530 ..Default::default()
531 };
532 let mut ctx =
533 HeartbeatResponseHandlerContext::new(Arc::new(HeartbeatMailbox::new(tx)), response);
534 alive_keeper.handle(&mut ctx).await.unwrap();
535 }
536
537 #[tokio::test(flavor = "multi_thread")]
538 async fn lease_responses_let_regions_write() {
539 common_telemetry::init_default_ut_logging();
540 let mut region_server = mock_region_server();
541 let mut engine_env = TestEnv::with_prefix("region-alive-keeper-write-lease").await;
542 let engine = engine_env.create_engine(MitoConfig::default()).await;
543 engine.require_write_lease();
544 engine.freeze_lease_clock(std::time::Instant::now());
546 region_server.register_engine(Arc::new(engine));
547 let alive_keeper =
548 RegionAliveKeeper::new(region_server.clone(), None, Duration::from_millis(100));
549 let create = |region_id| {
550 let request = RegionRequest::Create(CreateRequestBuilder::new().build());
551 region_server.handle_request(region_id, request)
552 };
553 let schema = rows_schema(&CreateRequestBuilder::new().build());
554 let put = |region_id| {
555 let rows = Rows {
556 schema: schema.clone(),
557 rows: build_rows(0, 1),
558 };
559 let request = RegionRequest::Put(RegionPutRequest {
560 rows,
561 hint: None,
562 partition_expr_version: None,
563 skip_wal: false,
564 });
565 region_server.handle_request(region_id, request)
566 };
567
568 let region_id = RegionId::new(1024, 1);
570 create(region_id).await.unwrap();
571 assert!(put(region_id).await.unwrap_err().is_retryable());
572
573 handle_lease_response(&alive_keeper, vec![]).await;
575 let created_region_id = RegionId::new(1024, 2);
576 create(created_region_id).await.unwrap();
577 put(created_region_id).await.unwrap();
578
579 alive_keeper.register_region(region_id).await;
581 let grant = GrantedRegion {
582 region_id: region_id.as_u64(),
583 role: api::v1::meta::RegionRole::Leader.into(),
584 extensions: HashMap::new(),
585 };
586 handle_lease_response(&alive_keeper, vec![grant]).await;
587 alive_keeper.deadline(region_id).await.unwrap();
589 put(region_id).await.unwrap();
590 }
591
592 #[tokio::test(flavor = "multi_thread")]
593 async fn region_alive_keeper() {
594 common_telemetry::init_default_ut_logging();
595 let mut region_server = mock_region_server();
596 let mut engine_env = TestEnv::with_prefix("region-alive-keeper").await;
597 let engine = engine_env.create_engine(MitoConfig::default()).await;
598 let engine = Arc::new(engine);
599 region_server.register_engine(engine.clone());
600
601 let alive_keeper = Arc::new(RegionAliveKeeper::new(
602 region_server.clone(),
603 None,
604 Duration::from_millis(100),
605 ));
606
607 let region_id = RegionId::new(1024, 1);
608 let builder = CreateRequestBuilder::new();
609 region_server
610 .handle_request(region_id, RegionRequest::Create(builder.build()))
611 .await
612 .unwrap();
613 region_server
614 .set_region_role(region_id, RegionRole::Leader)
615 .unwrap();
616
617 alive_keeper.register_region(region_id).await;
619 assert!(alive_keeper.find_handle(region_id).await.is_some());
620
621 info!("Start the keeper");
622 alive_keeper.start(None).await.unwrap();
623
624 let deadline = alive_keeper.deadline(region_id).await.unwrap();
626 assert!(deadline >= Instant::now());
627 assert_eq!(engine.role(region_id).unwrap(), RegionRole::Leader);
628
629 info!("Wait for lease expired");
630 tokio::time::sleep(Duration::from_millis(500)).await;
632 assert!(alive_keeper.find_handle(region_id).await.is_some());
633 assert_eq!(engine.role(region_id).unwrap(), RegionRole::Follower);
634
635 info!("Renew the region lease");
636 alive_keeper
638 .renew_region_leases(
639 &[GrantedRegion {
640 region_id: region_id.as_u64(),
641 role: api::v1::meta::RegionRole::Leader.into(),
642 extensions: HashMap::new(),
643 }],
644 Instant::now() + Duration::from_millis(200),
645 )
646 .await;
647 tokio::time::sleep(Duration::from_millis(100)).await;
648 assert!(alive_keeper.find_handle(region_id).await.is_some());
649 let deadline = alive_keeper.deadline(region_id).await.unwrap();
650 assert!(deadline >= Instant::now());
651 assert_eq!(engine.role(region_id).unwrap(), RegionRole::Leader);
652
653 info!("Wait for lease expired");
654 tokio::time::sleep(Duration::from_millis(200)).await;
656 assert!(alive_keeper.find_handle(region_id).await.is_some());
657 assert_eq!(engine.role(region_id).unwrap(), RegionRole::Follower);
658
659 let deadline = alive_keeper.deadline(region_id).await.unwrap();
660 assert!(deadline > Instant::now() + Duration::from_secs(86400 * 365 * 29));
661 }
662
663 #[tokio::test(flavor = "multi_thread")]
664 async fn countdown_task() {
665 let region_server = mock_region_server();
666
667 let countdown_handle =
668 CountdownTaskHandle::new(region_server, None, RegionId::new(9999, 2));
669
670 assert!(
672 countdown_handle.deadline().await.unwrap()
673 > Instant::now() + Duration::from_secs(86400 * 365 * 29)
674 );
675
676 let heartbeat_interval_millis = 100;
679 countdown_handle.start(heartbeat_interval_millis).await;
680 assert!(
681 countdown_handle.deadline().await.unwrap()
682 > Instant::now() + Duration::from_millis(heartbeat_interval_millis * 3)
683 );
684 tokio::time::sleep(Duration::from_millis(heartbeat_interval_millis * 5)).await;
685
686 countdown_handle.start(heartbeat_interval_millis).await;
688 assert!(
689 countdown_handle.deadline().await.unwrap()
690 > Instant::now() + Duration::from_secs(86400 * 365 * 29)
691 );
692
693 countdown_handle
695 .reset_deadline(
696 RegionRole::Leader,
697 Instant::now() + Duration::from_millis(heartbeat_interval_millis * 5),
698 HashMap::new(),
699 )
700 .await;
701 assert!(
702 countdown_handle.deadline().await.unwrap()
703 > Instant::now() + Duration::from_millis(heartbeat_interval_millis * 4)
704 );
705 }
706
707 #[tokio::test(flavor = "multi_thread")]
708 async fn renew_staging_leader_keeps_region_in_staging() {
709 let mut region_server = mock_region_server();
710 let mut engine_env = TestEnv::with_prefix("region-alive-keeper-staging").await;
711 let engine = engine_env.create_engine(MitoConfig::default()).await;
712 let engine = Arc::new(engine);
713 region_server.register_engine(engine.clone());
714
715 let alive_keeper = Arc::new(RegionAliveKeeper::new(
716 region_server.clone(),
717 None,
718 Duration::from_millis(100),
719 ));
720
721 let region_id = RegionId::new(1024, 2);
722 region_server
723 .handle_request(
724 region_id,
725 RegionRequest::Create(CreateRequestBuilder::new().build()),
726 )
727 .await
728 .unwrap();
729 region_server
730 .handle_request(
731 region_id,
732 RegionRequest::EnterStaging(EnterStagingRequest {
733 partition_directive: StagingPartitionDirective::RejectAllWrites,
734 }),
735 )
736 .await
737 .unwrap();
738
739 alive_keeper.register_region(region_id).await;
740 alive_keeper
741 .renew_region_leases(
742 &[GrantedRegion {
743 region_id: region_id.as_u64(),
744 role: api::v1::meta::RegionRole::StagingLeader.into(),
745 extensions: HashMap::new(),
746 }],
747 Instant::now() + Duration::from_millis(3000),
748 )
749 .await;
750
751 assert_eq!(engine.role(region_id).unwrap(), RegionRole::StagingLeader);
752 }
753
754 #[tokio::test(flavor = "multi_thread")]
755 async fn renew_staging_leader_exit_into_leader() {
756 common_telemetry::init_default_ut_logging();
757 let mut region_server = mock_region_server();
758 let mut engine_env = TestEnv::with_prefix("region-alive-keeper-staging-exit").await;
759 let engine = engine_env.create_engine(MitoConfig::default()).await;
760 let engine = Arc::new(engine);
761 region_server.register_engine(engine.clone());
762
763 let alive_keeper = Arc::new(RegionAliveKeeper::new(
764 region_server.clone(),
765 None,
766 Duration::from_millis(100),
767 ));
768
769 let region_id = RegionId::new(1024, 2);
770 region_server
771 .handle_request(
772 region_id,
773 RegionRequest::Create(CreateRequestBuilder::new().build()),
774 )
775 .await
776 .unwrap();
777 region_server
778 .handle_request(
779 region_id,
780 RegionRequest::EnterStaging(EnterStagingRequest {
781 partition_directive: StagingPartitionDirective::RejectAllWrites,
782 }),
783 )
784 .await
785 .unwrap();
786
787 alive_keeper.register_region(region_id).await;
788 alive_keeper
789 .renew_region_leases(
790 &[GrantedRegion {
791 region_id: region_id.as_u64(),
792 role: api::v1::meta::RegionRole::Leader.into(),
793 extensions: HashMap::new(),
794 }],
795 Instant::now() + Duration::from_millis(3000),
796 )
797 .await;
798
799 tokio::time::sleep(Duration::from_millis(100)).await;
800 assert_eq!(engine.role(region_id).unwrap(), RegionRole::Leader);
801 }
802
803 #[tokio::test(flavor = "multi_thread")]
804 async fn renew_staging_leader_does_not_promote_normal_leader_into_staging() {
805 let mut region_server = mock_region_server();
806 let mut engine_env = TestEnv::with_prefix("region-alive-keeper-non-staging").await;
807 let engine = engine_env.create_engine(MitoConfig::default()).await;
808 let engine = Arc::new(engine);
809 region_server.register_engine(engine.clone());
810
811 let alive_keeper = Arc::new(RegionAliveKeeper::new(
812 region_server.clone(),
813 None,
814 Duration::from_millis(100),
815 ));
816
817 let region_id = RegionId::new(1024, 4);
818 region_server
819 .handle_request(
820 region_id,
821 RegionRequest::Create(CreateRequestBuilder::new().build()),
822 )
823 .await
824 .unwrap();
825 region_server
826 .set_region_role(region_id, RegionRole::Leader)
827 .unwrap();
828
829 alive_keeper.register_region(region_id).await;
830 alive_keeper
831 .renew_region_leases(
832 &[GrantedRegion {
833 region_id: region_id.as_u64(),
834 role: api::v1::meta::RegionRole::StagingLeader.into(),
835 extensions: HashMap::new(),
836 }],
837 Instant::now() + Duration::from_millis(3000),
838 )
839 .await;
840 tokio::time::sleep(Duration::from_millis(100)).await;
841 assert_eq!(engine.role(region_id).unwrap(), RegionRole::Leader);
842 }
843}