Skip to main content

datanode/
region_server.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15mod catalog;
16mod registrations;
17mod remote_dyn_filter;
18
19use std::collections::HashMap;
20use std::fmt::Debug;
21use std::ops::Deref;
22use std::pin::Pin;
23use std::sync::atomic::{AtomicBool, Ordering};
24use std::sync::{Arc, RwLock};
25use std::task::{Context, Poll};
26use std::time::{Duration, Instant};
27
28use api::region::{BatchRegionResponse, RegionResponse};
29use api::v1::meta::TopicStat;
30use api::v1::region::sync_request::ManifestInfo;
31use api::v1::region::{
32    ListMetadataRequest, RegionRequest as RegionRequestV1, RegionRequestFailure,
33    RegionResponse as RegionResponseV1, SyncRequest, region_request,
34};
35use api::v1::{ResponseHeader, Status};
36use arrow_flight::{FlightData, Ticket};
37use async_trait::async_trait;
38use bytes::Bytes;
39use common_error::ext::{BoxedError, ErrorExt};
40use common_error::status_code::StatusCode;
41use common_meta::datanode::TopicStatsReporter;
42use common_query::OutputData;
43use common_query::request::QueryRequest;
44use common_recordbatch::adapter::RecordBatchMetrics;
45use common_recordbatch::{OrderOption, RecordBatch, RecordBatchStream, SendableRecordBatchStream};
46use common_runtime::{JoinHandle, Runtime};
47use common_telemetry::tracing::{self, info_span};
48use common_telemetry::tracing_context::{FutureExt, TracingContext};
49use common_telemetry::{debug, error, info, warn};
50use dashmap::DashMap;
51use datafusion::datasource::TableProvider;
52use datafusion_common::tree_node::TreeNode;
53use datatypes::schema::SchemaRef;
54use either::Either;
55use futures_util::stream::FuturesUnordered;
56use futures_util::{Stream, StreamExt};
57use metric_engine::engine::MetricEngine;
58use mito2::engine::{MITO_ENGINE_NAME, MitoEngine};
59use prost::Message;
60use query::QueryEngineRef;
61pub use query::dummy_catalog::{
62    DummyCatalogList, DummyTableProviderFactory, TableProviderFactoryRef,
63};
64use query::options::should_collect_region_watermark_from_extensions;
65use serde_json;
66use servers::error::{
67    self as servers_error, ExecuteGrpcRequestSnafu, Result as ServerResult, SuspendedSnafu,
68};
69use servers::grpc::FlightCompression;
70use servers::grpc::flight::{
71    FlightCraft, FlightRecordBatchSource, FlightRecordBatchStream, FlightRecordBatchStreamInput,
72    TonicStream,
73};
74use servers::grpc::region_server::RegionServerHandler;
75use session::context::{
76    FLIGHT_METRICS_HEARTBEAT_INTERVAL, QueryContext, QueryContextBuilder, QueryContextRef,
77};
78use snafu::{IntoError, OptionExt, ResultExt, ensure};
79use store_api::metric_engine_consts::{
80    FILE_ENGINE_NAME, LOGICAL_TABLE_METADATA_KEY, METRIC_ENGINE_NAME, RELATIONAL_ENGINE_NAME,
81};
82use store_api::region_engine::{
83    RegionEngineRef, RegionManifestInfo, RegionRole, RegionStatistic, RemapManifestsRequest,
84    RemapManifestsResponse, SetRegionRoleStateResponse, SettableRegionRoleState,
85    SyncRegionFromRequest,
86};
87use store_api::region_request::{
88    self as store_region_request, AffectedRows, BatchRegionDdlRequest, RegionCatchupRequest,
89    RegionCloseRequest, RegionOpenRequest, RegionRequest,
90};
91use store_api::storage::RegionId;
92use tokio::sync::{OwnedSemaphorePermit, Semaphore, mpsc};
93use tokio::time::{self, timeout};
94use tonic::{Request, Response, Result as TonicResult};
95
96use crate::datanode::record_shutdown_error;
97use crate::error::{
98    self, BuildRegionRequestsSnafu, ConcurrentQueryLimiterClosedSnafu,
99    ConcurrentQueryLimiterTimeoutSnafu, DataFusionSnafu, DecodeLogicalPlanSnafu,
100    ExecuteLogicalPlanSnafu, FindLogicalRegionsSnafu, GetRegionMetadataSnafu,
101    HandleBatchDdlRequestSnafu, HandleBatchOpenRequestSnafu, HandleRegionRequestSnafu,
102    NewPlanDecoderSnafu, RegionEngineNotFoundSnafu, RegionNotFoundSnafu, RegionNotReadySnafu,
103    Result, RuntimeJoinSnafu, SerializeJsonSnafu, StopRegionEngineSnafu, UnexpectedSnafu,
104    UnsupportedOutputSnafu,
105};
106use crate::event_listener::RegionServerEventListenerRef;
107use crate::query_stream::QueryRuntimeStream;
108use crate::region_server::catalog::{NameAwareCatalogList, NameAwareDataSourceInjectorBuilder};
109use crate::region_server::registrations::RemoteDynFilterRegistry;
110use crate::region_server::remote_dyn_filter::wrap_remote_dyn_filter_guarded_stream;
111
112const QUERY_RUNTIME_STREAM_BUFFER_SIZE: usize = 8;
113
114#[derive(Clone)]
115pub struct RegionServer {
116    inner: Arc<RegionServerInner>,
117    flight_compression: FlightCompression,
118    suspend: Arc<AtomicBool>,
119}
120
121pub struct RegionStat {
122    pub region_id: RegionId,
123    pub engine: String,
124    pub role: RegionRole,
125}
126
127impl RegionServer {
128    pub fn new(
129        query_engine: QueryEngineRef,
130        runtime: Runtime,
131        event_listener: RegionServerEventListenerRef,
132        flight_compression: FlightCompression,
133    ) -> Self {
134        Self::with_table_provider(
135            query_engine,
136            runtime,
137            event_listener,
138            Arc::new(DummyTableProviderFactory),
139            0,
140            Duration::from_millis(0),
141            flight_compression,
142        )
143    }
144
145    pub fn with_table_provider(
146        query_engine: QueryEngineRef,
147        runtime: Runtime,
148        event_listener: RegionServerEventListenerRef,
149        table_provider_factory: TableProviderFactoryRef,
150        max_concurrent_queries: usize,
151        concurrent_query_limiter_timeout: Duration,
152        flight_compression: FlightCompression,
153    ) -> Self {
154        Self {
155            inner: Arc::new(RegionServerInner::new(
156                query_engine,
157                runtime,
158                event_listener,
159                table_provider_factory,
160                RegionServerParallelism::from_opts(
161                    max_concurrent_queries,
162                    concurrent_query_limiter_timeout,
163                ),
164            )),
165            flight_compression,
166            suspend: Arc::new(AtomicBool::new(false)),
167        }
168    }
169
170    /// Registers an engine.
171    pub fn register_engine(&mut self, engine: RegionEngineRef) {
172        self.inner.register_engine(engine);
173    }
174
175    /// Sets the topic stats.
176    pub fn set_topic_stats_reporter(&mut self, topic_stats_reporter: Box<dyn TopicStatsReporter>) {
177        self.inner.set_topic_stats_reporter(topic_stats_reporter);
178    }
179
180    /// Finds the region's engine by its id. If the region is not ready, returns `None`.
181    pub fn find_engine(&self, region_id: RegionId) -> Result<Option<RegionEngineRef>> {
182        match self.inner.get_engine(region_id, &RegionChange::None) {
183            Ok(CurrentEngine::Engine(engine)) => Ok(Some(engine)),
184            Ok(CurrentEngine::EarlyReturn(_)) => Ok(None),
185            Err(error::Error::RegionNotFound { .. }) => Ok(None),
186            Err(err) => Err(err),
187        }
188    }
189
190    /// Gets the MitoEngine if it's registered.
191    pub fn mito_engine(&self) -> Option<MitoEngine> {
192        if let Some(mito) = self.inner.mito_engine.read().unwrap().clone() {
193            Some(mito)
194        } else {
195            self.inner
196                .engines
197                .read()
198                .unwrap()
199                .get(MITO_ENGINE_NAME)
200                .cloned()
201                .and_then(|e| {
202                    let mito = e.as_any().downcast_ref::<MitoEngine>().cloned();
203                    if mito.is_none() {
204                        warn!("Mito engine not found in region server engines");
205                    }
206                    mito
207                })
208        }
209    }
210
211    #[tracing::instrument(skip_all)]
212    pub async fn handle_batch_open_requests(
213        &self,
214        parallelism: usize,
215        requests: Vec<(RegionId, RegionOpenRequest)>,
216        ignore_nonexistent_region: bool,
217    ) -> Result<Vec<RegionId>> {
218        self.inner
219            .handle_batch_open_requests(parallelism, requests, ignore_nonexistent_region)
220            .await
221    }
222
223    #[tracing::instrument(skip_all)]
224    pub async fn handle_batch_catchup_requests(
225        &self,
226        parallelism: usize,
227        requests: Vec<(RegionId, RegionCatchupRequest)>,
228    ) -> Result<Vec<(RegionId, std::result::Result<(), BoxedError>)>> {
229        self.inner
230            .handle_batch_catchup_requests(parallelism, requests)
231            .await
232    }
233
234    #[tracing::instrument(skip_all, fields(request_type = request.request_type()))]
235    pub async fn handle_request(
236        &self,
237        region_id: RegionId,
238        request: RegionRequest,
239    ) -> Result<RegionResponse> {
240        if RegionServerInner::is_ingest_request(&request) {
241            let inner = self.inner.clone();
242            let request_type = request.request_type();
243            let task = common_runtime::spawn_ingest(async move {
244                inner.handle_request(region_id, request).await
245            });
246            return join_ingest_task(task, request_type).await?;
247        }
248
249        self.inner.handle_request(region_id, request).await
250    }
251
252    /// Returns a table provider for the region. Will set snapshot sequence if available in the context.
253    async fn table_provider(
254        &self,
255        region_id: RegionId,
256        ctx: Option<QueryContextRef>,
257    ) -> Result<Arc<dyn TableProvider>> {
258        let status = self
259            .inner
260            .region_map
261            .get(&region_id)
262            .context(RegionNotFoundSnafu { region_id })?
263            .clone();
264        ensure!(
265            matches!(status, RegionEngineWithStatus::Ready(_)),
266            RegionNotReadySnafu { region_id }
267        );
268
269        let provider = self
270            .inner
271            .table_provider_factory
272            .create(region_id, status.into_engine(), ctx)
273            .await
274            .context(ExecuteLogicalPlanSnafu)?;
275
276        Ok(provider)
277    }
278
279    /// Handle reads from remote. They're often query requests received by our Arrow Flight service.
280    pub async fn handle_remote_read(
281        &self,
282        request: api::v1::region::QueryRequest,
283        query_ctx: QueryContextRef,
284    ) -> Result<SendableRecordBatchStream> {
285        self.handle_remote_read_inner(request, query_ctx).await
286    }
287
288    async fn handle_remote_read_inner(
289        &self,
290        request: api::v1::region::QueryRequest,
291        query_ctx: QueryContextRef,
292    ) -> Result<SendableRecordBatchStream> {
293        let permit = if let Some(p) = &self.inner.parallelism {
294            Some(p.acquire().await?)
295        } else {
296            None
297        };
298
299        let region_id = RegionId::from_u64(request.region_id);
300        let engine_ctx = self
301            .inner
302            .query_engine
303            .engine_context(query_ctx)
304            .map_err(|error| {
305                crate::error::InvalidQueryContextSnafu {
306                    reason: error.to_string(),
307                }
308                .build()
309            })?;
310        let query_ctx = engine_ctx.query_ctx();
311        let catalog_list = Arc::new(NameAwareCatalogList::new(
312            self.clone(),
313            region_id,
314            query_ctx.clone(),
315        ));
316
317        if query_ctx.explain_verbose() {
318            common_telemetry::info!("Handle remote read for region: {}", region_id);
319        }
320
321        let decoder = engine_ctx.new_plan_decoder().context(NewPlanDecoderSnafu)?;
322
323        let plan = decoder
324            .decode(Bytes::from(request.plan), catalog_list, false)
325            .await
326            .context(DecodeLogicalPlanSnafu)?;
327
328        let cleanup = self.register_initial_remote_dyn_filter_cleanup(&query_ctx, region_id);
329
330        let stream = self
331            .inner
332            .handle_read(
333                QueryRequest {
334                    header: request.header,
335                    region_id,
336                    plan,
337                },
338                query_ctx.clone(),
339            )
340            .await?;
341
342        let stream = wrap_flow_region_watermark_stream(stream, region_id, &query_ctx);
343        let stream = if let Some(cleanup) = cleanup {
344            wrap_remote_dyn_filter_guarded_stream(stream, cleanup)
345        } else {
346            stream
347        };
348        Ok(maybe_guard_stream(stream, permit))
349    }
350
351    #[tracing::instrument(skip_all)]
352    pub async fn handle_read(&self, request: QueryRequest) -> Result<SendableRecordBatchStream> {
353        self.handle_read_inner(request).await
354    }
355
356    async fn handle_read_inner(&self, request: QueryRequest) -> Result<SendableRecordBatchStream> {
357        let permit = if let Some(p) = &self.inner.parallelism {
358            Some(p.acquire().await?)
359        } else {
360            None
361        };
362
363        let ctx = request
364            .header
365            .as_ref()
366            .map(QueryContext::try_from)
367            .transpose()
368            .map_err(|err| {
369                crate::error::InvalidQueryContextSnafu {
370                    reason: err.to_string(),
371                }
372                .build()
373            })?;
374        let query_ctx = Arc::new(ctx.unwrap_or_else(|| QueryContextBuilder::default().build()));
375
376        let region_id = request.region_id;
377        let injector_builder = NameAwareDataSourceInjectorBuilder::from_plan(&request.plan)
378            .context(DataFusionSnafu)?;
379        let mut injector = injector_builder
380            .build(self, request.region_id, query_ctx.clone())
381            .await?;
382
383        let plan = request
384            .plan
385            .rewrite(&mut injector)
386            .context(DataFusionSnafu)?
387            .data;
388
389        let cleanup = self.register_initial_remote_dyn_filter_cleanup(&query_ctx, region_id);
390
391        let stream = self
392            .inner
393            .handle_read(QueryRequest { plan, ..request }, query_ctx.clone())
394            .await?;
395
396        let stream = wrap_flow_region_watermark_stream(stream, region_id, &query_ctx);
397        let stream = if let Some(cleanup) = cleanup {
398            wrap_remote_dyn_filter_guarded_stream(stream, cleanup)
399        } else {
400            stream
401        };
402        Ok(maybe_guard_stream(stream, permit))
403    }
404
405    /// Returns all opened and reportable regions.
406    ///
407    /// Notes: except all metrics regions.
408    pub fn reportable_regions(&self) -> Vec<RegionStat> {
409        self.inner
410            .region_map
411            .iter()
412            .filter_map(|e| {
413                let region_id = *e.key();
414                // Filters out any regions whose role equals None.
415                e.role(region_id).map(|role| RegionStat {
416                    region_id,
417                    engine: e.value().name().to_string(),
418                    role,
419                })
420            })
421            .collect()
422    }
423
424    /// Returns the reportable topics.
425    pub fn topic_stats(&self) -> Vec<TopicStat> {
426        let mut reporter = self.inner.topic_stats_reporter.write().unwrap();
427        let Some(reporter) = reporter.as_mut() else {
428            return vec![];
429        };
430        reporter
431            .reportable_topics()
432            .into_iter()
433            .map(|stat| TopicStat {
434                topic_name: stat.topic,
435                record_size: stat.record_size,
436                record_num: stat.record_num,
437                latest_entry_id: stat.latest_entry_id,
438            })
439            .collect()
440    }
441
442    pub fn is_region_leader(&self, region_id: RegionId) -> Option<bool> {
443        self.inner.region_map.get(&region_id).and_then(|engine| {
444            engine.role(region_id).map(|role| match role {
445                RegionRole::Follower => false,
446                RegionRole::Leader => true,
447                RegionRole::StagingLeader => true,
448                RegionRole::DowngradingLeader => true,
449            })
450        })
451    }
452
453    pub fn set_region_role(&self, region_id: RegionId, role: RegionRole) -> Result<()> {
454        let engine = self
455            .inner
456            .region_map
457            .get(&region_id)
458            .with_context(|| RegionNotFoundSnafu { region_id })?;
459        engine
460            .set_region_role(region_id, role)
461            .with_context(|_| HandleRegionRequestSnafu { region_id })
462    }
463
464    /// Sets the role of a region from a lease the metasrv grants until `deadline`, in reply to a
465    /// heartbeat sent at `sent_at`. Returns false if the engine ignores a Leader lease because the
466    /// region was downgraded or (re)opened after `sent_at`.
467    pub fn set_region_role_with_lease(
468        &self,
469        region_id: RegionId,
470        role: RegionRole,
471        sent_at: std::time::Instant,
472        deadline: std::time::Instant,
473    ) -> Result<bool> {
474        let engine = self
475            .inner
476            .region_map
477            .get(&region_id)
478            .with_context(|| RegionNotFoundSnafu { region_id })?;
479        engine
480            .set_region_role_with_lease(region_id, role, sent_at, deadline)
481            .with_context(|_| HandleRegionRequestSnafu { region_id })
482    }
483
484    /// Set region role state gracefully.
485    ///
486    /// For [SettableRegionRoleState::Follower]:
487    /// After the call returns, the engine ensures that
488    /// no **further** write or flush operations will succeed in this region.
489    ///
490    /// For [SettableRegionRoleState::DowngradingLeader]:
491    /// After the call returns, the engine ensures that
492    /// no **further** write operations will succeed in this region.
493    pub async fn set_region_role_state_gracefully(
494        &self,
495        region_id: RegionId,
496        state: SettableRegionRoleState,
497    ) -> Result<SetRegionRoleStateResponse> {
498        // Cloning releases the DashMap guard before awaiting the engine operation.
499        let engine = self
500            .inner
501            .region_map
502            .get(&region_id)
503            .map(|entry| entry.value().clone());
504
505        match engine {
506            Some(engine) => Ok(engine
507                .set_region_role_state_gracefully(region_id, state)
508                .await
509                .with_context(|_| HandleRegionRequestSnafu { region_id })?),
510            None => Ok(SetRegionRoleStateResponse::NotFound),
511        }
512    }
513
514    pub fn runtime(&self) -> Runtime {
515        self.inner.runtime.clone()
516    }
517
518    pub fn region_statistic(&self, region_id: RegionId) -> Option<RegionStatistic> {
519        match self.inner.region_map.get(&region_id) {
520            Some(e) => e.region_statistic(region_id),
521            None => None,
522        }
523    }
524
525    /// Stop the region server.
526    pub async fn stop(&self) -> Result<()> {
527        self.inner.stop().await
528    }
529
530    #[cfg(test)]
531    /// Registers a region for test purpose.
532    pub(crate) fn register_test_region(&self, region_id: RegionId, engine: RegionEngineRef) {
533        {
534            let mut engines = self.inner.engines.write().unwrap();
535            if !engines.contains_key(engine.name()) {
536                debug!("Registering test engine: {}", engine.name());
537                engines.insert(engine.name().to_string(), engine.clone());
538            }
539        }
540
541        self.inner
542            .region_map
543            .insert(region_id, RegionEngineWithStatus::Ready(engine));
544    }
545
546    async fn handle_batch_ddl_requests(
547        &self,
548        request: region_request::Body,
549    ) -> Result<RegionResponse> {
550        // Safety: we have already checked the request type in `RegionServer::handle()`.
551        let batch_request = BatchRegionDdlRequest::try_from_request_body(request)
552            .context(BuildRegionRequestsSnafu)?
553            .unwrap();
554        let tracing_context = TracingContext::from_current_span();
555
556        let span = tracing_context.attach(info_span!("RegionServer::handle_batch_ddl_requests"));
557        self.inner
558            .handle_batch_ddl_requests(batch_request)
559            .trace(span)
560            .await
561    }
562
563    async fn handle_requests_in_parallel(
564        &self,
565        request: region_request::Body,
566    ) -> Result<BatchRegionResponse<error::Error>> {
567        let requests = prepare_batch_write_requests(request);
568        let requests = match self.try_handle_mito_batch_puts(requests).await? {
569            Either::Left(response) => return Ok(response),
570            Either::Right(requests) => requests,
571        };
572        let requests = match self.try_handle_metric_batch_puts(requests).await? {
573            Either::Left(response) => return Ok(response),
574            Either::Right(requests) => requests,
575        };
576        let tracing_context = TracingContext::from_current_span();
577        let results = futures::future::join_all(requests.into_iter().map(|request| {
578            let span = tracing_context.attach(info_span!(
579                "RegionServer::handle_region_request",
580                region_id = request.region_id.to_string()
581            ));
582            async move {
583                (
584                    request.index,
585                    self.handle_request(request.region_id, request.request)
586                        .trace(span)
587                        .await,
588                )
589            }
590        }))
591        .await;
592        let mut response = BatchRegionResponse {
593            affected_rows: 0,
594            extensions: HashMap::new(),
595            failures: Vec::new(),
596        };
597        for (index, result) in results {
598            match result {
599                Ok(result) => {
600                    response.affected_rows += result.affected_rows;
601                    response.extensions.extend(result.extensions);
602                }
603                Err(error) => {
604                    log_batch_write_error(&error, index);
605                    response.failures.push((index, error));
606                }
607            }
608        }
609        Ok(response)
610    }
611
612    async fn handle_requests_in_serial(
613        &self,
614        request: region_request::Body,
615    ) -> Result<RegionResponse> {
616        let requests =
617            RegionRequest::try_from_request_body(request).context(BuildRegionRequestsSnafu)?;
618        let tracing_context = TracingContext::from_current_span();
619
620        let mut affected_rows = 0;
621        let mut extensions = HashMap::new();
622        for (region_id, req) in requests {
623            let span = tracing_context.attach(info_span!(
624                "RegionServer::handle_region_request",
625                region_id = region_id.to_string()
626            ));
627            let result = self.handle_request(region_id, req).trace(span).await?;
628
629            affected_rows += result.affected_rows;
630            extensions.extend(result.extensions);
631        }
632
633        Ok(RegionResponse {
634            affected_rows,
635            extensions,
636            metadata: Vec::new(),
637        })
638    }
639
640    /// Attempts metric batch writes, returning the requests when ordinary execution is needed.
641    async fn try_handle_metric_batch_puts(
642        &self,
643        requests: Vec<IndexedRegionRequest>,
644    ) -> Result<Either<BatchRegionResponse<error::Error>, Vec<IndexedRegionRequest>>> {
645        let Some(first) = requests.first() else {
646            return Ok(Either::Right(requests));
647        };
648        if !matches!(first.request, RegionRequest::Put(_)) {
649            return Ok(Either::Right(requests));
650        }
651
652        let first_region_id = first.region_id;
653        let request_type = first.request.request_type();
654
655        // Upstream batching keeps requests from the same engine together.
656        // Ordinary execution reports engine lookup failures per entry.
657        let Ok(CurrentEngine::Engine(engine)) =
658            self.inner.get_engine(first_region_id, &RegionChange::None)
659        else {
660            return Ok(Either::Right(requests));
661        };
662        if engine.name() != METRIC_ENGINE_NAME
663            || !requests
664                .iter()
665                .all(|request| matches!(request.request, RegionRequest::Put(_)))
666        {
667            return Ok(Either::Right(requests));
668        }
669        let metric_engine = engine
670            .as_any()
671            .downcast_ref::<MetricEngine>()
672            .context(UnexpectedSnafu {
673                violated: "Failed to downcast to MetricEngine",
674            })?
675            .clone();
676
677        let indices: Vec<_> = requests
678            .iter()
679            .map(|request| (request.index, request.region_id))
680            .collect();
681        let put_requests = requests.into_iter().map(|request| match request.request {
682            RegionRequest::Put(put) => (request.region_id, put),
683            _ => unreachable!("Already checked all are Put"),
684        });
685        let tracing_context = TracingContext::from_current_span();
686        let batch_size = put_requests.len();
687        let span = tracing_context.attach(info_span!(
688            "RegionServer::handle_metric_batch_puts",
689            batch_size = batch_size
690        ));
691        let task = common_runtime::spawn_ingest(async move {
692            metric_engine
693                .put_regions_batch(put_requests)
694                .trace(span)
695                .await
696        });
697        let results = join_ingest_task(task, request_type).await?;
698        let mut response = BatchRegionResponse {
699            affected_rows: 0,
700            extensions: HashMap::new(),
701            failures: Vec::new(),
702        };
703        for group in results {
704            let region_id = indices[group.request_indices[0]].1;
705            let result = group
706                .result
707                .map_err(BoxedError::new)
708                .context(HandleRegionRequestSnafu { region_id })
709                .map(RegionResponse::new);
710            record_ingest_result(request_type, group.request_indices.len(), &result);
711            match result {
712                Ok(result) => {
713                    response.affected_rows += result.affected_rows;
714                }
715                Err(error) => {
716                    log_batch_write_error(&error, indices[group.request_indices[0]].0);
717                    let error = Arc::new(error);
718                    response
719                        .failures
720                        .extend(group.request_indices.into_iter().map(|index| {
721                            (
722                                indices[index].0,
723                                error::BatchWriteSnafu.into_error(Arc::clone(&error)),
724                            )
725                        }));
726                }
727            }
728        }
729        Ok(Either::Left(response))
730    }
731
732    /// Batches puts into ready mito regions and retains every entry's outcome.
733    async fn try_handle_mito_batch_puts(
734        &self,
735        requests: Vec<IndexedRegionRequest>,
736    ) -> Result<Either<BatchRegionResponse<error::Error>, Vec<IndexedRegionRequest>>> {
737        let Some(engine) = self.mito_engine_for_batch_puts(&requests) else {
738            return Ok(Either::Right(requests));
739        };
740        let request_type = requests[0].request.request_type();
741        let mut indices: HashMap<RegionId, std::collections::VecDeque<usize>> = HashMap::new();
742        let puts = requests
743            .into_iter()
744            .map(|request| {
745                indices
746                    .entry(request.region_id)
747                    .or_default()
748                    .push_back(request.index);
749                match request.request {
750                    RegionRequest::Put(put) => (request.region_id, put),
751                    _ => unreachable!("Already checked all are Put"),
752                }
753            })
754            .collect();
755        let started = Instant::now();
756        let tracing_context = TracingContext::from_current_span();
757        let task = common_runtime::spawn_ingest(async move {
758            let mut pending = engine
759                .handle_batch_put_requests(puts)
760                .into_iter()
761                .map(|(region_ids, response)| {
762                    let request_indices = region_ids
763                        .iter()
764                        .filter_map(|region_id| {
765                            indices
766                                .get_mut(region_id)
767                                .and_then(|indices| indices.pop_front())
768                        })
769                        .collect::<Vec<_>>();
770                    let span = tracing_context.attach(info_span!(
771                        "RegionServer::handle_region_request",
772                        region_id = region_ids[0].to_string()
773                    ));
774                    async move { (region_ids, request_indices, response.await) }.trace(span)
775                })
776                .collect::<FuturesUnordered<_>>();
777            let histogram =
778                crate::metrics::HANDLE_REGION_REQUEST_ELAPSED.with_label_values(&[request_type]);
779            let mut response = BatchRegionResponse {
780                affected_rows: 0,
781                extensions: HashMap::new(),
782                failures: Vec::new(),
783            };
784            while let Some((region_ids, request_indices, result)) = pending.next().await {
785                let elapsed = started.elapsed().as_secs_f64();
786                for _ in &region_ids {
787                    histogram.observe(elapsed);
788                }
789                let result = result.context(HandleRegionRequestSnafu {
790                    region_id: region_ids[0],
791                });
792                record_ingest_result(request_type, region_ids.len(), &result);
793                match result {
794                    Ok(result) => {
795                        response.affected_rows += result.affected_rows;
796                        response.extensions.extend(result.extensions);
797                    }
798                    Err(error) => {
799                        log_batch_write_error(&error, request_indices[0]);
800                        let error = Arc::new(error);
801                        response
802                            .failures
803                            .extend(request_indices.into_iter().map(|index| {
804                                (index, error::BatchWriteSnafu.into_error(Arc::clone(&error)))
805                            }));
806                    }
807                }
808            }
809            response.failures.sort_unstable_by_key(|(index, _)| *index);
810            response
811        });
812        join_ingest_task(task, request_type).await.map(Either::Left)
813    }
814
815    /// Returns the mito engine when there are at least two requests, every one a put into a ready
816    /// mito region.
817    fn mito_engine_for_batch_puts(
818        &self,
819        requests: &[IndexedRegionRequest],
820    ) -> Option<RegionEngineRef> {
821        if requests.len() < 2 {
822            return None;
823        }
824        let first_region_id = requests[0].region_id;
825        let all_puts_to_ready_mito_regions = requests.iter().all(|request| {
826            matches!(request.request, RegionRequest::Put(_))
827                && matches!(
828                    self.inner.region_map.get(&request.region_id).as_deref(),
829                    Some(RegionEngineWithStatus::Ready(engine)) if engine.name() == MITO_ENGINE_NAME
830                )
831        });
832        if !all_puts_to_ready_mito_regions {
833            return None;
834        }
835        match self.inner.region_map.get(&first_region_id).as_deref() {
836            Some(RegionEngineWithStatus::Ready(engine)) => Some(engine.clone()),
837            _ => None,
838        }
839    }
840
841    async fn handle_sync_region_request(&self, request: &SyncRequest) -> Result<RegionResponse> {
842        let region_id = RegionId::from_u64(request.region_id);
843        let manifest_info = request
844            .manifest_info
845            .context(error::MissingRequiredFieldSnafu {
846                name: "manifest_info",
847            })?;
848
849        let manifest_info = match manifest_info {
850            ManifestInfo::MitoManifestInfo(info) => {
851                RegionManifestInfo::mito(info.data_manifest_version, 0, 0)
852            }
853            ManifestInfo::MetricManifestInfo(info) => RegionManifestInfo::metric(
854                info.data_manifest_version,
855                0,
856                info.metadata_manifest_version,
857                0,
858            ),
859        };
860
861        let tracing_context = TracingContext::from_current_span();
862        let span = tracing_context.attach(info_span!("RegionServer::handle_sync_region_request"));
863
864        self.sync_region(
865            region_id,
866            SyncRegionFromRequest::from_manifest(manifest_info),
867        )
868        .trace(span)
869        .await
870        .map(|_| RegionResponse::new(AffectedRows::default()))
871    }
872
873    /// Handles the ListMetadata request and retrieves metadata for specified regions.
874    ///
875    /// Returns the results as a JSON-serialized list in the [RegionResponse]. It serializes
876    /// non-existing regions as `null`.
877    #[tracing::instrument(skip_all)]
878    async fn handle_list_metadata_request(
879        &self,
880        request: &ListMetadataRequest,
881    ) -> Result<RegionResponse> {
882        let mut region_metadatas = Vec::new();
883        // Collect metadata for each region
884        for region_id in &request.region_ids {
885            let region_id = RegionId::from_u64(*region_id);
886            // Get the engine.
887            let Some(engine) = self.find_engine(region_id)? else {
888                region_metadatas.push(None);
889                continue;
890            };
891
892            match engine.get_metadata(region_id).await {
893                Ok(metadata) => region_metadatas.push(Some(metadata)),
894                Err(err) => {
895                    if err.status_code() == StatusCode::RegionNotFound {
896                        region_metadatas.push(None);
897                    } else {
898                        Err(err).with_context(|_| GetRegionMetadataSnafu {
899                            engine: engine.name(),
900                            region_id,
901                        })?;
902                    }
903                }
904            }
905        }
906
907        // Serialize metadata to JSON
908        let json_result = serde_json::to_vec(&region_metadatas).context(SerializeJsonSnafu)?;
909
910        let response = RegionResponse::from_metadata(json_result);
911
912        Ok(response)
913    }
914
915    /// Sync region manifest and registers new opened logical regions.
916    pub async fn sync_region(
917        &self,
918        region_id: RegionId,
919        request: SyncRegionFromRequest,
920    ) -> Result<()> {
921        let engine = match self.inner.get_engine(region_id, &RegionChange::None)? {
922            CurrentEngine::Engine(engine) => engine,
923            _ => {
924                return UnexpectedSnafu {
925                    violated: "unexpected EarlyReturn engine status for a ready region",
926                }
927                .fail();
928            }
929        };
930
931        self.inner
932            .handle_sync_region(&engine, region_id, request)
933            .await
934    }
935
936    /// Remaps manifests from old regions to new regions.
937    pub async fn remap_manifests(
938        &self,
939        request: RemapManifestsRequest,
940    ) -> Result<RemapManifestsResponse> {
941        let region_id = request.region_id;
942        let engine = match self.inner.get_engine(region_id, &RegionChange::None)? {
943            CurrentEngine::Engine(engine) => engine,
944            _ => {
945                return UnexpectedSnafu {
946                    violated: "unexpected EarlyReturn engine status for a ready region",
947                }
948                .fail();
949            }
950        };
951
952        engine
953            .remap_manifests(request)
954            .await
955            .with_context(|_| HandleRegionRequestSnafu { region_id })
956    }
957
958    fn is_suspended(&self) -> bool {
959        self.suspend.load(Ordering::Relaxed)
960    }
961
962    pub(crate) fn suspend_state(&self) -> Arc<AtomicBool> {
963        self.suspend.clone()
964    }
965}
966
967fn wrap_flow_region_watermark_stream(
968    stream: SendableRecordBatchStream,
969    region_id: RegionId,
970    query_ctx: &QueryContextRef,
971) -> SendableRecordBatchStream {
972    if should_collect_region_watermark_from_extensions(&query_ctx.extensions())
973        && let Some(seq) = query_ctx.get_snapshot(region_id.as_u64())
974    {
975        Box::pin(RegionWatermarkStream::new(stream, region_id, seq)) as SendableRecordBatchStream
976    } else {
977        stream
978    }
979}
980
981/// Wraps a region read stream so terminal metrics can carry the scan-open watermark.
982struct RegionWatermarkStream {
983    stream: SendableRecordBatchStream,
984    region_id: u64,
985    snapshot_seq: u64,
986    finished: bool,
987}
988
989impl RegionWatermarkStream {
990    fn new(stream: SendableRecordBatchStream, region_id: RegionId, snapshot_seq: u64) -> Self {
991        Self {
992            stream,
993            region_id: region_id.as_u64(),
994            snapshot_seq,
995            finished: false,
996        }
997    }
998
999    fn merged_metrics(&self, mut metrics: RecordBatchMetrics) -> RecordBatchMetrics {
1000        if metrics
1001            .region_watermarks
1002            .iter()
1003            .any(|entry| entry.region_id == self.region_id)
1004        {
1005            return metrics;
1006        }
1007
1008        metrics
1009            .region_watermarks
1010            .push(common_recordbatch::adapter::RegionWatermarkEntry {
1011                region_id: self.region_id,
1012                watermark: Some(self.snapshot_seq),
1013            });
1014        metrics
1015    }
1016}
1017
1018impl RecordBatchStream for RegionWatermarkStream {
1019    fn name(&self) -> &str {
1020        self.stream.name()
1021    }
1022
1023    fn schema(&self) -> datatypes::schema::SchemaRef {
1024        self.stream.schema()
1025    }
1026
1027    fn output_ordering(&self) -> Option<&[OrderOption]> {
1028        self.stream.output_ordering()
1029    }
1030
1031    fn metrics(&self) -> Option<RecordBatchMetrics> {
1032        let base = self.stream.metrics();
1033        if !self.finished {
1034            return base;
1035        }
1036
1037        Some(self.merged_metrics(base.unwrap_or_default()))
1038    }
1039}
1040
1041impl Stream for RegionWatermarkStream {
1042    type Item = common_recordbatch::error::Result<RecordBatch>;
1043
1044    fn size_hint(&self) -> (usize, Option<usize>) {
1045        self.stream.size_hint()
1046    }
1047
1048    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
1049        match Pin::new(&mut self.stream).poll_next(cx) {
1050            Poll::Ready(None) => {
1051                self.finished = true;
1052                Poll::Ready(None)
1053            }
1054            other => other,
1055        }
1056    }
1057}
1058
1059#[async_trait]
1060impl RegionServerHandler for RegionServer {
1061    async fn handle_region_request(
1062        &self,
1063        request: RegionRequestV1,
1064    ) -> ServerResult<RegionResponseV1> {
1065        let accept_partial_result = request
1066            .header
1067            .as_ref()
1068            .and_then(|header| header.query_context.as_ref())
1069            .and_then(|context| context.extensions.get(api::region::ACCEPT_PARTIAL_RESULT))
1070            .is_some_and(|value| value == "true");
1071        let body = request.body.context(servers_error::InvalidQuerySnafu {
1072            reason: "Expecting non-empty region request body.",
1073        })?;
1074        self.handle_inner(body, accept_partial_result).await
1075    }
1076
1077    async fn handle(&self, request: region_request::Body) -> ServerResult<RegionResponseV1> {
1078        self.handle_inner(request, false).await
1079    }
1080}
1081
1082impl RegionServer {
1083    async fn handle_inner(
1084        &self,
1085        request: region_request::Body,
1086        accept_partial_result: bool,
1087    ) -> ServerResult<RegionResponseV1> {
1088        let request_count = match &request {
1089            region_request::Body::Inserts(requests) => Some(requests.requests.len()),
1090            region_request::Body::Deletes(requests) => Some(requests.requests.len()),
1091            _ => None,
1092        };
1093        if let Some(request_count) = request_count {
1094            return self
1095                .handle_write_request(request, request_count, accept_partial_result)
1096                .await;
1097        }
1098        let failed_requests_cnt = crate::metrics::REGION_SERVER_REQUEST_FAILURE_COUNT
1099            .with_label_values(&[request.as_ref()]);
1100        let response = match &request {
1101            region_request::Body::Creates(_)
1102            | region_request::Body::Drops(_)
1103            | region_request::Body::Alters(_) => self.handle_batch_ddl_requests(request).await,
1104            region_request::Body::Sync(sync_request) => {
1105                self.handle_sync_region_request(sync_request).await
1106            }
1107            region_request::Body::ListMetadata(list_metadata_request) => {
1108                self.handle_list_metadata_request(list_metadata_request)
1109                    .await
1110            }
1111            region_request::Body::RemoteDynFilter(remote_dyn_filter_request) => {
1112                self.handle_remote_dyn_filter_request(remote_dyn_filter_request)
1113                    .await
1114            }
1115            _ => self.handle_requests_in_serial(request).await,
1116        }
1117        .map_err(BoxedError::new)
1118        .inspect_err(|_| failed_requests_cnt.inc())
1119        .context(ExecuteGrpcRequestSnafu)?;
1120        Ok(RegionResponseV1 {
1121            header: Some(ResponseHeader {
1122                status: Some(Status {
1123                    status_code: StatusCode::Success as _,
1124                    ..Default::default()
1125                }),
1126            }),
1127            affected_rows: response.affected_rows as _,
1128            extensions: response.extensions,
1129            metadata: response.metadata,
1130            failures: Vec::new(),
1131        })
1132    }
1133
1134    async fn handle_write_request(
1135        &self,
1136        request: region_request::Body,
1137        entry_count: usize,
1138        accept_partial_result: bool,
1139    ) -> ServerResult<RegionResponseV1> {
1140        let failed_requests_cnt = crate::metrics::REGION_SERVER_REQUEST_FAILURE_COUNT
1141            .with_label_values(&[request.as_ref()]);
1142        let mut result = self
1143            .handle_requests_in_parallel(request)
1144            .await
1145            .map_err(BoxedError::new)
1146            .inspect_err(|_| failed_requests_cnt.inc())
1147            .context(ExecuteGrpcRequestSnafu)?;
1148        if !result.failures.is_empty() {
1149            failed_requests_cnt.inc();
1150            // Old clients and single-entry writes retain tonic errors and retry metadata.
1151            if (!accept_partial_result || entry_count == 1)
1152                && let Some((_, error)) = result.failures.drain(..).min_by_key(|(index, _)| *index)
1153            {
1154                return Err(BoxedError::new(error)).context(ExecuteGrpcRequestSnafu);
1155            }
1156        }
1157        Ok(encode_batch_write_response(result))
1158    }
1159}
1160
1161#[async_trait]
1162impl FlightCraft for RegionServer {
1163    async fn do_get(
1164        &self,
1165        request: Request<Ticket>,
1166    ) -> TonicResult<Response<TonicStream<FlightData>>> {
1167        ensure!(!self.is_suspended(), SuspendedSnafu);
1168
1169        let ticket = request.into_inner().ticket;
1170        let request = api::v1::region::QueryRequest::decode(ticket.as_ref())
1171            .context(servers_error::InvalidFlightTicketSnafu)?;
1172        let tracing_context = request
1173            .header
1174            .as_ref()
1175            .map(|h| TracingContext::from_w3c(&h.tracing_context))
1176            .unwrap_or_default();
1177        let query_ctx = request
1178            .header
1179            .as_ref()
1180            .map(QueryContext::try_from)
1181            .transpose()
1182            .map_err(|err| {
1183                servers_error::InvalidParameterSnafu {
1184                    reason: err.to_string(),
1185                }
1186                .build()
1187            })?
1188            .map(Arc::new)
1189            .unwrap_or(QueryContext::arc());
1190
1191        let region_server = self.clone();
1192        let initializer_query_ctx = query_ctx.clone();
1193        let initializer_tracing_context = tracing_context.clone();
1194        let initializer = async move {
1195            region_server
1196                .handle_remote_read(request, initializer_query_ctx)
1197                .trace(initializer_tracing_context.attach(info_span!("RegionServer::handle_read")))
1198                .await
1199                .map_err(Into::into)
1200        };
1201
1202        let stream = Box::pin(FlightRecordBatchStream::new(
1203            FlightRecordBatchStreamInput::initializer(async move {
1204                initializer
1205                    .await
1206                    .map(FlightRecordBatchSource::RecordBatches)
1207            }),
1208            tracing_context,
1209            self.flight_compression,
1210            query_ctx,
1211        ));
1212        Ok(Response::new(stream))
1213    }
1214}
1215
1216/// A decoded write retains its protobuf entry index even when preceding entries are empty.
1217struct IndexedRegionRequest {
1218    index: usize,
1219    region_id: RegionId,
1220    request: RegionRequest,
1221}
1222
1223fn prepare_batch_write_requests(body: region_request::Body) -> Vec<IndexedRegionRequest> {
1224    match body {
1225        region_request::Body::Inserts(inserts) => inserts
1226            .requests
1227            .into_iter()
1228            .enumerate()
1229            .filter_map(|(index, request)| {
1230                store_region_request::make_region_put(request).map(|(region_id, request)| {
1231                    IndexedRegionRequest {
1232                        index,
1233                        region_id,
1234                        request: RegionRequest::Put(request),
1235                    }
1236                })
1237            })
1238            .collect(),
1239        region_request::Body::Deletes(deletes) => deletes
1240            .requests
1241            .into_iter()
1242            .enumerate()
1243            .filter_map(|(index, request)| {
1244                store_region_request::make_region_delete(request).map(|(region_id, request)| {
1245                    IndexedRegionRequest {
1246                        index,
1247                        region_id,
1248                        request: RegionRequest::Delete(request),
1249                    }
1250                })
1251            })
1252            .collect(),
1253        _ => unreachable!("Only inserts/deletes are prepared as batch writes"),
1254    }
1255}
1256
1257fn encode_batch_write_response(result: BatchRegionResponse<error::Error>) -> RegionResponseV1 {
1258    RegionResponseV1 {
1259        header: Some(ResponseHeader {
1260            status: Some(Status {
1261                status_code: if result.failures.is_empty() {
1262                    StatusCode::Success
1263                } else {
1264                    StatusCode::PartialFailure
1265                } as u32,
1266                err_msg: if let Some((index, error)) = result.first_failure() {
1267                    format!(
1268                        "{} region requests failed; entry {index}: {}",
1269                        result.failures.len(),
1270                        error.output_msg()
1271                    )
1272                } else {
1273                    String::new()
1274                },
1275                ..Default::default()
1276            }),
1277        }),
1278        metadata: Vec::new(),
1279        affected_rows: result.affected_rows as _,
1280        extensions: result.extensions,
1281        failures: result
1282            .failures
1283            .into_iter()
1284            .map(|(index, error)| RegionRequestFailure {
1285                request_index: index as u32,
1286                status: Some(Status {
1287                    status_code: error.status_code() as u32,
1288                    err_msg: error.output_msg(),
1289                    retry_hint: error.retry_hint().as_str().to_string(),
1290                }),
1291            })
1292            .collect(),
1293    }
1294}
1295
1296fn log_batch_write_error(error: &error::Error, index: usize) {
1297    if error.status_code().should_log_error() {
1298        error!(error; "Failed to handle batch entry, request_index: {}", index);
1299    } else {
1300        debug!(
1301            "Failed to handle batch entry, request_index: {}, err: {}",
1302            index, error
1303        );
1304    }
1305}
1306
1307#[derive(Clone)]
1308enum RegionEngineWithStatus {
1309    // An opening, or creating region.
1310    Registering(RegionEngineRef),
1311    // A closing, or dropping region.
1312    Deregistering(RegionEngineRef),
1313    // A ready region.
1314    Ready(RegionEngineRef),
1315}
1316
1317impl RegionEngineWithStatus {
1318    /// Returns [RegionEngineRef].
1319    pub fn into_engine(self) -> RegionEngineRef {
1320        match self {
1321            RegionEngineWithStatus::Registering(engine) => engine,
1322            RegionEngineWithStatus::Deregistering(engine) => engine,
1323            RegionEngineWithStatus::Ready(engine) => engine,
1324        }
1325    }
1326}
1327
1328impl Deref for RegionEngineWithStatus {
1329    type Target = RegionEngineRef;
1330
1331    fn deref(&self) -> &Self::Target {
1332        match self {
1333            RegionEngineWithStatus::Registering(engine) => engine,
1334            RegionEngineWithStatus::Deregistering(engine) => engine,
1335            RegionEngineWithStatus::Ready(engine) => engine,
1336        }
1337    }
1338}
1339
1340struct RegionServerInner {
1341    engines: RwLock<HashMap<String, RegionEngineRef>>,
1342    region_map: DashMap<RegionId, RegionEngineWithStatus>,
1343    query_engine: QueryEngineRef,
1344    runtime: Runtime,
1345    event_listener: RegionServerEventListenerRef,
1346    table_provider_factory: TableProviderFactoryRef,
1347    /// The number of queries allowed to be executed at the same time.
1348    /// Act as last line of defense on datanode to prevent query overloading.
1349    parallelism: Option<RegionServerParallelism>,
1350    /// The topic stats reporter.
1351    topic_stats_reporter: RwLock<Option<Box<dyn TopicStatsReporter>>>,
1352    /// HACK(zhongzc): Direct MitoEngine handle for diagnostics. This couples the
1353    /// server with a concrete engine; acceptable for now to fetch Mito-specific
1354    /// info (e.g., list SSTs). Consider a diagnostics trait later.
1355    mito_engine: RwLock<Option<MitoEngine>>,
1356    /// TODO(remote-dyn-filter): Reap this query-scoped placeholder registry on query finish/cancel
1357    /// and later fold it into the real remote dyn filter runtime state lifecycle.
1358    initial_remote_dyn_filter_registrations: RemoteDynFilterRegistry,
1359}
1360
1361struct RegionServerParallelism {
1362    semaphore: Arc<Semaphore>,
1363    timeout: Duration,
1364}
1365
1366impl RegionServerParallelism {
1367    pub fn from_opts(
1368        max_concurrent_queries: usize,
1369        concurrent_query_limiter_timeout: Duration,
1370    ) -> Option<Self> {
1371        if max_concurrent_queries == 0 {
1372            return None;
1373        }
1374        Some(RegionServerParallelism {
1375            semaphore: Arc::new(Semaphore::new(max_concurrent_queries)),
1376            timeout: concurrent_query_limiter_timeout,
1377        })
1378    }
1379
1380    pub async fn acquire(&self) -> Result<OwnedSemaphorePermit> {
1381        timeout(self.timeout, self.semaphore.clone().acquire_owned())
1382            .await
1383            .context(ConcurrentQueryLimiterTimeoutSnafu)?
1384            .context(ConcurrentQueryLimiterClosedSnafu)
1385    }
1386}
1387
1388/// Wraps a record batch stream and holds a concurrency permit until the stream is
1389/// fully consumed (dropped), so `max_concurrent_queries` bounds the number of
1390/// in-flight read streams, not just query planning.
1391struct PermitGuardedStream {
1392    inner: SendableRecordBatchStream,
1393    _permit: OwnedSemaphorePermit,
1394}
1395
1396impl RecordBatchStream for PermitGuardedStream {
1397    fn name(&self) -> &str {
1398        self.inner.name()
1399    }
1400
1401    fn schema(&self) -> SchemaRef {
1402        self.inner.schema()
1403    }
1404
1405    fn output_ordering(&self) -> Option<&[OrderOption]> {
1406        self.inner.output_ordering()
1407    }
1408
1409    fn metrics(&self) -> Option<RecordBatchMetrics> {
1410        self.inner.metrics()
1411    }
1412}
1413
1414impl Stream for PermitGuardedStream {
1415    type Item = common_recordbatch::error::Result<RecordBatch>;
1416
1417    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
1418        self.inner.as_mut().poll_next(cx)
1419    }
1420}
1421
1422/// Wraps `stream` so it holds `permit` until fully consumed. Returns `stream`
1423/// unchanged when no permit was acquired (limiter disabled).
1424fn maybe_guard_stream(
1425    stream: SendableRecordBatchStream,
1426    permit: Option<OwnedSemaphorePermit>,
1427) -> SendableRecordBatchStream {
1428    match permit {
1429        Some(permit) => Box::pin(PermitGuardedStream {
1430            inner: stream,
1431            _permit: permit,
1432        }),
1433        None => stream,
1434    }
1435}
1436
1437enum CurrentEngine {
1438    Engine(RegionEngineRef),
1439    EarlyReturn(AffectedRows),
1440}
1441
1442impl Debug for CurrentEngine {
1443    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1444        match self {
1445            CurrentEngine::Engine(engine) => f
1446                .debug_struct("CurrentEngine")
1447                .field("engine", &engine.name())
1448                .finish(),
1449            CurrentEngine::EarlyReturn(rows) => f
1450                .debug_struct("CurrentEngine")
1451                .field("return", rows)
1452                .finish(),
1453        }
1454    }
1455}
1456
1457impl RegionServerInner {
1458    pub fn new(
1459        query_engine: QueryEngineRef,
1460        runtime: Runtime,
1461        event_listener: RegionServerEventListenerRef,
1462        table_provider_factory: TableProviderFactoryRef,
1463        parallelism: Option<RegionServerParallelism>,
1464    ) -> Self {
1465        Self {
1466            engines: RwLock::new(HashMap::new()),
1467            region_map: DashMap::new(),
1468            query_engine,
1469            runtime,
1470            event_listener,
1471            table_provider_factory,
1472            parallelism,
1473            topic_stats_reporter: RwLock::new(None),
1474            mito_engine: RwLock::new(None),
1475            initial_remote_dyn_filter_registrations: RemoteDynFilterRegistry::new(),
1476        }
1477    }
1478
1479    pub fn register_engine(&self, engine: RegionEngineRef) {
1480        let engine_name = engine.name();
1481        if engine_name == MITO_ENGINE_NAME
1482            && let Some(mito_engine) = engine.as_any().downcast_ref::<MitoEngine>()
1483        {
1484            *self.mito_engine.write().unwrap() = Some(mito_engine.clone());
1485        }
1486
1487        info!("Region Engine {engine_name} is registered");
1488        self.engines
1489            .write()
1490            .unwrap()
1491            .insert(engine_name.to_string(), engine);
1492    }
1493
1494    pub fn set_topic_stats_reporter(&self, topic_stats_reporter: Box<dyn TopicStatsReporter>) {
1495        info!("Set topic stats reporter");
1496        *self.topic_stats_reporter.write().unwrap() = Some(topic_stats_reporter);
1497    }
1498
1499    fn is_ingest_request(request: &RegionRequest) -> bool {
1500        matches!(
1501            request,
1502            RegionRequest::Put(_) | RegionRequest::Delete(_) | RegionRequest::BulkInserts(_)
1503        )
1504    }
1505
1506    fn get_engine(
1507        &self,
1508        region_id: RegionId,
1509        region_change: &RegionChange,
1510    ) -> Result<CurrentEngine> {
1511        let current_region_status = self.region_map.get(&region_id);
1512
1513        let engine = match region_change {
1514            RegionChange::Register(attribute) => match current_region_status {
1515                Some(status) => match status.clone() {
1516                    RegionEngineWithStatus::Registering(engine) => engine,
1517                    RegionEngineWithStatus::Deregistering(_) => {
1518                        return error::RegionBusySnafu { region_id }.fail();
1519                    }
1520                    RegionEngineWithStatus::Ready(_) => status.clone().into_engine(),
1521                },
1522                _ => self
1523                    .engines
1524                    .read()
1525                    .unwrap()
1526                    .get(attribute.engine())
1527                    .with_context(|| RegionEngineNotFoundSnafu {
1528                        name: attribute.engine(),
1529                    })?
1530                    .clone(),
1531            },
1532            RegionChange::OfflineCleanup(attribute) => match current_region_status {
1533                Some(status) => match status.clone() {
1534                    RegionEngineWithStatus::Registering(_)
1535                    | RegionEngineWithStatus::Deregistering(_)
1536                    | RegionEngineWithStatus::Ready(_) => {
1537                        return error::RegionBusySnafu { region_id }.fail();
1538                    }
1539                },
1540                None => self
1541                    .engines
1542                    .read()
1543                    .unwrap()
1544                    .get(attribute.engine())
1545                    .with_context(|| RegionEngineNotFoundSnafu {
1546                        name: attribute.engine(),
1547                    })?
1548                    .clone(),
1549            },
1550            RegionChange::Deregisters => match current_region_status {
1551                Some(status) => match status.clone() {
1552                    RegionEngineWithStatus::Registering(_) => {
1553                        return error::RegionBusySnafu { region_id }.fail();
1554                    }
1555                    RegionEngineWithStatus::Deregistering(_) => {
1556                        return Ok(CurrentEngine::EarlyReturn(0));
1557                    }
1558                    RegionEngineWithStatus::Ready(_) => status.clone().into_engine(),
1559                },
1560                None => return Ok(CurrentEngine::EarlyReturn(0)),
1561            },
1562            RegionChange::None | RegionChange::Catchup | RegionChange::Ingest => {
1563                match current_region_status {
1564                    Some(status) => match status.clone() {
1565                        RegionEngineWithStatus::Registering(_) => {
1566                            return error::RegionNotReadySnafu { region_id }.fail();
1567                        }
1568                        RegionEngineWithStatus::Deregistering(_) => {
1569                            return error::RegionNotFoundSnafu { region_id }.fail();
1570                        }
1571                        RegionEngineWithStatus::Ready(engine) => engine,
1572                    },
1573                    None => return error::RegionNotFoundSnafu { region_id }.fail(),
1574                }
1575            }
1576        };
1577
1578        Ok(CurrentEngine::Engine(engine))
1579    }
1580
1581    async fn handle_batch_open_requests_inner(
1582        &self,
1583        engine: RegionEngineRef,
1584        parallelism: usize,
1585        requests: Vec<(RegionId, RegionOpenRequest)>,
1586        ignore_nonexistent_region: bool,
1587    ) -> Result<Vec<RegionId>> {
1588        let request_count = requests.len();
1589        let region_changes = requests
1590            .iter()
1591            .map(|(region_id, open)| {
1592                let attribute = parse_region_attribute(&open.engine, &open.options)?;
1593                Ok((*region_id, RegionChange::Register(attribute)))
1594            })
1595            .collect::<Result<HashMap<_, _>>>()
1596            .inspect_err(|err| {
1597                record_region_open_failures(engine.name(), err.status_code(), request_count);
1598            })?;
1599
1600        for (&region_id, region_change) in &region_changes {
1601            self.set_region_status_not_ready(region_id, &engine, region_change)
1602        }
1603
1604        let mut open_regions = Vec::with_capacity(requests.len());
1605        let mut errors = vec![];
1606        match engine
1607            .handle_batch_open_requests(parallelism, requests)
1608            .await
1609            .with_context(|_| HandleBatchOpenRequestSnafu)
1610        {
1611            Ok(results) => {
1612                for (region_id, result) in results {
1613                    let region_change = &region_changes[&region_id];
1614                    match result {
1615                        Ok(_) => {
1616                            if let Err(e) = self
1617                                .set_region_status_ready(region_id, engine.clone(), *region_change)
1618                                .await
1619                            {
1620                                error!(e; "Failed to set region to ready: {}", region_id);
1621                                record_region_open_failures(engine.name(), e.status_code(), 1);
1622                                errors.push(BoxedError::new(e));
1623                            } else {
1624                                open_regions.push(region_id)
1625                            }
1626                        }
1627                        Err(e) => {
1628                            self.unset_region_status(region_id, &engine, *region_change);
1629                            if e.status_code() == StatusCode::RegionNotFound
1630                                && ignore_nonexistent_region
1631                            {
1632                                warn!("Region {} not found, ignore it, source: {:?}", region_id, e);
1633                            } else {
1634                                error!(e; "Failed to open region: {}", region_id);
1635                                record_region_open_failures(engine.name(), e.status_code(), 1);
1636                                errors.push(e);
1637                            }
1638                        }
1639                    }
1640                }
1641            }
1642            Err(e) => {
1643                for (&region_id, region_change) in &region_changes {
1644                    self.unset_region_status(region_id, &engine, *region_change);
1645                }
1646                error!(e; "Failed to open batch regions");
1647                record_region_open_failures(engine.name(), e.status_code(), request_count);
1648                errors.push(BoxedError::new(e));
1649            }
1650        }
1651
1652        if !errors.is_empty() {
1653            // Preserve the first region error so callers can honor its status code and retry hint.
1654            return Err(errors.swap_remove(0)).context(HandleBatchOpenRequestSnafu);
1655        }
1656
1657        Ok(open_regions)
1658    }
1659
1660    pub async fn handle_batch_open_requests(
1661        &self,
1662        parallelism: usize,
1663        requests: Vec<(RegionId, RegionOpenRequest)>,
1664        ignore_nonexistent_region: bool,
1665    ) -> Result<Vec<RegionId>> {
1666        let mut engine_grouped_requests: HashMap<String, Vec<_>> =
1667            HashMap::with_capacity(requests.len());
1668        for (region_id, request) in requests {
1669            if let Some(requests) = engine_grouped_requests.get_mut(&request.engine) {
1670                requests.push((region_id, request));
1671            } else {
1672                engine_grouped_requests.insert(request.engine.clone(), vec![(region_id, request)]);
1673            }
1674        }
1675
1676        let mut results = Vec::with_capacity(engine_grouped_requests.keys().len());
1677        for (engine, requests) in engine_grouped_requests {
1678            let engine = self
1679                .engines
1680                .read()
1681                .unwrap()
1682                .get(&engine)
1683                .with_context(|| RegionEngineNotFoundSnafu { name: &engine })
1684                .inspect_err(|err| {
1685                    record_region_open_failures(&engine, err.status_code(), requests.len());
1686                })?
1687                .clone();
1688            results.push(
1689                self.handle_batch_open_requests_inner(
1690                    engine,
1691                    parallelism,
1692                    requests,
1693                    ignore_nonexistent_region,
1694                )
1695                .await,
1696            )
1697        }
1698
1699        Ok(results
1700            .into_iter()
1701            .collect::<Result<Vec<_>>>()?
1702            .into_iter()
1703            .flatten()
1704            .collect::<Vec<_>>())
1705    }
1706
1707    pub async fn handle_batch_catchup_requests_inner(
1708        &self,
1709        engine: RegionEngineRef,
1710        parallelism: usize,
1711        requests: Vec<(RegionId, RegionCatchupRequest)>,
1712    ) -> Result<Vec<(RegionId, std::result::Result<(), BoxedError>)>> {
1713        for (region_id, _) in &requests {
1714            self.set_region_status_not_ready(*region_id, &engine, &RegionChange::Catchup);
1715        }
1716        let region_ids = requests
1717            .iter()
1718            .map(|(region_id, _)| *region_id)
1719            .collect::<Vec<_>>();
1720        let mut responses = Vec::with_capacity(requests.len());
1721        match engine
1722            .handle_batch_catchup_requests(parallelism, requests)
1723            .await
1724        {
1725            Ok(results) => {
1726                for (region_id, result) in results {
1727                    match result {
1728                        Ok(_) => {
1729                            if let Err(e) = self
1730                                .set_region_status_ready(
1731                                    region_id,
1732                                    engine.clone(),
1733                                    RegionChange::Catchup,
1734                                )
1735                                .await
1736                            {
1737                                error!(e; "Failed to set region to ready: {}", region_id);
1738                                responses.push((region_id, Err(BoxedError::new(e))));
1739                            } else {
1740                                responses.push((region_id, Ok(())));
1741                            }
1742                        }
1743                        Err(e) => {
1744                            self.unset_region_status(region_id, &engine, RegionChange::Catchup);
1745                            error!(e; "Failed to catchup region: {}", region_id);
1746                            responses.push((region_id, Err(e)));
1747                        }
1748                    }
1749                }
1750            }
1751            Err(e) => {
1752                for region_id in region_ids {
1753                    self.unset_region_status(region_id, &engine, RegionChange::Catchup);
1754                }
1755                error!(e; "Failed to catchup batch regions");
1756                return error::UnexpectedSnafu {
1757                    violated: format!("Failed to catchup batch regions: {:?}", e),
1758                }
1759                .fail();
1760            }
1761        }
1762
1763        Ok(responses)
1764    }
1765
1766    pub async fn handle_batch_catchup_requests(
1767        &self,
1768        parallelism: usize,
1769        requests: Vec<(RegionId, RegionCatchupRequest)>,
1770    ) -> Result<Vec<(RegionId, std::result::Result<(), BoxedError>)>> {
1771        let mut engine_grouped_requests: HashMap<String, Vec<_>> = HashMap::new();
1772
1773        let mut responses = Vec::with_capacity(requests.len());
1774        for (region_id, request) in requests {
1775            if let Ok(engine) = self.get_engine(region_id, &RegionChange::Catchup) {
1776                match engine {
1777                    CurrentEngine::Engine(engine) => {
1778                        engine_grouped_requests
1779                            .entry(engine.name().to_string())
1780                            .or_default()
1781                            .push((region_id, request));
1782                    }
1783                    CurrentEngine::EarlyReturn(_) => {
1784                        return error::UnexpectedSnafu {
1785                            violated: format!("Unexpected engine type for region {}", region_id),
1786                        }
1787                        .fail();
1788                    }
1789                }
1790            } else {
1791                responses.push((
1792                    region_id,
1793                    Err(BoxedError::new(
1794                        error::RegionNotFoundSnafu { region_id }.build(),
1795                    )),
1796                ));
1797            }
1798        }
1799
1800        for (engine, requests) in engine_grouped_requests {
1801            let engine = self
1802                .engines
1803                .read()
1804                .unwrap()
1805                .get(&engine)
1806                .with_context(|| RegionEngineNotFoundSnafu { name: &engine })?
1807                .clone();
1808            responses.extend(
1809                self.handle_batch_catchup_requests_inner(engine, parallelism, requests)
1810                    .await?,
1811            );
1812        }
1813
1814        Ok(responses)
1815    }
1816
1817    // Handle requests in batch.
1818    //
1819    // limitation: all create requests must be in the same engine.
1820    pub async fn handle_batch_ddl_requests(
1821        &self,
1822        batch_request: BatchRegionDdlRequest,
1823    ) -> Result<RegionResponse> {
1824        let region_changes = match &batch_request {
1825            BatchRegionDdlRequest::Create(requests) => requests
1826                .iter()
1827                .map(|(region_id, create)| {
1828                    let attribute = parse_region_attribute(&create.engine, &create.options)?;
1829                    Ok((*region_id, RegionChange::Register(attribute)))
1830                })
1831                .collect::<Result<Vec<_>>>()?,
1832            BatchRegionDdlRequest::Drop(requests) => requests
1833                .iter()
1834                .map(|(region_id, _)| (*region_id, RegionChange::Deregisters))
1835                .collect::<Vec<_>>(),
1836            BatchRegionDdlRequest::Alter(requests) => requests
1837                .iter()
1838                .map(|(region_id, _)| (*region_id, RegionChange::None))
1839                .collect::<Vec<_>>(),
1840        };
1841
1842        // The ddl procedure will ensure all requests are in the same engine.
1843        // Therefore, we can get the engine from the first request.
1844        let (first_region_id, first_region_change) = region_changes.first().unwrap();
1845        let engine = match self.get_engine(*first_region_id, first_region_change)? {
1846            CurrentEngine::Engine(engine) => engine,
1847            CurrentEngine::EarlyReturn(rows) => return Ok(RegionResponse::new(rows)),
1848        };
1849
1850        for (region_id, region_change) in region_changes.iter() {
1851            self.set_region_status_not_ready(*region_id, &engine, region_change);
1852        }
1853
1854        let ddl_type = batch_request.request_type();
1855        let result = engine
1856            .handle_batch_ddl_requests(batch_request)
1857            .await
1858            .context(HandleBatchDdlRequestSnafu { ddl_type });
1859
1860        match result {
1861            Ok(result) => {
1862                for (region_id, region_change) in &region_changes {
1863                    self.set_region_status_ready(*region_id, engine.clone(), *region_change)
1864                        .await?;
1865                }
1866
1867                Ok(RegionResponse {
1868                    affected_rows: result.affected_rows,
1869                    extensions: result.extensions,
1870                    metadata: Vec::new(),
1871                })
1872            }
1873            Err(err) => {
1874                for (region_id, region_change) in region_changes {
1875                    self.unset_region_status(region_id, &engine, region_change);
1876                }
1877
1878                Err(err)
1879            }
1880        }
1881    }
1882
1883    pub async fn handle_request(
1884        &self,
1885        region_id: RegionId,
1886        request: RegionRequest,
1887    ) -> Result<RegionResponse> {
1888        let open_engine = match &request {
1889            RegionRequest::Open(open) => Some(open.engine.clone()),
1890            _ => None,
1891        };
1892        self.handle_request_inner(region_id, request)
1893            .await
1894            .inspect_err(|err| {
1895                if let Some(engine) = open_engine {
1896                    record_region_open_failures(&engine, err.status_code(), 1);
1897                }
1898            })
1899    }
1900
1901    async fn handle_request_inner(
1902        &self,
1903        region_id: RegionId,
1904        request: RegionRequest,
1905    ) -> Result<RegionResponse> {
1906        let request_type = request.request_type();
1907        let _timer = crate::metrics::HANDLE_REGION_REQUEST_ELAPSED
1908            .with_label_values(&[request_type])
1909            .start_timer();
1910
1911        let region_change = match &request {
1912            RegionRequest::Create(create) => {
1913                let attribute = parse_region_attribute(&create.engine, &create.options)?;
1914                RegionChange::Register(attribute)
1915            }
1916            RegionRequest::Open(open) => {
1917                let attribute = parse_region_attribute(&open.engine, &open.options)?;
1918                RegionChange::Register(attribute)
1919            }
1920            RegionRequest::CleanUp(clean_up) => {
1921                let attribute = parse_region_attribute(&clean_up.engine, &clean_up.options)?;
1922                RegionChange::OfflineCleanup(attribute)
1923            }
1924            RegionRequest::Close(_) | RegionRequest::Drop(_) => RegionChange::Deregisters,
1925            RegionRequest::Put(_) | RegionRequest::Delete(_) | RegionRequest::BulkInserts(_) => {
1926                RegionChange::Ingest
1927            }
1928            RegionRequest::Alter(_)
1929            | RegionRequest::Flush(_)
1930            | RegionRequest::Compact(_)
1931            | RegionRequest::Truncate(_)
1932            | RegionRequest::BuildIndex(_)
1933            | RegionRequest::EnterStaging(_)
1934            | RegionRequest::ApplyStagingManifest(_) => RegionChange::None,
1935            RegionRequest::Catchup(_) => RegionChange::Catchup,
1936        };
1937
1938        let engine = match self.get_engine(region_id, &region_change)? {
1939            CurrentEngine::Engine(engine) => engine,
1940            CurrentEngine::EarlyReturn(rows) => return Ok(RegionResponse::new(rows)),
1941        };
1942
1943        // Sets corresponding region status to registering/deregistering before the operation.
1944        self.set_region_status_not_ready(region_id, &engine, &region_change);
1945
1946        let result = engine
1947            .handle_request(region_id, request)
1948            .await
1949            .with_context(|_| HandleRegionRequestSnafu { region_id });
1950        if matches!(region_change, RegionChange::Ingest) {
1951            record_ingest_result(request_type, 1, &result);
1952        }
1953        match result {
1954            Ok(result) => {
1955                // Sets corresponding region status to ready.
1956                self.set_region_status_ready(region_id, engine.clone(), region_change)
1957                    .await?;
1958
1959                Ok(RegionResponse {
1960                    affected_rows: result.affected_rows,
1961                    extensions: result.extensions,
1962                    metadata: Vec::new(),
1963                })
1964            }
1965            Err(err) => {
1966                // Removes the region status if the operation fails.
1967                self.unset_region_status(region_id, &engine, region_change);
1968                Err(err)
1969            }
1970        }
1971    }
1972
1973    /// Handles the sync region request.
1974    pub async fn handle_sync_region(
1975        &self,
1976        engine: &RegionEngineRef,
1977        region_id: RegionId,
1978        request: SyncRegionFromRequest,
1979    ) -> Result<()> {
1980        let Some(new_opened_regions) = engine
1981            .sync_region(region_id, request)
1982            .await
1983            .with_context(|_| HandleRegionRequestSnafu { region_id })?
1984            .new_opened_logical_region_ids()
1985        else {
1986            return Ok(());
1987        };
1988
1989        for region in &new_opened_regions {
1990            self.region_map
1991                .insert(*region, RegionEngineWithStatus::Ready(engine.clone()));
1992        }
1993        if !new_opened_regions.is_empty() {
1994            info!(
1995                region_id = %region_id,
1996                logical_region_count = new_opened_regions.len(),
1997                logical_regions = ?new_opened_regions,
1998                "Logical regions are registered"
1999            );
2000        }
2001
2002        Ok(())
2003    }
2004
2005    fn set_region_status_not_ready(
2006        &self,
2007        region_id: RegionId,
2008        engine: &RegionEngineRef,
2009        region_change: &RegionChange,
2010    ) {
2011        match region_change {
2012            RegionChange::Register(_) => {
2013                self.region_map.insert(
2014                    region_id,
2015                    RegionEngineWithStatus::Registering(engine.clone()),
2016                );
2017            }
2018            RegionChange::Deregisters => {
2019                self.region_map.insert(
2020                    region_id,
2021                    RegionEngineWithStatus::Deregistering(engine.clone()),
2022                );
2023            }
2024            _ => {}
2025        }
2026    }
2027
2028    fn unset_region_status(
2029        &self,
2030        region_id: RegionId,
2031        engine: &RegionEngineRef,
2032        region_change: RegionChange,
2033    ) {
2034        match region_change {
2035            RegionChange::None | RegionChange::Ingest | RegionChange::OfflineCleanup(_) => {}
2036            RegionChange::Register(_) => {
2037                self.region_map.remove(&region_id);
2038            }
2039            RegionChange::Deregisters => {
2040                self.region_map
2041                    .insert(region_id, RegionEngineWithStatus::Ready(engine.clone()));
2042            }
2043            RegionChange::Catchup => {}
2044        }
2045    }
2046
2047    async fn set_region_status_ready(
2048        &self,
2049        region_id: RegionId,
2050        engine: RegionEngineRef,
2051        region_change: RegionChange,
2052    ) -> Result<()> {
2053        let engine_type = engine.name();
2054        match region_change {
2055            RegionChange::None | RegionChange::Ingest | RegionChange::OfflineCleanup(_) => {}
2056            RegionChange::Register(attribute) => {
2057                info!(
2058                    "Region {region_id} is registered to engine {}",
2059                    attribute.engine()
2060                );
2061                self.region_map
2062                    .insert(region_id, RegionEngineWithStatus::Ready(engine.clone()));
2063
2064                match attribute {
2065                    RegionAttribute::Metric { physical } => {
2066                        if physical {
2067                            // Registers the logical regions belong to the physical region (`region_id`).
2068                            self.register_logical_regions(&engine, region_id).await?;
2069                            // We only send the `on_region_registered` event of the physical region.
2070                            self.event_listener.on_region_registered(region_id);
2071                        }
2072                    }
2073                    RegionAttribute::Mito => self.event_listener.on_region_registered(region_id),
2074                    RegionAttribute::File => {
2075                        // do nothing
2076                    }
2077                    RegionAttribute::Relational => {
2078                        // do nothing
2079                    }
2080                }
2081            }
2082            RegionChange::Deregisters => {
2083                info!("Region {region_id} is deregistered from engine {engine_type}");
2084                self.region_map
2085                    .remove(&region_id)
2086                    .map(|(id, engine)| engine.set_region_role(id, RegionRole::Follower));
2087                self.event_listener.on_region_deregistered(region_id);
2088            }
2089            RegionChange::Catchup => {
2090                if is_metric_engine(engine.name()) {
2091                    // Registers the logical regions belong to the physical region (`region_id`).
2092                    self.register_logical_regions(&engine, region_id).await?;
2093                }
2094            }
2095        }
2096        Ok(())
2097    }
2098
2099    async fn register_logical_regions(
2100        &self,
2101        engine: &RegionEngineRef,
2102        physical_region_id: RegionId,
2103    ) -> Result<()> {
2104        let metric_engine =
2105            engine
2106                .as_any()
2107                .downcast_ref::<MetricEngine>()
2108                .context(UnexpectedSnafu {
2109                    violated: format!(
2110                        "expecting engine type '{}', actual '{}'",
2111                        METRIC_ENGINE_NAME,
2112                        engine.name(),
2113                    ),
2114                })?;
2115
2116        let logical_regions = metric_engine
2117            .logical_regions(physical_region_id)
2118            .await
2119            .context(FindLogicalRegionsSnafu { physical_region_id })?;
2120
2121        for region in &logical_regions {
2122            self.region_map
2123                .insert(*region, RegionEngineWithStatus::Ready(engine.clone()));
2124        }
2125        if !logical_regions.is_empty() {
2126            info!(
2127                physical_region_id = %physical_region_id,
2128                logical_region_count = logical_regions.len(),
2129                logical_regions = ?logical_regions,
2130                "Logical regions are registered"
2131            );
2132        }
2133        Ok(())
2134    }
2135
2136    pub async fn handle_read(
2137        self: &Arc<Self>,
2138        request: QueryRequest,
2139        query_ctx: QueryContextRef,
2140    ) -> Result<SendableRecordBatchStream> {
2141        let live_analyze_metrics =
2142            query_ctx.explain_verbose() && query_ctx.live_analyze_metrics_enabled();
2143        let inner = self.clone();
2144        let mut stream = common_runtime::spawn_query(async move {
2145            inner.handle_read_inner(request, query_ctx).await
2146        })
2147        .await
2148        .context(RuntimeJoinSnafu {
2149            request_type: "read",
2150        })??;
2151        let schema = stream.schema();
2152        let output_ordering = stream.output_ordering().map(|ordering| ordering.to_vec());
2153
2154        let (sender, receiver) = mpsc::channel(QUERY_RUNTIME_STREAM_BUFFER_SIZE);
2155        let metrics = QueryRuntimeStream::metrics_store();
2156        let producer_metrics = metrics.clone();
2157
2158        let producer_handle = common_runtime::spawn_query(async move {
2159            if live_analyze_metrics {
2160                loop {
2161                    match time::timeout(FLIGHT_METRICS_HEARTBEAT_INTERVAL, stream.next()).await {
2162                        Ok(Some(batch)) => {
2163                            *producer_metrics.write().unwrap() = stream.metrics();
2164                            if sender.send(batch).await.is_err() {
2165                                return;
2166                            }
2167                        }
2168                        Ok(None) => break,
2169                        Err(_) => {
2170                            *producer_metrics.write().unwrap() = stream.metrics();
2171                        }
2172                    }
2173                }
2174            } else {
2175                while let Some(batch) = stream.next().await {
2176                    *producer_metrics.write().unwrap() = stream.metrics();
2177                    if sender.send(batch).await.is_err() {
2178                        break;
2179                    }
2180                }
2181            }
2182            *producer_metrics.write().unwrap() = stream.metrics();
2183        });
2184
2185        Ok(Box::pin(
2186            QueryRuntimeStream::new(schema, receiver)
2187                .with_output_ordering(output_ordering)
2188                .with_metrics_store(metrics)
2189                .with_producer_handle(producer_handle),
2190        ))
2191    }
2192
2193    async fn handle_read_inner(
2194        &self,
2195        request: QueryRequest,
2196        query_ctx: QueryContextRef,
2197    ) -> Result<SendableRecordBatchStream> {
2198        // TODO(ruihang): add metrics and set trace id
2199
2200        let result = self
2201            .query_engine
2202            .execute(request.plan, query_ctx)
2203            .await
2204            .context(ExecuteLogicalPlanSnafu)?;
2205
2206        match result.data {
2207            OutputData::AffectedRows(_) | OutputData::RecordBatches(_) => {
2208                UnsupportedOutputSnafu { expected: "stream" }.fail()
2209            }
2210            OutputData::Stream(stream) => Ok(stream),
2211        }
2212    }
2213
2214    async fn stop(&self) -> Result<()> {
2215        // Calling async functions while iterating inside the Dashmap could easily cause the Rust
2216        // complains "higher-ranked lifetime error". Rust can't prove some future is legit.
2217        // Possible related issue: https://github.com/rust-lang/rust/issues/102211
2218        //
2219        // The workaround is to put the async functions in the `common_runtime::spawn_global`. Or like
2220        // it here, collect the values first then use later separately.
2221
2222        let regions = self
2223            .region_map
2224            .iter()
2225            .map(|x| (*x.key(), x.value().clone()))
2226            .collect::<Vec<_>>();
2227        let num_regions = regions.len();
2228
2229        let mut first_error = None;
2230        for (region_id, engine) in regions {
2231            let closed = engine
2232                .handle_request(
2233                    region_id,
2234                    RegionRequest::Close(RegionCloseRequest::default()),
2235                )
2236                .await;
2237            match closed {
2238                Ok(_) => debug!("Region {region_id} is closed"),
2239                Err(e) => {
2240                    // A close that failed may not have flushed writes that
2241                    // skipped the WAL, which nothing replays.
2242                    error!(e; "Failed to close region {region_id}; writes that skipped the WAL may be lost");
2243                    record_shutdown_error(
2244                        &mut first_error,
2245                        Err(e).context(HandleRegionRequestSnafu { region_id }),
2246                    );
2247                }
2248            }
2249        }
2250        self.region_map.clear();
2251        info!("closed {num_regions} regions");
2252
2253        drop(self.mito_engine.write().unwrap().take());
2254        let engines = self.engines.write().unwrap().drain().collect::<Vec<_>>();
2255        for (engine_name, engine) in engines {
2256            let result = engine
2257                .stop()
2258                .await
2259                .context(StopRegionEngineSnafu { name: &engine_name });
2260            if result.is_ok() {
2261                info!("Region engine {engine_name} is stopped");
2262            }
2263            record_shutdown_error(&mut first_error, result);
2264        }
2265
2266        first_error.map_or(Ok(()), Err)
2267    }
2268}
2269
2270#[derive(Debug, Clone, Copy)]
2271enum RegionChange {
2272    None,
2273    Register(RegionAttribute),
2274    OfflineCleanup(RegionAttribute),
2275    Deregisters,
2276    Catchup,
2277    Ingest,
2278}
2279
2280fn is_metric_engine(engine: &str) -> bool {
2281    engine == METRIC_ENGINE_NAME
2282}
2283
2284/// Records failed open attempts without using arbitrary engine names as metric labels.
2285fn record_region_open_failures(engine: &str, status_code: StatusCode, count: usize) {
2286    let engine = match engine {
2287        MITO_ENGINE_NAME | METRIC_ENGINE_NAME | FILE_ENGINE_NAME | RELATIONAL_ENGINE_NAME => engine,
2288        _ => "unknown",
2289    };
2290    crate::metrics::REGION_OPEN_FAILURES_TOTAL
2291        .with_label_values(&[engine, status_code.as_ref()])
2292        .inc_by(count as u64);
2293}
2294
2295/// Awaits an ingest task without treating a join failure as an entry-level write result.
2296async fn join_ingest_task<T>(task: JoinHandle<T>, request_type: &'static str) -> Result<T> {
2297    task.await
2298        .inspect_err(|error| {
2299            let reason = if error.is_panic() {
2300                "panic"
2301            } else {
2302                "cancelled"
2303            };
2304            crate::metrics::INGEST_TASK_FAILURES_TOTAL
2305                .with_label_values(&[request_type, reason])
2306                .inc();
2307        })
2308        .context(RuntimeJoinSnafu { request_type })
2309}
2310
2311/// Records the result of `count` ingest requests answered by one response: the rows they
2312/// changed, or their failures.
2313fn record_ingest_result(request_type: &str, count: usize, result: &Result<RegionResponse>) {
2314    match result {
2315        Ok(response) => crate::metrics::REGION_CHANGED_ROW_COUNT
2316            .with_label_values(&[request_type])
2317            .inc_by(response.affected_rows as u64),
2318        Err(err) => crate::metrics::REGION_SERVER_INSERT_FAIL_COUNT
2319            .with_label_values(&[request_type, err.status_code().as_ref()])
2320            .inc_by(count as u64),
2321    }
2322}
2323
2324fn parse_region_attribute(
2325    engine: &str,
2326    options: &HashMap<String, String>,
2327) -> Result<RegionAttribute> {
2328    match engine {
2329        MITO_ENGINE_NAME => Ok(RegionAttribute::Mito),
2330        METRIC_ENGINE_NAME => {
2331            let physical = !options.contains_key(LOGICAL_TABLE_METADATA_KEY);
2332
2333            Ok(RegionAttribute::Metric { physical })
2334        }
2335        FILE_ENGINE_NAME => Ok(RegionAttribute::File),
2336        RELATIONAL_ENGINE_NAME => Ok(RegionAttribute::Relational),
2337        _ => error::UnexpectedSnafu {
2338            violated: format!("Unknown engine: {}", engine),
2339        }
2340        .fail(),
2341    }
2342}
2343
2344#[derive(Debug, Clone, Copy)]
2345enum RegionAttribute {
2346    Mito,
2347    Metric { physical: bool },
2348    File,
2349    Relational,
2350}
2351
2352impl RegionAttribute {
2353    fn engine(&self) -> &'static str {
2354        match self {
2355            RegionAttribute::Mito => MITO_ENGINE_NAME,
2356            RegionAttribute::Metric { .. } => METRIC_ENGINE_NAME,
2357            RegionAttribute::File => FILE_ENGINE_NAME,
2358            RegionAttribute::Relational => RELATIONAL_ENGINE_NAME,
2359        }
2360    }
2361}
2362
2363#[cfg(test)]
2364mod tests {
2365    use std::assert_matches;
2366    use std::collections::HashMap;
2367    use std::sync::Arc;
2368
2369    use api::v1::region::{InsertRequest, InsertRequests};
2370    use api::v1::{PartitionExprVersion, Rows, SemanticType};
2371    use common_error::ext::{ErrorExt, RetryHint};
2372    use common_recordbatch::RecordBatches;
2373    use common_recordbatch::adapter::{RecordBatchMetrics, RegionWatermarkEntry};
2374    use common_wal::config::object_store::{ObjectStoreWalConfig, STANDALONE_GENERATION};
2375    use common_wal::options::{ObjectStoreWalOptions, WAL_OPTIONS_KEY, WalOptions};
2376    use datatypes::prelude::{ConcreteDataType, VectorRef};
2377    use datatypes::schema::{ColumnSchema, Schema};
2378    use datatypes::vectors::Int32Vector;
2379    use futures_util::StreamExt;
2380    use log_store::ObjectStoreLogStore;
2381    use mito2::config::MitoConfig;
2382    use mito2::test_util::{CreateRequestBuilder, TestEnv, build_rows, rows_schema};
2383    use object_store::ObjectStore;
2384    use object_store::services::Memory;
2385    use query::options::FLOW_RETURN_REGION_SEQ;
2386    use store_api::metadata::{ColumnMetadata, RegionMetadata, RegionMetadataBuilder};
2387    use store_api::region_engine::RegionEngine;
2388    use store_api::region_request::{
2389        PathType, RegionCleanUpRequest, RegionCompactRequest, RegionDeleteRequest,
2390        RegionDropRequest, RegionOpenRequest, RegionPutRequest, RegionTruncateRequest,
2391    };
2392    use store_api::storage::RegionId;
2393
2394    use super::*;
2395    use crate::tests::{MockRegionEngine, mock_region_server};
2396
2397    #[test]
2398    fn test_is_ingest_request() {
2399        let rows = || Rows {
2400            schema: Vec::new(),
2401            rows: Vec::new(),
2402        };
2403
2404        assert!(RegionServerInner::is_ingest_request(&RegionRequest::Put(
2405            RegionPutRequest {
2406                skip_wal: false,
2407                rows: rows(),
2408                hint: None,
2409                partition_expr_version: None,
2410            },
2411        )));
2412        assert!(RegionServerInner::is_ingest_request(
2413            &RegionRequest::Delete(RegionDeleteRequest {
2414                rows: rows(),
2415                hint: None,
2416                partition_expr_version: None,
2417            },)
2418        ));
2419        assert!(!RegionServerInner::is_ingest_request(
2420            &RegionRequest::Compact(RegionCompactRequest::default()),
2421        ));
2422    }
2423
2424    fn single_value_stream() -> SendableRecordBatchStream {
2425        let schema = Arc::new(Schema::new(vec![ColumnSchema::new(
2426            "v",
2427            ConcreteDataType::int32_datatype(),
2428            false,
2429        )]));
2430        let values: VectorRef = Arc::new(Int32Vector::from_slice([1]));
2431        let batch = RecordBatch::new(schema.clone(), vec![values]).unwrap();
2432        RecordBatches::try_new(schema, vec![batch])
2433            .unwrap()
2434            .as_stream()
2435    }
2436
2437    #[tokio::test]
2438    async fn test_region_watermark_stream_only_sets_terminal_metrics() {
2439        let schema = Arc::new(Schema::new(vec![ColumnSchema::new(
2440            "v",
2441            ConcreteDataType::int32_datatype(),
2442            false,
2443        )]));
2444        let values: VectorRef = Arc::new(Int32Vector::from_slice([1, 2]));
2445        let batch = RecordBatch::new(schema.clone(), vec![values]).unwrap();
2446        let stream = RecordBatches::try_new(schema, vec![batch])
2447            .unwrap()
2448            .as_stream();
2449
2450        let region_id = RegionId::new(42, 7);
2451        let wrapped = RegionWatermarkStream::new(stream, region_id, 99);
2452        let mut pinned = Box::pin(wrapped);
2453
2454        assert!(pinned.as_ref().get_ref().metrics().is_none());
2455        while pinned.next().await.is_some() {}
2456
2457        let metrics = pinned.as_ref().get_ref().metrics().unwrap();
2458        assert_eq!(
2459            metrics.region_watermarks,
2460            vec![RegionWatermarkEntry {
2461                region_id: region_id.as_u64(),
2462                watermark: Some(99),
2463            }]
2464        );
2465    }
2466
2467    #[test]
2468    fn test_region_watermark_stream_preserves_unproved_watermark() {
2469        let schema = Arc::new(Schema::new(vec![ColumnSchema::new(
2470            "v",
2471            ConcreteDataType::int32_datatype(),
2472            false,
2473        )]));
2474        let values: VectorRef = Arc::new(Int32Vector::from_slice([1]));
2475        let batch = RecordBatch::new(schema.clone(), vec![values]).unwrap();
2476        let stream = RecordBatches::try_new(schema, vec![batch])
2477            .unwrap()
2478            .as_stream();
2479
2480        let region_id = RegionId::new(42, 7);
2481        let wrapped = RegionWatermarkStream::new(stream, region_id, 99);
2482        let metrics = RecordBatchMetrics {
2483            region_watermarks: vec![RegionWatermarkEntry {
2484                region_id: region_id.as_u64(),
2485                watermark: None,
2486            }],
2487            ..Default::default()
2488        };
2489
2490        let merged = wrapped.merged_metrics(metrics);
2491        assert_eq!(
2492            merged.region_watermarks,
2493            vec![RegionWatermarkEntry {
2494                region_id: region_id.as_u64(),
2495                watermark: None,
2496            }]
2497        );
2498    }
2499
2500    #[tokio::test]
2501    async fn test_wrap_flow_region_watermark_stream_adds_terminal_metrics() {
2502        let region_id = RegionId::new(42, 7);
2503        let query_ctx = Arc::new(
2504            QueryContextBuilder::default()
2505                .extensions(HashMap::from([(
2506                    FLOW_RETURN_REGION_SEQ.to_string(),
2507                    "true".to_string(),
2508                )]))
2509                .build(),
2510        );
2511        query_ctx.set_snapshot(region_id.as_u64(), 99);
2512
2513        let wrapped =
2514            wrap_flow_region_watermark_stream(single_value_stream(), region_id, &query_ctx);
2515        let mut pinned = Box::pin(wrapped);
2516        while pinned.next().await.is_some() {}
2517
2518        let metrics = pinned.as_ref().get_ref().metrics().unwrap();
2519        assert_eq!(
2520            metrics.region_watermarks,
2521            vec![RegionWatermarkEntry {
2522                region_id: region_id.as_u64(),
2523                watermark: Some(99),
2524            }]
2525        );
2526    }
2527
2528    #[tokio::test]
2529    async fn test_wrap_flow_region_watermark_stream_skips_without_extension() {
2530        let region_id = RegionId::new(42, 7);
2531        let query_ctx = Arc::new(QueryContextBuilder::default().build());
2532        query_ctx.set_snapshot(region_id.as_u64(), 99);
2533
2534        let wrapped =
2535            wrap_flow_region_watermark_stream(single_value_stream(), region_id, &query_ctx);
2536        let mut pinned = Box::pin(wrapped);
2537        while pinned.next().await.is_some() {}
2538
2539        assert!(pinned.as_ref().get_ref().metrics().is_none());
2540    }
2541
2542    #[tokio::test]
2543    async fn test_wrap_flow_region_watermark_stream_skips_without_snapshot() {
2544        let region_id = RegionId::new(42, 7);
2545        let query_ctx = Arc::new(
2546            QueryContextBuilder::default()
2547                .extensions(HashMap::from([(
2548                    FLOW_RETURN_REGION_SEQ.to_string(),
2549                    "true".to_string(),
2550                )]))
2551                .build(),
2552        );
2553
2554        let wrapped =
2555            wrap_flow_region_watermark_stream(single_value_stream(), region_id, &query_ctx);
2556        let mut pinned = Box::pin(wrapped);
2557        while pinned.next().await.is_some() {}
2558
2559        assert!(pinned.as_ref().get_ref().metrics().is_none());
2560    }
2561
2562    #[tokio::test]
2563    async fn test_offline_cleanup_does_not_register_region() {
2564        let mut mock_region_server = mock_region_server();
2565        let (engine, mut receiver) = MockRegionEngine::new(MITO_ENGINE_NAME);
2566        mock_region_server.register_engine(engine);
2567
2568        let region_id = RegionId::new(1, 1);
2569        let response = mock_region_server
2570            .handle_request(
2571                region_id,
2572                RegionRequest::CleanUp(RegionCleanUpRequest {
2573                    engine: MITO_ENGINE_NAME.to_string(),
2574                    table_dir: String::new(),
2575                    path_type: PathType::Bare,
2576                    options: HashMap::new(),
2577                }),
2578            )
2579            .await
2580            .unwrap();
2581
2582        assert_eq!(response.affected_rows, 0);
2583        let (handled_region_id, handled_request) = receiver.try_recv().unwrap();
2584        assert_eq!(handled_region_id, region_id);
2585        assert_matches!(handled_request, RegionRequest::CleanUp(_));
2586        assert!(
2587            mock_region_server
2588                .inner
2589                .region_map
2590                .get(&region_id)
2591                .is_none()
2592        );
2593    }
2594
2595    #[tokio::test]
2596    async fn test_offline_cleanup_rejects_registered_region() {
2597        let mut mock_region_server = mock_region_server();
2598        let (engine, mut receiver) = MockRegionEngine::new(MITO_ENGINE_NAME);
2599        mock_region_server.register_engine(engine.clone());
2600
2601        let region_id = RegionId::new(1, 1);
2602        mock_region_server
2603            .inner
2604            .region_map
2605            .insert(region_id, RegionEngineWithStatus::Ready(engine));
2606
2607        let err = mock_region_server
2608            .handle_request(
2609                region_id,
2610                RegionRequest::CleanUp(RegionCleanUpRequest {
2611                    engine: MITO_ENGINE_NAME.to_string(),
2612                    table_dir: String::new(),
2613                    path_type: PathType::Bare,
2614                    options: HashMap::new(),
2615                }),
2616            )
2617            .await
2618            .unwrap_err();
2619
2620        assert_eq!(err.status_code(), StatusCode::RegionBusy);
2621        assert!(receiver.try_recv().is_err());
2622        assert!(matches!(
2623            mock_region_server
2624                .inner
2625                .region_map
2626                .get(&region_id)
2627                .unwrap()
2628                .clone(),
2629            RegionEngineWithStatus::Ready(_)
2630        ));
2631    }
2632
2633    #[tokio::test]
2634    async fn test_region_registering() {
2635        common_telemetry::init_default_ut_logging();
2636
2637        let mut mock_region_server = mock_region_server();
2638        let (engine, _receiver) = MockRegionEngine::new(MITO_ENGINE_NAME);
2639        let engine_name = engine.name();
2640        mock_region_server.register_engine(engine.clone());
2641        let region_id = RegionId::new(1, 1);
2642        let builder = CreateRequestBuilder::new();
2643        let create_req = builder.build();
2644        // Tries to create/open a registering region.
2645        mock_region_server.inner.region_map.insert(
2646            region_id,
2647            RegionEngineWithStatus::Registering(engine.clone()),
2648        );
2649        let response = mock_region_server
2650            .handle_request(region_id, RegionRequest::Create(create_req))
2651            .await
2652            .unwrap();
2653        assert_eq!(response.affected_rows, 0);
2654        let status = mock_region_server
2655            .inner
2656            .region_map
2657            .get(&region_id)
2658            .unwrap()
2659            .clone();
2660        assert!(matches!(status, RegionEngineWithStatus::Ready(_)));
2661
2662        mock_region_server.inner.region_map.insert(
2663            region_id,
2664            RegionEngineWithStatus::Registering(engine.clone()),
2665        );
2666        let response = mock_region_server
2667            .handle_request(
2668                region_id,
2669                RegionRequest::Open(RegionOpenRequest {
2670                    engine: engine_name.to_string(),
2671                    table_dir: String::new(),
2672                    path_type: PathType::Bare,
2673                    options: Default::default(),
2674                    skip_wal_replay: false,
2675                    checkpoint: None,
2676                    requirements: Default::default(),
2677                }),
2678            )
2679            .await
2680            .unwrap();
2681        assert_eq!(response.affected_rows, 0);
2682        let status = mock_region_server
2683            .inner
2684            .region_map
2685            .get(&region_id)
2686            .unwrap()
2687            .clone();
2688        assert!(matches!(status, RegionEngineWithStatus::Ready(_)));
2689    }
2690
2691    #[tokio::test]
2692    async fn test_region_deregistering() {
2693        common_telemetry::init_default_ut_logging();
2694
2695        let mut mock_region_server = mock_region_server();
2696        let (engine, _receiver) = MockRegionEngine::new(MITO_ENGINE_NAME);
2697
2698        mock_region_server.register_engine(engine.clone());
2699
2700        let region_id = RegionId::new(1, 1);
2701
2702        // Tries to drop/close a registering region.
2703        mock_region_server.inner.region_map.insert(
2704            region_id,
2705            RegionEngineWithStatus::Deregistering(engine.clone()),
2706        );
2707
2708        let response = mock_region_server
2709            .handle_request(
2710                region_id,
2711                RegionRequest::Drop(RegionDropRequest {
2712                    fast_path: false,
2713                    force: false,
2714                    partial_drop: false,
2715                }),
2716            )
2717            .await
2718            .unwrap();
2719        assert_eq!(response.affected_rows, 0);
2720
2721        let status = mock_region_server
2722            .inner
2723            .region_map
2724            .get(&region_id)
2725            .unwrap()
2726            .clone();
2727        assert!(matches!(status, RegionEngineWithStatus::Deregistering(_)));
2728
2729        mock_region_server.inner.region_map.insert(
2730            region_id,
2731            RegionEngineWithStatus::Deregistering(engine.clone()),
2732        );
2733
2734        let response = mock_region_server
2735            .handle_request(
2736                region_id,
2737                RegionRequest::Close(RegionCloseRequest::default()),
2738            )
2739            .await
2740            .unwrap();
2741        assert_eq!(response.affected_rows, 0);
2742
2743        let status = mock_region_server
2744            .inner
2745            .region_map
2746            .get(&region_id)
2747            .unwrap()
2748            .clone();
2749        assert!(matches!(status, RegionEngineWithStatus::Deregistering(_)));
2750    }
2751
2752    #[tokio::test]
2753    async fn test_region_not_ready() {
2754        common_telemetry::init_default_ut_logging();
2755
2756        let mut mock_region_server = mock_region_server();
2757        let (engine, _receiver) = MockRegionEngine::new(MITO_ENGINE_NAME);
2758
2759        mock_region_server.register_engine(engine.clone());
2760
2761        let region_id = RegionId::new(1, 1);
2762
2763        // Tries to drop/close a registering region.
2764        mock_region_server.inner.region_map.insert(
2765            region_id,
2766            RegionEngineWithStatus::Registering(engine.clone()),
2767        );
2768
2769        let err = mock_region_server
2770            .handle_request(
2771                region_id,
2772                RegionRequest::Truncate(RegionTruncateRequest::All),
2773            )
2774            .await
2775            .unwrap_err();
2776
2777        assert_eq!(err.status_code(), StatusCode::RegionNotReady);
2778    }
2779
2780    #[test]
2781    fn test_batch_write_summary_uses_first_input_failure() {
2782        let first = error::RegionNotFoundSnafu {
2783            region_id: RegionId::new(1, 0),
2784        }
2785        .build();
2786        let expected = format!("2 region requests failed; entry 0: {}", first.output_msg());
2787        let later = error::RegionBusySnafu {
2788            region_id: RegionId::new(1, 1),
2789        }
2790        .build();
2791        let response = encode_batch_write_response(BatchRegionResponse {
2792            affected_rows: 0,
2793            extensions: HashMap::new(),
2794            failures: vec![(1, later), (0, first)],
2795        });
2796        let status = response.header.unwrap().status.unwrap();
2797        assert_eq!(status.status_code, StatusCode::PartialFailure as u32);
2798        assert_eq!(status.err_msg, expected);
2799        assert_eq!(response.failures[0].request_index, 1);
2800        assert_eq!(response.failures[1].request_index, 0);
2801    }
2802
2803    #[tokio::test]
2804    async fn test_write_failure_response_compatibility() {
2805        let server = mock_region_server();
2806        let missing = RegionId::new(1, 1);
2807        let registering = RegionId::new(1, 2);
2808        let (engine, _receiver) = MockRegionEngine::new(MITO_ENGINE_NAME);
2809        server
2810            .inner
2811            .region_map
2812            .insert(registering, RegionEngineWithStatus::Registering(engine));
2813        for (region_id, code) in [
2814            (missing, StatusCode::RegionNotFound),
2815            (registering, StatusCode::RegionNotReady),
2816        ] {
2817            for delete in [false, true] {
2818                for accept_partial in [false, true] {
2819                    // A preceding empty entry must still count toward the original envelope size.
2820                    for with_empty_entry in [false, true] {
2821                        let rows = Some(Rows {
2822                            schema: Vec::new(),
2823                            rows: Vec::new(),
2824                        });
2825                        let body = if delete {
2826                            let request = api::v1::region::DeleteRequest {
2827                                region_id: region_id.as_u64(),
2828                                rows,
2829                                ..Default::default()
2830                            };
2831                            region_request::Body::Deletes(api::v1::region::DeleteRequests {
2832                                requests: if with_empty_entry {
2833                                    vec![Default::default(), request]
2834                                } else {
2835                                    vec![request]
2836                                },
2837                            })
2838                        } else {
2839                            let request = InsertRequest {
2840                                region_id: region_id.as_u64(),
2841                                rows,
2842                                ..Default::default()
2843                            };
2844                            region_request::Body::Inserts(InsertRequests {
2845                                requests: if with_empty_entry {
2846                                    vec![Default::default(), request]
2847                                } else {
2848                                    vec![request]
2849                                },
2850                            })
2851                        };
2852                        let mut header = api::v1::region::RegionRequestHeader::default();
2853                        if accept_partial {
2854                            header
2855                                .query_context
2856                                .get_or_insert_with(Default::default)
2857                                .extensions
2858                                .insert(
2859                                    api::region::ACCEPT_PARTIAL_RESULT.to_string(),
2860                                    "true".to_string(),
2861                                );
2862                        }
2863                        let result = server
2864                            .handle_region_request(RegionRequestV1 {
2865                                header: Some(header),
2866                                body: Some(body),
2867                            })
2868                            .await;
2869                        if accept_partial && with_empty_entry {
2870                            let response = result.unwrap();
2871                            assert_eq!(
2872                                StatusCode::PartialFailure as u32,
2873                                response.header.unwrap().status.unwrap().status_code
2874                            );
2875                            assert_eq!(1, response.failures.len());
2876                            assert_eq!(1, response.failures[0].request_index);
2877                            let status = response.failures[0].status.as_ref().unwrap();
2878                            assert_eq!(code as u32, status.status_code);
2879                            assert_eq!(
2880                                RetryHint::RetryAfterRouteRefresh.as_str(),
2881                                status.retry_hint
2882                            );
2883                        } else {
2884                            let status: tonic::Status = result.unwrap_err().into();
2885                            assert_eq!(
2886                                common_error::status_code::status_to_tonic_code(code),
2887                                status.code()
2888                            );
2889                            assert_eq!(
2890                                (code as u32).to_string(),
2891                                status
2892                                    .metadata()
2893                                    .get(common_error::GREPTIME_DB_HEADER_ERROR_CODE)
2894                                    .unwrap()
2895                                    .to_str()
2896                                    .unwrap()
2897                            );
2898                            assert_eq!(
2899                                RetryHint::RetryAfterRouteRefresh.as_str(),
2900                                status
2901                                    .metadata()
2902                                    .get(common_error::GREPTIME_DB_HEADER_ERROR_RETRY_HINT)
2903                                    .unwrap()
2904                                    .to_str()
2905                                    .unwrap()
2906                            );
2907                        }
2908                    }
2909                }
2910            }
2911        }
2912    }
2913
2914    #[tokio::test]
2915    async fn test_legacy_batch_returns_first_input_error() {
2916        let server = mock_region_server();
2917        let first = RegionId::new(1, 1);
2918        let second = RegionId::new(1, 2);
2919        let (engine, _receiver) = MockRegionEngine::with_custom_apply_fn("mock", |engine| {
2920            engine.handle_request_delay = Some(Duration::from_millis(10));
2921            engine.handle_request_mock_fn = Some(Box::new(|region_id, _| {
2922                error::RegionBusySnafu { region_id }.fail()
2923            }));
2924        });
2925        server.register_test_region(first, engine);
2926        let requests = [first, second]
2927            .map(|region_id| InsertRequest {
2928                region_id: region_id.as_u64(),
2929                rows: Some(Rows::default()),
2930                ..Default::default()
2931            })
2932            .to_vec();
2933        let error = server
2934            .handle_region_request(RegionRequestV1 {
2935                header: Some(Default::default()),
2936                body: Some(region_request::Body::Inserts(InsertRequests { requests })),
2937            })
2938            .await
2939            .unwrap_err();
2940        assert_eq!(StatusCode::RegionBusy, error.status_code());
2941        assert_eq!(RetryHint::Retryable, error.retry_hint());
2942    }
2943
2944    #[tokio::test]
2945    async fn test_region_request_failed() {
2946        common_telemetry::init_default_ut_logging();
2947
2948        let mut mock_region_server = mock_region_server();
2949        let (engine, _receiver) = MockRegionEngine::with_mock_fn(
2950            MITO_ENGINE_NAME,
2951            Box::new(|_region_id, _request| {
2952                error::UnexpectedSnafu {
2953                    violated: "test".to_string(),
2954                }
2955                .fail()
2956            }),
2957        );
2958
2959        mock_region_server.register_engine(engine.clone());
2960
2961        let region_id = RegionId::new(1, 1);
2962        let builder = CreateRequestBuilder::new();
2963        let create_req = builder.build();
2964        mock_region_server
2965            .handle_request(region_id, RegionRequest::Create(create_req))
2966            .await
2967            .unwrap_err();
2968
2969        assert!(!mock_region_server.inner.region_map.contains_key(&region_id));
2970
2971        mock_region_server
2972            .inner
2973            .region_map
2974            .insert(region_id, RegionEngineWithStatus::Ready(engine.clone()));
2975
2976        mock_region_server
2977            .handle_request(
2978                region_id,
2979                RegionRequest::Drop(RegionDropRequest {
2980                    fast_path: false,
2981                    force: false,
2982                    partial_drop: false,
2983                }),
2984            )
2985            .await
2986            .unwrap_err();
2987
2988        assert!(mock_region_server.inner.region_map.contains_key(&region_id));
2989
2990        let insert = api::v1::region::InsertRequest {
2991            region_id: region_id.as_u64(),
2992            rows: Some(Rows {
2993                schema: Vec::new(),
2994                rows: Vec::new(),
2995            }),
2996            ..Default::default()
2997        };
2998        let success_region = RegionId::new(1, 2);
2999        let (success_engine, _receiver) =
3000            MockRegionEngine::with_custom_apply_fn("mock", |engine| {
3001                engine.handle_request_delay = Some(std::time::Duration::from_millis(10));
3002                engine.handle_request_mock_fn = Some(Box::new(|_, _| Ok(5)));
3003            });
3004        mock_region_server.register_test_region(success_region, success_engine);
3005        let successful_insert = api::v1::region::InsertRequest {
3006            region_id: success_region.as_u64(),
3007            ..insert.clone()
3008        };
3009        let response = mock_region_server
3010            .handle_region_request(RegionRequestV1 {
3011                header: Some(api::v1::region::RegionRequestHeader {
3012                    query_context: Some(api::v1::QueryContext {
3013                        extensions: HashMap::from([(
3014                            api::region::ACCEPT_PARTIAL_RESULT.to_string(),
3015                            "true".to_string(),
3016                        )]),
3017                        ..Default::default()
3018                    }),
3019                    ..Default::default()
3020                }),
3021                body: Some(region_request::Body::Inserts(InsertRequests {
3022                    requests: vec![
3023                        Default::default(),
3024                        insert.clone(),
3025                        successful_insert,
3026                        insert,
3027                    ],
3028                })),
3029            })
3030            .await
3031            .unwrap();
3032        assert_eq!(response.affected_rows, 5);
3033        assert_eq!(
3034            response
3035                .header
3036                .as_ref()
3037                .unwrap()
3038                .status
3039                .as_ref()
3040                .unwrap()
3041                .status_code,
3042            StatusCode::PartialFailure as u32
3043        );
3044        assert_eq!(
3045            response
3046                .failures
3047                .iter()
3048                .map(|error| error.request_index)
3049                .collect::<Vec<_>>(),
3050            vec![1, 3]
3051        );
3052        assert!(
3053            response
3054                .failures
3055                .iter()
3056                .all(|error| error.status.as_ref().is_some_and(|status| {
3057                    status.status_code == StatusCode::Unexpected as u32
3058                        && status.retry_hint == RetryHint::NonRetryable.as_str()
3059                }))
3060        );
3061    }
3062
3063    /// A region that fails to close is reported in the result of the stop,
3064    /// which still closes the other regions.
3065    #[tokio::test]
3066    async fn test_stop_reports_a_region_that_failed_to_close() {
3067        common_telemetry::init_default_ut_logging();
3068
3069        let mut mock_region_server = mock_region_server();
3070        let failing = RegionId::new(1, 1);
3071        let closing = RegionId::new(1, 2);
3072        let closed = Arc::new(std::sync::Mutex::new(Vec::new()));
3073        let (engine, _receiver) = MockRegionEngine::with_mock_fn(MITO_ENGINE_NAME, {
3074            let closed = closed.clone();
3075            Box::new(move |region_id, request| {
3076                if matches!(request, RegionRequest::Close(_)) {
3077                    closed.lock().unwrap().push(region_id);
3078                    if region_id == failing {
3079                        return error::UnexpectedSnafu {
3080                            violated: "close failed".to_string(),
3081                        }
3082                        .fail();
3083                    }
3084                }
3085                Ok(0)
3086            })
3087        });
3088        mock_region_server.register_engine(engine.clone());
3089        for region_id in [failing, closing] {
3090            mock_region_server
3091                .inner
3092                .region_map
3093                .insert(region_id, RegionEngineWithStatus::Ready(engine.clone()));
3094        }
3095
3096        let err = mock_region_server.stop().await.unwrap_err();
3097
3098        assert_matches!(err, error::Error::HandleRegionRequest { region_id, .. } if region_id == failing);
3099        let mut closed = closed.lock().unwrap().clone();
3100        closed.sort();
3101        assert_eq!(vec![failing, closing], closed);
3102    }
3103
3104    #[tokio::test]
3105    async fn test_batch_open_region_ignore_nonexistent_regions() {
3106        common_telemetry::init_default_ut_logging();
3107        let mut mock_region_server = mock_region_server();
3108        let (engine, _receiver) = MockRegionEngine::with_mock_fn(
3109            MITO_ENGINE_NAME,
3110            Box::new(|region_id, _request| {
3111                if region_id == RegionId::new(1, 1) {
3112                    error::RegionNotFoundSnafu { region_id }.fail()
3113                } else {
3114                    Ok(0)
3115                }
3116            }),
3117        );
3118        mock_region_server.register_engine(engine.clone());
3119
3120        let region_ids = mock_region_server
3121            .handle_batch_open_requests(
3122                8,
3123                vec![
3124                    (
3125                        RegionId::new(1, 1),
3126                        RegionOpenRequest {
3127                            engine: MITO_ENGINE_NAME.to_string(),
3128                            table_dir: String::new(),
3129                            path_type: PathType::Bare,
3130                            options: Default::default(),
3131                            skip_wal_replay: false,
3132                            checkpoint: None,
3133                            requirements: Default::default(),
3134                        },
3135                    ),
3136                    (
3137                        RegionId::new(1, 2),
3138                        RegionOpenRequest {
3139                            engine: MITO_ENGINE_NAME.to_string(),
3140                            table_dir: String::new(),
3141                            path_type: PathType::Bare,
3142                            options: Default::default(),
3143                            skip_wal_replay: false,
3144                            checkpoint: None,
3145                            requirements: Default::default(),
3146                        },
3147                    ),
3148                ],
3149                true,
3150            )
3151            .await
3152            .unwrap();
3153        assert_eq!(region_ids, vec![RegionId::new(1, 2)]);
3154
3155        let err = mock_region_server
3156            .handle_batch_open_requests(
3157                8,
3158                vec![
3159                    (
3160                        RegionId::new(1, 1),
3161                        RegionOpenRequest {
3162                            engine: MITO_ENGINE_NAME.to_string(),
3163                            table_dir: String::new(),
3164                            path_type: PathType::Bare,
3165                            options: Default::default(),
3166                            skip_wal_replay: false,
3167                            checkpoint: None,
3168                            requirements: Default::default(),
3169                        },
3170                    ),
3171                    (
3172                        RegionId::new(1, 2),
3173                        RegionOpenRequest {
3174                            engine: MITO_ENGINE_NAME.to_string(),
3175                            table_dir: String::new(),
3176                            path_type: PathType::Bare,
3177                            options: Default::default(),
3178                            skip_wal_replay: false,
3179                            checkpoint: None,
3180                            requirements: Default::default(),
3181                        },
3182                    ),
3183                ],
3184                false,
3185            )
3186            .await
3187            .unwrap_err();
3188        assert_matches!(&err, error::Error::HandleBatchOpenRequest { .. });
3189        assert_eq!(err.status_code(), StatusCode::RegionNotFound);
3190        assert_eq!(err.retry_hint(), RetryHint::RetryAfterRouteRefresh);
3191    }
3192
3193    struct CurrentEngineTest {
3194        region_id: RegionId,
3195        current_region_status: Option<RegionEngineWithStatus>,
3196        region_change: RegionChange,
3197        assert: Box<dyn FnOnce(Result<CurrentEngine>)>,
3198    }
3199
3200    #[tokio::test]
3201    async fn test_current_engine() {
3202        common_telemetry::init_default_ut_logging();
3203
3204        let mut mock_region_server = mock_region_server();
3205        let (engine, _) = MockRegionEngine::new(MITO_ENGINE_NAME);
3206        mock_region_server.register_engine(engine.clone());
3207
3208        let region_id = RegionId::new(1024, 1);
3209        let tests = vec![
3210            // RegionChange::None
3211            CurrentEngineTest {
3212                region_id,
3213                current_region_status: None,
3214                region_change: RegionChange::None,
3215                assert: Box::new(|result| {
3216                    let err = result.unwrap_err();
3217                    assert_eq!(err.status_code(), StatusCode::RegionNotFound);
3218                }),
3219            },
3220            CurrentEngineTest {
3221                region_id,
3222                current_region_status: Some(RegionEngineWithStatus::Ready(engine.clone())),
3223                region_change: RegionChange::None,
3224                assert: Box::new(|result| {
3225                    let current_engine = result.unwrap();
3226                    assert_matches!(current_engine, CurrentEngine::Engine(_));
3227                }),
3228            },
3229            CurrentEngineTest {
3230                region_id,
3231                current_region_status: Some(RegionEngineWithStatus::Registering(engine.clone())),
3232                region_change: RegionChange::None,
3233                assert: Box::new(|result| {
3234                    let err = result.unwrap_err();
3235                    assert_eq!(err.status_code(), StatusCode::RegionNotReady);
3236                }),
3237            },
3238            CurrentEngineTest {
3239                region_id,
3240                current_region_status: Some(RegionEngineWithStatus::Deregistering(engine.clone())),
3241                region_change: RegionChange::None,
3242                assert: Box::new(|result| {
3243                    let err = result.unwrap_err();
3244                    assert_eq!(err.status_code(), StatusCode::RegionNotFound);
3245                }),
3246            },
3247            // RegionChange::Register
3248            CurrentEngineTest {
3249                region_id,
3250                current_region_status: None,
3251                region_change: RegionChange::Register(RegionAttribute::Mito),
3252                assert: Box::new(|result| {
3253                    let current_engine = result.unwrap();
3254                    assert_matches!(current_engine, CurrentEngine::Engine(_));
3255                }),
3256            },
3257            CurrentEngineTest {
3258                region_id,
3259                current_region_status: Some(RegionEngineWithStatus::Registering(engine.clone())),
3260                region_change: RegionChange::Register(RegionAttribute::Mito),
3261                assert: Box::new(|result| {
3262                    let current_engine = result.unwrap();
3263                    assert_matches!(current_engine, CurrentEngine::Engine(_));
3264                }),
3265            },
3266            CurrentEngineTest {
3267                region_id,
3268                current_region_status: Some(RegionEngineWithStatus::Deregistering(engine.clone())),
3269                region_change: RegionChange::Register(RegionAttribute::Mito),
3270                assert: Box::new(|result| {
3271                    let err = result.unwrap_err();
3272                    assert_eq!(err.status_code(), StatusCode::RegionBusy);
3273                }),
3274            },
3275            CurrentEngineTest {
3276                region_id,
3277                current_region_status: Some(RegionEngineWithStatus::Ready(engine.clone())),
3278                region_change: RegionChange::Register(RegionAttribute::Mito),
3279                assert: Box::new(|result| {
3280                    let current_engine = result.unwrap();
3281                    assert_matches!(current_engine, CurrentEngine::Engine(_));
3282                }),
3283            },
3284            // RegionChange::Deregister
3285            CurrentEngineTest {
3286                region_id,
3287                current_region_status: None,
3288                region_change: RegionChange::Deregisters,
3289                assert: Box::new(|result| {
3290                    let current_engine = result.unwrap();
3291                    assert_matches!(current_engine, CurrentEngine::EarlyReturn(_));
3292                }),
3293            },
3294            CurrentEngineTest {
3295                region_id,
3296                current_region_status: Some(RegionEngineWithStatus::Registering(engine.clone())),
3297                region_change: RegionChange::Deregisters,
3298                assert: Box::new(|result| {
3299                    let err = result.unwrap_err();
3300                    assert_eq!(err.status_code(), StatusCode::RegionBusy);
3301                }),
3302            },
3303            CurrentEngineTest {
3304                region_id,
3305                current_region_status: Some(RegionEngineWithStatus::Deregistering(engine.clone())),
3306                region_change: RegionChange::Deregisters,
3307                assert: Box::new(|result| {
3308                    let current_engine = result.unwrap();
3309                    assert_matches!(current_engine, CurrentEngine::EarlyReturn(_));
3310                }),
3311            },
3312            CurrentEngineTest {
3313                region_id,
3314                current_region_status: Some(RegionEngineWithStatus::Ready(engine.clone())),
3315                region_change: RegionChange::Deregisters,
3316                assert: Box::new(|result| {
3317                    let current_engine = result.unwrap();
3318                    assert_matches!(current_engine, CurrentEngine::Engine(_));
3319                }),
3320            },
3321            // RegionChange::OfflineCleanup
3322            CurrentEngineTest {
3323                region_id,
3324                current_region_status: None,
3325                region_change: RegionChange::OfflineCleanup(RegionAttribute::Mito),
3326                assert: Box::new(|result| {
3327                    let current_engine = result.unwrap();
3328                    assert_matches!(current_engine, CurrentEngine::Engine(_));
3329                }),
3330            },
3331            CurrentEngineTest {
3332                region_id,
3333                current_region_status: Some(RegionEngineWithStatus::Registering(engine.clone())),
3334                region_change: RegionChange::OfflineCleanup(RegionAttribute::Mito),
3335                assert: Box::new(|result| {
3336                    let err = result.unwrap_err();
3337                    assert_eq!(err.status_code(), StatusCode::RegionBusy);
3338                }),
3339            },
3340            CurrentEngineTest {
3341                region_id,
3342                current_region_status: Some(RegionEngineWithStatus::Deregistering(engine.clone())),
3343                region_change: RegionChange::OfflineCleanup(RegionAttribute::Mito),
3344                assert: Box::new(|result| {
3345                    let err = result.unwrap_err();
3346                    assert_eq!(err.status_code(), StatusCode::RegionBusy);
3347                }),
3348            },
3349            CurrentEngineTest {
3350                region_id,
3351                current_region_status: Some(RegionEngineWithStatus::Ready(engine.clone())),
3352                region_change: RegionChange::OfflineCleanup(RegionAttribute::Mito),
3353                assert: Box::new(|result| {
3354                    let err = result.unwrap_err();
3355                    assert_eq!(err.status_code(), StatusCode::RegionBusy);
3356                }),
3357            },
3358        ];
3359
3360        for test in tests {
3361            let CurrentEngineTest {
3362                region_id,
3363                current_region_status,
3364                region_change,
3365                assert,
3366            } = test;
3367
3368            // Sets up
3369            if let Some(status) = current_region_status {
3370                mock_region_server
3371                    .inner
3372                    .region_map
3373                    .insert(region_id, status);
3374            } else {
3375                mock_region_server.inner.region_map.remove(&region_id);
3376            }
3377
3378            let result = mock_region_server
3379                .inner
3380                .get_engine(region_id, &region_change);
3381
3382            assert(result);
3383        }
3384    }
3385
3386    #[tokio::test]
3387    async fn test_region_server_parallelism() {
3388        let p = RegionServerParallelism::from_opts(2, Duration::from_millis(1)).unwrap();
3389        let first_query = p.acquire().await;
3390        assert!(first_query.is_ok());
3391        let second_query = p.acquire().await;
3392        assert!(second_query.is_ok());
3393        let third_query = p.acquire().await;
3394        assert!(third_query.is_err());
3395        let err = third_query.unwrap_err();
3396        assert_eq!(
3397            err.output_msg(),
3398            "Failed to acquire permit under timeouts: deadline has elapsed".to_string()
3399        );
3400        drop(first_query);
3401        let forth_query = p.acquire().await;
3402        assert!(forth_query.is_ok());
3403    }
3404
3405    fn mock_region_metadata(region_id: RegionId) -> RegionMetadata {
3406        let mut metadata_builder = RegionMetadataBuilder::new(region_id);
3407        metadata_builder.push_column_metadata(ColumnMetadata {
3408            column_schema: datatypes::schema::ColumnSchema::new(
3409                "timestamp",
3410                ConcreteDataType::timestamp_nanosecond_datatype(),
3411                false,
3412            ),
3413            semantic_type: SemanticType::Timestamp,
3414            column_id: 0,
3415        });
3416        metadata_builder.push_column_metadata(ColumnMetadata {
3417            column_schema: datatypes::schema::ColumnSchema::new(
3418                "file",
3419                ConcreteDataType::string_datatype(),
3420                true,
3421            ),
3422            semantic_type: SemanticType::Tag,
3423            column_id: 1,
3424        });
3425        metadata_builder.push_column_metadata(ColumnMetadata {
3426            column_schema: datatypes::schema::ColumnSchema::new(
3427                "message",
3428                ConcreteDataType::string_datatype(),
3429                true,
3430            ),
3431            semantic_type: SemanticType::Field,
3432            column_id: 2,
3433        });
3434        metadata_builder.primary_key(vec![1]);
3435        metadata_builder.build().unwrap()
3436    }
3437
3438    #[tokio::test]
3439    async fn test_handle_list_metadata_request() {
3440        common_telemetry::init_default_ut_logging();
3441
3442        let mut mock_region_server = mock_region_server();
3443        let region_id_1 = RegionId::new(1, 0);
3444        let region_id_2 = RegionId::new(2, 0);
3445
3446        let metadata_1 = mock_region_metadata(region_id_1);
3447        let metadata_2 = mock_region_metadata(region_id_2);
3448        let metadatas = vec![Some(metadata_1.clone()), Some(metadata_2.clone())];
3449
3450        let metadata_1 = Arc::new(metadata_1);
3451        let metadata_2 = Arc::new(metadata_2);
3452        let (engine, _) = MockRegionEngine::with_metadata_mock_fn(
3453            MITO_ENGINE_NAME,
3454            Box::new(move |region_id| {
3455                if region_id == region_id_1 {
3456                    Ok(metadata_1.clone())
3457                } else if region_id == region_id_2 {
3458                    Ok(metadata_2.clone())
3459                } else {
3460                    error::RegionNotFoundSnafu { region_id }.fail()
3461                }
3462            }),
3463        );
3464
3465        mock_region_server.register_engine(engine.clone());
3466        mock_region_server
3467            .inner
3468            .region_map
3469            .insert(region_id_1, RegionEngineWithStatus::Ready(engine.clone()));
3470        mock_region_server
3471            .inner
3472            .region_map
3473            .insert(region_id_2, RegionEngineWithStatus::Ready(engine.clone()));
3474
3475        // All regions exist.
3476        let list_metadata_request = ListMetadataRequest {
3477            region_ids: vec![region_id_1.as_u64(), region_id_2.as_u64()],
3478        };
3479        let response = mock_region_server
3480            .handle_list_metadata_request(&list_metadata_request)
3481            .await
3482            .unwrap();
3483        let decoded_metadata: Vec<Option<RegionMetadata>> =
3484            serde_json::from_slice(&response.metadata).unwrap();
3485        assert_eq!(metadatas, decoded_metadata);
3486    }
3487
3488    #[tokio::test]
3489    async fn test_handle_list_metadata_not_found() {
3490        common_telemetry::init_default_ut_logging();
3491
3492        let mut mock_region_server = mock_region_server();
3493        let region_id_1 = RegionId::new(1, 0);
3494        let region_id_2 = RegionId::new(2, 0);
3495
3496        let metadata_1 = mock_region_metadata(region_id_1);
3497        let metadatas = vec![Some(metadata_1.clone()), None];
3498
3499        let metadata_1 = Arc::new(metadata_1);
3500        let (engine, _) = MockRegionEngine::with_metadata_mock_fn(
3501            MITO_ENGINE_NAME,
3502            Box::new(move |region_id| {
3503                if region_id == region_id_1 {
3504                    Ok(metadata_1.clone())
3505                } else {
3506                    error::RegionNotFoundSnafu { region_id }.fail()
3507                }
3508            }),
3509        );
3510
3511        mock_region_server.register_engine(engine.clone());
3512        mock_region_server
3513            .inner
3514            .region_map
3515            .insert(region_id_1, RegionEngineWithStatus::Ready(engine.clone()));
3516
3517        // Not in region map.
3518        let list_metadata_request = ListMetadataRequest {
3519            region_ids: vec![region_id_1.as_u64(), region_id_2.as_u64()],
3520        };
3521        let response = mock_region_server
3522            .handle_list_metadata_request(&list_metadata_request)
3523            .await
3524            .unwrap();
3525        let decoded_metadata: Vec<Option<RegionMetadata>> =
3526            serde_json::from_slice(&response.metadata).unwrap();
3527        assert_eq!(metadatas, decoded_metadata);
3528
3529        // Not in region engine.
3530        mock_region_server
3531            .inner
3532            .region_map
3533            .insert(region_id_2, RegionEngineWithStatus::Ready(engine.clone()));
3534        let response = mock_region_server
3535            .handle_list_metadata_request(&list_metadata_request)
3536            .await
3537            .unwrap();
3538        let decoded_metadata: Vec<Option<RegionMetadata>> =
3539            serde_json::from_slice(&response.metadata).unwrap();
3540        assert_eq!(metadatas, decoded_metadata);
3541    }
3542
3543    #[tokio::test]
3544    async fn test_handle_list_metadata_failed() {
3545        common_telemetry::init_default_ut_logging();
3546
3547        let mut mock_region_server = mock_region_server();
3548        let region_id_1 = RegionId::new(1, 0);
3549
3550        let (engine, _) = MockRegionEngine::with_metadata_mock_fn(
3551            MITO_ENGINE_NAME,
3552            Box::new(move |region_id| {
3553                error::UnexpectedSnafu {
3554                    violated: format!("Failed to get region {region_id}"),
3555                }
3556                .fail()
3557            }),
3558        );
3559
3560        mock_region_server.register_engine(engine.clone());
3561        mock_region_server
3562            .inner
3563            .region_map
3564            .insert(region_id_1, RegionEngineWithStatus::Ready(engine.clone()));
3565
3566        // Failed to get.
3567        let list_metadata_request = ListMetadataRequest {
3568            region_ids: vec![region_id_1.as_u64()],
3569        };
3570        mock_region_server
3571            .handle_list_metadata_request(&list_metadata_request)
3572            .await
3573            .unwrap_err();
3574    }
3575
3576    /// Returns a region server with a Mito engine on a durable object store WAL, the WAL, and the
3577    /// WAL options of a region on it.
3578    async fn region_server_on_object_store_wal(
3579        env: &mut TestEnv,
3580        config: MitoConfig,
3581    ) -> (RegionServer, Arc<ObjectStoreLogStore>, String) {
3582        let wal_config = ObjectStoreWalConfig::default();
3583        let log_store = ObjectStoreLogStore::try_new(
3584            ObjectStore::new(Memory::default()).unwrap(),
3585            &wal_config,
3586            0,
3587            STANDALONE_GENERATION,
3588        )
3589        .await
3590        .unwrap();
3591        let engine = env
3592            .create_engine_with_log_store(config, log_store.clone())
3593            .await;
3594        let mut region_server = mock_region_server();
3595        region_server.register_engine(Arc::new(engine));
3596        let wal_options = serde_json::to_string(&WalOptions::ObjectStore(
3597            ObjectStoreWalOptions::new(wal_config.node_prefix(0, STANDALONE_GENERATION)),
3598        ))
3599        .unwrap();
3600        (region_server, log_store, wal_options)
3601    }
3602
3603    /// Creates a region with `wal_options` and returns an insert of three rows into it.
3604    async fn create_region(
3605        region_server: &RegionServer,
3606        region_id: RegionId,
3607        wal_options: &str,
3608    ) -> InsertRequest {
3609        let request = CreateRequestBuilder::new()
3610            .insert_option(WAL_OPTIONS_KEY, wal_options)
3611            .build();
3612        let rows = Rows {
3613            schema: rows_schema(&request),
3614            rows: build_rows(0, 3),
3615        };
3616        region_server
3617            .handle_request(region_id, RegionRequest::Create(request))
3618            .await
3619            .unwrap();
3620        InsertRequest {
3621            region_id: region_id.as_u64(),
3622            rows: Some(rows),
3623            partition_expr_version: None,
3624            skip_wal: false,
3625        }
3626    }
3627
3628    #[tokio::test]
3629    async fn test_metric_batch_failure_indices() {
3630        let mut env = TestEnv::with_prefix("region-server-metric-results").await;
3631        let mito = env.create_engine(MitoConfig::default()).await;
3632        let metric = Arc::new(
3633            MetricEngine::try_new(mito, metric_engine::config::EngineConfig::default()).unwrap(),
3634        );
3635        let mut server = mock_region_server();
3636        server.register_engine(metric.clone());
3637        let mut inserts = Vec::new();
3638        for table in [10, 20] {
3639            let physical = RegionId::new(table, 0);
3640            let logical = RegionId::new(table + 1, 0);
3641            let mut create = CreateRequestBuilder::new().build();
3642            create.engine = METRIC_ENGINE_NAME.to_string();
3643            create.column_metadatas = vec![
3644                store_api::metadata::ColumnMetadata {
3645                    column_id: 0,
3646                    semantic_type: SemanticType::Timestamp,
3647                    column_schema: ColumnSchema::new(
3648                        "greptime_timestamp",
3649                        ConcreteDataType::timestamp_millisecond_datatype(),
3650                        false,
3651                    ),
3652                },
3653                store_api::metadata::ColumnMetadata {
3654                    column_id: 1,
3655                    semantic_type: SemanticType::Field,
3656                    column_schema: ColumnSchema::new(
3657                        "greptime_value",
3658                        ConcreteDataType::float64_datatype(),
3659                        false,
3660                    ),
3661                },
3662            ];
3663            create.primary_key.clear();
3664            create.table_dir = format!("metric-results/{table}/");
3665            create.options = HashMap::from([(
3666                store_api::metric_engine_consts::PHYSICAL_TABLE_METADATA_KEY.to_string(),
3667                String::new(),
3668            )]);
3669            server
3670                .handle_request(physical, RegionRequest::Create(create.clone()))
3671                .await
3672                .unwrap();
3673            create.table_dir = format!("metric-results/{}/", table + 1);
3674            create.options = HashMap::from([(
3675                store_api::metric_engine_consts::LOGICAL_TABLE_METADATA_KEY.to_string(),
3676                physical.as_u64().to_string(),
3677            )]);
3678            server
3679                .handle_request(logical, RegionRequest::Create(create.clone()))
3680                .await
3681                .unwrap();
3682            inserts.push(InsertRequest {
3683                region_id: logical.as_u64(),
3684                rows: Some(Rows {
3685                    schema: rows_schema(&create),
3686                    rows: vec![api::v1::Row {
3687                        values: vec![
3688                            api::v1::Value {
3689                                value_data: Some(
3690                                    api::v1::value::ValueData::TimestampMillisecondValue(1),
3691                                ),
3692                            },
3693                            api::v1::Value {
3694                                value_data: Some(api::v1::value::ValueData::F64Value(1.0)),
3695                            },
3696                        ],
3697                    }],
3698                }),
3699                ..Default::default()
3700            });
3701        }
3702        // Both entries of the second physical group fail at write_data.
3703        metric
3704            .set_region_role(RegionId::new(20, 0), RegionRole::Follower)
3705            .unwrap();
3706        let response = server
3707            .handle_requests_in_parallel(region_request::Body::Inserts(InsertRequests {
3708                requests: vec![
3709                    Default::default(),
3710                    inserts[0].clone(),
3711                    inserts[1].clone(),
3712                    inserts[1].clone(),
3713                ],
3714            }))
3715            .await
3716            .unwrap();
3717        assert_eq!(1, response.affected_rows);
3718        let mut failures = response.failures;
3719        failures.sort_unstable_by_key(|(index, _)| *index);
3720        assert_eq!(
3721            vec![2, 3],
3722            failures.iter().map(|(index, _)| *index).collect::<Vec<_>>()
3723        );
3724        assert!(
3725            failures
3726                .iter()
3727                .all(|(_, error)| error.status_code() == StatusCode::RegionNotReady)
3728        );
3729        assert!(
3730            failures
3731                .iter()
3732                .all(|(_, error)| error.retry_hint() == RetryHint::RetryAfterRouteRefresh)
3733        );
3734    }
3735
3736    #[tokio::test]
3737    async fn test_mito_puts_of_one_request_share_a_wal_append() {
3738        // One worker that takes one message at a time, so that only puts that
3739        // arrive in one message share a WAL append.
3740        let mut env = TestEnv::with_prefix("region-server-mito-batch-puts").await;
3741        let config = MitoConfig {
3742            num_workers: 1,
3743            worker_request_batch_size: 1,
3744            ..Default::default()
3745        };
3746        let (region_server, log_store, wal_options) =
3747            region_server_on_object_store_wal(&mut env, config).await;
3748        let mut requests = Vec::new();
3749        for region_number in 1..=2 {
3750            let region_id = RegionId::new(1, region_number);
3751            requests.push(create_region(&region_server, region_id, &wal_options).await);
3752        }
3753
3754        let response = region_server
3755            .handle_requests_in_parallel(region_request::Body::Inserts(InsertRequests { requests }))
3756            .await
3757            .unwrap();
3758
3759        assert_eq!(6, response.affected_rows);
3760        // The worker got both puts at once and appended them together.
3761        log_store.wait_for_admitted_appends(1).await.unwrap();
3762        assert!(
3763            tokio::time::timeout(Duration::ZERO, log_store.wait_for_admitted_appends(2))
3764                .await
3765                .is_err()
3766        );
3767    }
3768
3769    #[tokio::test]
3770    async fn test_mito_puts_to_one_region_share_a_wal_append() {
3771        // As above: only puts that arrive in one message share a WAL append.
3772        let mut env = TestEnv::with_prefix("region-server-mito-batch-puts-one-region").await;
3773        let config = MitoConfig {
3774            num_workers: 1,
3775            worker_request_batch_size: 1,
3776            ..Default::default()
3777        };
3778        let (region_server, log_store, wal_options) =
3779            region_server_on_object_store_wal(&mut env, config).await;
3780        let insert = create_region(&region_server, RegionId::new(1, 1), &wal_options).await;
3781        let requests = vec![insert.clone(), insert];
3782
3783        let response = region_server
3784            .handle_requests_in_parallel(region_request::Body::Inserts(InsertRequests { requests }))
3785            .await
3786            .unwrap();
3787
3788        assert_eq!(6, response.affected_rows);
3789        log_store.wait_for_admitted_appends(1).await.unwrap();
3790        assert!(
3791            tokio::time::timeout(Duration::ZERO, log_store.wait_for_admitted_appends(2))
3792                .await
3793                .is_err()
3794        );
3795    }
3796
3797    #[tokio::test]
3798    async fn test_mito_batch_failure_indices_for_same_region() {
3799        for failed_index in [0, 1] {
3800            let mut env = TestEnv::with_prefix("region-server-mito-same-region-failure").await;
3801            let (server, _log_store, wal_options) =
3802                region_server_on_object_store_wal(&mut env, MitoConfig::default()).await;
3803            let region_id = RegionId::new(1, 1);
3804            let insert = create_region(&server, region_id, &wal_options).await;
3805            let mut requests = vec![insert.clone(), insert];
3806            requests[failed_index].partition_expr_version = Some(PartitionExprVersion { value: 1 });
3807            let response = server
3808                .handle_requests_in_parallel(region_request::Body::Inserts(InsertRequests {
3809                    requests,
3810                }))
3811                .await
3812                .unwrap();
3813            assert_eq!(response.affected_rows, 3);
3814            assert_eq!(response.failures.len(), 1);
3815            assert_eq!(response.failures[0].0, failed_index);
3816            assert_eq!(
3817                response.failures[0].1.status_code(),
3818                StatusCode::InvalidArguments
3819            );
3820            let engine = server
3821                .inner
3822                .region_map
3823                .get(&region_id)
3824                .unwrap()
3825                .clone()
3826                .into_engine();
3827            let mito = engine.as_any().downcast_ref::<MitoEngine>().unwrap();
3828            let stream = mito
3829                .scan_to_stream(region_id, Default::default())
3830                .await
3831                .unwrap();
3832            let batches = RecordBatches::try_collect(stream).await.unwrap();
3833            assert_eq!(
3834                batches.iter().map(|batch| batch.num_rows()).sum::<usize>(),
3835                3
3836            );
3837        }
3838    }
3839
3840    #[tokio::test]
3841    async fn test_mito_batch_puts_retain_successful_regions() {
3842        for accept_partial_result in [false, true] {
3843            let mut env = TestEnv::with_prefix("region-server-mito-batch-puts-error").await;
3844            let config = MitoConfig {
3845                num_workers: 2,
3846                ..Default::default()
3847            };
3848            let (region_server, log_store, wal_options) =
3849                region_server_on_object_store_wal(&mut env, config).await;
3850            // Regions 1 and 2 of table 1 belong to different workers. The put to region 1 waits for a
3851            // WAL object whose create is held; Mito does not know region 2, so its put fails at once.
3852            let held = RegionId::new(1, 1);
3853            let unknown = RegionId::new(1, 2);
3854            let held_insert = create_region(&region_server, held, &wal_options).await;
3855            let unknown_insert = InsertRequest {
3856                region_id: unknown.as_u64(),
3857                ..held_insert.clone()
3858            };
3859            let mito = region_server
3860                .inner
3861                .region_map
3862                .get(&held)
3863                .unwrap()
3864                .clone()
3865                .into_engine();
3866            region_server
3867                .inner
3868                .region_map
3869                .insert(unknown, RegionEngineWithStatus::Ready(mito.clone()));
3870            log_store.hold_creates();
3871
3872            let requests = vec![Default::default(), held_insert, unknown_insert];
3873            let mut header = api::v1::region::RegionRequestHeader::default();
3874            if accept_partial_result {
3875                api::region::set_accept_partial_result(&mut header);
3876            }
3877            let write = region_server.handle_region_request(RegionRequestV1 {
3878                header: Some(header),
3879                body: Some(region_request::Body::Inserts(InsertRequests { requests })),
3880            });
3881            tokio::pin!(write);
3882            assert!(
3883                tokio::time::timeout(Duration::from_millis(100), &mut write)
3884                    .await
3885                    .is_err()
3886            );
3887            log_store.release_creates();
3888            let result = tokio::time::timeout(Duration::from_secs(10), write)
3889                .await
3890                .unwrap();
3891            if accept_partial_result {
3892                let response = result.unwrap();
3893                assert_eq!(3, response.affected_rows);
3894                assert_eq!(
3895                    StatusCode::PartialFailure as u32,
3896                    response.header.unwrap().status.unwrap().status_code
3897                );
3898                assert_eq!(1, response.failures.len());
3899                assert_eq!(2, response.failures[0].request_index);
3900                assert_eq!(
3901                    StatusCode::RegionNotFound as u32,
3902                    response.failures[0].status.as_ref().unwrap().status_code
3903                );
3904            } else {
3905                assert_eq!(
3906                    StatusCode::RegionNotFound,
3907                    result.unwrap_err().status_code()
3908                );
3909            }
3910            let mito = mito.as_any().downcast_ref::<MitoEngine>().unwrap();
3911            let stream = mito.scan_to_stream(held, Default::default()).await.unwrap();
3912            let batches = RecordBatches::try_collect(stream).await.unwrap();
3913            assert_eq!(
3914                batches.iter().map(|batch| batch.num_rows()).sum::<usize>(),
3915                3
3916            );
3917        }
3918    }
3919
3920    #[tokio::test]
3921    async fn test_mito_batch_puts_to_a_stopped_worker_fail_as_a_single_put_does() {
3922        let mut env = TestEnv::with_prefix("region-server-mito-batch-puts-stopped").await;
3923        let (region_server, _log_store, wal_options) =
3924            region_server_on_object_store_wal(&mut env, MitoConfig::default()).await;
3925        let region_id = RegionId::new(1, 1);
3926        let insert = create_region(&region_server, region_id, &wal_options).await;
3927        let mito = region_server
3928            .inner
3929            .region_map
3930            .get(&region_id)
3931            .unwrap()
3932            .clone()
3933            .into_engine();
3934        mito.stop().await.unwrap();
3935
3936        // One put takes the per-region path and two take the batch path.
3937        for requests in [vec![insert.clone()], vec![insert.clone(), insert]] {
3938            let count = requests.len();
3939            let response = region_server
3940                .handle_requests_in_parallel(region_request::Body::Inserts(InsertRequests {
3941                    requests,
3942                }))
3943                .await
3944                .unwrap();
3945            assert_eq!(0, response.affected_rows);
3946            assert_eq!(count, response.failures.len());
3947            for (index, (request_index, error)) in response.failures.iter().enumerate() {
3948                assert_eq!(index, *request_index);
3949                assert!(format!("{error:?}").contains("is stopped"), "{error:?}");
3950            }
3951        }
3952    }
3953
3954    #[tokio::test]
3955    async fn test_default_batch_puts_handle_each_put_as_a_request() {
3956        let failing = RegionId::new(1, 2);
3957        let (engine, _receiver) = MockRegionEngine::with_mock_fn(
3958            "mock",
3959            Box::new(move |region_id, request| {
3960                assert!(matches!(request, RegionRequest::Put(_)));
3961                if region_id == failing {
3962                    return error::UnexpectedSnafu {
3963                        violated: "test".to_string(),
3964                    }
3965                    .fail();
3966                }
3967                Ok(region_id.region_number() as usize)
3968            }),
3969        );
3970        let region_ids = [1, 2, 3].map(|n| RegionId::new(1, n));
3971        let puts = region_ids
3972            .iter()
3973            .map(|region_id| {
3974                let request = RegionPutRequest {
3975                    rows: Rows {
3976                        schema: Vec::new(),
3977                        rows: Vec::new(),
3978                    },
3979                    hint: None,
3980                    skip_wal: false,
3981                    partition_expr_version: None,
3982                };
3983                (*region_id, request)
3984            })
3985            .collect();
3986
3987        let (answered, responses): (Vec<_>, Vec<_>) =
3988            engine.handle_batch_put_requests(puts).into_iter().unzip();
3989        let responses = futures_util::future::join_all(responses).await;
3990
3991        let answered_regions = region_ids.map(|region_id| vec![region_id]);
3992        assert_eq!(answered_regions.to_vec(), answered);
3993        assert_eq!(1, responses[0].as_ref().unwrap().affected_rows);
3994        assert!(responses[1].is_err());
3995        assert_eq!(3, responses[2].as_ref().unwrap().affected_rows);
3996    }
3997
3998    #[tokio::test]
3999    async fn test_only_several_puts_into_ready_mito_regions_are_batched() {
4000        let mut env = TestEnv::with_prefix("region-server-mito-batch-puts-guard").await;
4001        let mito: RegionEngineRef = Arc::new(env.create_engine(MitoConfig::default()).await);
4002        let (other, _receiver) = MockRegionEngine::new("mock");
4003        let region_server = mock_region_server();
4004        let [mito_a, mito_b, registering, other_region] = [1, 2, 3, 4].map(|n| RegionId::new(1, n));
4005        let region_map = &region_server.inner.region_map;
4006        region_map.insert(mito_a, RegionEngineWithStatus::Ready(mito.clone()));
4007        region_map.insert(mito_b, RegionEngineWithStatus::Ready(mito.clone()));
4008        region_map.insert(registering, RegionEngineWithStatus::Registering(mito));
4009        region_map.insert(other_region, RegionEngineWithStatus::Ready(other));
4010        let rows = || Rows {
4011            schema: Vec::new(),
4012            rows: Vec::new(),
4013        };
4014        let put = |region_id| {
4015            let request = RegionPutRequest {
4016                rows: rows(),
4017                hint: None,
4018                skip_wal: false,
4019                partition_expr_version: None,
4020            };
4021            IndexedRegionRequest {
4022                index: 0,
4023                region_id,
4024                request: RegionRequest::Put(request),
4025            }
4026        };
4027        let delete = |region_id| {
4028            let request = RegionDeleteRequest {
4029                rows: rows(),
4030                hint: None,
4031                partition_expr_version: None,
4032            };
4033            IndexedRegionRequest {
4034                index: 0,
4035                region_id,
4036                request: RegionRequest::Delete(request),
4037            }
4038        };
4039
4040        for requests in [
4041            vec![put(mito_a), put(mito_b)],
4042            vec![put(mito_a), put(mito_a)],
4043        ] {
4044            assert!(
4045                region_server
4046                    .mito_engine_for_batch_puts(&requests)
4047                    .is_some()
4048            );
4049        }
4050        for requests in [
4051            vec![put(mito_a)],
4052            vec![put(mito_a), delete(mito_b)],
4053            vec![put(mito_a), put(registering)],
4054            vec![put(mito_a), put(other_region)],
4055            vec![put(other_region), put(mito_a)],
4056        ] {
4057            assert!(
4058                region_server
4059                    .mito_engine_for_batch_puts(&requests)
4060                    .is_none()
4061            );
4062        }
4063    }
4064}