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