Skip to main content

datanode/
region_server.rs

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