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