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, ConvertColumnDataTypeSnafu, CreateDefaultSnafu, Error, FillDefaultSnafu,
53 FlushRegionSnafu, InvalidPartitionExprSnafu, InvalidRequestSnafu, MissingPartitionExprSnafu,
54 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 CompactionUnit(CompactionUnitNotification),
910 CompactionDdlComplete {
912 generation: u64,
913 request_index: usize,
914 },
915 CompactionPickFinished(CompactionPickFinished),
917 FlushFinished(FlushFinished),
919 FlushFailed(FlushFailed),
921 IndexBuildFinished(IndexBuildFinished),
923 IndexBuildStopped(IndexBuildStopped),
925 IndexBuildFailed(IndexBuildFailed),
927 IndexBuildRetry(BuildIndexRequest),
929 CompactionFinished(CompactionFinished),
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) enum CompactionUnitNotification {
1023 Finished {
1025 plan_id: u64,
1026 result: std::result::Result<RegionEdit, Arc<Error>>,
1027 applied: tokio::sync::oneshot::Sender<()>,
1028 },
1029 Released {
1031 plan_id: u64,
1033 },
1034}
1035
1036#[derive(Debug)]
1038pub(crate) struct CompactionFinished {
1039 pub(crate) region_id: RegionId,
1041 pub(crate) execution: CompactionExecution,
1043 pub(crate) senders: Vec<OutputTx>,
1045 pub(crate) start_time: Instant,
1047 pub(crate) edit: RegionEdit,
1049}
1050
1051impl CompactionFinished {
1052 pub fn on_success(self) {
1053 COMPACTION_ELAPSED_TOTAL
1055 .with_label_values(&["remote"])
1056 .observe(self.start_time.elapsed().as_secs_f64());
1057
1058 for sender in self.senders {
1059 sender.send(Ok(0));
1060 }
1061 info!("Successfully compacted region: {}", self.region_id);
1062 }
1063}
1064
1065impl OnFailure for CompactionFinished {
1066 fn on_failure(&mut self, err: Error) {
1068 let err = Arc::new(err);
1069 for sender in self.senders.drain(..) {
1070 sender.send(Err(err.clone()).context(CompactRegionSnafu {
1071 region_id: self.region_id,
1072 }));
1073 }
1074 }
1075}
1076
1077#[derive(Debug)]
1079pub(crate) struct CompactionFailed {
1080 pub(crate) region_id: RegionId,
1081 pub(crate) execution: CompactionExecution,
1083 pub(crate) err: Arc<Error>,
1085}
1086
1087#[derive(Debug)]
1089pub(crate) struct TruncateResult {
1090 pub(crate) region_id: RegionId,
1092 pub(crate) sender: OptionOutputTx,
1094 pub(crate) result: Result<()>,
1096 pub(crate) kind: TruncateKind,
1097}
1098
1099#[derive(Debug)]
1101pub(crate) struct DiscardUnflushedResult {
1102 pub(crate) region_id: RegionId,
1104 pub(crate) sender: OptionOutputTx,
1106 pub(crate) result: Result<()>,
1108 pub(crate) discarded_entry_id: EntryId,
1110 pub(crate) discarded_sequence: SequenceNumber,
1112 pub(crate) discarded_rows: u64,
1114 pub(crate) discarded_bytes: u64,
1116}
1117
1118#[derive(Debug)]
1120pub(crate) struct RegionChangeResult {
1121 pub(crate) region_id: RegionId,
1123 pub(crate) new_meta: RegionMetadataRef,
1125 pub(crate) sender: OptionOutputTx,
1127 pub(crate) result: Result<()>,
1129 pub(crate) need_index: bool,
1131 pub(crate) new_options: Option<RegionOptions>,
1133}
1134
1135#[derive(Debug)]
1137pub(crate) struct EnterStagingResult {
1138 pub(crate) region_id: RegionId,
1140 pub(crate) partition_directive: StagingPartitionDirective,
1142 pub(crate) sender: OptionOutputTx,
1144 pub(crate) result: Result<()>,
1146}
1147
1148#[derive(Debug)]
1149pub(crate) struct CopyRegionFromFinished {
1150 pub(crate) region_id: RegionId,
1152 pub(crate) edit: RegionEdit,
1154 pub(crate) sender: Sender<Result<MitoCopyRegionFromResponse>>,
1156}
1157
1158#[derive(Debug, Default)]
1159pub(crate) struct Waiters(SmallVec<[Sender<Result<()>>; 1]>);
1160
1161impl Waiters {
1162 pub(crate) fn one(waiter: Sender<Result<()>>) -> Self {
1163 let mut waiters = SmallVec::new();
1164 waiters.push(waiter);
1165 Self(waiters)
1166 }
1167
1168 pub(crate) fn reply_with<F: Fn() -> Result<()>>(self, f: F) {
1169 for tx in self.0 {
1170 let _ = tx.send(f());
1171 }
1172 }
1173
1174 pub(crate) fn merge(&mut self, other: Self) {
1175 self.0.extend(other.0);
1176 }
1177}
1178
1179#[derive(Debug)]
1181pub(crate) struct RegionEditRequest {
1182 pub(crate) region_id: RegionId,
1183 pub(crate) edit: RegionEdit,
1184 pub(crate) preload_sst_cache: bool,
1186 pub(crate) waiters: Waiters,
1188}
1189
1190impl RegionEditRequest {
1191 pub(crate) fn new(
1192 region_id: RegionId,
1193 edit: RegionEdit,
1194 preload_sst_cache: bool,
1195 waiter: Sender<Result<()>>,
1196 ) -> Self {
1197 Self {
1198 region_id,
1199 edit,
1200 preload_sst_cache,
1201 waiters: Waiters::one(waiter),
1202 }
1203 }
1204}
1205
1206#[derive(Debug)]
1208pub(crate) struct RegionEditResult {
1209 pub(crate) region_id: RegionId,
1211 pub(crate) waiters: Waiters,
1213 pub(crate) edit: RegionEdit,
1215 pub(crate) result: std::result::Result<(), Arc<Error>>,
1217 pub(crate) update_region_state: bool,
1219 pub(crate) is_staging: bool,
1221}
1222
1223#[derive(Debug)]
1224pub(crate) struct BuildIndexRequest {
1225 pub(crate) region_id: RegionId,
1226 pub(crate) build_type: IndexBuildType,
1227 pub(crate) file_metas: Vec<FileMeta>,
1229}
1230
1231#[derive(Debug)]
1232pub(crate) struct RegionSyncRequest {
1233 pub(crate) region_id: RegionId,
1234 pub(crate) manifest_version: ManifestVersion,
1235 pub(crate) sender: Sender<Result<(ManifestVersion, bool)>>,
1237}
1238
1239#[derive(Debug)]
1240pub(crate) struct RemapManifestsRequest {
1241 pub(crate) region_id: RegionId,
1243 pub(crate) input_regions: Vec<RegionId>,
1245 pub(crate) region_mapping: HashMap<RegionId, Vec<RegionId>>,
1247 pub(crate) new_partition_exprs: HashMap<RegionId, PartitionExpr>,
1249 pub(crate) sender: Sender<Result<HashMap<RegionId, String>>>,
1253}
1254
1255#[derive(Debug)]
1256pub(crate) struct CopyRegionFromRequest {
1257 pub(crate) region_id: RegionId,
1259 pub(crate) source_region_id: RegionId,
1261 pub(crate) parallelism: usize,
1263 pub(crate) sender: Sender<Result<MitoCopyRegionFromResponse>>,
1265}
1266
1267#[cfg(test)]
1268mod tests {
1269 use api::v1::value::ValueData;
1270 use api::v1::{Row, SemanticType};
1271 use datatypes::prelude::ConcreteDataType;
1272 use datatypes::schema::ColumnDefaultConstraint;
1273 use mito_codec::test_util::i64_value;
1274 use store_api::metadata::RegionMetadataBuilder;
1275 use tokio::sync::oneshot;
1276
1277 use super::*;
1278 use crate::error::Error;
1279 use crate::test_util::ts_ms_value;
1280
1281 fn new_column_schema(
1282 name: &str,
1283 data_type: ColumnDataType,
1284 semantic_type: SemanticType,
1285 ) -> ColumnSchema {
1286 ColumnSchema {
1287 column_name: name.to_string(),
1288 datatype: data_type as i32,
1289 semantic_type: semantic_type as i32,
1290 ..Default::default()
1291 }
1292 }
1293
1294 fn check_invalid_request(err: &Error, expect: &str) {
1295 if let Error::InvalidRequest {
1296 region_id: _,
1297 reason,
1298 location: _,
1299 } = err
1300 {
1301 assert_eq!(reason, expect);
1302 } else {
1303 panic!("Unexpected error {err}")
1304 }
1305 }
1306
1307 fn waiter() -> (Sender<Result<()>>, Receiver<Result<()>>) {
1308 oneshot::channel()
1309 }
1310
1311 fn assert_waiter_ok(rx: &mut Receiver<Result<()>>) {
1312 rx.try_recv().unwrap().unwrap();
1313 }
1314
1315 #[test]
1316 fn test_waiters_reply_with_single_waiter() {
1317 let (tx, mut rx) = waiter();
1318 Waiters::one(tx).reply_with(|| Ok(()));
1319 assert_waiter_ok(&mut rx);
1320 }
1321
1322 #[test]
1323 fn test_waiters_reply_with_many_waiters() {
1324 let (tx1, mut rx1) = waiter();
1325 let (tx2, mut rx2) = waiter();
1326 let (tx3, mut rx3) = waiter();
1327
1328 let waiters = Waiters(vec![tx1, tx2, tx3].into());
1329 waiters.reply_with(|| Ok(()));
1330
1331 assert_waiter_ok(&mut rx1);
1332 assert_waiter_ok(&mut rx2);
1333 assert_waiter_ok(&mut rx3);
1334 }
1335
1336 #[test]
1337 fn test_waiters_merge() {
1338 let (tx1, mut rx1) = waiter();
1339 let (tx2, mut rx2) = waiter();
1340 let (tx3, mut rx3) = waiter();
1341 let (tx4, mut rx4) = waiter();
1342
1343 let mut waiters = Waiters::one(tx1);
1344 waiters.merge(Waiters::one(tx2));
1345 waiters.merge(Waiters(vec![tx3, tx4].into()));
1346 assert_eq!(4, waiters.0.len());
1347
1348 waiters.reply_with(|| Ok(()));
1349
1350 assert_waiter_ok(&mut rx1);
1351 assert_waiter_ok(&mut rx2);
1352 assert_waiter_ok(&mut rx3);
1353 assert_waiter_ok(&mut rx4);
1354 }
1355
1356 #[test]
1357 fn test_write_request_duplicate_column() {
1358 let rows = Rows {
1359 schema: vec![
1360 new_column_schema("c0", ColumnDataType::Int64, SemanticType::Tag),
1361 new_column_schema("c0", ColumnDataType::Int64, SemanticType::Tag),
1362 ],
1363 rows: vec![],
1364 };
1365
1366 let err = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap_err();
1367 check_invalid_request(&err, "duplicate column c0");
1368 }
1369
1370 #[test]
1371 fn test_valid_write_request() {
1372 let rows = Rows {
1373 schema: vec![
1374 new_column_schema("c0", ColumnDataType::Int64, SemanticType::Tag),
1375 new_column_schema("c1", ColumnDataType::Int64, SemanticType::Tag),
1376 ],
1377 rows: vec![Row {
1378 values: vec![i64_value(1), i64_value(2)],
1379 }],
1380 };
1381
1382 let request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1383 assert_eq!(0, request.column_index_by_name("c0").unwrap());
1384 assert_eq!(1, request.column_index_by_name("c1").unwrap());
1385 assert_eq!(None, request.column_index_by_name("c2"));
1386 }
1387
1388 #[test]
1389 fn test_write_request_column_num() {
1390 let rows = Rows {
1391 schema: vec![
1392 new_column_schema("c0", ColumnDataType::Int64, SemanticType::Tag),
1393 new_column_schema("c1", ColumnDataType::Int64, SemanticType::Tag),
1394 ],
1395 rows: vec![Row {
1396 values: vec![i64_value(1), i64_value(2), i64_value(3)],
1397 }],
1398 };
1399
1400 let err = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap_err();
1401 check_invalid_request(&err, "row has 3 columns but schema has 2");
1402 }
1403
1404 fn new_region_metadata() -> RegionMetadata {
1405 let mut builder = RegionMetadataBuilder::new(RegionId::new(1, 1));
1406 builder
1407 .push_column_metadata(ColumnMetadata {
1408 column_schema: datatypes::schema::ColumnSchema::new(
1409 "ts",
1410 ConcreteDataType::timestamp_millisecond_datatype(),
1411 false,
1412 ),
1413 semantic_type: SemanticType::Timestamp,
1414 column_id: 1,
1415 })
1416 .push_column_metadata(ColumnMetadata {
1417 column_schema: datatypes::schema::ColumnSchema::new(
1418 "k0",
1419 ConcreteDataType::int64_datatype(),
1420 true,
1421 ),
1422 semantic_type: SemanticType::Tag,
1423 column_id: 2,
1424 })
1425 .primary_key(vec![2]);
1426 builder.build().unwrap()
1427 }
1428
1429 #[test]
1430 fn test_check_schema() {
1431 let rows = Rows {
1432 schema: vec![
1433 new_column_schema(
1434 "ts",
1435 ColumnDataType::TimestampMillisecond,
1436 SemanticType::Timestamp,
1437 ),
1438 new_column_schema("k0", ColumnDataType::Int64, SemanticType::Tag),
1439 ],
1440 rows: vec![Row {
1441 values: vec![ts_ms_value(1), i64_value(2)],
1442 }],
1443 };
1444 let metadata = new_region_metadata();
1445
1446 let request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1447 request.check_schema(&metadata).unwrap();
1448 }
1449
1450 #[test]
1451 fn test_column_type() {
1452 let rows = Rows {
1453 schema: vec![
1454 new_column_schema("ts", ColumnDataType::Int64, SemanticType::Timestamp),
1455 new_column_schema("k0", ColumnDataType::Int64, SemanticType::Tag),
1456 ],
1457 rows: vec![Row {
1458 values: vec![i64_value(1), i64_value(2)],
1459 }],
1460 };
1461 let metadata = new_region_metadata();
1462
1463 let request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1464 let err = request.check_schema(&metadata).unwrap_err();
1465 check_invalid_request(
1466 &err,
1467 "column ts expect type Timestamp(Millisecond(TimestampMillisecondType)), given: INT64(4)",
1468 );
1469 }
1470
1471 #[test]
1472 fn test_semantic_type() {
1473 let rows = Rows {
1474 schema: vec![
1475 new_column_schema(
1476 "ts",
1477 ColumnDataType::TimestampMillisecond,
1478 SemanticType::Tag,
1479 ),
1480 new_column_schema("k0", ColumnDataType::Int64, SemanticType::Tag),
1481 ],
1482 rows: vec![Row {
1483 values: vec![ts_ms_value(1), i64_value(2)],
1484 }],
1485 };
1486 let metadata = new_region_metadata();
1487
1488 let request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1489 let err = request.check_schema(&metadata).unwrap_err();
1490 check_invalid_request(&err, "column ts has semantic type Timestamp, given: TAG(0)");
1491 }
1492
1493 #[test]
1494 fn test_column_nullable() {
1495 let rows = Rows {
1496 schema: vec![
1497 new_column_schema(
1498 "ts",
1499 ColumnDataType::TimestampMillisecond,
1500 SemanticType::Timestamp,
1501 ),
1502 new_column_schema("k0", ColumnDataType::Int64, SemanticType::Tag),
1503 ],
1504 rows: vec![Row {
1505 values: vec![Value { value_data: None }, i64_value(2)],
1506 }],
1507 };
1508 let metadata = new_region_metadata();
1509
1510 let request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1511 let err = request.check_schema(&metadata).unwrap_err();
1512 check_invalid_request(&err, "column ts is not null but input has null");
1513 }
1514
1515 #[test]
1516 fn test_column_default() {
1517 let rows = Rows {
1518 schema: vec![new_column_schema(
1519 "k0",
1520 ColumnDataType::Int64,
1521 SemanticType::Tag,
1522 )],
1523 rows: vec![Row {
1524 values: vec![i64_value(1)],
1525 }],
1526 };
1527 let metadata = new_region_metadata();
1528
1529 let request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1530 let err = request.check_schema(&metadata).unwrap_err();
1531 check_invalid_request(&err, "missing column ts");
1532 }
1533
1534 #[test]
1535 fn test_unknown_column() {
1536 let rows = Rows {
1537 schema: vec![
1538 new_column_schema(
1539 "ts",
1540 ColumnDataType::TimestampMillisecond,
1541 SemanticType::Timestamp,
1542 ),
1543 new_column_schema("k0", ColumnDataType::Int64, SemanticType::Tag),
1544 new_column_schema("k1", ColumnDataType::Int64, SemanticType::Tag),
1545 ],
1546 rows: vec![Row {
1547 values: vec![ts_ms_value(1), i64_value(2), i64_value(3)],
1548 }],
1549 };
1550 let metadata = new_region_metadata();
1551
1552 let request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1553 let err = request.check_schema(&metadata).unwrap_err();
1554 check_invalid_request(&err, r#"unknown columns: ["k1"]"#);
1555 }
1556
1557 #[test]
1558 fn test_fill_impure_columns_err() {
1559 let rows = Rows {
1560 schema: vec![new_column_schema(
1561 "k0",
1562 ColumnDataType::Int64,
1563 SemanticType::Tag,
1564 )],
1565 rows: vec![Row {
1566 values: vec![i64_value(1)],
1567 }],
1568 };
1569 let metadata = {
1570 let mut builder = RegionMetadataBuilder::new(RegionId::new(1, 1));
1571 builder
1572 .push_column_metadata(ColumnMetadata {
1573 column_schema: datatypes::schema::ColumnSchema::new(
1574 "ts",
1575 ConcreteDataType::timestamp_millisecond_datatype(),
1576 false,
1577 )
1578 .with_default_constraint(Some(ColumnDefaultConstraint::Function(
1579 "now()".to_string(),
1580 )))
1581 .unwrap(),
1582 semantic_type: SemanticType::Timestamp,
1583 column_id: 1,
1584 })
1585 .push_column_metadata(ColumnMetadata {
1586 column_schema: datatypes::schema::ColumnSchema::new(
1587 "k0",
1588 ConcreteDataType::int64_datatype(),
1589 true,
1590 ),
1591 semantic_type: SemanticType::Tag,
1592 column_id: 2,
1593 })
1594 .primary_key(vec![2]);
1595 builder.build().unwrap()
1596 };
1597
1598 let mut request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1599 let err = request.check_schema(&metadata).unwrap_err();
1600 assert!(err.is_fill_default());
1601 assert!(
1602 request
1603 .fill_missing_columns(&metadata)
1604 .unwrap_err()
1605 .to_string()
1606 .contains("unexpected impure default value with region_id")
1607 );
1608 }
1609
1610 #[test]
1611 fn test_fill_missing_columns() {
1612 let rows = Rows {
1613 schema: vec![new_column_schema(
1614 "ts",
1615 ColumnDataType::TimestampMillisecond,
1616 SemanticType::Timestamp,
1617 )],
1618 rows: vec![Row {
1619 values: vec![ts_ms_value(1)],
1620 }],
1621 };
1622 let metadata = new_region_metadata();
1623
1624 let mut request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1625 let err = request.check_schema(&metadata).unwrap_err();
1626 assert!(err.is_fill_default());
1627 request.fill_missing_columns(&metadata).unwrap();
1628
1629 let expect_rows = Rows {
1630 schema: vec![new_column_schema(
1631 "ts",
1632 ColumnDataType::TimestampMillisecond,
1633 SemanticType::Timestamp,
1634 )],
1635 rows: vec![Row {
1636 values: vec![ts_ms_value(1)],
1637 }],
1638 };
1639 assert_eq!(expect_rows, request.rows);
1640 }
1641
1642 fn builder_with_ts_tag() -> RegionMetadataBuilder {
1643 let mut builder = RegionMetadataBuilder::new(RegionId::new(1, 1));
1644 builder
1645 .push_column_metadata(ColumnMetadata {
1646 column_schema: datatypes::schema::ColumnSchema::new(
1647 "ts",
1648 ConcreteDataType::timestamp_millisecond_datatype(),
1649 false,
1650 ),
1651 semantic_type: SemanticType::Timestamp,
1652 column_id: 1,
1653 })
1654 .push_column_metadata(ColumnMetadata {
1655 column_schema: datatypes::schema::ColumnSchema::new(
1656 "k0",
1657 ConcreteDataType::int64_datatype(),
1658 true,
1659 ),
1660 semantic_type: SemanticType::Tag,
1661 column_id: 2,
1662 })
1663 .primary_key(vec![2]);
1664 builder
1665 }
1666
1667 fn region_metadata_two_fields() -> RegionMetadata {
1668 let mut builder = builder_with_ts_tag();
1669 builder
1670 .push_column_metadata(ColumnMetadata {
1671 column_schema: datatypes::schema::ColumnSchema::new(
1672 "f0",
1673 ConcreteDataType::int64_datatype(),
1674 true,
1675 ),
1676 semantic_type: SemanticType::Field,
1677 column_id: 3,
1678 })
1679 .push_column_metadata(ColumnMetadata {
1681 column_schema: datatypes::schema::ColumnSchema::new(
1682 "f1",
1683 ConcreteDataType::int64_datatype(),
1684 false,
1685 )
1686 .with_default_constraint(Some(ColumnDefaultConstraint::Value(
1687 datatypes::value::Value::Int64(100),
1688 )))
1689 .unwrap(),
1690 semantic_type: SemanticType::Field,
1691 column_id: 4,
1692 });
1693 builder.build().unwrap()
1694 }
1695
1696 #[test]
1697 fn test_fill_missing_for_delete() {
1698 let rows = Rows {
1699 schema: vec![new_column_schema(
1700 "ts",
1701 ColumnDataType::TimestampMillisecond,
1702 SemanticType::Timestamp,
1703 )],
1704 rows: vec![Row {
1705 values: vec![ts_ms_value(1)],
1706 }],
1707 };
1708 let metadata = region_metadata_two_fields();
1709
1710 let mut request =
1711 WriteRequest::new(RegionId::new(1, 1), OpType::Delete, rows, None).unwrap();
1712 let err = request.check_schema(&metadata).unwrap_err();
1713 check_invalid_request(&err, "delete requests need column k0");
1714 let err = request.fill_missing_columns(&metadata).unwrap_err();
1715 check_invalid_request(&err, "delete requests need column k0");
1716
1717 let rows = Rows {
1718 schema: vec![
1719 new_column_schema("k0", ColumnDataType::Int64, SemanticType::Tag),
1720 new_column_schema(
1721 "ts",
1722 ColumnDataType::TimestampMillisecond,
1723 SemanticType::Timestamp,
1724 ),
1725 ],
1726 rows: vec![Row {
1727 values: vec![i64_value(100), ts_ms_value(1)],
1728 }],
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 assert!(err.is_fill_default());
1734 request.fill_missing_columns(&metadata).unwrap();
1735
1736 let expect_rows = Rows {
1737 schema: vec![
1738 new_column_schema("k0", ColumnDataType::Int64, SemanticType::Tag),
1739 new_column_schema(
1740 "ts",
1741 ColumnDataType::TimestampMillisecond,
1742 SemanticType::Timestamp,
1743 ),
1744 new_column_schema("f1", ColumnDataType::Int64, SemanticType::Field),
1745 ],
1746 rows: vec![Row {
1748 values: vec![i64_value(100), ts_ms_value(1), i64_value(0)],
1749 }],
1750 };
1751 assert_eq!(expect_rows, request.rows);
1752 }
1753
1754 #[test]
1755 fn test_fill_missing_without_default_in_delete() {
1756 let mut builder = builder_with_ts_tag();
1757 builder
1758 .push_column_metadata(ColumnMetadata {
1760 column_schema: datatypes::schema::ColumnSchema::new(
1761 "f0",
1762 ConcreteDataType::int64_datatype(),
1763 true,
1764 ),
1765 semantic_type: SemanticType::Field,
1766 column_id: 3,
1767 })
1768 .push_column_metadata(ColumnMetadata {
1770 column_schema: datatypes::schema::ColumnSchema::new(
1771 "f1",
1772 ConcreteDataType::int64_datatype(),
1773 false,
1774 ),
1775 semantic_type: SemanticType::Field,
1776 column_id: 4,
1777 });
1778 let metadata = builder.build().unwrap();
1779
1780 let rows = Rows {
1781 schema: vec![
1782 new_column_schema("k0", ColumnDataType::Int64, SemanticType::Tag),
1783 new_column_schema(
1784 "ts",
1785 ColumnDataType::TimestampMillisecond,
1786 SemanticType::Timestamp,
1787 ),
1788 ],
1789 rows: vec![Row {
1791 values: vec![i64_value(100), ts_ms_value(1)],
1792 }],
1793 };
1794 let mut request =
1795 WriteRequest::new(RegionId::new(1, 1), OpType::Delete, rows, None).unwrap();
1796 let err = request.check_schema(&metadata).unwrap_err();
1797 assert!(err.is_fill_default());
1798 request.fill_missing_columns(&metadata).unwrap();
1799
1800 let expect_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 new_column_schema("f1", ColumnDataType::Int64, SemanticType::Field),
1809 ],
1810 rows: vec![Row {
1812 values: vec![i64_value(100), ts_ms_value(1), i64_value(0)],
1813 }],
1814 };
1815 assert_eq!(expect_rows, request.rows);
1816 }
1817
1818 #[test]
1819 fn test_no_default() {
1820 let rows = Rows {
1821 schema: vec![new_column_schema(
1822 "k0",
1823 ColumnDataType::Int64,
1824 SemanticType::Tag,
1825 )],
1826 rows: vec![Row {
1827 values: vec![i64_value(1)],
1828 }],
1829 };
1830 let metadata = new_region_metadata();
1831
1832 let mut request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1833 let err = request.fill_missing_columns(&metadata).unwrap_err();
1834 check_invalid_request(&err, "column ts does not have default value");
1835 }
1836
1837 #[test]
1838 fn test_missing_and_invalid() {
1839 let rows = Rows {
1841 schema: vec![
1842 new_column_schema("k0", ColumnDataType::Int64, SemanticType::Tag),
1843 new_column_schema(
1844 "ts",
1845 ColumnDataType::TimestampMillisecond,
1846 SemanticType::Timestamp,
1847 ),
1848 new_column_schema("f1", ColumnDataType::String, SemanticType::Field),
1849 ],
1850 rows: vec![Row {
1851 values: vec![
1852 i64_value(100),
1853 ts_ms_value(1),
1854 Value {
1855 value_data: Some(ValueData::StringValue("xxxxx".to_string())),
1856 },
1857 ],
1858 }],
1859 };
1860 let metadata = region_metadata_two_fields();
1861
1862 let request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1863 let err = request.check_schema(&metadata).unwrap_err();
1864 check_invalid_request(
1865 &err,
1866 "column f1 expect type Int64(Int64Type), given: STRING(12)",
1867 );
1868 }
1869
1870 #[test]
1871 fn test_delete_request_defaults_to_writing_wal() {
1872 let (request, _receiver) = WorkerRequest::try_from_region_request(
1873 RegionId::new(1, 1),
1874 RegionRequest::Delete(store_api::region_request::RegionDeleteRequest {
1875 rows: Rows::default(),
1876 hint: None,
1877 partition_expr_version: None,
1878 }),
1879 None,
1880 )
1881 .unwrap();
1882 let WorkerRequest::Write(request) = request else {
1883 panic!("expected a write request");
1884 };
1885 assert_eq!(request.request.op_type, OpType::Delete);
1886 assert!(!request.request.skip_wal);
1887 }
1888
1889 #[test]
1890 fn test_write_request_metadata() {
1891 let rows = Rows {
1892 schema: vec![
1893 new_column_schema("c0", ColumnDataType::Int64, SemanticType::Tag),
1894 new_column_schema("c1", ColumnDataType::Int64, SemanticType::Tag),
1895 ],
1896 rows: vec![Row {
1897 values: vec![i64_value(1), i64_value(2)],
1898 }],
1899 };
1900
1901 let metadata = Arc::new(new_region_metadata());
1902 let request = WriteRequest::new(
1903 RegionId::new(1, 1),
1904 OpType::Put,
1905 rows,
1906 Some(metadata.clone()),
1907 )
1908 .unwrap();
1909
1910 assert!(request.region_metadata.is_some());
1911 assert_eq!(
1912 request.region_metadata.unwrap().region_id,
1913 RegionId::new(1, 1)
1914 );
1915 }
1916}