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