Skip to main content

datanode/
region_server.rs

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