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