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