1mod catalog;
16mod registrations;
17mod remote_dyn_filter;
18
19use std::collections::HashMap;
20use std::fmt::Debug;
21use std::ops::Deref;
22use std::pin::Pin;
23use std::sync::atomic::{AtomicBool, Ordering};
24use std::sync::{Arc, RwLock};
25use std::task::{Context, Poll};
26use std::time::Duration;
27
28use api::region::RegionResponse;
29use api::v1::meta::TopicStat;
30use api::v1::region::sync_request::ManifestInfo;
31use api::v1::region::{
32 ListMetadataRequest, RegionResponse as RegionResponseV1, SyncRequest, region_request,
33};
34use api::v1::{ResponseHeader, Status};
35use arrow_flight::{FlightData, Ticket};
36use async_trait::async_trait;
37use bytes::Bytes;
38use common_error::ext::{BoxedError, ErrorExt};
39use common_error::status_code::StatusCode;
40use common_meta::datanode::TopicStatsReporter;
41use common_query::OutputData;
42use common_query::request::QueryRequest;
43use common_recordbatch::adapter::RecordBatchMetrics;
44use common_recordbatch::{OrderOption, RecordBatch, RecordBatchStream, SendableRecordBatchStream};
45use common_runtime::Runtime;
46use common_telemetry::tracing::{self, info_span};
47use common_telemetry::tracing_context::{FutureExt, TracingContext};
48use common_telemetry::{debug, error, info, warn};
49use dashmap::DashMap;
50use datafusion::datasource::TableProvider;
51use datafusion_common::tree_node::TreeNode;
52use datatypes::schema::SchemaRef;
53use either::Either;
54use futures_util::future::try_join_all;
55use futures_util::{Stream, StreamExt};
56use metric_engine::engine::MetricEngine;
57use mito2::engine::{MITO_ENGINE_NAME, MitoEngine};
58use prost::Message;
59use query::QueryEngineRef;
60pub use query::dummy_catalog::{
61 DummyCatalogList, DummyTableProviderFactory, TableProviderFactoryRef,
62};
63use query::options::should_collect_region_watermark_from_extensions;
64use serde_json;
65use servers::error::{
66 self as servers_error, ExecuteGrpcRequestSnafu, Result as ServerResult, SuspendedSnafu,
67};
68use servers::grpc::FlightCompression;
69use servers::grpc::flight::{
70 FlightCraft, FlightRecordBatchSource, FlightRecordBatchStream, FlightRecordBatchStreamInput,
71 TonicStream,
72};
73use servers::grpc::region_server::RegionServerHandler;
74use session::context::{
75 FLIGHT_METRICS_HEARTBEAT_INTERVAL, QueryContext, QueryContextBuilder, QueryContextRef,
76};
77use snafu::{OptionExt, ResultExt, ensure};
78use store_api::metric_engine_consts::{
79 FILE_ENGINE_NAME, LOGICAL_TABLE_METADATA_KEY, METRIC_ENGINE_NAME,
80};
81use store_api::region_engine::{
82 RegionEngineRef, RegionManifestInfo, RegionRole, RegionStatistic, RemapManifestsRequest,
83 RemapManifestsResponse, SetRegionRoleStateResponse, SettableRegionRoleState,
84 SyncRegionFromRequest,
85};
86use store_api::region_request::{
87 AffectedRows, BatchRegionDdlRequest, RegionCatchupRequest, RegionCloseRequest,
88 RegionOpenRequest, RegionRequest,
89};
90use store_api::storage::RegionId;
91use tokio::sync::{OwnedSemaphorePermit, Semaphore, mpsc};
92use tokio::time::{self, timeout};
93use tonic::{Request, Response, Result as TonicResult};
94
95use crate::datanode::record_shutdown_error;
96use crate::error::{
97 self, BuildRegionRequestsSnafu, ConcurrentQueryLimiterClosedSnafu,
98 ConcurrentQueryLimiterTimeoutSnafu, DataFusionSnafu, DecodeLogicalPlanSnafu,
99 ExecuteLogicalPlanSnafu, FindLogicalRegionsSnafu, GetRegionMetadataSnafu,
100 HandleBatchDdlRequestSnafu, HandleBatchOpenRequestSnafu, HandleRegionRequestSnafu,
101 NewPlanDecoderSnafu, RegionEngineNotFoundSnafu, RegionNotFoundSnafu, RegionNotReadySnafu,
102 Result, RuntimeJoinSnafu, SerializeJsonSnafu, StopRegionEngineSnafu, UnexpectedSnafu,
103 UnsupportedOutputSnafu,
104};
105use crate::event_listener::RegionServerEventListenerRef;
106use crate::query_stream::QueryRuntimeStream;
107use crate::region_server::catalog::{NameAwareCatalogList, NameAwareDataSourceInjectorBuilder};
108use crate::region_server::registrations::RemoteDynFilterRegistry;
109use crate::region_server::remote_dyn_filter::wrap_remote_dyn_filter_guarded_stream;
110
111const QUERY_RUNTIME_STREAM_BUFFER_SIZE: usize = 8;
112
113#[derive(Clone)]
114pub struct RegionServer {
115 inner: Arc<RegionServerInner>,
116 flight_compression: FlightCompression,
117 suspend: Arc<AtomicBool>,
118}
119
120pub struct RegionStat {
121 pub region_id: RegionId,
122 pub engine: String,
123 pub role: RegionRole,
124}
125
126impl RegionServer {
127 pub fn new(
128 query_engine: QueryEngineRef,
129 runtime: Runtime,
130 event_listener: RegionServerEventListenerRef,
131 flight_compression: FlightCompression,
132 ) -> Self {
133 Self::with_table_provider(
134 query_engine,
135 runtime,
136 event_listener,
137 Arc::new(DummyTableProviderFactory),
138 0,
139 Duration::from_millis(0),
140 flight_compression,
141 )
142 }
143
144 pub fn with_table_provider(
145 query_engine: QueryEngineRef,
146 runtime: Runtime,
147 event_listener: RegionServerEventListenerRef,
148 table_provider_factory: TableProviderFactoryRef,
149 max_concurrent_queries: usize,
150 concurrent_query_limiter_timeout: Duration,
151 flight_compression: FlightCompression,
152 ) -> Self {
153 Self {
154 inner: Arc::new(RegionServerInner::new(
155 query_engine,
156 runtime,
157 event_listener,
158 table_provider_factory,
159 RegionServerParallelism::from_opts(
160 max_concurrent_queries,
161 concurrent_query_limiter_timeout,
162 ),
163 )),
164 flight_compression,
165 suspend: Arc::new(AtomicBool::new(false)),
166 }
167 }
168
169 pub fn register_engine(&mut self, engine: RegionEngineRef) {
171 self.inner.register_engine(engine);
172 }
173
174 pub fn set_topic_stats_reporter(&mut self, topic_stats_reporter: Box<dyn TopicStatsReporter>) {
176 self.inner.set_topic_stats_reporter(topic_stats_reporter);
177 }
178
179 pub fn find_engine(&self, region_id: RegionId) -> Result<Option<RegionEngineRef>> {
181 match self.inner.get_engine(region_id, &RegionChange::None) {
182 Ok(CurrentEngine::Engine(engine)) => Ok(Some(engine)),
183 Ok(CurrentEngine::EarlyReturn(_)) => Ok(None),
184 Err(error::Error::RegionNotFound { .. }) => Ok(None),
185 Err(err) => Err(err),
186 }
187 }
188
189 pub fn mito_engine(&self) -> Option<MitoEngine> {
191 if let Some(mito) = self.inner.mito_engine.read().unwrap().clone() {
192 Some(mito)
193 } else {
194 self.inner
195 .engines
196 .read()
197 .unwrap()
198 .get(MITO_ENGINE_NAME)
199 .cloned()
200 .and_then(|e| {
201 let mito = e.as_any().downcast_ref::<MitoEngine>().cloned();
202 if mito.is_none() {
203 warn!("Mito engine not found in region server engines");
204 }
205 mito
206 })
207 }
208 }
209
210 #[tracing::instrument(skip_all)]
211 pub async fn handle_batch_open_requests(
212 &self,
213 parallelism: usize,
214 requests: Vec<(RegionId, RegionOpenRequest)>,
215 ignore_nonexistent_region: bool,
216 ) -> Result<Vec<RegionId>> {
217 self.inner
218 .handle_batch_open_requests(parallelism, requests, ignore_nonexistent_region)
219 .await
220 }
221
222 #[tracing::instrument(skip_all)]
223 pub async fn handle_batch_catchup_requests(
224 &self,
225 parallelism: usize,
226 requests: Vec<(RegionId, RegionCatchupRequest)>,
227 ) -> Result<Vec<(RegionId, std::result::Result<(), BoxedError>)>> {
228 self.inner
229 .handle_batch_catchup_requests(parallelism, requests)
230 .await
231 }
232
233 #[tracing::instrument(skip_all, fields(request_type = request.request_type()))]
234 pub async fn handle_request(
235 &self,
236 region_id: RegionId,
237 request: RegionRequest,
238 ) -> Result<RegionResponse> {
239 if RegionServerInner::is_ingest_request(&request) {
240 let inner = self.inner.clone();
241 let request_type = request.request_type();
242 return common_runtime::spawn_ingest(async move {
243 inner.handle_request(region_id, request).await
244 })
245 .await
246 .context(RuntimeJoinSnafu { request_type })?;
247 }
248
249 self.inner.handle_request(region_id, request).await
250 }
251
252 async fn table_provider(
254 &self,
255 region_id: RegionId,
256 ctx: Option<QueryContextRef>,
257 ) -> Result<Arc<dyn TableProvider>> {
258 let status = self
259 .inner
260 .region_map
261 .get(®ion_id)
262 .context(RegionNotFoundSnafu { region_id })?
263 .clone();
264 ensure!(
265 matches!(status, RegionEngineWithStatus::Ready(_)),
266 RegionNotReadySnafu { region_id }
267 );
268
269 let provider = self
270 .inner
271 .table_provider_factory
272 .create(region_id, status.into_engine(), ctx)
273 .await
274 .context(ExecuteLogicalPlanSnafu)?;
275
276 Ok(provider)
277 }
278
279 pub async fn handle_remote_read(
281 &self,
282 request: api::v1::region::QueryRequest,
283 query_ctx: QueryContextRef,
284 ) -> Result<SendableRecordBatchStream> {
285 self.handle_remote_read_inner(request, query_ctx).await
286 }
287
288 async fn handle_remote_read_inner(
289 &self,
290 request: api::v1::region::QueryRequest,
291 query_ctx: QueryContextRef,
292 ) -> Result<SendableRecordBatchStream> {
293 let permit = if let Some(p) = &self.inner.parallelism {
294 Some(p.acquire().await?)
295 } else {
296 None
297 };
298
299 let region_id = RegionId::from_u64(request.region_id);
300 let catalog_list = Arc::new(NameAwareCatalogList::new(
301 self.clone(),
302 region_id,
303 query_ctx.clone(),
304 ));
305
306 if query_ctx.explain_verbose() {
307 common_telemetry::info!("Handle remote read for region: {}", region_id);
308 }
309
310 let decoder = self
311 .inner
312 .query_engine
313 .engine_context(query_ctx.clone())
314 .new_plan_decoder()
315 .context(NewPlanDecoderSnafu)?;
316
317 let plan = decoder
318 .decode(Bytes::from(request.plan), catalog_list, false)
319 .await
320 .context(DecodeLogicalPlanSnafu)?;
321
322 let cleanup = self.register_initial_remote_dyn_filter_cleanup(&query_ctx, region_id);
323
324 let stream = self
325 .inner
326 .handle_read(
327 QueryRequest {
328 header: request.header,
329 region_id,
330 plan,
331 },
332 query_ctx.clone(),
333 )
334 .await?;
335
336 let stream = wrap_flow_region_watermark_stream(stream, region_id, &query_ctx);
337 let stream = if let Some(cleanup) = cleanup {
338 wrap_remote_dyn_filter_guarded_stream(stream, cleanup)
339 } else {
340 stream
341 };
342 Ok(maybe_guard_stream(stream, permit))
343 }
344
345 #[tracing::instrument(skip_all)]
346 pub async fn handle_read(&self, request: QueryRequest) -> Result<SendableRecordBatchStream> {
347 self.handle_read_inner(request).await
348 }
349
350 async fn handle_read_inner(&self, request: QueryRequest) -> Result<SendableRecordBatchStream> {
351 let permit = if let Some(p) = &self.inner.parallelism {
352 Some(p.acquire().await?)
353 } else {
354 None
355 };
356
357 let ctx = request
358 .header
359 .as_ref()
360 .map(QueryContext::try_from)
361 .transpose()
362 .map_err(|err| {
363 crate::error::InvalidQueryContextSnafu {
364 reason: err.to_string(),
365 }
366 .build()
367 })?;
368 let query_ctx = Arc::new(ctx.unwrap_or_else(|| QueryContextBuilder::default().build()));
369
370 let region_id = request.region_id;
371 let injector_builder = NameAwareDataSourceInjectorBuilder::from_plan(&request.plan)
372 .context(DataFusionSnafu)?;
373 let mut injector = injector_builder
374 .build(self, request.region_id, query_ctx.clone())
375 .await?;
376
377 let plan = request
378 .plan
379 .rewrite(&mut injector)
380 .context(DataFusionSnafu)?
381 .data;
382
383 let cleanup = self.register_initial_remote_dyn_filter_cleanup(&query_ctx, region_id);
384
385 let stream = self
386 .inner
387 .handle_read(QueryRequest { plan, ..request }, query_ctx.clone())
388 .await?;
389
390 let stream = wrap_flow_region_watermark_stream(stream, region_id, &query_ctx);
391 let stream = if let Some(cleanup) = cleanup {
392 wrap_remote_dyn_filter_guarded_stream(stream, cleanup)
393 } else {
394 stream
395 };
396 Ok(maybe_guard_stream(stream, permit))
397 }
398
399 pub fn reportable_regions(&self) -> Vec<RegionStat> {
403 self.inner
404 .region_map
405 .iter()
406 .filter_map(|e| {
407 let region_id = *e.key();
408 e.role(region_id).map(|role| RegionStat {
410 region_id,
411 engine: e.value().name().to_string(),
412 role,
413 })
414 })
415 .collect()
416 }
417
418 pub fn topic_stats(&self) -> Vec<TopicStat> {
420 let mut reporter = self.inner.topic_stats_reporter.write().unwrap();
421 let Some(reporter) = reporter.as_mut() else {
422 return vec![];
423 };
424 reporter
425 .reportable_topics()
426 .into_iter()
427 .map(|stat| TopicStat {
428 topic_name: stat.topic,
429 record_size: stat.record_size,
430 record_num: stat.record_num,
431 latest_entry_id: stat.latest_entry_id,
432 })
433 .collect()
434 }
435
436 pub fn is_region_leader(&self, region_id: RegionId) -> Option<bool> {
437 self.inner.region_map.get(®ion_id).and_then(|engine| {
438 engine.role(region_id).map(|role| match role {
439 RegionRole::Follower => false,
440 RegionRole::Leader => true,
441 RegionRole::StagingLeader => true,
442 RegionRole::DowngradingLeader => true,
443 })
444 })
445 }
446
447 pub fn set_region_role(&self, region_id: RegionId, role: RegionRole) -> Result<()> {
448 let engine = self
449 .inner
450 .region_map
451 .get(®ion_id)
452 .with_context(|| RegionNotFoundSnafu { region_id })?;
453 engine
454 .set_region_role(region_id, role)
455 .with_context(|_| HandleRegionRequestSnafu { region_id })
456 }
457
458 pub async fn set_region_role_state_gracefully(
468 &self,
469 region_id: RegionId,
470 state: SettableRegionRoleState,
471 ) -> Result<SetRegionRoleStateResponse> {
472 match self.inner.region_map.get(®ion_id) {
473 Some(engine) => Ok(engine
474 .set_region_role_state_gracefully(region_id, state)
475 .await
476 .with_context(|_| HandleRegionRequestSnafu { region_id })?),
477 None => Ok(SetRegionRoleStateResponse::NotFound),
478 }
479 }
480
481 pub fn runtime(&self) -> Runtime {
482 self.inner.runtime.clone()
483 }
484
485 pub fn region_statistic(&self, region_id: RegionId) -> Option<RegionStatistic> {
486 match self.inner.region_map.get(®ion_id) {
487 Some(e) => e.region_statistic(region_id),
488 None => None,
489 }
490 }
491
492 pub async fn stop(&self) -> Result<()> {
494 self.inner.stop().await
495 }
496
497 #[cfg(test)]
498 pub(crate) fn register_test_region(&self, region_id: RegionId, engine: RegionEngineRef) {
500 {
501 let mut engines = self.inner.engines.write().unwrap();
502 if !engines.contains_key(engine.name()) {
503 debug!("Registering test engine: {}", engine.name());
504 engines.insert(engine.name().to_string(), engine.clone());
505 }
506 }
507
508 self.inner
509 .region_map
510 .insert(region_id, RegionEngineWithStatus::Ready(engine));
511 }
512
513 async fn handle_batch_ddl_requests(
514 &self,
515 request: region_request::Body,
516 ) -> Result<RegionResponse> {
517 let batch_request = BatchRegionDdlRequest::try_from_request_body(request)
519 .context(BuildRegionRequestsSnafu)?
520 .unwrap();
521 let tracing_context = TracingContext::from_current_span();
522
523 let span = tracing_context.attach(info_span!("RegionServer::handle_batch_ddl_requests"));
524 self.inner
525 .handle_batch_request(batch_request)
526 .trace(span)
527 .await
528 }
529
530 async fn handle_requests_in_parallel(
531 &self,
532 request: region_request::Body,
533 ) -> Result<RegionResponse> {
534 let requests =
535 RegionRequest::try_from_request_body(request).context(BuildRegionRequestsSnafu)?;
536
537 match self.try_handle_metric_batch_puts(requests).await? {
540 Either::Left(response) => Ok(response),
541 Either::Right(requests) => {
542 let tracing_context = TracingContext::from_current_span();
544 let join_tasks =
545 requests
546 .into_iter()
547 .map(|(region_id, req): (RegionId, RegionRequest)| {
548 let self_to_move = self;
549 let span = tracing_context.attach(info_span!(
550 "RegionServer::handle_region_request",
551 region_id = region_id.to_string()
552 ));
553 async move {
554 self_to_move
555 .handle_request(region_id, req)
556 .trace(span)
557 .await
558 }
559 });
560
561 let results = try_join_all(join_tasks).await?;
562 let mut affected_rows = 0;
563 let mut extensions = HashMap::new();
564 for result in results {
565 affected_rows += result.affected_rows;
566 extensions.extend(result.extensions);
567 }
568
569 Ok(RegionResponse {
570 affected_rows,
571 extensions,
572 metadata: Vec::new(),
573 })
574 }
575 }
576 }
577
578 async fn handle_requests_in_serial(
579 &self,
580 request: region_request::Body,
581 ) -> Result<RegionResponse> {
582 let requests =
583 RegionRequest::try_from_request_body(request).context(BuildRegionRequestsSnafu)?;
584 let tracing_context = TracingContext::from_current_span();
585
586 let mut affected_rows = 0;
587 let mut extensions = HashMap::new();
588 for (region_id, req) in requests {
589 let span = tracing_context.attach(info_span!(
590 "RegionServer::handle_region_request",
591 region_id = region_id.to_string()
592 ));
593 let result = self.handle_request(region_id, req).trace(span).await?;
594
595 affected_rows += result.affected_rows;
596 extensions.extend(result.extensions);
597 }
598
599 Ok(RegionResponse {
600 affected_rows,
601 extensions,
602 metadata: Vec::new(),
603 })
604 }
605
606 async fn try_handle_metric_batch_puts(
613 &self,
614 requests: Vec<(RegionId, RegionRequest)>,
615 ) -> Result<Either<RegionResponse, Vec<(RegionId, RegionRequest)>>> {
616 if requests.is_empty() {
617 return Ok(Either::Right(requests));
618 }
619
620 if !matches!(requests[0].1, RegionRequest::Put(_)) {
622 return Ok(Either::Right(requests));
623 }
624 let first_region_id = requests[0].0;
625 let request_type = requests[0].1.request_type();
626
627 let engine = match self
631 .inner
632 .get_engine(first_region_id, &RegionChange::None)?
633 {
634 CurrentEngine::Engine(e) => e,
635 _ => return Ok(Either::Right(requests)),
636 };
637
638 if engine.name() != METRIC_ENGINE_NAME {
639 return Ok(Either::Right(requests));
640 }
641
642 let mut all_puts = true;
644 for (_, req) in &requests {
645 if !matches!(req, RegionRequest::Put(_)) {
646 all_puts = false;
647 break;
648 }
649 }
650
651 if !all_puts {
652 return Ok(Either::Right(requests));
653 }
654
655 let put_requests = requests.into_iter().map(|(region_id, req)| {
657 if let RegionRequest::Put(put) = req {
658 (region_id, put)
659 } else {
660 unreachable!("Already checked all are Put")
661 }
662 });
663
664 let metric_engine = engine
666 .as_any()
667 .downcast_ref::<MetricEngine>()
668 .context(UnexpectedSnafu {
669 violated: "Failed to downcast to MetricEngine",
670 })?
671 .clone();
672
673 let tracing_context = TracingContext::from_current_span();
674 let batch_size = put_requests.len();
675 let span = tracing_context.attach(info_span!(
676 "RegionServer::handle_metric_batch_puts",
677 batch_size = batch_size,
678 ));
679 let result = common_runtime::spawn_ingest(async move {
680 metric_engine
681 .put_regions_batch(put_requests)
682 .trace(span)
683 .await
684 })
685 .await
686 .context(RuntimeJoinSnafu { request_type })?
687 .map_err(BoxedError::new)
688 .context(HandleRegionRequestSnafu {
689 region_id: first_region_id,
690 });
691
692 match result {
693 Ok(total_affected) => {
694 crate::metrics::REGION_CHANGED_ROW_COUNT
695 .with_label_values(&[request_type])
696 .inc_by(total_affected as u64);
697 Ok(Either::Left(RegionResponse::new(total_affected)))
698 }
699 Err(err) => {
700 crate::metrics::REGION_SERVER_INSERT_FAIL_COUNT
701 .with_label_values(&[request_type, err.status_code().as_ref()])
702 .inc_by(batch_size as u64);
703 Err(err)
704 }
705 }
706 }
707
708 async fn handle_sync_region_request(&self, request: &SyncRequest) -> Result<RegionResponse> {
709 let region_id = RegionId::from_u64(request.region_id);
710 let manifest_info = request
711 .manifest_info
712 .context(error::MissingRequiredFieldSnafu {
713 name: "manifest_info",
714 })?;
715
716 let manifest_info = match manifest_info {
717 ManifestInfo::MitoManifestInfo(info) => {
718 RegionManifestInfo::mito(info.data_manifest_version, 0, 0)
719 }
720 ManifestInfo::MetricManifestInfo(info) => RegionManifestInfo::metric(
721 info.data_manifest_version,
722 0,
723 info.metadata_manifest_version,
724 0,
725 ),
726 };
727
728 let tracing_context = TracingContext::from_current_span();
729 let span = tracing_context.attach(info_span!("RegionServer::handle_sync_region_request"));
730
731 self.sync_region(
732 region_id,
733 SyncRegionFromRequest::from_manifest(manifest_info),
734 )
735 .trace(span)
736 .await
737 .map(|_| RegionResponse::new(AffectedRows::default()))
738 }
739
740 #[tracing::instrument(skip_all)]
745 async fn handle_list_metadata_request(
746 &self,
747 request: &ListMetadataRequest,
748 ) -> Result<RegionResponse> {
749 let mut region_metadatas = Vec::new();
750 for region_id in &request.region_ids {
752 let region_id = RegionId::from_u64(*region_id);
753 let Some(engine) = self.find_engine(region_id)? else {
755 region_metadatas.push(None);
756 continue;
757 };
758
759 match engine.get_metadata(region_id).await {
760 Ok(metadata) => region_metadatas.push(Some(metadata)),
761 Err(err) => {
762 if err.status_code() == StatusCode::RegionNotFound {
763 region_metadatas.push(None);
764 } else {
765 Err(err).with_context(|_| GetRegionMetadataSnafu {
766 engine: engine.name(),
767 region_id,
768 })?;
769 }
770 }
771 }
772 }
773
774 let json_result = serde_json::to_vec(®ion_metadatas).context(SerializeJsonSnafu)?;
776
777 let response = RegionResponse::from_metadata(json_result);
778
779 Ok(response)
780 }
781
782 pub async fn sync_region(
784 &self,
785 region_id: RegionId,
786 request: SyncRegionFromRequest,
787 ) -> Result<()> {
788 let engine = match self.inner.get_engine(region_id, &RegionChange::None)? {
789 CurrentEngine::Engine(engine) => engine,
790 _ => {
791 return UnexpectedSnafu {
792 violated: "unexpected EarlyReturn engine status for a ready region",
793 }
794 .fail();
795 }
796 };
797
798 self.inner
799 .handle_sync_region(&engine, region_id, request)
800 .await
801 }
802
803 pub async fn remap_manifests(
805 &self,
806 request: RemapManifestsRequest,
807 ) -> Result<RemapManifestsResponse> {
808 let region_id = request.region_id;
809 let engine = match self.inner.get_engine(region_id, &RegionChange::None)? {
810 CurrentEngine::Engine(engine) => engine,
811 _ => {
812 return UnexpectedSnafu {
813 violated: "unexpected EarlyReturn engine status for a ready region",
814 }
815 .fail();
816 }
817 };
818
819 engine
820 .remap_manifests(request)
821 .await
822 .with_context(|_| HandleRegionRequestSnafu { region_id })
823 }
824
825 fn is_suspended(&self) -> bool {
826 self.suspend.load(Ordering::Relaxed)
827 }
828
829 pub(crate) fn suspend_state(&self) -> Arc<AtomicBool> {
830 self.suspend.clone()
831 }
832}
833
834fn wrap_flow_region_watermark_stream(
835 stream: SendableRecordBatchStream,
836 region_id: RegionId,
837 query_ctx: &QueryContextRef,
838) -> SendableRecordBatchStream {
839 if should_collect_region_watermark_from_extensions(&query_ctx.extensions())
840 && let Some(seq) = query_ctx.get_snapshot(region_id.as_u64())
841 {
842 Box::pin(RegionWatermarkStream::new(stream, region_id, seq)) as SendableRecordBatchStream
843 } else {
844 stream
845 }
846}
847
848struct RegionWatermarkStream {
850 stream: SendableRecordBatchStream,
851 region_id: u64,
852 snapshot_seq: u64,
853 finished: bool,
854}
855
856impl RegionWatermarkStream {
857 fn new(stream: SendableRecordBatchStream, region_id: RegionId, snapshot_seq: u64) -> Self {
858 Self {
859 stream,
860 region_id: region_id.as_u64(),
861 snapshot_seq,
862 finished: false,
863 }
864 }
865
866 fn merged_metrics(&self, mut metrics: RecordBatchMetrics) -> RecordBatchMetrics {
867 if metrics
868 .region_watermarks
869 .iter()
870 .any(|entry| entry.region_id == self.region_id)
871 {
872 return metrics;
873 }
874
875 metrics
876 .region_watermarks
877 .push(common_recordbatch::adapter::RegionWatermarkEntry {
878 region_id: self.region_id,
879 watermark: Some(self.snapshot_seq),
880 });
881 metrics
882 }
883}
884
885impl RecordBatchStream for RegionWatermarkStream {
886 fn name(&self) -> &str {
887 self.stream.name()
888 }
889
890 fn schema(&self) -> datatypes::schema::SchemaRef {
891 self.stream.schema()
892 }
893
894 fn output_ordering(&self) -> Option<&[OrderOption]> {
895 self.stream.output_ordering()
896 }
897
898 fn metrics(&self) -> Option<RecordBatchMetrics> {
899 let base = self.stream.metrics();
900 if !self.finished {
901 return base;
902 }
903
904 Some(self.merged_metrics(base.unwrap_or_default()))
905 }
906}
907
908impl Stream for RegionWatermarkStream {
909 type Item = common_recordbatch::error::Result<RecordBatch>;
910
911 fn size_hint(&self) -> (usize, Option<usize>) {
912 self.stream.size_hint()
913 }
914
915 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
916 match Pin::new(&mut self.stream).poll_next(cx) {
917 Poll::Ready(None) => {
918 self.finished = true;
919 Poll::Ready(None)
920 }
921 other => other,
922 }
923 }
924}
925
926#[async_trait]
927impl RegionServerHandler for RegionServer {
928 async fn handle(&self, request: region_request::Body) -> ServerResult<RegionResponseV1> {
929 let failed_requests_cnt = crate::metrics::REGION_SERVER_REQUEST_FAILURE_COUNT
930 .with_label_values(&[request.as_ref()]);
931 let response = match &request {
932 region_request::Body::Creates(_)
933 | region_request::Body::Drops(_)
934 | region_request::Body::Alters(_) => self.handle_batch_ddl_requests(request).await,
935 region_request::Body::Inserts(_) | region_request::Body::Deletes(_) => {
936 self.handle_requests_in_parallel(request).await
937 }
938 region_request::Body::Sync(sync_request) => {
939 self.handle_sync_region_request(sync_request).await
940 }
941 region_request::Body::ListMetadata(list_metadata_request) => {
942 self.handle_list_metadata_request(list_metadata_request)
943 .await
944 }
945 region_request::Body::RemoteDynFilter(remote_dyn_filter_request) => {
946 self.handle_remote_dyn_filter_request(remote_dyn_filter_request)
947 .await
948 }
949 _ => self.handle_requests_in_serial(request).await,
950 }
951 .map_err(BoxedError::new)
952 .inspect_err(|_| {
953 failed_requests_cnt.inc();
954 })
955 .context(ExecuteGrpcRequestSnafu)?;
956
957 Ok(RegionResponseV1 {
958 header: Some(ResponseHeader {
959 status: Some(Status {
960 status_code: StatusCode::Success as _,
961 ..Default::default()
962 }),
963 }),
964 affected_rows: response.affected_rows as _,
965 extensions: response.extensions,
966 metadata: response.metadata,
967 })
968 }
969}
970
971#[async_trait]
972impl FlightCraft for RegionServer {
973 async fn do_get(
974 &self,
975 request: Request<Ticket>,
976 ) -> TonicResult<Response<TonicStream<FlightData>>> {
977 ensure!(!self.is_suspended(), SuspendedSnafu);
978
979 let ticket = request.into_inner().ticket;
980 let request = api::v1::region::QueryRequest::decode(ticket.as_ref())
981 .context(servers_error::InvalidFlightTicketSnafu)?;
982 let tracing_context = request
983 .header
984 .as_ref()
985 .map(|h| TracingContext::from_w3c(&h.tracing_context))
986 .unwrap_or_default();
987 let query_ctx = request
988 .header
989 .as_ref()
990 .map(QueryContext::try_from)
991 .transpose()
992 .map_err(|err| {
993 servers_error::InvalidParameterSnafu {
994 reason: err.to_string(),
995 }
996 .build()
997 })?
998 .map(Arc::new)
999 .unwrap_or(QueryContext::arc());
1000
1001 let region_server = self.clone();
1002 let initializer_query_ctx = query_ctx.clone();
1003 let initializer_tracing_context = tracing_context.clone();
1004 let initializer = async move {
1005 region_server
1006 .handle_remote_read(request, initializer_query_ctx)
1007 .trace(initializer_tracing_context.attach(info_span!("RegionServer::handle_read")))
1008 .await
1009 .map_err(Into::into)
1010 };
1011
1012 let stream = Box::pin(FlightRecordBatchStream::new(
1013 FlightRecordBatchStreamInput::initializer(async move {
1014 initializer
1015 .await
1016 .map(FlightRecordBatchSource::RecordBatches)
1017 }),
1018 tracing_context,
1019 self.flight_compression,
1020 query_ctx,
1021 ));
1022 Ok(Response::new(stream))
1023 }
1024}
1025
1026#[derive(Clone)]
1027enum RegionEngineWithStatus {
1028 Registering(RegionEngineRef),
1030 Deregistering(RegionEngineRef),
1032 Ready(RegionEngineRef),
1034}
1035
1036impl RegionEngineWithStatus {
1037 pub fn into_engine(self) -> RegionEngineRef {
1039 match self {
1040 RegionEngineWithStatus::Registering(engine) => engine,
1041 RegionEngineWithStatus::Deregistering(engine) => engine,
1042 RegionEngineWithStatus::Ready(engine) => engine,
1043 }
1044 }
1045}
1046
1047impl Deref for RegionEngineWithStatus {
1048 type Target = RegionEngineRef;
1049
1050 fn deref(&self) -> &Self::Target {
1051 match self {
1052 RegionEngineWithStatus::Registering(engine) => engine,
1053 RegionEngineWithStatus::Deregistering(engine) => engine,
1054 RegionEngineWithStatus::Ready(engine) => engine,
1055 }
1056 }
1057}
1058
1059struct RegionServerInner {
1060 engines: RwLock<HashMap<String, RegionEngineRef>>,
1061 region_map: DashMap<RegionId, RegionEngineWithStatus>,
1062 query_engine: QueryEngineRef,
1063 runtime: Runtime,
1064 event_listener: RegionServerEventListenerRef,
1065 table_provider_factory: TableProviderFactoryRef,
1066 parallelism: Option<RegionServerParallelism>,
1069 topic_stats_reporter: RwLock<Option<Box<dyn TopicStatsReporter>>>,
1071 mito_engine: RwLock<Option<MitoEngine>>,
1075 initial_remote_dyn_filter_registrations: RemoteDynFilterRegistry,
1078}
1079
1080struct RegionServerParallelism {
1081 semaphore: Arc<Semaphore>,
1082 timeout: Duration,
1083}
1084
1085impl RegionServerParallelism {
1086 pub fn from_opts(
1087 max_concurrent_queries: usize,
1088 concurrent_query_limiter_timeout: Duration,
1089 ) -> Option<Self> {
1090 if max_concurrent_queries == 0 {
1091 return None;
1092 }
1093 Some(RegionServerParallelism {
1094 semaphore: Arc::new(Semaphore::new(max_concurrent_queries)),
1095 timeout: concurrent_query_limiter_timeout,
1096 })
1097 }
1098
1099 pub async fn acquire(&self) -> Result<OwnedSemaphorePermit> {
1100 timeout(self.timeout, self.semaphore.clone().acquire_owned())
1101 .await
1102 .context(ConcurrentQueryLimiterTimeoutSnafu)?
1103 .context(ConcurrentQueryLimiterClosedSnafu)
1104 }
1105}
1106
1107struct PermitGuardedStream {
1111 inner: SendableRecordBatchStream,
1112 _permit: OwnedSemaphorePermit,
1113}
1114
1115impl RecordBatchStream for PermitGuardedStream {
1116 fn name(&self) -> &str {
1117 self.inner.name()
1118 }
1119
1120 fn schema(&self) -> SchemaRef {
1121 self.inner.schema()
1122 }
1123
1124 fn output_ordering(&self) -> Option<&[OrderOption]> {
1125 self.inner.output_ordering()
1126 }
1127
1128 fn metrics(&self) -> Option<RecordBatchMetrics> {
1129 self.inner.metrics()
1130 }
1131}
1132
1133impl Stream for PermitGuardedStream {
1134 type Item = common_recordbatch::error::Result<RecordBatch>;
1135
1136 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
1137 self.inner.as_mut().poll_next(cx)
1138 }
1139}
1140
1141fn maybe_guard_stream(
1144 stream: SendableRecordBatchStream,
1145 permit: Option<OwnedSemaphorePermit>,
1146) -> SendableRecordBatchStream {
1147 match permit {
1148 Some(permit) => Box::pin(PermitGuardedStream {
1149 inner: stream,
1150 _permit: permit,
1151 }),
1152 None => stream,
1153 }
1154}
1155
1156enum CurrentEngine {
1157 Engine(RegionEngineRef),
1158 EarlyReturn(AffectedRows),
1159}
1160
1161impl Debug for CurrentEngine {
1162 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1163 match self {
1164 CurrentEngine::Engine(engine) => f
1165 .debug_struct("CurrentEngine")
1166 .field("engine", &engine.name())
1167 .finish(),
1168 CurrentEngine::EarlyReturn(rows) => f
1169 .debug_struct("CurrentEngine")
1170 .field("return", rows)
1171 .finish(),
1172 }
1173 }
1174}
1175
1176impl RegionServerInner {
1177 pub fn new(
1178 query_engine: QueryEngineRef,
1179 runtime: Runtime,
1180 event_listener: RegionServerEventListenerRef,
1181 table_provider_factory: TableProviderFactoryRef,
1182 parallelism: Option<RegionServerParallelism>,
1183 ) -> Self {
1184 Self {
1185 engines: RwLock::new(HashMap::new()),
1186 region_map: DashMap::new(),
1187 query_engine,
1188 runtime,
1189 event_listener,
1190 table_provider_factory,
1191 parallelism,
1192 topic_stats_reporter: RwLock::new(None),
1193 mito_engine: RwLock::new(None),
1194 initial_remote_dyn_filter_registrations: RemoteDynFilterRegistry::new(),
1195 }
1196 }
1197
1198 pub fn register_engine(&self, engine: RegionEngineRef) {
1199 let engine_name = engine.name();
1200 if engine_name == MITO_ENGINE_NAME
1201 && let Some(mito_engine) = engine.as_any().downcast_ref::<MitoEngine>()
1202 {
1203 *self.mito_engine.write().unwrap() = Some(mito_engine.clone());
1204 }
1205
1206 info!("Region Engine {engine_name} is registered");
1207 self.engines
1208 .write()
1209 .unwrap()
1210 .insert(engine_name.to_string(), engine);
1211 }
1212
1213 pub fn set_topic_stats_reporter(&self, topic_stats_reporter: Box<dyn TopicStatsReporter>) {
1214 info!("Set topic stats reporter");
1215 *self.topic_stats_reporter.write().unwrap() = Some(topic_stats_reporter);
1216 }
1217
1218 fn is_ingest_request(request: &RegionRequest) -> bool {
1219 matches!(
1220 request,
1221 RegionRequest::Put(_) | RegionRequest::Delete(_) | RegionRequest::BulkInserts(_)
1222 )
1223 }
1224
1225 fn get_engine(
1226 &self,
1227 region_id: RegionId,
1228 region_change: &RegionChange,
1229 ) -> Result<CurrentEngine> {
1230 let current_region_status = self.region_map.get(®ion_id);
1231
1232 let engine = match region_change {
1233 RegionChange::Register(attribute) => match current_region_status {
1234 Some(status) => match status.clone() {
1235 RegionEngineWithStatus::Registering(engine) => engine,
1236 RegionEngineWithStatus::Deregistering(_) => {
1237 return error::RegionBusySnafu { region_id }.fail();
1238 }
1239 RegionEngineWithStatus::Ready(_) => status.clone().into_engine(),
1240 },
1241 _ => self
1242 .engines
1243 .read()
1244 .unwrap()
1245 .get(attribute.engine())
1246 .with_context(|| RegionEngineNotFoundSnafu {
1247 name: attribute.engine(),
1248 })?
1249 .clone(),
1250 },
1251 RegionChange::OfflineCleanup(attribute) => match current_region_status {
1252 Some(status) => match status.clone() {
1253 RegionEngineWithStatus::Registering(_)
1254 | RegionEngineWithStatus::Deregistering(_)
1255 | RegionEngineWithStatus::Ready(_) => {
1256 return error::RegionBusySnafu { region_id }.fail();
1257 }
1258 },
1259 None => self
1260 .engines
1261 .read()
1262 .unwrap()
1263 .get(attribute.engine())
1264 .with_context(|| RegionEngineNotFoundSnafu {
1265 name: attribute.engine(),
1266 })?
1267 .clone(),
1268 },
1269 RegionChange::Deregisters => match current_region_status {
1270 Some(status) => match status.clone() {
1271 RegionEngineWithStatus::Registering(_) => {
1272 return error::RegionBusySnafu { region_id }.fail();
1273 }
1274 RegionEngineWithStatus::Deregistering(_) => {
1275 return Ok(CurrentEngine::EarlyReturn(0));
1276 }
1277 RegionEngineWithStatus::Ready(_) => status.clone().into_engine(),
1278 },
1279 None => return Ok(CurrentEngine::EarlyReturn(0)),
1280 },
1281 RegionChange::None | RegionChange::Catchup | RegionChange::Ingest => {
1282 match current_region_status {
1283 Some(status) => match status.clone() {
1284 RegionEngineWithStatus::Registering(_) => {
1285 return error::RegionNotReadySnafu { region_id }.fail();
1286 }
1287 RegionEngineWithStatus::Deregistering(_) => {
1288 return error::RegionNotFoundSnafu { region_id }.fail();
1289 }
1290 RegionEngineWithStatus::Ready(engine) => engine,
1291 },
1292 None => return error::RegionNotFoundSnafu { region_id }.fail(),
1293 }
1294 }
1295 };
1296
1297 Ok(CurrentEngine::Engine(engine))
1298 }
1299
1300 async fn handle_batch_open_requests_inner(
1301 &self,
1302 engine: RegionEngineRef,
1303 parallelism: usize,
1304 requests: Vec<(RegionId, RegionOpenRequest)>,
1305 ignore_nonexistent_region: bool,
1306 ) -> Result<Vec<RegionId>> {
1307 let request_count = requests.len();
1308 let region_changes = requests
1309 .iter()
1310 .map(|(region_id, open)| {
1311 let attribute = parse_region_attribute(&open.engine, &open.options)?;
1312 Ok((*region_id, RegionChange::Register(attribute)))
1313 })
1314 .collect::<Result<HashMap<_, _>>>()
1315 .inspect_err(|err| {
1316 record_region_open_failures(engine.name(), err.status_code(), request_count);
1317 })?;
1318
1319 for (®ion_id, region_change) in ®ion_changes {
1320 self.set_region_status_not_ready(region_id, &engine, region_change)
1321 }
1322
1323 let mut open_regions = Vec::with_capacity(requests.len());
1324 let mut errors = vec![];
1325 match engine
1326 .handle_batch_open_requests(parallelism, requests)
1327 .await
1328 .with_context(|_| HandleBatchOpenRequestSnafu)
1329 {
1330 Ok(results) => {
1331 for (region_id, result) in results {
1332 let region_change = ®ion_changes[®ion_id];
1333 match result {
1334 Ok(_) => {
1335 if let Err(e) = self
1336 .set_region_status_ready(region_id, engine.clone(), *region_change)
1337 .await
1338 {
1339 error!(e; "Failed to set region to ready: {}", region_id);
1340 record_region_open_failures(engine.name(), e.status_code(), 1);
1341 errors.push(BoxedError::new(e));
1342 } else {
1343 open_regions.push(region_id)
1344 }
1345 }
1346 Err(e) => {
1347 self.unset_region_status(region_id, &engine, *region_change);
1348 if e.status_code() == StatusCode::RegionNotFound
1349 && ignore_nonexistent_region
1350 {
1351 warn!("Region {} not found, ignore it, source: {:?}", region_id, e);
1352 } else {
1353 error!(e; "Failed to open region: {}", region_id);
1354 record_region_open_failures(engine.name(), e.status_code(), 1);
1355 errors.push(e);
1356 }
1357 }
1358 }
1359 }
1360 }
1361 Err(e) => {
1362 for (®ion_id, region_change) in ®ion_changes {
1363 self.unset_region_status(region_id, &engine, *region_change);
1364 }
1365 error!(e; "Failed to open batch regions");
1366 record_region_open_failures(engine.name(), e.status_code(), request_count);
1367 errors.push(BoxedError::new(e));
1368 }
1369 }
1370
1371 if !errors.is_empty() {
1372 return Err(errors.swap_remove(0)).context(HandleBatchOpenRequestSnafu);
1374 }
1375
1376 Ok(open_regions)
1377 }
1378
1379 pub async fn handle_batch_open_requests(
1380 &self,
1381 parallelism: usize,
1382 requests: Vec<(RegionId, RegionOpenRequest)>,
1383 ignore_nonexistent_region: bool,
1384 ) -> Result<Vec<RegionId>> {
1385 let mut engine_grouped_requests: HashMap<String, Vec<_>> =
1386 HashMap::with_capacity(requests.len());
1387 for (region_id, request) in requests {
1388 if let Some(requests) = engine_grouped_requests.get_mut(&request.engine) {
1389 requests.push((region_id, request));
1390 } else {
1391 engine_grouped_requests.insert(request.engine.clone(), vec![(region_id, request)]);
1392 }
1393 }
1394
1395 let mut results = Vec::with_capacity(engine_grouped_requests.keys().len());
1396 for (engine, requests) in engine_grouped_requests {
1397 let engine = self
1398 .engines
1399 .read()
1400 .unwrap()
1401 .get(&engine)
1402 .with_context(|| RegionEngineNotFoundSnafu { name: &engine })
1403 .inspect_err(|err| {
1404 record_region_open_failures(&engine, err.status_code(), requests.len());
1405 })?
1406 .clone();
1407 results.push(
1408 self.handle_batch_open_requests_inner(
1409 engine,
1410 parallelism,
1411 requests,
1412 ignore_nonexistent_region,
1413 )
1414 .await,
1415 )
1416 }
1417
1418 Ok(results
1419 .into_iter()
1420 .collect::<Result<Vec<_>>>()?
1421 .into_iter()
1422 .flatten()
1423 .collect::<Vec<_>>())
1424 }
1425
1426 pub async fn handle_batch_catchup_requests_inner(
1427 &self,
1428 engine: RegionEngineRef,
1429 parallelism: usize,
1430 requests: Vec<(RegionId, RegionCatchupRequest)>,
1431 ) -> Result<Vec<(RegionId, std::result::Result<(), BoxedError>)>> {
1432 for (region_id, _) in &requests {
1433 self.set_region_status_not_ready(*region_id, &engine, &RegionChange::Catchup);
1434 }
1435 let region_ids = requests
1436 .iter()
1437 .map(|(region_id, _)| *region_id)
1438 .collect::<Vec<_>>();
1439 let mut responses = Vec::with_capacity(requests.len());
1440 match engine
1441 .handle_batch_catchup_requests(parallelism, requests)
1442 .await
1443 {
1444 Ok(results) => {
1445 for (region_id, result) in results {
1446 match result {
1447 Ok(_) => {
1448 if let Err(e) = self
1449 .set_region_status_ready(
1450 region_id,
1451 engine.clone(),
1452 RegionChange::Catchup,
1453 )
1454 .await
1455 {
1456 error!(e; "Failed to set region to ready: {}", region_id);
1457 responses.push((region_id, Err(BoxedError::new(e))));
1458 } else {
1459 responses.push((region_id, Ok(())));
1460 }
1461 }
1462 Err(e) => {
1463 self.unset_region_status(region_id, &engine, RegionChange::Catchup);
1464 error!(e; "Failed to catchup region: {}", region_id);
1465 responses.push((region_id, Err(e)));
1466 }
1467 }
1468 }
1469 }
1470 Err(e) => {
1471 for region_id in region_ids {
1472 self.unset_region_status(region_id, &engine, RegionChange::Catchup);
1473 }
1474 error!(e; "Failed to catchup batch regions");
1475 return error::UnexpectedSnafu {
1476 violated: format!("Failed to catchup batch regions: {:?}", e),
1477 }
1478 .fail();
1479 }
1480 }
1481
1482 Ok(responses)
1483 }
1484
1485 pub async fn handle_batch_catchup_requests(
1486 &self,
1487 parallelism: usize,
1488 requests: Vec<(RegionId, RegionCatchupRequest)>,
1489 ) -> Result<Vec<(RegionId, std::result::Result<(), BoxedError>)>> {
1490 let mut engine_grouped_requests: HashMap<String, Vec<_>> = HashMap::new();
1491
1492 let mut responses = Vec::with_capacity(requests.len());
1493 for (region_id, request) in requests {
1494 if let Ok(engine) = self.get_engine(region_id, &RegionChange::Catchup) {
1495 match engine {
1496 CurrentEngine::Engine(engine) => {
1497 engine_grouped_requests
1498 .entry(engine.name().to_string())
1499 .or_default()
1500 .push((region_id, request));
1501 }
1502 CurrentEngine::EarlyReturn(_) => {
1503 return error::UnexpectedSnafu {
1504 violated: format!("Unexpected engine type for region {}", region_id),
1505 }
1506 .fail();
1507 }
1508 }
1509 } else {
1510 responses.push((
1511 region_id,
1512 Err(BoxedError::new(
1513 error::RegionNotFoundSnafu { region_id }.build(),
1514 )),
1515 ));
1516 }
1517 }
1518
1519 for (engine, requests) in engine_grouped_requests {
1520 let engine = self
1521 .engines
1522 .read()
1523 .unwrap()
1524 .get(&engine)
1525 .with_context(|| RegionEngineNotFoundSnafu { name: &engine })?
1526 .clone();
1527 responses.extend(
1528 self.handle_batch_catchup_requests_inner(engine, parallelism, requests)
1529 .await?,
1530 );
1531 }
1532
1533 Ok(responses)
1534 }
1535
1536 pub async fn handle_batch_request(
1540 &self,
1541 batch_request: BatchRegionDdlRequest,
1542 ) -> Result<RegionResponse> {
1543 let region_changes = match &batch_request {
1544 BatchRegionDdlRequest::Create(requests) => requests
1545 .iter()
1546 .map(|(region_id, create)| {
1547 let attribute = parse_region_attribute(&create.engine, &create.options)?;
1548 Ok((*region_id, RegionChange::Register(attribute)))
1549 })
1550 .collect::<Result<Vec<_>>>()?,
1551 BatchRegionDdlRequest::Drop(requests) => requests
1552 .iter()
1553 .map(|(region_id, _)| (*region_id, RegionChange::Deregisters))
1554 .collect::<Vec<_>>(),
1555 BatchRegionDdlRequest::Alter(requests) => requests
1556 .iter()
1557 .map(|(region_id, _)| (*region_id, RegionChange::None))
1558 .collect::<Vec<_>>(),
1559 };
1560
1561 let (first_region_id, first_region_change) = region_changes.first().unwrap();
1564 let engine = match self.get_engine(*first_region_id, first_region_change)? {
1565 CurrentEngine::Engine(engine) => engine,
1566 CurrentEngine::EarlyReturn(rows) => return Ok(RegionResponse::new(rows)),
1567 };
1568
1569 for (region_id, region_change) in region_changes.iter() {
1570 self.set_region_status_not_ready(*region_id, &engine, region_change);
1571 }
1572
1573 let ddl_type = batch_request.request_type();
1574 let result = engine
1575 .handle_batch_ddl_requests(batch_request)
1576 .await
1577 .context(HandleBatchDdlRequestSnafu { ddl_type });
1578
1579 match result {
1580 Ok(result) => {
1581 for (region_id, region_change) in ®ion_changes {
1582 self.set_region_status_ready(*region_id, engine.clone(), *region_change)
1583 .await?;
1584 }
1585
1586 Ok(RegionResponse {
1587 affected_rows: result.affected_rows,
1588 extensions: result.extensions,
1589 metadata: Vec::new(),
1590 })
1591 }
1592 Err(err) => {
1593 for (region_id, region_change) in region_changes {
1594 self.unset_region_status(region_id, &engine, region_change);
1595 }
1596
1597 Err(err)
1598 }
1599 }
1600 }
1601
1602 pub async fn handle_request(
1603 &self,
1604 region_id: RegionId,
1605 request: RegionRequest,
1606 ) -> Result<RegionResponse> {
1607 let open_engine = match &request {
1608 RegionRequest::Open(open) => Some(open.engine.clone()),
1609 _ => None,
1610 };
1611 self.handle_request_inner(region_id, request)
1612 .await
1613 .inspect_err(|err| {
1614 if let Some(engine) = open_engine {
1615 record_region_open_failures(&engine, err.status_code(), 1);
1616 }
1617 })
1618 }
1619
1620 async fn handle_request_inner(
1621 &self,
1622 region_id: RegionId,
1623 request: RegionRequest,
1624 ) -> Result<RegionResponse> {
1625 let request_type = request.request_type();
1626 let _timer = crate::metrics::HANDLE_REGION_REQUEST_ELAPSED
1627 .with_label_values(&[request_type])
1628 .start_timer();
1629
1630 let region_change = match &request {
1631 RegionRequest::Create(create) => {
1632 let attribute = parse_region_attribute(&create.engine, &create.options)?;
1633 RegionChange::Register(attribute)
1634 }
1635 RegionRequest::Open(open) => {
1636 let attribute = parse_region_attribute(&open.engine, &open.options)?;
1637 RegionChange::Register(attribute)
1638 }
1639 RegionRequest::CleanUp(clean_up) => {
1640 let attribute = parse_region_attribute(&clean_up.engine, &clean_up.options)?;
1641 RegionChange::OfflineCleanup(attribute)
1642 }
1643 RegionRequest::Close(_) | RegionRequest::Drop(_) => RegionChange::Deregisters,
1644 RegionRequest::Put(_) | RegionRequest::Delete(_) | RegionRequest::BulkInserts(_) => {
1645 RegionChange::Ingest
1646 }
1647 RegionRequest::Alter(_)
1648 | RegionRequest::Flush(_)
1649 | RegionRequest::Compact(_)
1650 | RegionRequest::Truncate(_)
1651 | RegionRequest::BuildIndex(_)
1652 | RegionRequest::EnterStaging(_)
1653 | RegionRequest::ApplyStagingManifest(_) => RegionChange::None,
1654 RegionRequest::Catchup(_) => RegionChange::Catchup,
1655 };
1656
1657 let engine = match self.get_engine(region_id, ®ion_change)? {
1658 CurrentEngine::Engine(engine) => engine,
1659 CurrentEngine::EarlyReturn(rows) => return Ok(RegionResponse::new(rows)),
1660 };
1661
1662 self.set_region_status_not_ready(region_id, &engine, ®ion_change);
1664
1665 match engine
1666 .handle_request(region_id, request)
1667 .await
1668 .with_context(|_| HandleRegionRequestSnafu { region_id })
1669 {
1670 Ok(result) => {
1671 if matches!(region_change, RegionChange::Ingest) {
1673 crate::metrics::REGION_CHANGED_ROW_COUNT
1674 .with_label_values(&[request_type])
1675 .inc_by(result.affected_rows as u64);
1676 }
1677 self.set_region_status_ready(region_id, engine.clone(), region_change)
1679 .await?;
1680
1681 Ok(RegionResponse {
1682 affected_rows: result.affected_rows,
1683 extensions: result.extensions,
1684 metadata: Vec::new(),
1685 })
1686 }
1687 Err(err) => {
1688 if matches!(region_change, RegionChange::Ingest) {
1689 crate::metrics::REGION_SERVER_INSERT_FAIL_COUNT
1690 .with_label_values(&[request_type, err.status_code().as_ref()])
1691 .inc();
1692 }
1693 self.unset_region_status(region_id, &engine, region_change);
1695 Err(err)
1696 }
1697 }
1698 }
1699
1700 pub async fn handle_sync_region(
1702 &self,
1703 engine: &RegionEngineRef,
1704 region_id: RegionId,
1705 request: SyncRegionFromRequest,
1706 ) -> Result<()> {
1707 let Some(new_opened_regions) = engine
1708 .sync_region(region_id, request)
1709 .await
1710 .with_context(|_| HandleRegionRequestSnafu { region_id })?
1711 .new_opened_logical_region_ids()
1712 else {
1713 return Ok(());
1714 };
1715
1716 for region in &new_opened_regions {
1717 self.region_map
1718 .insert(*region, RegionEngineWithStatus::Ready(engine.clone()));
1719 }
1720 if !new_opened_regions.is_empty() {
1721 info!(
1722 region_id = %region_id,
1723 logical_region_count = new_opened_regions.len(),
1724 logical_regions = ?new_opened_regions,
1725 "Logical regions are registered"
1726 );
1727 }
1728
1729 Ok(())
1730 }
1731
1732 fn set_region_status_not_ready(
1733 &self,
1734 region_id: RegionId,
1735 engine: &RegionEngineRef,
1736 region_change: &RegionChange,
1737 ) {
1738 match region_change {
1739 RegionChange::Register(_) => {
1740 self.region_map.insert(
1741 region_id,
1742 RegionEngineWithStatus::Registering(engine.clone()),
1743 );
1744 }
1745 RegionChange::Deregisters => {
1746 self.region_map.insert(
1747 region_id,
1748 RegionEngineWithStatus::Deregistering(engine.clone()),
1749 );
1750 }
1751 _ => {}
1752 }
1753 }
1754
1755 fn unset_region_status(
1756 &self,
1757 region_id: RegionId,
1758 engine: &RegionEngineRef,
1759 region_change: RegionChange,
1760 ) {
1761 match region_change {
1762 RegionChange::None | RegionChange::Ingest | RegionChange::OfflineCleanup(_) => {}
1763 RegionChange::Register(_) => {
1764 self.region_map.remove(®ion_id);
1765 }
1766 RegionChange::Deregisters => {
1767 self.region_map
1768 .insert(region_id, RegionEngineWithStatus::Ready(engine.clone()));
1769 }
1770 RegionChange::Catchup => {}
1771 }
1772 }
1773
1774 async fn set_region_status_ready(
1775 &self,
1776 region_id: RegionId,
1777 engine: RegionEngineRef,
1778 region_change: RegionChange,
1779 ) -> Result<()> {
1780 let engine_type = engine.name();
1781 match region_change {
1782 RegionChange::None | RegionChange::Ingest | RegionChange::OfflineCleanup(_) => {}
1783 RegionChange::Register(attribute) => {
1784 info!(
1785 "Region {region_id} is registered to engine {}",
1786 attribute.engine()
1787 );
1788 self.region_map
1789 .insert(region_id, RegionEngineWithStatus::Ready(engine.clone()));
1790
1791 match attribute {
1792 RegionAttribute::Metric { physical } => {
1793 if physical {
1794 self.register_logical_regions(&engine, region_id).await?;
1796 self.event_listener.on_region_registered(region_id);
1798 }
1799 }
1800 RegionAttribute::Mito => self.event_listener.on_region_registered(region_id),
1801 RegionAttribute::File => {
1802 }
1804 }
1805 }
1806 RegionChange::Deregisters => {
1807 info!("Region {region_id} is deregistered from engine {engine_type}");
1808 self.region_map
1809 .remove(®ion_id)
1810 .map(|(id, engine)| engine.set_region_role(id, RegionRole::Follower));
1811 self.event_listener.on_region_deregistered(region_id);
1812 }
1813 RegionChange::Catchup => {
1814 if is_metric_engine(engine.name()) {
1815 self.register_logical_regions(&engine, region_id).await?;
1817 }
1818 }
1819 }
1820 Ok(())
1821 }
1822
1823 async fn register_logical_regions(
1824 &self,
1825 engine: &RegionEngineRef,
1826 physical_region_id: RegionId,
1827 ) -> Result<()> {
1828 let metric_engine =
1829 engine
1830 .as_any()
1831 .downcast_ref::<MetricEngine>()
1832 .context(UnexpectedSnafu {
1833 violated: format!(
1834 "expecting engine type '{}', actual '{}'",
1835 METRIC_ENGINE_NAME,
1836 engine.name(),
1837 ),
1838 })?;
1839
1840 let logical_regions = metric_engine
1841 .logical_regions(physical_region_id)
1842 .await
1843 .context(FindLogicalRegionsSnafu { physical_region_id })?;
1844
1845 for region in &logical_regions {
1846 self.region_map
1847 .insert(*region, RegionEngineWithStatus::Ready(engine.clone()));
1848 }
1849 if !logical_regions.is_empty() {
1850 info!(
1851 physical_region_id = %physical_region_id,
1852 logical_region_count = logical_regions.len(),
1853 logical_regions = ?logical_regions,
1854 "Logical regions are registered"
1855 );
1856 }
1857 Ok(())
1858 }
1859
1860 pub async fn handle_read(
1861 self: &Arc<Self>,
1862 request: QueryRequest,
1863 query_ctx: QueryContextRef,
1864 ) -> Result<SendableRecordBatchStream> {
1865 let live_analyze_metrics =
1866 query_ctx.explain_verbose() && query_ctx.live_analyze_metrics_enabled();
1867 let inner = self.clone();
1868 let mut stream = common_runtime::spawn_query(async move {
1869 inner.handle_read_inner(request, query_ctx).await
1870 })
1871 .await
1872 .context(RuntimeJoinSnafu {
1873 request_type: "read",
1874 })??;
1875 let schema = stream.schema();
1876 let output_ordering = stream.output_ordering().map(|ordering| ordering.to_vec());
1877
1878 let (sender, receiver) = mpsc::channel(QUERY_RUNTIME_STREAM_BUFFER_SIZE);
1879 let metrics = QueryRuntimeStream::metrics_store();
1880 let producer_metrics = metrics.clone();
1881
1882 let producer_handle = common_runtime::spawn_query(async move {
1883 if live_analyze_metrics {
1884 loop {
1885 match time::timeout(FLIGHT_METRICS_HEARTBEAT_INTERVAL, stream.next()).await {
1886 Ok(Some(batch)) => {
1887 *producer_metrics.write().unwrap() = stream.metrics();
1888 if sender.send(batch).await.is_err() {
1889 return;
1890 }
1891 }
1892 Ok(None) => break,
1893 Err(_) => {
1894 *producer_metrics.write().unwrap() = stream.metrics();
1895 }
1896 }
1897 }
1898 } else {
1899 while let Some(batch) = stream.next().await {
1900 *producer_metrics.write().unwrap() = stream.metrics();
1901 if sender.send(batch).await.is_err() {
1902 break;
1903 }
1904 }
1905 }
1906 *producer_metrics.write().unwrap() = stream.metrics();
1907 });
1908
1909 Ok(Box::pin(
1910 QueryRuntimeStream::new(schema, receiver)
1911 .with_output_ordering(output_ordering)
1912 .with_metrics_store(metrics)
1913 .with_producer_handle(producer_handle),
1914 ))
1915 }
1916
1917 async fn handle_read_inner(
1918 &self,
1919 request: QueryRequest,
1920 query_ctx: QueryContextRef,
1921 ) -> Result<SendableRecordBatchStream> {
1922 let result = self
1925 .query_engine
1926 .execute(request.plan, query_ctx)
1927 .await
1928 .context(ExecuteLogicalPlanSnafu)?;
1929
1930 match result.data {
1931 OutputData::AffectedRows(_) | OutputData::RecordBatches(_) => {
1932 UnsupportedOutputSnafu { expected: "stream" }.fail()
1933 }
1934 OutputData::Stream(stream) => Ok(stream),
1935 }
1936 }
1937
1938 async fn stop(&self) -> Result<()> {
1939 let regions = self
1947 .region_map
1948 .iter()
1949 .map(|x| (*x.key(), x.value().clone()))
1950 .collect::<Vec<_>>();
1951 let num_regions = regions.len();
1952
1953 for (region_id, engine) in regions {
1954 let closed = engine
1955 .handle_request(
1956 region_id,
1957 RegionRequest::Close(RegionCloseRequest::default()),
1958 )
1959 .await;
1960 match closed {
1961 Ok(_) => debug!("Region {region_id} is closed"),
1962 Err(e) => warn!("Failed to close region {region_id}, err: {e}"),
1963 }
1964 }
1965 self.region_map.clear();
1966 info!("closed {num_regions} regions");
1967
1968 drop(self.mito_engine.write().unwrap().take());
1969 let engines = self.engines.write().unwrap().drain().collect::<Vec<_>>();
1970 let mut first_error = None;
1971 for (engine_name, engine) in engines {
1972 let result = engine
1973 .stop()
1974 .await
1975 .context(StopRegionEngineSnafu { name: &engine_name });
1976 if result.is_ok() {
1977 info!("Region engine {engine_name} is stopped");
1978 }
1979 record_shutdown_error(&mut first_error, result);
1980 }
1981
1982 first_error.map_or(Ok(()), Err)
1983 }
1984}
1985
1986#[derive(Debug, Clone, Copy)]
1987enum RegionChange {
1988 None,
1989 Register(RegionAttribute),
1990 OfflineCleanup(RegionAttribute),
1991 Deregisters,
1992 Catchup,
1993 Ingest,
1994}
1995
1996fn is_metric_engine(engine: &str) -> bool {
1997 engine == METRIC_ENGINE_NAME
1998}
1999
2000fn record_region_open_failures(engine: &str, status_code: StatusCode, count: usize) {
2002 let engine = match engine {
2003 MITO_ENGINE_NAME | METRIC_ENGINE_NAME | FILE_ENGINE_NAME => engine,
2004 _ => "unknown",
2005 };
2006 crate::metrics::REGION_OPEN_FAILURES_TOTAL
2007 .with_label_values(&[engine, status_code.as_ref()])
2008 .inc_by(count as u64);
2009}
2010
2011fn parse_region_attribute(
2012 engine: &str,
2013 options: &HashMap<String, String>,
2014) -> Result<RegionAttribute> {
2015 match engine {
2016 MITO_ENGINE_NAME => Ok(RegionAttribute::Mito),
2017 METRIC_ENGINE_NAME => {
2018 let physical = !options.contains_key(LOGICAL_TABLE_METADATA_KEY);
2019
2020 Ok(RegionAttribute::Metric { physical })
2021 }
2022 FILE_ENGINE_NAME => Ok(RegionAttribute::File),
2023 _ => error::UnexpectedSnafu {
2024 violated: format!("Unknown engine: {}", engine),
2025 }
2026 .fail(),
2027 }
2028}
2029
2030#[derive(Debug, Clone, Copy)]
2031enum RegionAttribute {
2032 Mito,
2033 Metric { physical: bool },
2034 File,
2035}
2036
2037impl RegionAttribute {
2038 fn engine(&self) -> &'static str {
2039 match self {
2040 RegionAttribute::Mito => MITO_ENGINE_NAME,
2041 RegionAttribute::Metric { .. } => METRIC_ENGINE_NAME,
2042 RegionAttribute::File => FILE_ENGINE_NAME,
2043 }
2044 }
2045}
2046
2047#[cfg(test)]
2048mod tests {
2049 use std::assert_matches;
2050 use std::collections::HashMap;
2051 use std::sync::Arc;
2052
2053 use api::v1::{Rows, SemanticType};
2054 use common_error::ext::{ErrorExt, RetryHint};
2055 use common_recordbatch::RecordBatches;
2056 use common_recordbatch::adapter::{RecordBatchMetrics, RegionWatermarkEntry};
2057 use datatypes::prelude::{ConcreteDataType, VectorRef};
2058 use datatypes::schema::{ColumnSchema, Schema};
2059 use datatypes::vectors::Int32Vector;
2060 use futures_util::StreamExt;
2061 use mito2::test_util::CreateRequestBuilder;
2062 use query::options::FLOW_RETURN_REGION_SEQ;
2063 use store_api::metadata::{ColumnMetadata, RegionMetadata, RegionMetadataBuilder};
2064 use store_api::region_engine::RegionEngine;
2065 use store_api::region_request::{
2066 PathType, RegionCleanUpRequest, RegionCompactRequest, RegionDeleteRequest,
2067 RegionDropRequest, RegionOpenRequest, RegionPutRequest, RegionTruncateRequest,
2068 };
2069 use store_api::storage::RegionId;
2070
2071 use super::*;
2072 use crate::tests::{MockRegionEngine, mock_region_server};
2073
2074 #[test]
2075 fn test_is_ingest_request() {
2076 let rows = || Rows {
2077 schema: Vec::new(),
2078 rows: Vec::new(),
2079 };
2080
2081 assert!(RegionServerInner::is_ingest_request(&RegionRequest::Put(
2082 RegionPutRequest {
2083 skip_wal: false,
2084 rows: rows(),
2085 hint: None,
2086 partition_expr_version: None,
2087 },
2088 )));
2089 assert!(RegionServerInner::is_ingest_request(
2090 &RegionRequest::Delete(RegionDeleteRequest {
2091 rows: rows(),
2092 hint: None,
2093 partition_expr_version: None,
2094 },)
2095 ));
2096 assert!(!RegionServerInner::is_ingest_request(
2097 &RegionRequest::Compact(RegionCompactRequest::default()),
2098 ));
2099 }
2100
2101 fn single_value_stream() -> SendableRecordBatchStream {
2102 let schema = Arc::new(Schema::new(vec![ColumnSchema::new(
2103 "v",
2104 ConcreteDataType::int32_datatype(),
2105 false,
2106 )]));
2107 let values: VectorRef = Arc::new(Int32Vector::from_slice([1]));
2108 let batch = RecordBatch::new(schema.clone(), vec![values]).unwrap();
2109 RecordBatches::try_new(schema, vec![batch])
2110 .unwrap()
2111 .as_stream()
2112 }
2113
2114 #[tokio::test]
2115 async fn test_region_watermark_stream_only_sets_terminal_metrics() {
2116 let schema = Arc::new(Schema::new(vec![ColumnSchema::new(
2117 "v",
2118 ConcreteDataType::int32_datatype(),
2119 false,
2120 )]));
2121 let values: VectorRef = Arc::new(Int32Vector::from_slice([1, 2]));
2122 let batch = RecordBatch::new(schema.clone(), vec![values]).unwrap();
2123 let stream = RecordBatches::try_new(schema, vec![batch])
2124 .unwrap()
2125 .as_stream();
2126
2127 let region_id = RegionId::new(42, 7);
2128 let wrapped = RegionWatermarkStream::new(stream, region_id, 99);
2129 let mut pinned = Box::pin(wrapped);
2130
2131 assert!(pinned.as_ref().get_ref().metrics().is_none());
2132 while pinned.next().await.is_some() {}
2133
2134 let metrics = pinned.as_ref().get_ref().metrics().unwrap();
2135 assert_eq!(
2136 metrics.region_watermarks,
2137 vec![RegionWatermarkEntry {
2138 region_id: region_id.as_u64(),
2139 watermark: Some(99),
2140 }]
2141 );
2142 }
2143
2144 #[test]
2145 fn test_region_watermark_stream_preserves_unproved_watermark() {
2146 let schema = Arc::new(Schema::new(vec![ColumnSchema::new(
2147 "v",
2148 ConcreteDataType::int32_datatype(),
2149 false,
2150 )]));
2151 let values: VectorRef = Arc::new(Int32Vector::from_slice([1]));
2152 let batch = RecordBatch::new(schema.clone(), vec![values]).unwrap();
2153 let stream = RecordBatches::try_new(schema, vec![batch])
2154 .unwrap()
2155 .as_stream();
2156
2157 let region_id = RegionId::new(42, 7);
2158 let wrapped = RegionWatermarkStream::new(stream, region_id, 99);
2159 let metrics = RecordBatchMetrics {
2160 region_watermarks: vec![RegionWatermarkEntry {
2161 region_id: region_id.as_u64(),
2162 watermark: None,
2163 }],
2164 ..Default::default()
2165 };
2166
2167 let merged = wrapped.merged_metrics(metrics);
2168 assert_eq!(
2169 merged.region_watermarks,
2170 vec![RegionWatermarkEntry {
2171 region_id: region_id.as_u64(),
2172 watermark: None,
2173 }]
2174 );
2175 }
2176
2177 #[tokio::test]
2178 async fn test_wrap_flow_region_watermark_stream_adds_terminal_metrics() {
2179 let region_id = RegionId::new(42, 7);
2180 let query_ctx = Arc::new(
2181 QueryContextBuilder::default()
2182 .extensions(HashMap::from([(
2183 FLOW_RETURN_REGION_SEQ.to_string(),
2184 "true".to_string(),
2185 )]))
2186 .build(),
2187 );
2188 query_ctx.set_snapshot(region_id.as_u64(), 99);
2189
2190 let wrapped =
2191 wrap_flow_region_watermark_stream(single_value_stream(), region_id, &query_ctx);
2192 let mut pinned = Box::pin(wrapped);
2193 while pinned.next().await.is_some() {}
2194
2195 let metrics = pinned.as_ref().get_ref().metrics().unwrap();
2196 assert_eq!(
2197 metrics.region_watermarks,
2198 vec![RegionWatermarkEntry {
2199 region_id: region_id.as_u64(),
2200 watermark: Some(99),
2201 }]
2202 );
2203 }
2204
2205 #[tokio::test]
2206 async fn test_wrap_flow_region_watermark_stream_skips_without_extension() {
2207 let region_id = RegionId::new(42, 7);
2208 let query_ctx = Arc::new(QueryContextBuilder::default().build());
2209 query_ctx.set_snapshot(region_id.as_u64(), 99);
2210
2211 let wrapped =
2212 wrap_flow_region_watermark_stream(single_value_stream(), region_id, &query_ctx);
2213 let mut pinned = Box::pin(wrapped);
2214 while pinned.next().await.is_some() {}
2215
2216 assert!(pinned.as_ref().get_ref().metrics().is_none());
2217 }
2218
2219 #[tokio::test]
2220 async fn test_wrap_flow_region_watermark_stream_skips_without_snapshot() {
2221 let region_id = RegionId::new(42, 7);
2222 let query_ctx = Arc::new(
2223 QueryContextBuilder::default()
2224 .extensions(HashMap::from([(
2225 FLOW_RETURN_REGION_SEQ.to_string(),
2226 "true".to_string(),
2227 )]))
2228 .build(),
2229 );
2230
2231 let wrapped =
2232 wrap_flow_region_watermark_stream(single_value_stream(), region_id, &query_ctx);
2233 let mut pinned = Box::pin(wrapped);
2234 while pinned.next().await.is_some() {}
2235
2236 assert!(pinned.as_ref().get_ref().metrics().is_none());
2237 }
2238
2239 #[tokio::test]
2240 async fn test_offline_cleanup_does_not_register_region() {
2241 let mut mock_region_server = mock_region_server();
2242 let (engine, mut receiver) = MockRegionEngine::new(MITO_ENGINE_NAME);
2243 mock_region_server.register_engine(engine);
2244
2245 let region_id = RegionId::new(1, 1);
2246 let response = mock_region_server
2247 .handle_request(
2248 region_id,
2249 RegionRequest::CleanUp(RegionCleanUpRequest {
2250 engine: MITO_ENGINE_NAME.to_string(),
2251 table_dir: String::new(),
2252 path_type: PathType::Bare,
2253 options: HashMap::new(),
2254 }),
2255 )
2256 .await
2257 .unwrap();
2258
2259 assert_eq!(response.affected_rows, 0);
2260 let (handled_region_id, handled_request) = receiver.try_recv().unwrap();
2261 assert_eq!(handled_region_id, region_id);
2262 assert_matches!(handled_request, RegionRequest::CleanUp(_));
2263 assert!(
2264 mock_region_server
2265 .inner
2266 .region_map
2267 .get(®ion_id)
2268 .is_none()
2269 );
2270 }
2271
2272 #[tokio::test]
2273 async fn test_offline_cleanup_rejects_registered_region() {
2274 let mut mock_region_server = mock_region_server();
2275 let (engine, mut receiver) = MockRegionEngine::new(MITO_ENGINE_NAME);
2276 mock_region_server.register_engine(engine.clone());
2277
2278 let region_id = RegionId::new(1, 1);
2279 mock_region_server
2280 .inner
2281 .region_map
2282 .insert(region_id, RegionEngineWithStatus::Ready(engine));
2283
2284 let err = mock_region_server
2285 .handle_request(
2286 region_id,
2287 RegionRequest::CleanUp(RegionCleanUpRequest {
2288 engine: MITO_ENGINE_NAME.to_string(),
2289 table_dir: String::new(),
2290 path_type: PathType::Bare,
2291 options: HashMap::new(),
2292 }),
2293 )
2294 .await
2295 .unwrap_err();
2296
2297 assert_eq!(err.status_code(), StatusCode::RegionBusy);
2298 assert!(receiver.try_recv().is_err());
2299 assert!(matches!(
2300 mock_region_server
2301 .inner
2302 .region_map
2303 .get(®ion_id)
2304 .unwrap()
2305 .clone(),
2306 RegionEngineWithStatus::Ready(_)
2307 ));
2308 }
2309
2310 #[tokio::test]
2311 async fn test_region_registering() {
2312 common_telemetry::init_default_ut_logging();
2313
2314 let mut mock_region_server = mock_region_server();
2315 let (engine, _receiver) = MockRegionEngine::new(MITO_ENGINE_NAME);
2316 let engine_name = engine.name();
2317 mock_region_server.register_engine(engine.clone());
2318 let region_id = RegionId::new(1, 1);
2319 let builder = CreateRequestBuilder::new();
2320 let create_req = builder.build();
2321 mock_region_server.inner.region_map.insert(
2323 region_id,
2324 RegionEngineWithStatus::Registering(engine.clone()),
2325 );
2326 let response = mock_region_server
2327 .handle_request(region_id, RegionRequest::Create(create_req))
2328 .await
2329 .unwrap();
2330 assert_eq!(response.affected_rows, 0);
2331 let status = mock_region_server
2332 .inner
2333 .region_map
2334 .get(®ion_id)
2335 .unwrap()
2336 .clone();
2337 assert!(matches!(status, RegionEngineWithStatus::Ready(_)));
2338
2339 mock_region_server.inner.region_map.insert(
2340 region_id,
2341 RegionEngineWithStatus::Registering(engine.clone()),
2342 );
2343 let response = mock_region_server
2344 .handle_request(
2345 region_id,
2346 RegionRequest::Open(RegionOpenRequest {
2347 engine: engine_name.to_string(),
2348 table_dir: String::new(),
2349 path_type: PathType::Bare,
2350 options: Default::default(),
2351 skip_wal_replay: false,
2352 checkpoint: None,
2353 requirements: Default::default(),
2354 }),
2355 )
2356 .await
2357 .unwrap();
2358 assert_eq!(response.affected_rows, 0);
2359 let status = mock_region_server
2360 .inner
2361 .region_map
2362 .get(®ion_id)
2363 .unwrap()
2364 .clone();
2365 assert!(matches!(status, RegionEngineWithStatus::Ready(_)));
2366 }
2367
2368 #[tokio::test]
2369 async fn test_region_deregistering() {
2370 common_telemetry::init_default_ut_logging();
2371
2372 let mut mock_region_server = mock_region_server();
2373 let (engine, _receiver) = MockRegionEngine::new(MITO_ENGINE_NAME);
2374
2375 mock_region_server.register_engine(engine.clone());
2376
2377 let region_id = RegionId::new(1, 1);
2378
2379 mock_region_server.inner.region_map.insert(
2381 region_id,
2382 RegionEngineWithStatus::Deregistering(engine.clone()),
2383 );
2384
2385 let response = mock_region_server
2386 .handle_request(
2387 region_id,
2388 RegionRequest::Drop(RegionDropRequest {
2389 fast_path: false,
2390 force: false,
2391 partial_drop: false,
2392 }),
2393 )
2394 .await
2395 .unwrap();
2396 assert_eq!(response.affected_rows, 0);
2397
2398 let status = mock_region_server
2399 .inner
2400 .region_map
2401 .get(®ion_id)
2402 .unwrap()
2403 .clone();
2404 assert!(matches!(status, RegionEngineWithStatus::Deregistering(_)));
2405
2406 mock_region_server.inner.region_map.insert(
2407 region_id,
2408 RegionEngineWithStatus::Deregistering(engine.clone()),
2409 );
2410
2411 let response = mock_region_server
2412 .handle_request(
2413 region_id,
2414 RegionRequest::Close(RegionCloseRequest::default()),
2415 )
2416 .await
2417 .unwrap();
2418 assert_eq!(response.affected_rows, 0);
2419
2420 let status = mock_region_server
2421 .inner
2422 .region_map
2423 .get(®ion_id)
2424 .unwrap()
2425 .clone();
2426 assert!(matches!(status, RegionEngineWithStatus::Deregistering(_)));
2427 }
2428
2429 #[tokio::test]
2430 async fn test_region_not_ready() {
2431 common_telemetry::init_default_ut_logging();
2432
2433 let mut mock_region_server = mock_region_server();
2434 let (engine, _receiver) = MockRegionEngine::new(MITO_ENGINE_NAME);
2435
2436 mock_region_server.register_engine(engine.clone());
2437
2438 let region_id = RegionId::new(1, 1);
2439
2440 mock_region_server.inner.region_map.insert(
2442 region_id,
2443 RegionEngineWithStatus::Registering(engine.clone()),
2444 );
2445
2446 let err = mock_region_server
2447 .handle_request(
2448 region_id,
2449 RegionRequest::Truncate(RegionTruncateRequest::All),
2450 )
2451 .await
2452 .unwrap_err();
2453
2454 assert_eq!(err.status_code(), StatusCode::RegionNotReady);
2455 }
2456
2457 #[tokio::test]
2458 async fn test_region_request_failed() {
2459 common_telemetry::init_default_ut_logging();
2460
2461 let mut mock_region_server = mock_region_server();
2462 let (engine, _receiver) = MockRegionEngine::with_mock_fn(
2463 MITO_ENGINE_NAME,
2464 Box::new(|_region_id, _request| {
2465 error::UnexpectedSnafu {
2466 violated: "test".to_string(),
2467 }
2468 .fail()
2469 }),
2470 );
2471
2472 mock_region_server.register_engine(engine.clone());
2473
2474 let region_id = RegionId::new(1, 1);
2475 let builder = CreateRequestBuilder::new();
2476 let create_req = builder.build();
2477 mock_region_server
2478 .handle_request(region_id, RegionRequest::Create(create_req))
2479 .await
2480 .unwrap_err();
2481
2482 let status = mock_region_server.inner.region_map.get(®ion_id);
2483 assert!(status.is_none());
2484
2485 mock_region_server
2486 .inner
2487 .region_map
2488 .insert(region_id, RegionEngineWithStatus::Ready(engine.clone()));
2489
2490 mock_region_server
2491 .handle_request(
2492 region_id,
2493 RegionRequest::Drop(RegionDropRequest {
2494 fast_path: false,
2495 force: false,
2496 partial_drop: false,
2497 }),
2498 )
2499 .await
2500 .unwrap_err();
2501
2502 let status = mock_region_server.inner.region_map.get(®ion_id);
2503 assert!(status.is_some());
2504 }
2505
2506 #[tokio::test]
2507 async fn test_batch_open_region_ignore_nonexistent_regions() {
2508 common_telemetry::init_default_ut_logging();
2509 let mut mock_region_server = mock_region_server();
2510 let (engine, _receiver) = MockRegionEngine::with_mock_fn(
2511 MITO_ENGINE_NAME,
2512 Box::new(|region_id, _request| {
2513 if region_id == RegionId::new(1, 1) {
2514 error::RegionNotFoundSnafu { region_id }.fail()
2515 } else {
2516 Ok(0)
2517 }
2518 }),
2519 );
2520 mock_region_server.register_engine(engine.clone());
2521
2522 let region_ids = mock_region_server
2523 .handle_batch_open_requests(
2524 8,
2525 vec![
2526 (
2527 RegionId::new(1, 1),
2528 RegionOpenRequest {
2529 engine: MITO_ENGINE_NAME.to_string(),
2530 table_dir: String::new(),
2531 path_type: PathType::Bare,
2532 options: Default::default(),
2533 skip_wal_replay: false,
2534 checkpoint: None,
2535 requirements: Default::default(),
2536 },
2537 ),
2538 (
2539 RegionId::new(1, 2),
2540 RegionOpenRequest {
2541 engine: MITO_ENGINE_NAME.to_string(),
2542 table_dir: String::new(),
2543 path_type: PathType::Bare,
2544 options: Default::default(),
2545 skip_wal_replay: false,
2546 checkpoint: None,
2547 requirements: Default::default(),
2548 },
2549 ),
2550 ],
2551 true,
2552 )
2553 .await
2554 .unwrap();
2555 assert_eq!(region_ids, vec![RegionId::new(1, 2)]);
2556
2557 let err = mock_region_server
2558 .handle_batch_open_requests(
2559 8,
2560 vec![
2561 (
2562 RegionId::new(1, 1),
2563 RegionOpenRequest {
2564 engine: MITO_ENGINE_NAME.to_string(),
2565 table_dir: String::new(),
2566 path_type: PathType::Bare,
2567 options: Default::default(),
2568 skip_wal_replay: false,
2569 checkpoint: None,
2570 requirements: Default::default(),
2571 },
2572 ),
2573 (
2574 RegionId::new(1, 2),
2575 RegionOpenRequest {
2576 engine: MITO_ENGINE_NAME.to_string(),
2577 table_dir: String::new(),
2578 path_type: PathType::Bare,
2579 options: Default::default(),
2580 skip_wal_replay: false,
2581 checkpoint: None,
2582 requirements: Default::default(),
2583 },
2584 ),
2585 ],
2586 false,
2587 )
2588 .await
2589 .unwrap_err();
2590 assert_matches!(&err, error::Error::HandleBatchOpenRequest { .. });
2591 assert_eq!(err.status_code(), StatusCode::RegionNotFound);
2592 assert_eq!(err.retry_hint(), RetryHint::NonRetryable);
2593 }
2594
2595 struct CurrentEngineTest {
2596 region_id: RegionId,
2597 current_region_status: Option<RegionEngineWithStatus>,
2598 region_change: RegionChange,
2599 assert: Box<dyn FnOnce(Result<CurrentEngine>)>,
2600 }
2601
2602 #[tokio::test]
2603 async fn test_current_engine() {
2604 common_telemetry::init_default_ut_logging();
2605
2606 let mut mock_region_server = mock_region_server();
2607 let (engine, _) = MockRegionEngine::new(MITO_ENGINE_NAME);
2608 mock_region_server.register_engine(engine.clone());
2609
2610 let region_id = RegionId::new(1024, 1);
2611 let tests = vec![
2612 CurrentEngineTest {
2614 region_id,
2615 current_region_status: None,
2616 region_change: RegionChange::None,
2617 assert: Box::new(|result| {
2618 let err = result.unwrap_err();
2619 assert_eq!(err.status_code(), StatusCode::RegionNotFound);
2620 }),
2621 },
2622 CurrentEngineTest {
2623 region_id,
2624 current_region_status: Some(RegionEngineWithStatus::Ready(engine.clone())),
2625 region_change: RegionChange::None,
2626 assert: Box::new(|result| {
2627 let current_engine = result.unwrap();
2628 assert_matches!(current_engine, CurrentEngine::Engine(_));
2629 }),
2630 },
2631 CurrentEngineTest {
2632 region_id,
2633 current_region_status: Some(RegionEngineWithStatus::Registering(engine.clone())),
2634 region_change: RegionChange::None,
2635 assert: Box::new(|result| {
2636 let err = result.unwrap_err();
2637 assert_eq!(err.status_code(), StatusCode::RegionNotReady);
2638 }),
2639 },
2640 CurrentEngineTest {
2641 region_id,
2642 current_region_status: Some(RegionEngineWithStatus::Deregistering(engine.clone())),
2643 region_change: RegionChange::None,
2644 assert: Box::new(|result| {
2645 let err = result.unwrap_err();
2646 assert_eq!(err.status_code(), StatusCode::RegionNotFound);
2647 }),
2648 },
2649 CurrentEngineTest {
2651 region_id,
2652 current_region_status: None,
2653 region_change: RegionChange::Register(RegionAttribute::Mito),
2654 assert: Box::new(|result| {
2655 let current_engine = result.unwrap();
2656 assert_matches!(current_engine, CurrentEngine::Engine(_));
2657 }),
2658 },
2659 CurrentEngineTest {
2660 region_id,
2661 current_region_status: Some(RegionEngineWithStatus::Registering(engine.clone())),
2662 region_change: RegionChange::Register(RegionAttribute::Mito),
2663 assert: Box::new(|result| {
2664 let current_engine = result.unwrap();
2665 assert_matches!(current_engine, CurrentEngine::Engine(_));
2666 }),
2667 },
2668 CurrentEngineTest {
2669 region_id,
2670 current_region_status: Some(RegionEngineWithStatus::Deregistering(engine.clone())),
2671 region_change: RegionChange::Register(RegionAttribute::Mito),
2672 assert: Box::new(|result| {
2673 let err = result.unwrap_err();
2674 assert_eq!(err.status_code(), StatusCode::RegionBusy);
2675 }),
2676 },
2677 CurrentEngineTest {
2678 region_id,
2679 current_region_status: Some(RegionEngineWithStatus::Ready(engine.clone())),
2680 region_change: RegionChange::Register(RegionAttribute::Mito),
2681 assert: Box::new(|result| {
2682 let current_engine = result.unwrap();
2683 assert_matches!(current_engine, CurrentEngine::Engine(_));
2684 }),
2685 },
2686 CurrentEngineTest {
2688 region_id,
2689 current_region_status: None,
2690 region_change: RegionChange::Deregisters,
2691 assert: Box::new(|result| {
2692 let current_engine = result.unwrap();
2693 assert_matches!(current_engine, CurrentEngine::EarlyReturn(_));
2694 }),
2695 },
2696 CurrentEngineTest {
2697 region_id,
2698 current_region_status: Some(RegionEngineWithStatus::Registering(engine.clone())),
2699 region_change: RegionChange::Deregisters,
2700 assert: Box::new(|result| {
2701 let err = result.unwrap_err();
2702 assert_eq!(err.status_code(), StatusCode::RegionBusy);
2703 }),
2704 },
2705 CurrentEngineTest {
2706 region_id,
2707 current_region_status: Some(RegionEngineWithStatus::Deregistering(engine.clone())),
2708 region_change: RegionChange::Deregisters,
2709 assert: Box::new(|result| {
2710 let current_engine = result.unwrap();
2711 assert_matches!(current_engine, CurrentEngine::EarlyReturn(_));
2712 }),
2713 },
2714 CurrentEngineTest {
2715 region_id,
2716 current_region_status: Some(RegionEngineWithStatus::Ready(engine.clone())),
2717 region_change: RegionChange::Deregisters,
2718 assert: Box::new(|result| {
2719 let current_engine = result.unwrap();
2720 assert_matches!(current_engine, CurrentEngine::Engine(_));
2721 }),
2722 },
2723 CurrentEngineTest {
2725 region_id,
2726 current_region_status: None,
2727 region_change: RegionChange::OfflineCleanup(RegionAttribute::Mito),
2728 assert: Box::new(|result| {
2729 let current_engine = result.unwrap();
2730 assert_matches!(current_engine, CurrentEngine::Engine(_));
2731 }),
2732 },
2733 CurrentEngineTest {
2734 region_id,
2735 current_region_status: Some(RegionEngineWithStatus::Registering(engine.clone())),
2736 region_change: RegionChange::OfflineCleanup(RegionAttribute::Mito),
2737 assert: Box::new(|result| {
2738 let err = result.unwrap_err();
2739 assert_eq!(err.status_code(), StatusCode::RegionBusy);
2740 }),
2741 },
2742 CurrentEngineTest {
2743 region_id,
2744 current_region_status: Some(RegionEngineWithStatus::Deregistering(engine.clone())),
2745 region_change: RegionChange::OfflineCleanup(RegionAttribute::Mito),
2746 assert: Box::new(|result| {
2747 let err = result.unwrap_err();
2748 assert_eq!(err.status_code(), StatusCode::RegionBusy);
2749 }),
2750 },
2751 CurrentEngineTest {
2752 region_id,
2753 current_region_status: Some(RegionEngineWithStatus::Ready(engine.clone())),
2754 region_change: RegionChange::OfflineCleanup(RegionAttribute::Mito),
2755 assert: Box::new(|result| {
2756 let err = result.unwrap_err();
2757 assert_eq!(err.status_code(), StatusCode::RegionBusy);
2758 }),
2759 },
2760 ];
2761
2762 for test in tests {
2763 let CurrentEngineTest {
2764 region_id,
2765 current_region_status,
2766 region_change,
2767 assert,
2768 } = test;
2769
2770 if let Some(status) = current_region_status {
2772 mock_region_server
2773 .inner
2774 .region_map
2775 .insert(region_id, status);
2776 } else {
2777 mock_region_server.inner.region_map.remove(®ion_id);
2778 }
2779
2780 let result = mock_region_server
2781 .inner
2782 .get_engine(region_id, ®ion_change);
2783
2784 assert(result);
2785 }
2786 }
2787
2788 #[tokio::test]
2789 async fn test_region_server_parallelism() {
2790 let p = RegionServerParallelism::from_opts(2, Duration::from_millis(1)).unwrap();
2791 let first_query = p.acquire().await;
2792 assert!(first_query.is_ok());
2793 let second_query = p.acquire().await;
2794 assert!(second_query.is_ok());
2795 let third_query = p.acquire().await;
2796 assert!(third_query.is_err());
2797 let err = third_query.unwrap_err();
2798 assert_eq!(
2799 err.output_msg(),
2800 "Failed to acquire permit under timeouts: deadline has elapsed".to_string()
2801 );
2802 drop(first_query);
2803 let forth_query = p.acquire().await;
2804 assert!(forth_query.is_ok());
2805 }
2806
2807 fn mock_region_metadata(region_id: RegionId) -> RegionMetadata {
2808 let mut metadata_builder = RegionMetadataBuilder::new(region_id);
2809 metadata_builder.push_column_metadata(ColumnMetadata {
2810 column_schema: datatypes::schema::ColumnSchema::new(
2811 "timestamp",
2812 ConcreteDataType::timestamp_nanosecond_datatype(),
2813 false,
2814 ),
2815 semantic_type: SemanticType::Timestamp,
2816 column_id: 0,
2817 });
2818 metadata_builder.push_column_metadata(ColumnMetadata {
2819 column_schema: datatypes::schema::ColumnSchema::new(
2820 "file",
2821 ConcreteDataType::string_datatype(),
2822 true,
2823 ),
2824 semantic_type: SemanticType::Tag,
2825 column_id: 1,
2826 });
2827 metadata_builder.push_column_metadata(ColumnMetadata {
2828 column_schema: datatypes::schema::ColumnSchema::new(
2829 "message",
2830 ConcreteDataType::string_datatype(),
2831 true,
2832 ),
2833 semantic_type: SemanticType::Field,
2834 column_id: 2,
2835 });
2836 metadata_builder.primary_key(vec![1]);
2837 metadata_builder.build().unwrap()
2838 }
2839
2840 #[tokio::test]
2841 async fn test_handle_list_metadata_request() {
2842 common_telemetry::init_default_ut_logging();
2843
2844 let mut mock_region_server = mock_region_server();
2845 let region_id_1 = RegionId::new(1, 0);
2846 let region_id_2 = RegionId::new(2, 0);
2847
2848 let metadata_1 = mock_region_metadata(region_id_1);
2849 let metadata_2 = mock_region_metadata(region_id_2);
2850 let metadatas = vec![Some(metadata_1.clone()), Some(metadata_2.clone())];
2851
2852 let metadata_1 = Arc::new(metadata_1);
2853 let metadata_2 = Arc::new(metadata_2);
2854 let (engine, _) = MockRegionEngine::with_metadata_mock_fn(
2855 MITO_ENGINE_NAME,
2856 Box::new(move |region_id| {
2857 if region_id == region_id_1 {
2858 Ok(metadata_1.clone())
2859 } else if region_id == region_id_2 {
2860 Ok(metadata_2.clone())
2861 } else {
2862 error::RegionNotFoundSnafu { region_id }.fail()
2863 }
2864 }),
2865 );
2866
2867 mock_region_server.register_engine(engine.clone());
2868 mock_region_server
2869 .inner
2870 .region_map
2871 .insert(region_id_1, RegionEngineWithStatus::Ready(engine.clone()));
2872 mock_region_server
2873 .inner
2874 .region_map
2875 .insert(region_id_2, RegionEngineWithStatus::Ready(engine.clone()));
2876
2877 let list_metadata_request = ListMetadataRequest {
2879 region_ids: vec![region_id_1.as_u64(), region_id_2.as_u64()],
2880 };
2881 let response = mock_region_server
2882 .handle_list_metadata_request(&list_metadata_request)
2883 .await
2884 .unwrap();
2885 let decoded_metadata: Vec<Option<RegionMetadata>> =
2886 serde_json::from_slice(&response.metadata).unwrap();
2887 assert_eq!(metadatas, decoded_metadata);
2888 }
2889
2890 #[tokio::test]
2891 async fn test_handle_list_metadata_not_found() {
2892 common_telemetry::init_default_ut_logging();
2893
2894 let mut mock_region_server = mock_region_server();
2895 let region_id_1 = RegionId::new(1, 0);
2896 let region_id_2 = RegionId::new(2, 0);
2897
2898 let metadata_1 = mock_region_metadata(region_id_1);
2899 let metadatas = vec![Some(metadata_1.clone()), None];
2900
2901 let metadata_1 = Arc::new(metadata_1);
2902 let (engine, _) = MockRegionEngine::with_metadata_mock_fn(
2903 MITO_ENGINE_NAME,
2904 Box::new(move |region_id| {
2905 if region_id == region_id_1 {
2906 Ok(metadata_1.clone())
2907 } else {
2908 error::RegionNotFoundSnafu { region_id }.fail()
2909 }
2910 }),
2911 );
2912
2913 mock_region_server.register_engine(engine.clone());
2914 mock_region_server
2915 .inner
2916 .region_map
2917 .insert(region_id_1, RegionEngineWithStatus::Ready(engine.clone()));
2918
2919 let list_metadata_request = ListMetadataRequest {
2921 region_ids: vec![region_id_1.as_u64(), region_id_2.as_u64()],
2922 };
2923 let response = mock_region_server
2924 .handle_list_metadata_request(&list_metadata_request)
2925 .await
2926 .unwrap();
2927 let decoded_metadata: Vec<Option<RegionMetadata>> =
2928 serde_json::from_slice(&response.metadata).unwrap();
2929 assert_eq!(metadatas, decoded_metadata);
2930
2931 mock_region_server
2933 .inner
2934 .region_map
2935 .insert(region_id_2, RegionEngineWithStatus::Ready(engine.clone()));
2936 let response = mock_region_server
2937 .handle_list_metadata_request(&list_metadata_request)
2938 .await
2939 .unwrap();
2940 let decoded_metadata: Vec<Option<RegionMetadata>> =
2941 serde_json::from_slice(&response.metadata).unwrap();
2942 assert_eq!(metadatas, decoded_metadata);
2943 }
2944
2945 #[tokio::test]
2946 async fn test_handle_list_metadata_failed() {
2947 common_telemetry::init_default_ut_logging();
2948
2949 let mut mock_region_server = mock_region_server();
2950 let region_id_1 = RegionId::new(1, 0);
2951
2952 let (engine, _) = MockRegionEngine::with_metadata_mock_fn(
2953 MITO_ENGINE_NAME,
2954 Box::new(move |region_id| {
2955 error::UnexpectedSnafu {
2956 violated: format!("Failed to get region {region_id}"),
2957 }
2958 .fail()
2959 }),
2960 );
2961
2962 mock_region_server.register_engine(engine.clone());
2963 mock_region_server
2964 .inner
2965 .region_map
2966 .insert(region_id_1, RegionEngineWithStatus::Ready(engine.clone()));
2967
2968 let list_metadata_request = ListMetadataRequest {
2970 region_ids: vec![region_id_1.as_u64()],
2971 };
2972 mock_region_server
2973 .handle_list_metadata_request(&list_metadata_request)
2974 .await
2975 .unwrap_err();
2976 }
2977}