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