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