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