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