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