Skip to main content

datanode/
region_server.rs

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