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