1use std::collections::HashMap;
18use std::sync::Arc;
19use std::time::Instant;
20
21use api::helper::{
22 ColumnDataTypeWrapper, is_column_type_value_eq, is_semantic_type_eq, proto_value_type,
23 proto_value_type_match,
24};
25use api::v1::column_def::options_from_column_schema;
26use api::v1::{ColumnDataType, ColumnSchema, OpType, Rows, SemanticType, Value, WriteHint};
27use common_telemetry::info;
28use datatypes::prelude::DataType;
29use partition::expr::PartitionExpr;
30use prometheus::HistogramTimer;
31use prost::Message;
32use smallvec::SmallVec;
33use snafu::{OptionExt, ResultExt, ensure};
34use store_api::ManifestVersion;
35use store_api::codec::{PrimaryKeyEncoding, infer_primary_key_encoding_from_hint};
36use store_api::metadata::{ColumnMetadata, RegionMetadata, RegionMetadataRef};
37use store_api::region_engine::{
38 MitoCopyRegionFromResponse, SetRegionRoleStateResponse, SettableRegionRoleState,
39};
40use store_api::region_request::{
41 AffectedRows, ApplyStagingManifestRequest, EnterStagingRequest, RegionAlterRequest,
42 RegionBuildIndexRequest, RegionBulkInsertsRequest, RegionCatchupRequest, RegionCleanUpRequest,
43 RegionCloseRequest, RegionCompactRequest, RegionCreateRequest, RegionDropRequest,
44 RegionFlushRequest, RegionOpenRequest, RegionRequest, RegionTruncateRequest,
45 StagingPartitionDirective,
46};
47use store_api::storage::{FileId, RegionId, SequenceNumber};
48use tokio::sync::oneshot::{self, Receiver, Sender};
49
50use crate::compaction::{CompactionExecution, CompactionPickFinished};
51use crate::error::{
52 CompactRegionSnafu, CompactionCancelledSnafu, ConvertColumnDataTypeSnafu, CreateDefaultSnafu,
53 Error, FillDefaultSnafu, FlushRegionSnafu, InvalidPartitionExprSnafu, InvalidRequestSnafu,
54 MissingPartitionExprSnafu, Result, UnexpectedSnafu,
55};
56use crate::flush::FlushReason;
57use crate::manifest::action::{RegionEdit, TruncateKind};
58use crate::memtable::MemtableId;
59use crate::memtable::bulk::part::BulkPart;
60use crate::metrics::COMPACTION_ELAPSED_TOTAL;
61use crate::region::MitoRegionRef;
62use crate::region::options::RegionOptions;
63use crate::sst::file::FileMeta;
64use crate::sst::index::IndexBuildType;
65use crate::wal::EntryId;
66use crate::wal::entry_distributor::WalEntryReceiver;
67
68#[derive(Debug)]
70pub struct WriteRequest {
71 pub region_id: RegionId,
73 pub op_type: OpType,
75 pub rows: Rows,
77 pub name_to_index: HashMap<String, usize>,
79 pub has_null: Vec<bool>,
81 pub skip_wal: bool,
83 pub hint: Option<WriteHint>,
85 pub(crate) region_metadata: Option<RegionMetadataRef>,
87 pub partition_expr_version: Option<u64>,
89}
90
91impl WriteRequest {
92 pub fn new(
96 region_id: RegionId,
97 op_type: OpType,
98 rows: Rows,
99 region_metadata: Option<RegionMetadataRef>,
100 ) -> Result<WriteRequest> {
101 let mut name_to_index = HashMap::with_capacity(rows.schema.len());
102 for (index, column) in rows.schema.iter().enumerate() {
103 ensure!(
104 name_to_index
105 .insert(column.column_name.clone(), index)
106 .is_none(),
107 InvalidRequestSnafu {
108 region_id,
109 reason: format!("duplicate column {}", column.column_name),
110 }
111 );
112 }
113
114 let mut has_null = vec![false; rows.schema.len()];
115 for row in &rows.rows {
116 ensure!(
117 row.values.len() == rows.schema.len(),
118 InvalidRequestSnafu {
119 region_id,
120 reason: format!(
121 "row has {} columns but schema has {}",
122 row.values.len(),
123 rows.schema.len()
124 ),
125 }
126 );
127
128 for (i, (value, column_schema)) in row.values.iter().zip(&rows.schema).enumerate() {
129 validate_proto_value(region_id, value, column_schema)?;
130
131 if value.value_data.is_none() {
132 has_null[i] = true;
133 }
134 }
135 }
136
137 Ok(WriteRequest {
138 region_id,
139 op_type,
140 rows,
141 name_to_index,
142 has_null,
143 hint: None,
144 skip_wal: false,
145 region_metadata,
146 partition_expr_version: None,
147 })
148 }
149
150 pub fn with_skip_wal(mut self, skip_wal: bool) -> Self {
152 self.skip_wal = skip_wal;
153 self
154 }
155
156 pub fn with_hint(mut self, hint: Option<WriteHint>) -> Self {
158 self.hint = hint;
159 self
160 }
161
162 pub fn with_partition_expr_version(mut self, partition_expr_version: Option<u64>) -> Self {
163 self.partition_expr_version = partition_expr_version;
164 self
165 }
166
167 pub fn primary_key_encoding(&self) -> PrimaryKeyEncoding {
169 infer_primary_key_encoding_from_hint(self.hint.as_ref())
170 }
171
172 pub(crate) fn estimated_size(&self) -> usize {
174 let row_size = self
175 .rows
176 .rows
177 .first()
178 .map(|row| row.encoded_len())
179 .unwrap_or(0);
180 row_size * self.rows.rows.len()
181 }
182
183 pub fn column_index_by_name(&self, name: &str) -> Option<usize> {
185 self.name_to_index.get(name).copied()
186 }
187
188 pub(crate) fn check_schema(&self, metadata: &RegionMetadata) -> Result<()> {
193 debug_assert_eq!(self.region_id, metadata.region_id);
194
195 let region_id = self.region_id;
196 let mut rows_columns: HashMap<_, _> = self
198 .rows
199 .schema
200 .iter()
201 .map(|column| (&column.column_name, column))
202 .collect();
203
204 let mut need_fill_default = false;
205 for column in &metadata.column_metadatas {
207 if let Some(input_col) = rows_columns.remove(&column.column_schema.name) {
208 ensure!(
210 is_column_type_value_eq(
211 input_col.datatype,
212 input_col.datatype_extension.clone(),
213 &column.column_schema.data_type
214 ),
215 InvalidRequestSnafu {
216 region_id,
217 reason: format!(
218 "column {} expect type {:?}, given: {}({})",
219 column.column_schema.name,
220 column.column_schema.data_type,
221 ColumnDataType::try_from(input_col.datatype)
222 .map(|v| v.as_str_name())
223 .unwrap_or("Unknown"),
224 input_col.datatype,
225 )
226 }
227 );
228
229 ensure!(
231 is_semantic_type_eq(input_col.semantic_type, column.semantic_type),
232 InvalidRequestSnafu {
233 region_id,
234 reason: format!(
235 "column {} has semantic type {:?}, given: {}({})",
236 column.column_schema.name,
237 column.semantic_type,
238 api::v1::SemanticType::try_from(input_col.semantic_type)
239 .map(|v| v.as_str_name())
240 .unwrap_or("Unknown"),
241 input_col.semantic_type
242 ),
243 }
244 );
245
246 let has_null = self.has_null[self.name_to_index[&column.column_schema.name]];
249 ensure!(
250 !has_null || column.column_schema.is_nullable(),
251 InvalidRequestSnafu {
252 region_id,
253 reason: format!(
254 "column {} is not null but input has null",
255 column.column_schema.name
256 ),
257 }
258 );
259 } else {
260 self.check_missing_column(column)?;
262
263 need_fill_default = true;
264 }
265 }
266
267 if !rows_columns.is_empty() {
269 let names: Vec<_> = rows_columns.into_keys().collect();
270 return InvalidRequestSnafu {
271 region_id,
272 reason: format!("unknown columns: {:?}", names),
273 }
274 .fail();
275 }
276
277 ensure!(!need_fill_default, FillDefaultSnafu { region_id });
279
280 Ok(())
281 }
282
283 pub(crate) fn fill_missing_columns(&mut self, metadata: &RegionMetadata) -> Result<()> {
288 debug_assert_eq!(self.region_id, metadata.region_id);
289
290 let mut columns_to_fill = vec![];
291 for column in &metadata.column_metadatas {
292 if !self.name_to_index.contains_key(&column.column_schema.name) {
293 columns_to_fill.push(column);
294 }
295 }
296 self.fill_columns(columns_to_fill)?;
297
298 Ok(())
299 }
300
301 pub(crate) fn maybe_fill_missing_columns(&mut self, metadata: &RegionMetadata) -> Result<()> {
303 if let Err(e) = self.check_schema(metadata) {
304 if e.is_fill_default() {
305 self.fill_missing_columns(metadata)?;
309 } else {
310 return Err(e);
311 }
312 }
313
314 Ok(())
315 }
316
317 fn fill_columns(&mut self, columns: Vec<&ColumnMetadata>) -> Result<()> {
319 let mut default_values = Vec::with_capacity(columns.len());
320 let mut columns_to_fill = Vec::with_capacity(columns.len());
321 for column in columns {
322 let default_value = self.column_default_value(column)?;
323 if default_value.value_data.is_some() {
324 default_values.push(default_value);
325 columns_to_fill.push(column);
326 }
327 }
328
329 for row in &mut self.rows.rows {
330 row.values.extend(default_values.iter().cloned());
331 }
332
333 for column in columns_to_fill {
334 let (datatype, datatype_ext) =
335 ColumnDataTypeWrapper::try_from(column.column_schema.data_type.clone())
336 .with_context(|_| ConvertColumnDataTypeSnafu {
337 reason: format!(
338 "no protobuf type for column {} ({:?})",
339 column.column_schema.name, column.column_schema.data_type
340 ),
341 })?
342 .to_parts();
343 self.rows.schema.push(ColumnSchema {
344 column_name: column.column_schema.name.clone(),
345 datatype: datatype as i32,
346 semantic_type: column.semantic_type as i32,
347 datatype_extension: datatype_ext,
348 options: options_from_column_schema(&column.column_schema),
349 });
350 }
351
352 Ok(())
353 }
354
355 fn check_missing_column(&self, column: &ColumnMetadata) -> Result<()> {
357 if self.op_type == OpType::Delete {
358 if column.semantic_type == SemanticType::Field {
359 return Ok(());
362 } else {
363 return InvalidRequestSnafu {
364 region_id: self.region_id,
365 reason: format!("delete requests need column {}", column.column_schema.name),
366 }
367 .fail();
368 }
369 }
370
371 ensure!(
373 column.column_schema.is_nullable()
374 || column.column_schema.default_constraint().is_some(),
375 InvalidRequestSnafu {
376 region_id: self.region_id,
377 reason: format!("missing column {}", column.column_schema.name),
378 }
379 );
380
381 Ok(())
382 }
383
384 fn column_default_value(&self, column: &ColumnMetadata) -> Result<Value> {
386 let default_value = match self.op_type {
387 OpType::Delete => {
388 ensure!(
389 column.semantic_type == SemanticType::Field,
390 InvalidRequestSnafu {
391 region_id: self.region_id,
392 reason: format!(
393 "delete requests need column {}",
394 column.column_schema.name
395 ),
396 }
397 );
398
399 if column.column_schema.is_nullable() {
404 datatypes::value::Value::Null
405 } else {
406 column.column_schema.data_type.default_value()
407 }
408 }
409 OpType::Put => {
410 if column.column_schema.is_default_impure() {
412 UnexpectedSnafu {
413 reason: format!(
414 "unexpected impure default value with region_id: {}, column: {}, default_value: {:?}",
415 self.region_id,
416 column.column_schema.name,
417 column.column_schema.default_constraint(),
418 ),
419 }
420 .fail()?
421 }
422 column
423 .column_schema
424 .create_default()
425 .context(CreateDefaultSnafu {
426 region_id: self.region_id,
427 column: &column.column_schema.name,
428 })?
429 .with_context(|| InvalidRequestSnafu {
431 region_id: self.region_id,
432 reason: format!(
433 "column {} does not have default value",
434 column.column_schema.name
435 ),
436 })?
437 }
438 };
439
440 Ok(api::helper::to_grpc_value(default_value))
442 }
443}
444
445pub(crate) fn validate_proto_value(
447 region_id: RegionId,
448 value: &Value,
449 column_schema: &ColumnSchema,
450) -> Result<()> {
451 if let Some(value_type) = proto_value_type(value) {
452 let column_type = ColumnDataType::try_from(column_schema.datatype).map_err(|_| {
453 InvalidRequestSnafu {
454 region_id,
455 reason: format!(
456 "column {} has unknown type {}",
457 column_schema.column_name, column_schema.datatype
458 ),
459 }
460 .build()
461 })?;
462 ensure!(
463 proto_value_type_match(column_type, value_type),
464 InvalidRequestSnafu {
465 region_id,
466 reason: format!(
467 "value has type {:?}, but column {} has type {:?}({})",
468 value_type, column_schema.column_name, column_type, column_schema.datatype,
469 ),
470 }
471 );
472 }
473
474 Ok(())
475}
476
477#[derive(Debug)]
479pub struct OutputTx(Sender<Result<AffectedRows>>);
480
481impl OutputTx {
482 pub(crate) fn new(sender: Sender<Result<AffectedRows>>) -> OutputTx {
484 OutputTx(sender)
485 }
486
487 pub(crate) fn send(self, result: Result<AffectedRows>) {
489 let _ = self.0.send(result);
491 }
492}
493
494#[derive(Debug)]
496pub(crate) struct OptionOutputTx(Option<OutputTx>);
497
498impl OptionOutputTx {
499 pub(crate) fn new(sender: Option<OutputTx>) -> OptionOutputTx {
501 OptionOutputTx(sender)
502 }
503
504 pub(crate) fn none() -> OptionOutputTx {
506 OptionOutputTx(None)
507 }
508
509 pub(crate) fn send_mut(&mut self, result: Result<AffectedRows>) {
511 if let Some(sender) = self.0.take() {
512 sender.send(result);
513 }
514 }
515
516 pub(crate) fn send(mut self, result: Result<AffectedRows>) {
518 if let Some(sender) = self.0.take() {
519 sender.send(result);
520 }
521 }
522
523 pub(crate) fn take_inner(&mut self) -> Option<OutputTx> {
525 self.0.take()
526 }
527}
528
529impl From<Sender<Result<AffectedRows>>> for OptionOutputTx {
530 fn from(sender: Sender<Result<AffectedRows>>) -> Self {
531 Self::new(Some(OutputTx::new(sender)))
532 }
533}
534
535impl OnFailure for OptionOutputTx {
536 fn on_failure(&mut self, err: Error) {
537 self.send_mut(Err(err));
538 }
539}
540
541pub(crate) trait OnFailure {
543 fn on_failure(&mut self, err: Error);
545}
546
547#[derive(Debug)]
549pub(crate) struct SenderWriteRequest {
550 pub(crate) sender: OptionOutputTx,
552 pub(crate) request: WriteRequest,
553}
554
555pub(crate) struct SenderBulkRequest {
556 pub(crate) skip_wal: bool,
557 pub(crate) sender: OptionOutputTx,
558 pub(crate) region_id: RegionId,
559 pub(crate) request: BulkPart,
560 pub(crate) region_metadata: Option<RegionMetadataRef>,
561 pub(crate) partition_expr_version: Option<u64>,
562}
563
564#[derive(Debug)]
565pub(crate) struct BulkInsertRequest {
566 pub(crate) metadata: Option<RegionMetadataRef>,
567 pub(crate) request: RegionBulkInsertsRequest,
568 pub(crate) sender: OptionOutputTx,
569}
570
571#[derive(Debug)]
573pub(crate) struct WorkerRequestWithTime {
574 pub(crate) request: WorkerRequest,
575 pub(crate) created_at: Instant,
576}
577
578impl WorkerRequestWithTime {
579 pub(crate) fn new(request: WorkerRequest) -> Self {
580 Self {
581 request,
582 created_at: Instant::now(),
583 }
584 }
585}
586
587#[derive(Debug)]
589pub(crate) enum WorkerRequest {
590 Write(SenderWriteRequest),
592
593 Ddl(SenderDdlRequest),
595
596 Background {
598 region_id: RegionId,
600 notify: BackgroundNotify,
602 },
603
604 SetRegionRoleStateGracefully {
606 region_id: RegionId,
608 region_role_state: SettableRegionRoleState,
610 sender: Sender<SetRegionRoleStateResponse>,
612 },
613
614 Stop,
616
617 EditRegion(RegionEditRequest),
619
620 SyncRegion(RegionSyncRequest),
622
623 BulkInserts(BulkInsertRequest),
625
626 RemapManifests(RemapManifestsRequest),
628
629 CopyRegionFrom(CopyRegionFromRequest),
631}
632
633impl WorkerRequest {
634 pub(crate) fn new_open_region_request(
636 region_id: RegionId,
637 request: RegionOpenRequest,
638 entry_receiver: Option<WalEntryReceiver>,
639 ) -> (WorkerRequest, Receiver<Result<AffectedRows>>) {
640 let (sender, receiver) = oneshot::channel();
641
642 let worker_request = WorkerRequest::Ddl(SenderDdlRequest {
643 region_id,
644 sender: sender.into(),
645 request: DdlRequest::Open((request, entry_receiver)),
646 });
647
648 (worker_request, receiver)
649 }
650
651 pub(crate) fn new_catchup_region_request(
653 region_id: RegionId,
654 request: RegionCatchupRequest,
655 entry_receiver: Option<WalEntryReceiver>,
656 ) -> (WorkerRequest, Receiver<Result<AffectedRows>>) {
657 let (sender, receiver) = oneshot::channel();
658 let worker_request = WorkerRequest::Ddl(SenderDdlRequest {
659 region_id,
660 sender: sender.into(),
661 request: DdlRequest::Catchup((request, entry_receiver)),
662 });
663 (worker_request, receiver)
664 }
665
666 pub(crate) fn try_from_region_request(
668 region_id: RegionId,
669 value: RegionRequest,
670 region_metadata: Option<RegionMetadataRef>,
671 ) -> Result<(WorkerRequest, Receiver<Result<AffectedRows>>)> {
672 let (sender, receiver) = oneshot::channel();
673 let worker_request = match value {
674 RegionRequest::Put(v) => {
675 let mut write_request =
676 WriteRequest::new(region_id, OpType::Put, v.rows, region_metadata.clone())?
677 .with_hint(v.hint)
678 .with_skip_wal(v.skip_wal)
679 .with_partition_expr_version(v.partition_expr_version);
680 if write_request.primary_key_encoding() == PrimaryKeyEncoding::Dense
681 && let Some(region_metadata) = ®ion_metadata
682 {
683 write_request.maybe_fill_missing_columns(region_metadata)?;
684 }
685 WorkerRequest::Write(SenderWriteRequest {
686 sender: sender.into(),
687 request: write_request,
688 })
689 }
690 RegionRequest::Delete(v) => {
691 let mut write_request =
692 WriteRequest::new(region_id, OpType::Delete, v.rows, region_metadata.clone())?
693 .with_hint(v.hint)
694 .with_partition_expr_version(v.partition_expr_version);
695 if write_request.primary_key_encoding() == PrimaryKeyEncoding::Dense
696 && let Some(region_metadata) = ®ion_metadata
697 {
698 write_request.maybe_fill_missing_columns(region_metadata)?;
699 }
700 WorkerRequest::Write(SenderWriteRequest {
701 sender: sender.into(),
702 request: write_request,
703 })
704 }
705 RegionRequest::Create(v) => WorkerRequest::Ddl(SenderDdlRequest {
706 region_id,
707 sender: sender.into(),
708 request: DdlRequest::Create(v),
709 }),
710 RegionRequest::Drop(v) => WorkerRequest::Ddl(SenderDdlRequest {
711 region_id,
712 sender: sender.into(),
713 request: DdlRequest::Drop(v),
714 }),
715 RegionRequest::Open(v) => WorkerRequest::Ddl(SenderDdlRequest {
716 region_id,
717 sender: sender.into(),
718 request: DdlRequest::Open((v, None)),
719 }),
720 RegionRequest::CleanUp(v) => WorkerRequest::Ddl(SenderDdlRequest {
721 region_id,
722 sender: sender.into(),
723 request: DdlRequest::OfflineCleanup(v),
724 }),
725 RegionRequest::Close(v) => WorkerRequest::Ddl(SenderDdlRequest {
726 region_id,
727 sender: sender.into(),
728 request: DdlRequest::Close(v),
729 }),
730 RegionRequest::Alter(v) => WorkerRequest::Ddl(SenderDdlRequest {
731 region_id,
732 sender: sender.into(),
733 request: DdlRequest::Alter(v),
734 }),
735 RegionRequest::Flush(v) => WorkerRequest::Ddl(SenderDdlRequest {
736 region_id,
737 sender: sender.into(),
738 request: DdlRequest::Flush(v),
739 }),
740 RegionRequest::Compact(v) => WorkerRequest::Ddl(SenderDdlRequest {
741 region_id,
742 sender: sender.into(),
743 request: DdlRequest::Compact(v),
744 }),
745 RegionRequest::BuildIndex(v) => WorkerRequest::Ddl(SenderDdlRequest {
746 region_id,
747 sender: sender.into(),
748 request: DdlRequest::BuildIndex(v),
749 }),
750 RegionRequest::Truncate(v) => WorkerRequest::Ddl(SenderDdlRequest {
751 region_id,
752 sender: sender.into(),
753 request: DdlRequest::Truncate(v),
754 }),
755 RegionRequest::Catchup(v) => WorkerRequest::Ddl(SenderDdlRequest {
756 region_id,
757 sender: sender.into(),
758 request: DdlRequest::Catchup((v, None)),
759 }),
760 RegionRequest::EnterStaging(v) => WorkerRequest::Ddl(SenderDdlRequest {
761 region_id,
762 sender: sender.into(),
763 request: DdlRequest::EnterStaging(v),
764 }),
765 RegionRequest::BulkInserts(region_bulk_inserts_request) => {
766 WorkerRequest::BulkInserts(BulkInsertRequest {
767 metadata: region_metadata,
768 sender: sender.into(),
769 request: region_bulk_inserts_request,
770 })
771 }
772 RegionRequest::ApplyStagingManifest(v) => WorkerRequest::Ddl(SenderDdlRequest {
773 region_id,
774 sender: sender.into(),
775 request: DdlRequest::ApplyStagingManifest(v),
776 }),
777 };
778
779 Ok((worker_request, receiver))
780 }
781
782 pub(crate) fn new_set_readonly_gracefully(
783 region_id: RegionId,
784 region_role_state: SettableRegionRoleState,
785 ) -> (WorkerRequest, Receiver<SetRegionRoleStateResponse>) {
786 let (sender, receiver) = oneshot::channel();
787
788 (
789 WorkerRequest::SetRegionRoleStateGracefully {
790 region_id,
791 region_role_state,
792 sender,
793 },
794 receiver,
795 )
796 }
797
798 pub(crate) fn new_sync_region_request(
799 region_id: RegionId,
800 manifest_version: ManifestVersion,
801 ) -> (WorkerRequest, Receiver<Result<(ManifestVersion, bool)>>) {
802 let (sender, receiver) = oneshot::channel();
803 (
804 WorkerRequest::SyncRegion(RegionSyncRequest {
805 region_id,
806 manifest_version,
807 sender,
808 }),
809 receiver,
810 )
811 }
812
813 #[allow(clippy::type_complexity)]
820 pub(crate) fn try_from_remap_manifests_request(
821 store_api::region_engine::RemapManifestsRequest {
822 region_id,
823 input_regions,
824 region_mapping,
825 new_partition_exprs,
826 }: store_api::region_engine::RemapManifestsRequest,
827 ) -> Result<(WorkerRequest, Receiver<Result<HashMap<RegionId, String>>>)> {
828 let (sender, receiver) = oneshot::channel();
829 let new_partition_exprs = new_partition_exprs
830 .into_iter()
831 .map(|(k, v)| {
832 Ok((
833 k,
834 PartitionExpr::from_json_str(&v)
835 .context(InvalidPartitionExprSnafu { expr: v })?
836 .context(MissingPartitionExprSnafu { region_id: k })?,
837 ))
838 })
839 .collect::<Result<HashMap<_, _>>>()?;
840
841 let request = RemapManifestsRequest {
842 region_id,
843 input_regions,
844 region_mapping,
845 new_partition_exprs,
846 sender,
847 };
848
849 Ok((WorkerRequest::RemapManifests(request), receiver))
850 }
851
852 pub(crate) fn try_from_copy_region_from_request(
854 region_id: RegionId,
855 store_api::region_engine::MitoCopyRegionFromRequest {
856 source_region_id,
857 parallelism,
858 }: store_api::region_engine::MitoCopyRegionFromRequest,
859 ) -> Result<(WorkerRequest, Receiver<Result<MitoCopyRegionFromResponse>>)> {
860 let (sender, receiver) = oneshot::channel();
861 let request = CopyRegionFromRequest {
862 region_id,
863 source_region_id,
864 parallelism,
865 sender,
866 };
867 Ok((WorkerRequest::CopyRegionFrom(request), receiver))
868 }
869}
870
871#[derive(Debug)]
873pub(crate) enum DdlRequest {
874 Create(RegionCreateRequest),
875 Drop(RegionDropRequest),
876 Open((RegionOpenRequest, Option<WalEntryReceiver>)),
877 OfflineCleanup(RegionCleanUpRequest),
878 Close(RegionCloseRequest),
879 Alter(RegionAlterRequest),
880 Flush(RegionFlushRequest),
881 Compact(RegionCompactRequest),
882 BuildIndex(RegionBuildIndexRequest),
883 Truncate(RegionTruncateRequest),
884 Catchup((RegionCatchupRequest, Option<WalEntryReceiver>)),
885 EnterStaging(EnterStagingRequest),
886 ApplyStagingManifest(ApplyStagingManifestRequest),
887}
888
889#[derive(Debug)]
891pub(crate) struct SenderDdlRequest {
892 pub(crate) region_id: RegionId,
894 pub(crate) sender: OptionOutputTx,
896 pub(crate) request: DdlRequest,
898}
899
900#[derive(Debug)]
902pub(crate) enum BackgroundNotify {
903 RegionOpened {
905 region: MitoRegionRef,
906 registered: Sender<()>,
907 },
908 CompactionDdlComplete {
910 generation: u64,
911 request_index: usize,
912 },
913 CompactionPickFinished(CompactionPickFinished),
915 FlushFinished(FlushFinished),
917 FlushFailed(FlushFailed),
919 IndexBuildFinished(IndexBuildFinished),
921 IndexBuildStopped(IndexBuildStopped),
923 IndexBuildFailed(IndexBuildFailed),
925 IndexBuildRetry(BuildIndexRequest),
927 CompactionFinished(CompactionFinished),
929 CompactionCancelled(CompactionCancelled),
931 CompactionFailed(CompactionFailed),
933 Truncate(TruncateResult),
935 DiscardUnflushed(DiscardUnflushedResult),
937 RegionChange(RegionChangeResult),
939 RegionEdit(RegionEditResult),
941 EnterStaging(EnterStagingResult),
943 CopyRegionFromFinished(CopyRegionFromFinished),
945}
946
947#[derive(Debug)]
949pub(crate) struct FlushFinished {
950 pub(crate) region_id: RegionId,
952 pub(crate) flush_reason: FlushReason,
954 pub(crate) flushed_entry_id: EntryId,
956 pub(crate) senders: Vec<OutputTx>,
958 pub(crate) _timer: HistogramTimer,
960 pub(crate) edit: RegionEdit,
962 pub(crate) memtables_to_remove: SmallVec<[MemtableId; 2]>,
964 pub(crate) is_staging: bool,
966}
967
968impl FlushFinished {
969 pub(crate) fn on_success(self) {
971 for sender in self.senders {
972 sender.send(Ok(0));
973 }
974 }
975}
976
977impl OnFailure for FlushFinished {
978 fn on_failure(&mut self, err: Error) {
979 let err = Arc::new(err);
980 for sender in self.senders.drain(..) {
981 sender.send(Err(err.clone()).context(FlushRegionSnafu {
982 region_id: self.region_id,
983 }));
984 }
985 }
986}
987
988#[derive(Debug)]
990pub(crate) struct FlushFailed {
991 pub(crate) err: Arc<Error>,
993}
994
995impl FlushFailed {
996 pub(crate) fn is_cancelled(&self) -> bool {
998 matches!(self.err.as_ref(), Error::FlushCancelled { .. })
999 }
1000}
1001
1002#[derive(Debug)]
1003pub(crate) struct IndexBuildFinished {
1004 pub(crate) manifest_version: ManifestVersion,
1005 pub(crate) file_meta: FileMeta,
1006}
1007
1008#[derive(Debug)]
1010pub(crate) struct IndexBuildStopped {
1011 pub(crate) file_id: FileId,
1012}
1013
1014#[derive(Debug)]
1016pub(crate) struct IndexBuildFailed {
1017 pub(crate) err: Arc<Error>,
1018}
1019
1020#[derive(Debug)]
1022pub(crate) struct CompactionFinished {
1023 pub(crate) region_id: RegionId,
1025 pub(crate) execution: CompactionExecution,
1027 pub(crate) senders: Vec<OutputTx>,
1029 pub(crate) start_time: Instant,
1031 pub(crate) edit: RegionEdit,
1033}
1034
1035#[derive(Debug)]
1037pub(crate) struct CompactionCancelled {
1038 pub(crate) region_id: RegionId,
1040 pub(crate) execution: CompactionExecution,
1042 pub(crate) senders: Vec<OutputTx>,
1044}
1045
1046impl CompactionCancelled {
1047 pub(crate) fn on_success(self) {
1048 for sender in self.senders {
1049 sender.send(CompactionCancelledSnafu {}.fail());
1050 }
1051 info!("Compaction cancelled for region: {}", self.region_id);
1052 }
1053}
1054
1055impl CompactionFinished {
1056 pub fn on_success(self) {
1057 COMPACTION_ELAPSED_TOTAL.observe(self.start_time.elapsed().as_secs_f64());
1059
1060 for sender in self.senders {
1061 sender.send(Ok(0));
1062 }
1063 info!("Successfully compacted region: {}", self.region_id);
1064 }
1065}
1066
1067impl OnFailure for CompactionFinished {
1068 fn on_failure(&mut self, err: Error) {
1070 let err = Arc::new(err);
1071 for sender in self.senders.drain(..) {
1072 sender.send(Err(err.clone()).context(CompactRegionSnafu {
1073 region_id: self.region_id,
1074 }));
1075 }
1076 }
1077}
1078
1079#[derive(Debug)]
1081pub(crate) struct CompactionFailed {
1082 pub(crate) region_id: RegionId,
1083 pub(crate) execution: CompactionExecution,
1085 pub(crate) err: Arc<Error>,
1087}
1088
1089#[derive(Debug)]
1091pub(crate) struct TruncateResult {
1092 pub(crate) region_id: RegionId,
1094 pub(crate) sender: OptionOutputTx,
1096 pub(crate) result: Result<()>,
1098 pub(crate) kind: TruncateKind,
1099}
1100
1101#[derive(Debug)]
1103pub(crate) struct DiscardUnflushedResult {
1104 pub(crate) region_id: RegionId,
1106 pub(crate) sender: OptionOutputTx,
1108 pub(crate) result: Result<()>,
1110 pub(crate) discarded_entry_id: EntryId,
1112 pub(crate) discarded_sequence: SequenceNumber,
1114 pub(crate) discarded_rows: u64,
1116 pub(crate) discarded_bytes: u64,
1118}
1119
1120#[derive(Debug)]
1122pub(crate) struct RegionChangeResult {
1123 pub(crate) region_id: RegionId,
1125 pub(crate) new_meta: RegionMetadataRef,
1127 pub(crate) sender: OptionOutputTx,
1129 pub(crate) result: Result<()>,
1131 pub(crate) need_index: bool,
1133 pub(crate) new_options: Option<RegionOptions>,
1135}
1136
1137#[derive(Debug)]
1139pub(crate) struct EnterStagingResult {
1140 pub(crate) region_id: RegionId,
1142 pub(crate) partition_directive: StagingPartitionDirective,
1144 pub(crate) sender: OptionOutputTx,
1146 pub(crate) result: Result<()>,
1148}
1149
1150#[derive(Debug)]
1151pub(crate) struct CopyRegionFromFinished {
1152 pub(crate) region_id: RegionId,
1154 pub(crate) edit: RegionEdit,
1156 pub(crate) sender: Sender<Result<MitoCopyRegionFromResponse>>,
1158}
1159
1160#[derive(Debug, Default)]
1161pub(crate) struct Waiters(SmallVec<[Sender<Result<()>>; 1]>);
1162
1163impl Waiters {
1164 pub(crate) fn one(waiter: Sender<Result<()>>) -> Self {
1165 let mut waiters = SmallVec::new();
1166 waiters.push(waiter);
1167 Self(waiters)
1168 }
1169
1170 pub(crate) fn reply_with<F: Fn() -> Result<()>>(self, f: F) {
1171 for tx in self.0 {
1172 let _ = tx.send(f());
1173 }
1174 }
1175
1176 pub(crate) fn merge(&mut self, other: Self) {
1177 self.0.extend(other.0);
1178 }
1179}
1180
1181#[derive(Debug)]
1183pub(crate) struct RegionEditRequest {
1184 pub(crate) region_id: RegionId,
1185 pub(crate) edit: RegionEdit,
1186 pub(crate) preload_sst_cache: bool,
1188 pub(crate) waiters: Waiters,
1190}
1191
1192impl RegionEditRequest {
1193 pub(crate) fn new(
1194 region_id: RegionId,
1195 edit: RegionEdit,
1196 preload_sst_cache: bool,
1197 waiter: Sender<Result<()>>,
1198 ) -> Self {
1199 Self {
1200 region_id,
1201 edit,
1202 preload_sst_cache,
1203 waiters: Waiters::one(waiter),
1204 }
1205 }
1206}
1207
1208#[derive(Debug)]
1210pub(crate) struct RegionEditResult {
1211 pub(crate) region_id: RegionId,
1213 pub(crate) waiters: Waiters,
1215 pub(crate) edit: RegionEdit,
1217 pub(crate) result: std::result::Result<(), Arc<Error>>,
1219 pub(crate) update_region_state: bool,
1221 pub(crate) is_staging: bool,
1223}
1224
1225#[derive(Debug)]
1226pub(crate) struct BuildIndexRequest {
1227 pub(crate) region_id: RegionId,
1228 pub(crate) build_type: IndexBuildType,
1229 pub(crate) file_metas: Vec<FileMeta>,
1231}
1232
1233#[derive(Debug)]
1234pub(crate) struct RegionSyncRequest {
1235 pub(crate) region_id: RegionId,
1236 pub(crate) manifest_version: ManifestVersion,
1237 pub(crate) sender: Sender<Result<(ManifestVersion, bool)>>,
1239}
1240
1241#[derive(Debug)]
1242pub(crate) struct RemapManifestsRequest {
1243 pub(crate) region_id: RegionId,
1245 pub(crate) input_regions: Vec<RegionId>,
1247 pub(crate) region_mapping: HashMap<RegionId, Vec<RegionId>>,
1249 pub(crate) new_partition_exprs: HashMap<RegionId, PartitionExpr>,
1251 pub(crate) sender: Sender<Result<HashMap<RegionId, String>>>,
1255}
1256
1257#[derive(Debug)]
1258pub(crate) struct CopyRegionFromRequest {
1259 pub(crate) region_id: RegionId,
1261 pub(crate) source_region_id: RegionId,
1263 pub(crate) parallelism: usize,
1265 pub(crate) sender: Sender<Result<MitoCopyRegionFromResponse>>,
1267}
1268
1269#[cfg(test)]
1270mod tests {
1271 use api::v1::value::ValueData;
1272 use api::v1::{Row, SemanticType};
1273 use common_error::ext::ErrorExt;
1274 use common_error::status_code::StatusCode;
1275 use datatypes::prelude::ConcreteDataType;
1276 use datatypes::schema::ColumnDefaultConstraint;
1277 use mito_codec::test_util::i64_value;
1278 use store_api::metadata::RegionMetadataBuilder;
1279 use tokio::sync::oneshot;
1280
1281 use super::*;
1282 use crate::error::Error;
1283 use crate::test_util::ts_ms_value;
1284
1285 fn new_column_schema(
1286 name: &str,
1287 data_type: ColumnDataType,
1288 semantic_type: SemanticType,
1289 ) -> ColumnSchema {
1290 ColumnSchema {
1291 column_name: name.to_string(),
1292 datatype: data_type as i32,
1293 semantic_type: semantic_type as i32,
1294 ..Default::default()
1295 }
1296 }
1297
1298 fn check_invalid_request(err: &Error, expect: &str) {
1299 if let Error::InvalidRequest {
1300 region_id: _,
1301 reason,
1302 location: _,
1303 } = err
1304 {
1305 assert_eq!(reason, expect);
1306 } else {
1307 panic!("Unexpected error {err}")
1308 }
1309 }
1310
1311 fn waiter() -> (Sender<Result<()>>, Receiver<Result<()>>) {
1312 oneshot::channel()
1313 }
1314
1315 fn assert_waiter_ok(rx: &mut Receiver<Result<()>>) {
1316 rx.try_recv().unwrap().unwrap();
1317 }
1318
1319 #[test]
1320 fn test_waiters_reply_with_single_waiter() {
1321 let (tx, mut rx) = waiter();
1322 Waiters::one(tx).reply_with(|| Ok(()));
1323 assert_waiter_ok(&mut rx);
1324 }
1325
1326 #[test]
1327 fn test_waiters_reply_with_many_waiters() {
1328 let (tx1, mut rx1) = waiter();
1329 let (tx2, mut rx2) = waiter();
1330 let (tx3, mut rx3) = waiter();
1331
1332 let waiters = Waiters(vec![tx1, tx2, tx3].into());
1333 waiters.reply_with(|| Ok(()));
1334
1335 assert_waiter_ok(&mut rx1);
1336 assert_waiter_ok(&mut rx2);
1337 assert_waiter_ok(&mut rx3);
1338 }
1339
1340 #[test]
1341 fn test_waiters_merge() {
1342 let (tx1, mut rx1) = waiter();
1343 let (tx2, mut rx2) = waiter();
1344 let (tx3, mut rx3) = waiter();
1345 let (tx4, mut rx4) = waiter();
1346
1347 let mut waiters = Waiters::one(tx1);
1348 waiters.merge(Waiters::one(tx2));
1349 waiters.merge(Waiters(vec![tx3, tx4].into()));
1350 assert_eq!(4, waiters.0.len());
1351
1352 waiters.reply_with(|| Ok(()));
1353
1354 assert_waiter_ok(&mut rx1);
1355 assert_waiter_ok(&mut rx2);
1356 assert_waiter_ok(&mut rx3);
1357 assert_waiter_ok(&mut rx4);
1358 }
1359
1360 #[test]
1361 fn test_write_request_duplicate_column() {
1362 let rows = Rows {
1363 schema: vec![
1364 new_column_schema("c0", ColumnDataType::Int64, SemanticType::Tag),
1365 new_column_schema("c0", ColumnDataType::Int64, SemanticType::Tag),
1366 ],
1367 rows: vec![],
1368 };
1369
1370 let err = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap_err();
1371 check_invalid_request(&err, "duplicate column c0");
1372 }
1373
1374 #[test]
1375 fn test_valid_write_request() {
1376 let rows = Rows {
1377 schema: vec![
1378 new_column_schema("c0", ColumnDataType::Int64, SemanticType::Tag),
1379 new_column_schema("c1", ColumnDataType::Int64, SemanticType::Tag),
1380 ],
1381 rows: vec![Row {
1382 values: vec![i64_value(1), i64_value(2)],
1383 }],
1384 };
1385
1386 let request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1387 assert_eq!(0, request.column_index_by_name("c0").unwrap());
1388 assert_eq!(1, request.column_index_by_name("c1").unwrap());
1389 assert_eq!(None, request.column_index_by_name("c2"));
1390 }
1391
1392 #[test]
1393 fn test_compaction_cancelled_sends_cancelled_error() {
1394 let (tx, rx) = oneshot::channel();
1395 let request = CompactionCancelled {
1396 region_id: RegionId::new(1, 1),
1397 execution: crate::compaction::CompactionExecution::for_test(0),
1398 senders: vec![OutputTx::new(tx)],
1399 };
1400
1401 request.on_success();
1402
1403 let err = rx.blocking_recv().unwrap().unwrap_err();
1404 assert!(matches!(err, Error::CompactionCancelled { .. }));
1405 assert_eq!(err.status_code(), StatusCode::Cancelled);
1406 }
1407
1408 #[test]
1409 fn test_write_request_column_num() {
1410 let rows = Rows {
1411 schema: vec![
1412 new_column_schema("c0", ColumnDataType::Int64, SemanticType::Tag),
1413 new_column_schema("c1", ColumnDataType::Int64, SemanticType::Tag),
1414 ],
1415 rows: vec![Row {
1416 values: vec![i64_value(1), i64_value(2), i64_value(3)],
1417 }],
1418 };
1419
1420 let err = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap_err();
1421 check_invalid_request(&err, "row has 3 columns but schema has 2");
1422 }
1423
1424 fn new_region_metadata() -> RegionMetadata {
1425 let mut builder = RegionMetadataBuilder::new(RegionId::new(1, 1));
1426 builder
1427 .push_column_metadata(ColumnMetadata {
1428 column_schema: datatypes::schema::ColumnSchema::new(
1429 "ts",
1430 ConcreteDataType::timestamp_millisecond_datatype(),
1431 false,
1432 ),
1433 semantic_type: SemanticType::Timestamp,
1434 column_id: 1,
1435 })
1436 .push_column_metadata(ColumnMetadata {
1437 column_schema: datatypes::schema::ColumnSchema::new(
1438 "k0",
1439 ConcreteDataType::int64_datatype(),
1440 true,
1441 ),
1442 semantic_type: SemanticType::Tag,
1443 column_id: 2,
1444 })
1445 .primary_key(vec![2]);
1446 builder.build().unwrap()
1447 }
1448
1449 #[test]
1450 fn test_check_schema() {
1451 let rows = Rows {
1452 schema: vec![
1453 new_column_schema(
1454 "ts",
1455 ColumnDataType::TimestampMillisecond,
1456 SemanticType::Timestamp,
1457 ),
1458 new_column_schema("k0", ColumnDataType::Int64, SemanticType::Tag),
1459 ],
1460 rows: vec![Row {
1461 values: vec![ts_ms_value(1), i64_value(2)],
1462 }],
1463 };
1464 let metadata = new_region_metadata();
1465
1466 let request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1467 request.check_schema(&metadata).unwrap();
1468 }
1469
1470 #[test]
1471 fn test_column_type() {
1472 let rows = Rows {
1473 schema: vec![
1474 new_column_schema("ts", ColumnDataType::Int64, SemanticType::Timestamp),
1475 new_column_schema("k0", ColumnDataType::Int64, SemanticType::Tag),
1476 ],
1477 rows: vec![Row {
1478 values: vec![i64_value(1), i64_value(2)],
1479 }],
1480 };
1481 let metadata = new_region_metadata();
1482
1483 let request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1484 let err = request.check_schema(&metadata).unwrap_err();
1485 check_invalid_request(
1486 &err,
1487 "column ts expect type Timestamp(Millisecond(TimestampMillisecondType)), given: INT64(4)",
1488 );
1489 }
1490
1491 #[test]
1492 fn test_semantic_type() {
1493 let rows = Rows {
1494 schema: vec![
1495 new_column_schema(
1496 "ts",
1497 ColumnDataType::TimestampMillisecond,
1498 SemanticType::Tag,
1499 ),
1500 new_column_schema("k0", ColumnDataType::Int64, SemanticType::Tag),
1501 ],
1502 rows: vec![Row {
1503 values: vec![ts_ms_value(1), i64_value(2)],
1504 }],
1505 };
1506 let metadata = new_region_metadata();
1507
1508 let request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1509 let err = request.check_schema(&metadata).unwrap_err();
1510 check_invalid_request(&err, "column ts has semantic type Timestamp, given: TAG(0)");
1511 }
1512
1513 #[test]
1514 fn test_column_nullable() {
1515 let rows = Rows {
1516 schema: vec![
1517 new_column_schema(
1518 "ts",
1519 ColumnDataType::TimestampMillisecond,
1520 SemanticType::Timestamp,
1521 ),
1522 new_column_schema("k0", ColumnDataType::Int64, SemanticType::Tag),
1523 ],
1524 rows: vec![Row {
1525 values: vec![Value { value_data: None }, i64_value(2)],
1526 }],
1527 };
1528 let metadata = new_region_metadata();
1529
1530 let request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1531 let err = request.check_schema(&metadata).unwrap_err();
1532 check_invalid_request(&err, "column ts is not null but input has null");
1533 }
1534
1535 #[test]
1536 fn test_column_default() {
1537 let rows = Rows {
1538 schema: vec![new_column_schema(
1539 "k0",
1540 ColumnDataType::Int64,
1541 SemanticType::Tag,
1542 )],
1543 rows: vec![Row {
1544 values: vec![i64_value(1)],
1545 }],
1546 };
1547 let metadata = new_region_metadata();
1548
1549 let request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1550 let err = request.check_schema(&metadata).unwrap_err();
1551 check_invalid_request(&err, "missing column ts");
1552 }
1553
1554 #[test]
1555 fn test_unknown_column() {
1556 let rows = Rows {
1557 schema: vec![
1558 new_column_schema(
1559 "ts",
1560 ColumnDataType::TimestampMillisecond,
1561 SemanticType::Timestamp,
1562 ),
1563 new_column_schema("k0", ColumnDataType::Int64, SemanticType::Tag),
1564 new_column_schema("k1", ColumnDataType::Int64, SemanticType::Tag),
1565 ],
1566 rows: vec![Row {
1567 values: vec![ts_ms_value(1), i64_value(2), i64_value(3)],
1568 }],
1569 };
1570 let metadata = new_region_metadata();
1571
1572 let request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1573 let err = request.check_schema(&metadata).unwrap_err();
1574 check_invalid_request(&err, r#"unknown columns: ["k1"]"#);
1575 }
1576
1577 #[test]
1578 fn test_fill_impure_columns_err() {
1579 let rows = Rows {
1580 schema: vec![new_column_schema(
1581 "k0",
1582 ColumnDataType::Int64,
1583 SemanticType::Tag,
1584 )],
1585 rows: vec![Row {
1586 values: vec![i64_value(1)],
1587 }],
1588 };
1589 let metadata = {
1590 let mut builder = RegionMetadataBuilder::new(RegionId::new(1, 1));
1591 builder
1592 .push_column_metadata(ColumnMetadata {
1593 column_schema: datatypes::schema::ColumnSchema::new(
1594 "ts",
1595 ConcreteDataType::timestamp_millisecond_datatype(),
1596 false,
1597 )
1598 .with_default_constraint(Some(ColumnDefaultConstraint::Function(
1599 "now()".to_string(),
1600 )))
1601 .unwrap(),
1602 semantic_type: SemanticType::Timestamp,
1603 column_id: 1,
1604 })
1605 .push_column_metadata(ColumnMetadata {
1606 column_schema: datatypes::schema::ColumnSchema::new(
1607 "k0",
1608 ConcreteDataType::int64_datatype(),
1609 true,
1610 ),
1611 semantic_type: SemanticType::Tag,
1612 column_id: 2,
1613 })
1614 .primary_key(vec![2]);
1615 builder.build().unwrap()
1616 };
1617
1618 let mut request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1619 let err = request.check_schema(&metadata).unwrap_err();
1620 assert!(err.is_fill_default());
1621 assert!(
1622 request
1623 .fill_missing_columns(&metadata)
1624 .unwrap_err()
1625 .to_string()
1626 .contains("unexpected impure default value with region_id")
1627 );
1628 }
1629
1630 #[test]
1631 fn test_fill_missing_columns() {
1632 let rows = Rows {
1633 schema: vec![new_column_schema(
1634 "ts",
1635 ColumnDataType::TimestampMillisecond,
1636 SemanticType::Timestamp,
1637 )],
1638 rows: vec![Row {
1639 values: vec![ts_ms_value(1)],
1640 }],
1641 };
1642 let metadata = new_region_metadata();
1643
1644 let mut request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1645 let err = request.check_schema(&metadata).unwrap_err();
1646 assert!(err.is_fill_default());
1647 request.fill_missing_columns(&metadata).unwrap();
1648
1649 let expect_rows = Rows {
1650 schema: vec![new_column_schema(
1651 "ts",
1652 ColumnDataType::TimestampMillisecond,
1653 SemanticType::Timestamp,
1654 )],
1655 rows: vec![Row {
1656 values: vec![ts_ms_value(1)],
1657 }],
1658 };
1659 assert_eq!(expect_rows, request.rows);
1660 }
1661
1662 fn builder_with_ts_tag() -> RegionMetadataBuilder {
1663 let mut builder = RegionMetadataBuilder::new(RegionId::new(1, 1));
1664 builder
1665 .push_column_metadata(ColumnMetadata {
1666 column_schema: datatypes::schema::ColumnSchema::new(
1667 "ts",
1668 ConcreteDataType::timestamp_millisecond_datatype(),
1669 false,
1670 ),
1671 semantic_type: SemanticType::Timestamp,
1672 column_id: 1,
1673 })
1674 .push_column_metadata(ColumnMetadata {
1675 column_schema: datatypes::schema::ColumnSchema::new(
1676 "k0",
1677 ConcreteDataType::int64_datatype(),
1678 true,
1679 ),
1680 semantic_type: SemanticType::Tag,
1681 column_id: 2,
1682 })
1683 .primary_key(vec![2]);
1684 builder
1685 }
1686
1687 fn region_metadata_two_fields() -> RegionMetadata {
1688 let mut builder = builder_with_ts_tag();
1689 builder
1690 .push_column_metadata(ColumnMetadata {
1691 column_schema: datatypes::schema::ColumnSchema::new(
1692 "f0",
1693 ConcreteDataType::int64_datatype(),
1694 true,
1695 ),
1696 semantic_type: SemanticType::Field,
1697 column_id: 3,
1698 })
1699 .push_column_metadata(ColumnMetadata {
1701 column_schema: datatypes::schema::ColumnSchema::new(
1702 "f1",
1703 ConcreteDataType::int64_datatype(),
1704 false,
1705 )
1706 .with_default_constraint(Some(ColumnDefaultConstraint::Value(
1707 datatypes::value::Value::Int64(100),
1708 )))
1709 .unwrap(),
1710 semantic_type: SemanticType::Field,
1711 column_id: 4,
1712 });
1713 builder.build().unwrap()
1714 }
1715
1716 #[test]
1717 fn test_fill_missing_for_delete() {
1718 let rows = Rows {
1719 schema: vec![new_column_schema(
1720 "ts",
1721 ColumnDataType::TimestampMillisecond,
1722 SemanticType::Timestamp,
1723 )],
1724 rows: vec![Row {
1725 values: vec![ts_ms_value(1)],
1726 }],
1727 };
1728 let metadata = region_metadata_two_fields();
1729
1730 let mut request =
1731 WriteRequest::new(RegionId::new(1, 1), OpType::Delete, rows, None).unwrap();
1732 let err = request.check_schema(&metadata).unwrap_err();
1733 check_invalid_request(&err, "delete requests need column k0");
1734 let err = request.fill_missing_columns(&metadata).unwrap_err();
1735 check_invalid_request(&err, "delete requests need column k0");
1736
1737 let rows = Rows {
1738 schema: vec![
1739 new_column_schema("k0", ColumnDataType::Int64, SemanticType::Tag),
1740 new_column_schema(
1741 "ts",
1742 ColumnDataType::TimestampMillisecond,
1743 SemanticType::Timestamp,
1744 ),
1745 ],
1746 rows: vec![Row {
1747 values: vec![i64_value(100), ts_ms_value(1)],
1748 }],
1749 };
1750 let mut request =
1751 WriteRequest::new(RegionId::new(1, 1), OpType::Delete, rows, None).unwrap();
1752 let err = request.check_schema(&metadata).unwrap_err();
1753 assert!(err.is_fill_default());
1754 request.fill_missing_columns(&metadata).unwrap();
1755
1756 let expect_rows = Rows {
1757 schema: vec![
1758 new_column_schema("k0", ColumnDataType::Int64, SemanticType::Tag),
1759 new_column_schema(
1760 "ts",
1761 ColumnDataType::TimestampMillisecond,
1762 SemanticType::Timestamp,
1763 ),
1764 new_column_schema("f1", ColumnDataType::Int64, SemanticType::Field),
1765 ],
1766 rows: vec![Row {
1768 values: vec![i64_value(100), ts_ms_value(1), i64_value(0)],
1769 }],
1770 };
1771 assert_eq!(expect_rows, request.rows);
1772 }
1773
1774 #[test]
1775 fn test_fill_missing_without_default_in_delete() {
1776 let mut builder = builder_with_ts_tag();
1777 builder
1778 .push_column_metadata(ColumnMetadata {
1780 column_schema: datatypes::schema::ColumnSchema::new(
1781 "f0",
1782 ConcreteDataType::int64_datatype(),
1783 true,
1784 ),
1785 semantic_type: SemanticType::Field,
1786 column_id: 3,
1787 })
1788 .push_column_metadata(ColumnMetadata {
1790 column_schema: datatypes::schema::ColumnSchema::new(
1791 "f1",
1792 ConcreteDataType::int64_datatype(),
1793 false,
1794 ),
1795 semantic_type: SemanticType::Field,
1796 column_id: 4,
1797 });
1798 let metadata = builder.build().unwrap();
1799
1800 let rows = Rows {
1801 schema: vec![
1802 new_column_schema("k0", ColumnDataType::Int64, SemanticType::Tag),
1803 new_column_schema(
1804 "ts",
1805 ColumnDataType::TimestampMillisecond,
1806 SemanticType::Timestamp,
1807 ),
1808 ],
1809 rows: vec![Row {
1811 values: vec![i64_value(100), ts_ms_value(1)],
1812 }],
1813 };
1814 let mut request =
1815 WriteRequest::new(RegionId::new(1, 1), OpType::Delete, rows, None).unwrap();
1816 let err = request.check_schema(&metadata).unwrap_err();
1817 assert!(err.is_fill_default());
1818 request.fill_missing_columns(&metadata).unwrap();
1819
1820 let expect_rows = Rows {
1821 schema: vec![
1822 new_column_schema("k0", ColumnDataType::Int64, SemanticType::Tag),
1823 new_column_schema(
1824 "ts",
1825 ColumnDataType::TimestampMillisecond,
1826 SemanticType::Timestamp,
1827 ),
1828 new_column_schema("f1", ColumnDataType::Int64, SemanticType::Field),
1829 ],
1830 rows: vec![Row {
1832 values: vec![i64_value(100), ts_ms_value(1), i64_value(0)],
1833 }],
1834 };
1835 assert_eq!(expect_rows, request.rows);
1836 }
1837
1838 #[test]
1839 fn test_no_default() {
1840 let rows = Rows {
1841 schema: vec![new_column_schema(
1842 "k0",
1843 ColumnDataType::Int64,
1844 SemanticType::Tag,
1845 )],
1846 rows: vec![Row {
1847 values: vec![i64_value(1)],
1848 }],
1849 };
1850 let metadata = new_region_metadata();
1851
1852 let mut request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1853 let err = request.fill_missing_columns(&metadata).unwrap_err();
1854 check_invalid_request(&err, "column ts does not have default value");
1855 }
1856
1857 #[test]
1858 fn test_missing_and_invalid() {
1859 let rows = Rows {
1861 schema: vec![
1862 new_column_schema("k0", ColumnDataType::Int64, SemanticType::Tag),
1863 new_column_schema(
1864 "ts",
1865 ColumnDataType::TimestampMillisecond,
1866 SemanticType::Timestamp,
1867 ),
1868 new_column_schema("f1", ColumnDataType::String, SemanticType::Field),
1869 ],
1870 rows: vec![Row {
1871 values: vec![
1872 i64_value(100),
1873 ts_ms_value(1),
1874 Value {
1875 value_data: Some(ValueData::StringValue("xxxxx".to_string())),
1876 },
1877 ],
1878 }],
1879 };
1880 let metadata = region_metadata_two_fields();
1881
1882 let request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1883 let err = request.check_schema(&metadata).unwrap_err();
1884 check_invalid_request(
1885 &err,
1886 "column f1 expect type Int64(Int64Type), given: STRING(12)",
1887 );
1888 }
1889
1890 #[test]
1891 fn test_delete_request_defaults_to_writing_wal() {
1892 let (request, _receiver) = WorkerRequest::try_from_region_request(
1893 RegionId::new(1, 1),
1894 RegionRequest::Delete(store_api::region_request::RegionDeleteRequest {
1895 rows: Rows::default(),
1896 hint: None,
1897 partition_expr_version: None,
1898 }),
1899 None,
1900 )
1901 .unwrap();
1902 let WorkerRequest::Write(request) = request else {
1903 panic!("expected a write request");
1904 };
1905 assert_eq!(request.request.op_type, OpType::Delete);
1906 assert!(!request.request.skip_wal);
1907 }
1908
1909 #[test]
1910 fn test_write_request_metadata() {
1911 let rows = Rows {
1912 schema: vec![
1913 new_column_schema("c0", ColumnDataType::Int64, SemanticType::Tag),
1914 new_column_schema("c1", ColumnDataType::Int64, SemanticType::Tag),
1915 ],
1916 rows: vec![Row {
1917 values: vec![i64_value(1), i64_value(2)],
1918 }],
1919 };
1920
1921 let metadata = Arc::new(new_region_metadata());
1922 let request = WriteRequest::new(
1923 RegionId::new(1, 1),
1924 OpType::Put,
1925 rows,
1926 Some(metadata.clone()),
1927 )
1928 .unwrap();
1929
1930 assert!(request.region_metadata.is_some());
1931 assert_eq!(
1932 request.region_metadata.unwrap().region_id,
1933 RegionId::new(1, 1)
1934 );
1935 }
1936}