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::arrow::array::{Array, ArrayRef};
29use datatypes::arrow::datatypes::DataType as ArrowDataType;
30use datatypes::arrow::record_batch::RecordBatch;
31use datatypes::prelude::DataType;
32use partition::expr::PartitionExpr;
33use prometheus::HistogramTimer;
34use prost::Message;
35use smallvec::SmallVec;
36use snafu::{OptionExt, ResultExt, ensure};
37use store_api::ManifestVersion;
38use store_api::codec::{PrimaryKeyEncoding, infer_primary_key_encoding_from_hint};
39use store_api::metadata::{ColumnMetadata, RegionMetadata, RegionMetadataRef};
40use store_api::region_engine::{
41 MitoCopyRegionFromResponse, SetRegionRoleStateResponse, SettableRegionRoleState,
42};
43use store_api::region_request::{
44 AffectedRows, ApplyStagingManifestRequest, EnterStagingRequest, RegionAlterRequest,
45 RegionBuildIndexRequest, RegionBulkInsertsRequest, RegionCatchupRequest, RegionCleanUpRequest,
46 RegionCloseRequest, RegionCompactRequest, RegionCreateRequest, RegionDropRequest,
47 RegionFlushRequest, RegionOpenRequest, RegionRequest, RegionTruncateRequest,
48 StagingPartitionDirective,
49};
50use store_api::storage::consts::PRIMARY_KEY_COLUMN_NAME;
51use store_api::storage::{FileId, RegionId, SequenceNumber};
52use tokio::sync::oneshot::{self, Receiver, Sender};
53
54use crate::compaction::{CompactionExecution, CompactionPickFinished};
55use crate::error::{
56 CompactRegionSnafu, ConvertColumnDataTypeSnafu, CreateDefaultSnafu, Error, FillDefaultSnafu,
57 FlushRegionSnafu, InvalidPartitionExprSnafu, InvalidRequestSnafu, MissingPartitionExprSnafu,
58 Result, UnexpectedSnafu,
59};
60use crate::flush::FlushReason;
61use crate::manifest::action::{RegionEdit, TruncateKind};
62use crate::memtable::MemtableId;
63use crate::memtable::bulk::part::BulkPart;
64use crate::metrics::COMPACTION_ELAPSED_TOTAL;
65use crate::region::MitoRegionRef;
66use crate::region::options::RegionOptions;
67use crate::sst::file::FileMeta;
68use crate::sst::index::IndexBuildType;
69use crate::wal::EntryId;
70use crate::wal::entry_distributor::WalEntryReceiver;
71
72#[derive(Debug)]
74pub struct WriteRequest {
75 pub region_id: RegionId,
77 pub op_type: OpType,
79 pub rows: Rows,
81 pub name_to_index: HashMap<String, usize>,
83 pub has_null: Vec<bool>,
85 pub skip_wal: bool,
87 pub hint: Option<WriteHint>,
89 pub(crate) region_metadata: Option<RegionMetadataRef>,
91 pub partition_expr_version: Option<u64>,
93}
94
95impl WriteRequest {
96 pub fn new(
100 region_id: RegionId,
101 op_type: OpType,
102 rows: Rows,
103 region_metadata: Option<RegionMetadataRef>,
104 ) -> Result<WriteRequest> {
105 let mut name_to_index = HashMap::with_capacity(rows.schema.len());
106 for (index, column) in rows.schema.iter().enumerate() {
107 ensure!(
108 name_to_index
109 .insert(column.column_name.clone(), index)
110 .is_none(),
111 InvalidRequestSnafu {
112 region_id,
113 reason: format!("duplicate column {}", column.column_name),
114 }
115 );
116 }
117
118 let mut has_null = vec![false; rows.schema.len()];
119 for row in &rows.rows {
120 ensure!(
121 row.values.len() == rows.schema.len(),
122 InvalidRequestSnafu {
123 region_id,
124 reason: format!(
125 "row has {} columns but schema has {}",
126 row.values.len(),
127 rows.schema.len()
128 ),
129 }
130 );
131
132 for (i, (value, column_schema)) in row.values.iter().zip(&rows.schema).enumerate() {
133 validate_proto_value(region_id, value, column_schema)?;
134
135 if value.value_data.is_none() {
136 has_null[i] = true;
137 }
138 }
139 }
140
141 Ok(WriteRequest {
142 region_id,
143 op_type,
144 rows,
145 name_to_index,
146 has_null,
147 hint: None,
148 skip_wal: false,
149 region_metadata,
150 partition_expr_version: None,
151 })
152 }
153
154 pub fn with_skip_wal(mut self, skip_wal: bool) -> Self {
156 self.skip_wal = skip_wal;
157 self
158 }
159
160 pub fn with_hint(mut self, hint: Option<WriteHint>) -> Self {
162 self.hint = hint;
163 self
164 }
165
166 pub fn with_partition_expr_version(mut self, partition_expr_version: Option<u64>) -> Self {
167 self.partition_expr_version = partition_expr_version;
168 self
169 }
170
171 pub fn primary_key_encoding(&self) -> PrimaryKeyEncoding {
173 infer_primary_key_encoding_from_hint(self.hint.as_ref())
174 }
175
176 pub(crate) fn estimated_size(&self) -> usize {
178 let row_size = self
179 .rows
180 .rows
181 .first()
182 .map(|row| row.encoded_len())
183 .unwrap_or(0);
184 row_size * self.rows.rows.len()
185 }
186
187 pub fn column_index_by_name(&self, name: &str) -> Option<usize> {
189 self.name_to_index.get(name).copied()
190 }
191
192 pub(crate) fn check_schema(&self, metadata: &RegionMetadata) -> Result<()> {
197 debug_assert_eq!(self.region_id, metadata.region_id);
198
199 let region_id = self.region_id;
200 let rows_columns = self
202 .rows
203 .schema
204 .iter()
205 .map(|schema| {
206 let column = RowColumn {
207 request: self,
208 schema,
209 };
210 (schema.column_name.as_str(), column)
211 })
212 .collect();
213 let need_fill_default =
214 check_request_columns(region_id, metadata, rows_columns, |column| {
215 self.check_missing_column(column)
216 })?;
217
218 ensure!(!need_fill_default, FillDefaultSnafu { region_id });
220
221 Ok(())
222 }
223
224 pub(crate) fn fill_missing_columns(&mut self, metadata: &RegionMetadata) -> Result<()> {
229 debug_assert_eq!(self.region_id, metadata.region_id);
230
231 let mut columns_to_fill = vec![];
232 for column in &metadata.column_metadatas {
233 if !self.name_to_index.contains_key(&column.column_schema.name) {
234 columns_to_fill.push(column);
235 }
236 }
237 self.fill_columns(columns_to_fill)?;
238
239 Ok(())
240 }
241
242 pub(crate) fn maybe_fill_missing_columns(&mut self, metadata: &RegionMetadata) -> Result<()> {
244 if let Err(e) = self.check_schema(metadata) {
245 if e.is_fill_default() {
246 self.fill_missing_columns(metadata)?;
250 } else {
251 return Err(e);
252 }
253 }
254
255 Ok(())
256 }
257
258 fn fill_columns(&mut self, columns: Vec<&ColumnMetadata>) -> Result<()> {
260 let mut default_values = Vec::with_capacity(columns.len());
261 let mut columns_to_fill = Vec::with_capacity(columns.len());
262 for column in columns {
263 let default_value = self.column_default_value(column)?;
264 if default_value.value_data.is_some() {
265 default_values.push(default_value);
266 columns_to_fill.push(column);
267 }
268 }
269
270 for row in &mut self.rows.rows {
271 row.values.extend(default_values.iter().cloned());
272 }
273
274 for column in columns_to_fill {
275 let (datatype, datatype_ext) =
276 ColumnDataTypeWrapper::try_from(column.column_schema.data_type.clone())
277 .with_context(|_| ConvertColumnDataTypeSnafu {
278 reason: format!(
279 "no protobuf type for column {} ({:?})",
280 column.column_schema.name, column.column_schema.data_type
281 ),
282 })?
283 .to_parts();
284 self.rows.schema.push(ColumnSchema {
285 column_name: column.column_schema.name.clone(),
286 datatype: datatype as i32,
287 semantic_type: column.semantic_type as i32,
288 datatype_extension: datatype_ext,
289 options: options_from_column_schema(&column.column_schema),
290 });
291 }
292
293 Ok(())
294 }
295
296 fn check_missing_column(&self, column: &ColumnMetadata) -> Result<()> {
298 if self.op_type == OpType::Delete {
299 if column.semantic_type == SemanticType::Field {
300 return Ok(());
303 } else {
304 return InvalidRequestSnafu {
305 region_id: self.region_id,
306 reason: format!("delete requests need column {}", column.column_schema.name),
307 }
308 .fail();
309 }
310 }
311
312 check_column_can_be_filled(self.region_id, column)
314 }
315
316 fn column_default_value(&self, column: &ColumnMetadata) -> Result<Value> {
318 let default_value = match self.op_type {
319 OpType::Delete => {
320 ensure!(
321 column.semantic_type == SemanticType::Field,
322 InvalidRequestSnafu {
323 region_id: self.region_id,
324 reason: format!(
325 "delete requests need column {}",
326 column.column_schema.name
327 ),
328 }
329 );
330
331 if column.column_schema.is_nullable() {
336 datatypes::value::Value::Null
337 } else {
338 column.column_schema.data_type.default_value()
339 }
340 }
341 OpType::Put => {
342 if column.column_schema.is_default_impure() {
344 UnexpectedSnafu {
345 reason: format!(
346 "unexpected impure default value with region_id: {}, column: {}, default_value: {:?}",
347 self.region_id,
348 column.column_schema.name,
349 column.column_schema.default_constraint(),
350 ),
351 }
352 .fail()?
353 }
354 column
355 .column_schema
356 .create_default()
357 .context(CreateDefaultSnafu {
358 region_id: self.region_id,
359 column: &column.column_schema.name,
360 })?
361 .with_context(|| InvalidRequestSnafu {
363 region_id: self.region_id,
364 reason: format!(
365 "column {} does not have default value",
366 column.column_schema.name
367 ),
368 })?
369 }
370 };
371
372 Ok(api::helper::to_grpc_value(default_value))
374 }
375}
376
377trait RequestColumn {
379 fn has_type_of(&self, column: &ColumnMetadata) -> bool;
381
382 fn type_name(&self) -> String;
384
385 fn semantic_type(&self) -> Option<i32>;
387
388 fn has_null(&self) -> bool;
390}
391
392fn check_request_columns<C: RequestColumn>(
398 region_id: RegionId,
399 metadata: &RegionMetadata,
400 mut columns: HashMap<&str, C>,
401 mut check_missing: impl FnMut(&ColumnMetadata) -> Result<()>,
402) -> Result<bool> {
403 let mut has_missing = false;
404 for column in &metadata.column_metadatas {
405 let Some(input_col) = columns.remove(column.column_schema.name.as_str()) else {
406 check_missing(column)?;
407 has_missing = true;
408 continue;
409 };
410 ensure!(
412 input_col.has_type_of(column),
413 InvalidRequestSnafu {
414 region_id,
415 reason: format!(
416 "column {} expect type {:?}, given: {}",
417 column.column_schema.name,
418 column.column_schema.data_type,
419 input_col.type_name(),
420 )
421 }
422 );
423
424 if let Some(semantic_type) = input_col.semantic_type() {
426 ensure!(
427 is_semantic_type_eq(semantic_type, column.semantic_type),
428 InvalidRequestSnafu {
429 region_id,
430 reason: format!(
431 "column {} has semantic type {:?}, given: {}({})",
432 column.column_schema.name,
433 column.semantic_type,
434 api::v1::SemanticType::try_from(semantic_type)
435 .map(|v| v.as_str_name())
436 .unwrap_or("Unknown"),
437 semantic_type
438 ),
439 }
440 );
441 }
442
443 ensure!(
445 !input_col.has_null() || column.column_schema.is_nullable(),
446 InvalidRequestSnafu {
447 region_id,
448 reason: format!(
449 "column {} is not null but input has null",
450 column.column_schema.name
451 ),
452 }
453 );
454 }
455
456 if !columns.is_empty() {
458 let names: Vec<_> = columns.into_keys().collect();
459 return InvalidRequestSnafu {
460 region_id,
461 reason: format!("unknown columns: {:?}", names),
462 }
463 .fail();
464 }
465
466 Ok(has_missing)
467}
468
469fn check_column_can_be_filled(region_id: RegionId, column: &ColumnMetadata) -> Result<()> {
472 ensure!(
473 column.column_schema.is_nullable() || column.column_schema.default_constraint().is_some(),
474 InvalidRequestSnafu {
475 region_id,
476 reason: format!("missing column {}", column.column_schema.name),
477 }
478 );
479 Ok(())
480}
481
482struct RowColumn<'a> {
484 request: &'a WriteRequest,
485 schema: &'a ColumnSchema,
486}
487
488impl RequestColumn for RowColumn<'_> {
489 fn has_type_of(&self, column: &ColumnMetadata) -> bool {
490 is_column_type_value_eq(
491 self.schema.datatype,
492 self.schema.datatype_extension.clone(),
493 &column.column_schema.data_type,
494 )
495 }
496
497 fn type_name(&self) -> String {
498 format!(
499 "{}({})",
500 ColumnDataType::try_from(self.schema.datatype)
501 .map(|v| v.as_str_name())
502 .unwrap_or("Unknown"),
503 self.schema.datatype,
504 )
505 }
506
507 fn semantic_type(&self) -> Option<i32> {
508 Some(self.schema.semantic_type)
509 }
510
511 fn has_null(&self) -> bool {
512 self.request.has_null[self.request.name_to_index[&self.schema.column_name]]
514 }
515}
516
517struct BulkColumn<'a> {
519 array: &'a ArrayRef,
520}
521
522impl RequestColumn for BulkColumn<'_> {
523 fn has_type_of(&self, column: &ColumnMetadata) -> bool {
524 let actual = self.array.data_type();
525 let data_type = &column.column_schema.data_type;
526 if column.semantic_type == SemanticType::Tag && data_type.is_string() {
528 return match actual {
529 ArrowDataType::Dictionary(key, value) => key.is_integer() && value.is_string(),
530 actual => actual.is_string(),
531 };
532 }
533 *actual == data_type.as_arrow_type()
534 }
535
536 fn type_name(&self) -> String {
537 self.array.data_type().to_string()
538 }
539
540 fn semantic_type(&self) -> Option<i32> {
541 None
542 }
543
544 fn has_null(&self) -> bool {
545 self.array.logical_null_count() > 0
546 }
547}
548
549pub fn check_bulk_insert_batch(metadata: &RegionMetadata, batch: &RecordBatch) -> Result<bool> {
557 let region_id = metadata.region_id;
558 let sparse = metadata.primary_key_encoding == PrimaryKeyEncoding::Sparse;
559 let mut primary_key = None;
560 let mut columns = HashMap::with_capacity(batch.num_columns());
561 for (field, array) in batch.schema_ref().fields().iter().zip(batch.columns()) {
562 let duplicate = if sparse && field.name() == PRIMARY_KEY_COLUMN_NAME {
563 primary_key.replace(array).is_some()
564 } else {
565 columns
566 .insert(field.name().as_str(), BulkColumn { array })
567 .is_some()
568 };
569 ensure!(
570 !duplicate,
571 InvalidRequestSnafu {
572 region_id,
573 reason: format!("duplicate column {}", field.name()),
574 }
575 );
576 }
577 if sparse {
578 let primary_key = primary_key.with_context(|| InvalidRequestSnafu {
579 region_id,
580 reason: format!("missing column {PRIMARY_KEY_COLUMN_NAME}"),
581 })?;
582 let type_matches = match primary_key.data_type() {
584 ArrowDataType::Binary => true,
585 ArrowDataType::Dictionary(key, value) => {
586 key.is_integer() && **value == ArrowDataType::Binary
587 }
588 _ => false,
589 };
590 ensure!(
591 type_matches && primary_key.logical_null_count() == 0,
592 InvalidRequestSnafu {
593 region_id,
594 reason: format!(
595 "column {PRIMARY_KEY_COLUMN_NAME} must be binary without nulls, given: {}",
596 primary_key.data_type()
597 ),
598 }
599 );
600 }
601 let mut needs_fill = false;
602 check_request_columns(region_id, metadata, columns, |column| {
603 if sparse && column.semantic_type == SemanticType::Tag {
604 Ok(())
605 } else {
606 needs_fill = true;
607 check_column_can_be_filled(region_id, column)
608 }
609 })?;
610 Ok(needs_fill)
611}
612
613pub(crate) fn validate_proto_value(
615 region_id: RegionId,
616 value: &Value,
617 column_schema: &ColumnSchema,
618) -> Result<()> {
619 if let Some(value_type) = proto_value_type(value) {
620 let column_type = ColumnDataType::try_from(column_schema.datatype).map_err(|_| {
621 InvalidRequestSnafu {
622 region_id,
623 reason: format!(
624 "column {} has unknown type {}",
625 column_schema.column_name, column_schema.datatype
626 ),
627 }
628 .build()
629 })?;
630 ensure!(
631 proto_value_type_match(column_type, value_type),
632 InvalidRequestSnafu {
633 region_id,
634 reason: format!(
635 "value has type {:?}, but column {} has type {:?}({})",
636 value_type, column_schema.column_name, column_type, column_schema.datatype,
637 ),
638 }
639 );
640 }
641
642 Ok(())
643}
644
645#[derive(Debug)]
647pub struct OutputTx(Sender<Result<AffectedRows>>);
648
649impl OutputTx {
650 pub(crate) fn new(sender: Sender<Result<AffectedRows>>) -> OutputTx {
652 OutputTx(sender)
653 }
654
655 pub(crate) fn send(self, result: Result<AffectedRows>) {
657 let _ = self.0.send(result);
659 }
660}
661
662#[derive(Debug)]
664pub(crate) struct OptionOutputTx(Option<OutputTx>);
665
666impl OptionOutputTx {
667 pub(crate) fn new(sender: Option<OutputTx>) -> OptionOutputTx {
669 OptionOutputTx(sender)
670 }
671
672 pub(crate) fn none() -> OptionOutputTx {
674 OptionOutputTx(None)
675 }
676
677 pub(crate) fn send_mut(&mut self, result: Result<AffectedRows>) {
679 if let Some(sender) = self.0.take() {
680 sender.send(result);
681 }
682 }
683
684 pub(crate) fn send(mut self, result: Result<AffectedRows>) {
686 if let Some(sender) = self.0.take() {
687 sender.send(result);
688 }
689 }
690
691 pub(crate) fn take_inner(&mut self) -> Option<OutputTx> {
693 self.0.take()
694 }
695}
696
697impl From<Sender<Result<AffectedRows>>> for OptionOutputTx {
698 fn from(sender: Sender<Result<AffectedRows>>) -> Self {
699 Self::new(Some(OutputTx::new(sender)))
700 }
701}
702
703impl OnFailure for OptionOutputTx {
704 fn on_failure(&mut self, err: Error) {
705 self.send_mut(Err(err));
706 }
707}
708
709pub(crate) trait OnFailure {
711 fn on_failure(&mut self, err: Error);
713}
714
715#[derive(Debug)]
717pub(crate) struct SenderWriteRequest {
718 pub(crate) sender: OptionOutputTx,
720 pub(crate) request: WriteRequest,
721}
722
723pub(crate) struct SenderBulkRequest {
724 pub(crate) skip_wal: bool,
725 pub(crate) sender: OptionOutputTx,
726 pub(crate) region_id: RegionId,
727 pub(crate) request: BulkPart,
728 pub(crate) region_metadata: Option<RegionMetadataRef>,
729 pub(crate) partition_expr_version: Option<u64>,
730}
731
732#[derive(Debug)]
733pub(crate) struct BulkInsertRequest {
734 pub(crate) metadata: Option<RegionMetadataRef>,
735 pub(crate) request: RegionBulkInsertsRequest,
736 pub(crate) sender: OptionOutputTx,
737}
738
739#[derive(Debug)]
741pub(crate) struct WorkerRequestWithTime {
742 pub(crate) request: WorkerRequest,
743 pub(crate) created_at: Instant,
744}
745
746impl WorkerRequestWithTime {
747 pub(crate) fn new(request: WorkerRequest) -> Self {
748 Self {
749 request,
750 created_at: Instant::now(),
751 }
752 }
753}
754
755#[derive(Debug)]
757pub(crate) enum WorkerRequest {
758 Write(SenderWriteRequest),
760
761 Ddl(SenderDdlRequest),
763
764 Background {
766 region_id: RegionId,
768 notify: BackgroundNotify,
770 },
771
772 SetRegionRoleStateGracefully {
774 region_id: RegionId,
776 region_role_state: SettableRegionRoleState,
778 sender: Sender<SetRegionRoleStateResponse>,
780 },
781
782 Stop,
784
785 EditRegion(RegionEditRequest),
787
788 SyncRegion(RegionSyncRequest),
790
791 BulkInserts(BulkInsertRequest),
793
794 RemapManifests(RemapManifestsRequest),
796
797 CopyRegionFrom(CopyRegionFromRequest),
799}
800
801impl WorkerRequest {
802 pub(crate) fn new_open_region_request(
804 region_id: RegionId,
805 request: RegionOpenRequest,
806 entry_receiver: Option<WalEntryReceiver>,
807 ) -> (WorkerRequest, Receiver<Result<AffectedRows>>) {
808 let (sender, receiver) = oneshot::channel();
809
810 let worker_request = WorkerRequest::Ddl(SenderDdlRequest {
811 region_id,
812 sender: sender.into(),
813 request: DdlRequest::Open((request, entry_receiver)),
814 });
815
816 (worker_request, receiver)
817 }
818
819 pub(crate) fn new_catchup_region_request(
821 region_id: RegionId,
822 request: RegionCatchupRequest,
823 entry_receiver: Option<WalEntryReceiver>,
824 ) -> (WorkerRequest, Receiver<Result<AffectedRows>>) {
825 let (sender, receiver) = oneshot::channel();
826 let worker_request = WorkerRequest::Ddl(SenderDdlRequest {
827 region_id,
828 sender: sender.into(),
829 request: DdlRequest::Catchup((request, entry_receiver)),
830 });
831 (worker_request, receiver)
832 }
833
834 pub(crate) fn try_from_region_request(
836 region_id: RegionId,
837 value: RegionRequest,
838 region_metadata: Option<RegionMetadataRef>,
839 ) -> Result<(WorkerRequest, Receiver<Result<AffectedRows>>)> {
840 let (sender, receiver) = oneshot::channel();
841 let worker_request = match value {
842 RegionRequest::Put(v) => {
843 let mut write_request =
844 WriteRequest::new(region_id, OpType::Put, v.rows, region_metadata.clone())?
845 .with_hint(v.hint)
846 .with_skip_wal(v.skip_wal)
847 .with_partition_expr_version(v.partition_expr_version);
848 if write_request.primary_key_encoding() == PrimaryKeyEncoding::Dense
849 && let Some(region_metadata) = ®ion_metadata
850 {
851 write_request.maybe_fill_missing_columns(region_metadata)?;
852 }
853 WorkerRequest::Write(SenderWriteRequest {
854 sender: sender.into(),
855 request: write_request,
856 })
857 }
858 RegionRequest::Delete(v) => {
859 let mut write_request =
860 WriteRequest::new(region_id, OpType::Delete, v.rows, region_metadata.clone())?
861 .with_hint(v.hint)
862 .with_partition_expr_version(v.partition_expr_version);
863 if write_request.primary_key_encoding() == PrimaryKeyEncoding::Dense
864 && let Some(region_metadata) = ®ion_metadata
865 {
866 write_request.maybe_fill_missing_columns(region_metadata)?;
867 }
868 WorkerRequest::Write(SenderWriteRequest {
869 sender: sender.into(),
870 request: write_request,
871 })
872 }
873 RegionRequest::Create(v) => WorkerRequest::Ddl(SenderDdlRequest {
874 region_id,
875 sender: sender.into(),
876 request: DdlRequest::Create(v),
877 }),
878 RegionRequest::Drop(v) => WorkerRequest::Ddl(SenderDdlRequest {
879 region_id,
880 sender: sender.into(),
881 request: DdlRequest::Drop(v),
882 }),
883 RegionRequest::Open(v) => WorkerRequest::Ddl(SenderDdlRequest {
884 region_id,
885 sender: sender.into(),
886 request: DdlRequest::Open((v, None)),
887 }),
888 RegionRequest::CleanUp(v) => WorkerRequest::Ddl(SenderDdlRequest {
889 region_id,
890 sender: sender.into(),
891 request: DdlRequest::OfflineCleanup(v),
892 }),
893 RegionRequest::Close(v) => WorkerRequest::Ddl(SenderDdlRequest {
894 region_id,
895 sender: sender.into(),
896 request: DdlRequest::Close(v),
897 }),
898 RegionRequest::Alter(v) => WorkerRequest::Ddl(SenderDdlRequest {
899 region_id,
900 sender: sender.into(),
901 request: DdlRequest::Alter(v),
902 }),
903 RegionRequest::Flush(v) => WorkerRequest::Ddl(SenderDdlRequest {
904 region_id,
905 sender: sender.into(),
906 request: DdlRequest::Flush(v),
907 }),
908 RegionRequest::Compact(v) => WorkerRequest::Ddl(SenderDdlRequest {
909 region_id,
910 sender: sender.into(),
911 request: DdlRequest::Compact(v),
912 }),
913 RegionRequest::BuildIndex(v) => WorkerRequest::Ddl(SenderDdlRequest {
914 region_id,
915 sender: sender.into(),
916 request: DdlRequest::BuildIndex(v),
917 }),
918 RegionRequest::Truncate(v) => WorkerRequest::Ddl(SenderDdlRequest {
919 region_id,
920 sender: sender.into(),
921 request: DdlRequest::Truncate(v),
922 }),
923 RegionRequest::Catchup(v) => WorkerRequest::Ddl(SenderDdlRequest {
924 region_id,
925 sender: sender.into(),
926 request: DdlRequest::Catchup((v, None)),
927 }),
928 RegionRequest::EnterStaging(v) => WorkerRequest::Ddl(SenderDdlRequest {
929 region_id,
930 sender: sender.into(),
931 request: DdlRequest::EnterStaging(v),
932 }),
933 RegionRequest::BulkInserts(mut region_bulk_inserts_request) => {
934 if let Some(region_metadata) = ®ion_metadata
936 && region_bulk_inserts_request.payload.num_rows() > 0
937 && check_bulk_insert_batch(
938 region_metadata,
939 ®ion_bulk_inserts_request.payload,
940 )?
941 {
942 region_bulk_inserts_request.aligned_schema_version = None;
944 }
945 WorkerRequest::BulkInserts(BulkInsertRequest {
946 metadata: region_metadata,
947 sender: sender.into(),
948 request: region_bulk_inserts_request,
949 })
950 }
951 RegionRequest::ApplyStagingManifest(v) => WorkerRequest::Ddl(SenderDdlRequest {
952 region_id,
953 sender: sender.into(),
954 request: DdlRequest::ApplyStagingManifest(v),
955 }),
956 };
957
958 Ok((worker_request, receiver))
959 }
960
961 pub(crate) fn new_set_readonly_gracefully(
962 region_id: RegionId,
963 region_role_state: SettableRegionRoleState,
964 ) -> (WorkerRequest, Receiver<SetRegionRoleStateResponse>) {
965 let (sender, receiver) = oneshot::channel();
966
967 (
968 WorkerRequest::SetRegionRoleStateGracefully {
969 region_id,
970 region_role_state,
971 sender,
972 },
973 receiver,
974 )
975 }
976
977 pub(crate) fn new_sync_region_request(
978 region_id: RegionId,
979 manifest_version: ManifestVersion,
980 ) -> (WorkerRequest, Receiver<Result<(ManifestVersion, bool)>>) {
981 let (sender, receiver) = oneshot::channel();
982 (
983 WorkerRequest::SyncRegion(RegionSyncRequest {
984 region_id,
985 manifest_version,
986 sender,
987 }),
988 receiver,
989 )
990 }
991
992 #[allow(clippy::type_complexity)]
999 pub(crate) fn try_from_remap_manifests_request(
1000 store_api::region_engine::RemapManifestsRequest {
1001 region_id,
1002 input_regions,
1003 region_mapping,
1004 new_partition_exprs,
1005 }: store_api::region_engine::RemapManifestsRequest,
1006 ) -> Result<(WorkerRequest, Receiver<Result<HashMap<RegionId, String>>>)> {
1007 let (sender, receiver) = oneshot::channel();
1008 let new_partition_exprs = new_partition_exprs
1009 .into_iter()
1010 .map(|(k, v)| {
1011 Ok((
1012 k,
1013 PartitionExpr::from_json_str(&v)
1014 .context(InvalidPartitionExprSnafu { expr: v })?
1015 .context(MissingPartitionExprSnafu { region_id: k })?,
1016 ))
1017 })
1018 .collect::<Result<HashMap<_, _>>>()?;
1019
1020 let request = RemapManifestsRequest {
1021 region_id,
1022 input_regions,
1023 region_mapping,
1024 new_partition_exprs,
1025 sender,
1026 };
1027
1028 Ok((WorkerRequest::RemapManifests(request), receiver))
1029 }
1030
1031 pub(crate) fn try_from_copy_region_from_request(
1033 region_id: RegionId,
1034 store_api::region_engine::MitoCopyRegionFromRequest {
1035 source_region_id,
1036 parallelism,
1037 }: store_api::region_engine::MitoCopyRegionFromRequest,
1038 ) -> Result<(WorkerRequest, Receiver<Result<MitoCopyRegionFromResponse>>)> {
1039 let (sender, receiver) = oneshot::channel();
1040 let request = CopyRegionFromRequest {
1041 region_id,
1042 source_region_id,
1043 parallelism,
1044 sender,
1045 };
1046 Ok((WorkerRequest::CopyRegionFrom(request), receiver))
1047 }
1048}
1049
1050#[derive(Debug)]
1052pub(crate) enum DdlRequest {
1053 Create(RegionCreateRequest),
1054 Drop(RegionDropRequest),
1055 Open((RegionOpenRequest, Option<WalEntryReceiver>)),
1056 OfflineCleanup(RegionCleanUpRequest),
1057 Close(RegionCloseRequest),
1058 Alter(RegionAlterRequest),
1059 Flush(RegionFlushRequest),
1060 Compact(RegionCompactRequest),
1061 BuildIndex(RegionBuildIndexRequest),
1062 Truncate(RegionTruncateRequest),
1063 Catchup((RegionCatchupRequest, Option<WalEntryReceiver>)),
1064 EnterStaging(EnterStagingRequest),
1065 ApplyStagingManifest(ApplyStagingManifestRequest),
1066}
1067
1068#[derive(Debug)]
1070pub(crate) struct SenderDdlRequest {
1071 pub(crate) region_id: RegionId,
1073 pub(crate) sender: OptionOutputTx,
1075 pub(crate) request: DdlRequest,
1077}
1078
1079#[derive(Debug)]
1081pub(crate) enum BackgroundNotify {
1082 RegionOpened {
1084 region: MitoRegionRef,
1085 registered: Sender<()>,
1086 },
1087 CompactionUnit(CompactionUnitNotification),
1089 CompactionDdlComplete {
1091 generation: u64,
1092 request_index: usize,
1093 },
1094 CompactionPickFinished(CompactionPickFinished),
1096 FlushFinished(FlushFinished),
1098 FlushFailed(FlushFailed),
1100 IndexBuildFinished(IndexBuildFinished),
1102 IndexBuildStopped(IndexBuildStopped),
1104 IndexBuildFailed(IndexBuildFailed),
1106 IndexBuildRetry(BuildIndexRequest),
1108 CompactionFinished(CompactionFinished),
1110 CompactionFailed(CompactionFailed),
1112 Truncate(TruncateResult),
1114 DiscardUnflushed(DiscardUnflushedResult),
1116 RegionChange(RegionChangeResult),
1118 RegionEdit(RegionEditResult),
1120 EnterStaging(EnterStagingResult),
1122 CopyRegionFromFinished(CopyRegionFromFinished),
1124}
1125
1126#[derive(Debug)]
1128pub(crate) struct FlushFinished {
1129 pub(crate) region_id: RegionId,
1131 pub(crate) flush_reason: FlushReason,
1133 pub(crate) flushed_entry_id: EntryId,
1135 pub(crate) senders: Vec<OutputTx>,
1137 pub(crate) _timer: HistogramTimer,
1139 pub(crate) edit: RegionEdit,
1141 pub(crate) memtables_to_remove: SmallVec<[MemtableId; 2]>,
1143 pub(crate) is_staging: bool,
1145}
1146
1147impl FlushFinished {
1148 pub(crate) fn on_success(self) {
1150 for sender in self.senders {
1151 sender.send(Ok(0));
1152 }
1153 }
1154}
1155
1156impl OnFailure for FlushFinished {
1157 fn on_failure(&mut self, err: Error) {
1158 let err = Arc::new(err);
1159 for sender in self.senders.drain(..) {
1160 sender.send(Err(err.clone()).context(FlushRegionSnafu {
1161 region_id: self.region_id,
1162 }));
1163 }
1164 }
1165}
1166
1167#[derive(Debug)]
1169pub(crate) struct FlushFailed {
1170 pub(crate) err: Arc<Error>,
1172}
1173
1174impl FlushFailed {
1175 pub(crate) fn is_cancelled(&self) -> bool {
1177 matches!(self.err.as_ref(), Error::FlushCancelled { .. })
1178 }
1179}
1180
1181#[derive(Debug)]
1182pub(crate) struct IndexBuildFinished {
1183 pub(crate) manifest_version: ManifestVersion,
1184 pub(crate) file_meta: FileMeta,
1185}
1186
1187#[derive(Debug)]
1189pub(crate) struct IndexBuildStopped {
1190 pub(crate) file_id: FileId,
1191}
1192
1193#[derive(Debug)]
1195pub(crate) struct IndexBuildFailed {
1196 pub(crate) err: Arc<Error>,
1197}
1198
1199#[derive(Debug)]
1201pub(crate) enum CompactionUnitNotification {
1202 Finished {
1204 plan_id: u64,
1205 result: std::result::Result<RegionEdit, Arc<Error>>,
1206 applied: tokio::sync::oneshot::Sender<()>,
1207 },
1208 Released {
1210 plan_id: u64,
1212 },
1213}
1214
1215#[derive(Debug)]
1217pub(crate) struct CompactionFinished {
1218 pub(crate) region_id: RegionId,
1220 pub(crate) execution: CompactionExecution,
1222 pub(crate) senders: Vec<OutputTx>,
1224 pub(crate) start_time: Instant,
1226 pub(crate) edit: RegionEdit,
1228}
1229
1230impl CompactionFinished {
1231 pub fn on_success(self) {
1232 COMPACTION_ELAPSED_TOTAL
1234 .with_label_values(&["remote"])
1235 .observe(self.start_time.elapsed().as_secs_f64());
1236
1237 for sender in self.senders {
1238 sender.send(Ok(0));
1239 }
1240 info!("Successfully compacted region: {}", self.region_id);
1241 }
1242}
1243
1244impl OnFailure for CompactionFinished {
1245 fn on_failure(&mut self, err: Error) {
1247 let err = Arc::new(err);
1248 for sender in self.senders.drain(..) {
1249 sender.send(Err(err.clone()).context(CompactRegionSnafu {
1250 region_id: self.region_id,
1251 }));
1252 }
1253 }
1254}
1255
1256#[derive(Debug)]
1258pub(crate) struct CompactionFailed {
1259 pub(crate) region_id: RegionId,
1260 pub(crate) execution: CompactionExecution,
1262 pub(crate) err: Arc<Error>,
1264}
1265
1266#[derive(Debug)]
1268pub(crate) struct TruncateResult {
1269 pub(crate) region_id: RegionId,
1271 pub(crate) sender: OptionOutputTx,
1273 pub(crate) result: Result<()>,
1275 pub(crate) kind: TruncateKind,
1276}
1277
1278#[derive(Debug)]
1280pub(crate) struct DiscardUnflushedResult {
1281 pub(crate) region_id: RegionId,
1283 pub(crate) sender: OptionOutputTx,
1285 pub(crate) result: Result<()>,
1287 pub(crate) discarded_entry_id: EntryId,
1289 pub(crate) discarded_sequence: SequenceNumber,
1291 pub(crate) discarded_rows: u64,
1293 pub(crate) discarded_bytes: u64,
1295}
1296
1297#[derive(Debug)]
1299pub(crate) struct RegionChangeResult {
1300 pub(crate) region_id: RegionId,
1302 pub(crate) new_meta: RegionMetadataRef,
1304 pub(crate) sender: OptionOutputTx,
1306 pub(crate) result: Result<()>,
1308 pub(crate) need_index: bool,
1310 pub(crate) new_options: Option<RegionOptions>,
1312}
1313
1314#[derive(Debug)]
1316pub(crate) struct EnterStagingResult {
1317 pub(crate) region_id: RegionId,
1319 pub(crate) partition_directive: StagingPartitionDirective,
1321 pub(crate) sender: OptionOutputTx,
1323 pub(crate) result: Result<()>,
1325}
1326
1327#[derive(Debug)]
1328pub(crate) struct CopyRegionFromFinished {
1329 pub(crate) region_id: RegionId,
1331 pub(crate) edit: RegionEdit,
1333 pub(crate) sender: Sender<Result<MitoCopyRegionFromResponse>>,
1335}
1336
1337#[derive(Debug, Default)]
1338pub(crate) struct Waiters(SmallVec<[Sender<Result<()>>; 1]>);
1339
1340impl Waiters {
1341 pub(crate) fn one(waiter: Sender<Result<()>>) -> Self {
1342 let mut waiters = SmallVec::new();
1343 waiters.push(waiter);
1344 Self(waiters)
1345 }
1346
1347 pub(crate) fn reply_with<F: Fn() -> Result<()>>(self, f: F) {
1348 for tx in self.0 {
1349 let _ = tx.send(f());
1350 }
1351 }
1352
1353 pub(crate) fn merge(&mut self, other: Self) {
1354 self.0.extend(other.0);
1355 }
1356}
1357
1358#[derive(Debug)]
1360pub(crate) struct RegionEditRequest {
1361 pub(crate) region_id: RegionId,
1362 pub(crate) edit: RegionEdit,
1363 pub(crate) preload_sst_cache: bool,
1365 pub(crate) waiters: Waiters,
1367}
1368
1369impl RegionEditRequest {
1370 pub(crate) fn new(
1371 region_id: RegionId,
1372 edit: RegionEdit,
1373 preload_sst_cache: bool,
1374 waiter: Sender<Result<()>>,
1375 ) -> Self {
1376 Self {
1377 region_id,
1378 edit,
1379 preload_sst_cache,
1380 waiters: Waiters::one(waiter),
1381 }
1382 }
1383}
1384
1385#[derive(Debug)]
1387pub(crate) struct RegionEditResult {
1388 pub(crate) region_id: RegionId,
1390 pub(crate) waiters: Waiters,
1392 pub(crate) edit: RegionEdit,
1394 pub(crate) result: std::result::Result<(), Arc<Error>>,
1396 pub(crate) update_region_state: bool,
1398 pub(crate) is_staging: bool,
1400}
1401
1402#[derive(Debug)]
1403pub(crate) struct BuildIndexRequest {
1404 pub(crate) region_id: RegionId,
1405 pub(crate) build_type: IndexBuildType,
1406 pub(crate) file_metas: Vec<FileMeta>,
1408}
1409
1410#[derive(Debug)]
1411pub(crate) struct RegionSyncRequest {
1412 pub(crate) region_id: RegionId,
1413 pub(crate) manifest_version: ManifestVersion,
1414 pub(crate) sender: Sender<Result<(ManifestVersion, bool)>>,
1416}
1417
1418#[derive(Debug)]
1419pub(crate) struct RemapManifestsRequest {
1420 pub(crate) region_id: RegionId,
1422 pub(crate) input_regions: Vec<RegionId>,
1424 pub(crate) region_mapping: HashMap<RegionId, Vec<RegionId>>,
1426 pub(crate) new_partition_exprs: HashMap<RegionId, PartitionExpr>,
1428 pub(crate) sender: Sender<Result<HashMap<RegionId, String>>>,
1432}
1433
1434#[derive(Debug)]
1435pub(crate) struct CopyRegionFromRequest {
1436 pub(crate) region_id: RegionId,
1438 pub(crate) source_region_id: RegionId,
1440 pub(crate) parallelism: usize,
1442 pub(crate) sender: Sender<Result<MitoCopyRegionFromResponse>>,
1444}
1445
1446#[cfg(test)]
1447mod tests {
1448 use api::v1::value::ValueData;
1449 use api::v1::{Row, SemanticType};
1450 use datatypes::prelude::ConcreteDataType;
1451 use datatypes::schema::ColumnDefaultConstraint;
1452 use mito_codec::test_util::i64_value;
1453 use store_api::metadata::RegionMetadataBuilder;
1454 use tokio::sync::oneshot;
1455
1456 use super::*;
1457 use crate::error::Error;
1458 use crate::test_util::ts_ms_value;
1459
1460 fn new_column_schema(
1461 name: &str,
1462 data_type: ColumnDataType,
1463 semantic_type: SemanticType,
1464 ) -> ColumnSchema {
1465 ColumnSchema {
1466 column_name: name.to_string(),
1467 datatype: data_type as i32,
1468 semantic_type: semantic_type as i32,
1469 ..Default::default()
1470 }
1471 }
1472
1473 fn check_invalid_request(err: &Error, expect: &str) {
1474 if let Error::InvalidRequest {
1475 region_id: _,
1476 reason,
1477 location: _,
1478 } = err
1479 {
1480 assert_eq!(reason, expect);
1481 } else {
1482 panic!("Unexpected error {err}")
1483 }
1484 }
1485
1486 fn waiter() -> (Sender<Result<()>>, Receiver<Result<()>>) {
1487 oneshot::channel()
1488 }
1489
1490 fn assert_waiter_ok(rx: &mut Receiver<Result<()>>) {
1491 rx.try_recv().unwrap().unwrap();
1492 }
1493
1494 #[test]
1495 fn test_waiters_reply_with_single_waiter() {
1496 let (tx, mut rx) = waiter();
1497 Waiters::one(tx).reply_with(|| Ok(()));
1498 assert_waiter_ok(&mut rx);
1499 }
1500
1501 #[test]
1502 fn test_waiters_reply_with_many_waiters() {
1503 let (tx1, mut rx1) = waiter();
1504 let (tx2, mut rx2) = waiter();
1505 let (tx3, mut rx3) = waiter();
1506
1507 let waiters = Waiters(vec![tx1, tx2, tx3].into());
1508 waiters.reply_with(|| Ok(()));
1509
1510 assert_waiter_ok(&mut rx1);
1511 assert_waiter_ok(&mut rx2);
1512 assert_waiter_ok(&mut rx3);
1513 }
1514
1515 #[test]
1516 fn test_waiters_merge() {
1517 let (tx1, mut rx1) = waiter();
1518 let (tx2, mut rx2) = waiter();
1519 let (tx3, mut rx3) = waiter();
1520 let (tx4, mut rx4) = waiter();
1521
1522 let mut waiters = Waiters::one(tx1);
1523 waiters.merge(Waiters::one(tx2));
1524 waiters.merge(Waiters(vec![tx3, tx4].into()));
1525 assert_eq!(4, waiters.0.len());
1526
1527 waiters.reply_with(|| Ok(()));
1528
1529 assert_waiter_ok(&mut rx1);
1530 assert_waiter_ok(&mut rx2);
1531 assert_waiter_ok(&mut rx3);
1532 assert_waiter_ok(&mut rx4);
1533 }
1534
1535 #[test]
1536 fn test_write_request_duplicate_column() {
1537 let rows = Rows {
1538 schema: vec![
1539 new_column_schema("c0", ColumnDataType::Int64, SemanticType::Tag),
1540 new_column_schema("c0", ColumnDataType::Int64, SemanticType::Tag),
1541 ],
1542 rows: vec![],
1543 };
1544
1545 let err = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap_err();
1546 check_invalid_request(&err, "duplicate column c0");
1547 }
1548
1549 #[test]
1550 fn test_valid_write_request() {
1551 let rows = Rows {
1552 schema: vec![
1553 new_column_schema("c0", ColumnDataType::Int64, SemanticType::Tag),
1554 new_column_schema("c1", ColumnDataType::Int64, SemanticType::Tag),
1555 ],
1556 rows: vec![Row {
1557 values: vec![i64_value(1), i64_value(2)],
1558 }],
1559 };
1560
1561 let request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1562 assert_eq!(0, request.column_index_by_name("c0").unwrap());
1563 assert_eq!(1, request.column_index_by_name("c1").unwrap());
1564 assert_eq!(None, request.column_index_by_name("c2"));
1565 }
1566
1567 #[test]
1568 fn test_write_request_column_num() {
1569 let rows = Rows {
1570 schema: vec![
1571 new_column_schema("c0", ColumnDataType::Int64, SemanticType::Tag),
1572 new_column_schema("c1", ColumnDataType::Int64, SemanticType::Tag),
1573 ],
1574 rows: vec![Row {
1575 values: vec![i64_value(1), i64_value(2), i64_value(3)],
1576 }],
1577 };
1578
1579 let err = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap_err();
1580 check_invalid_request(&err, "row has 3 columns but schema has 2");
1581 }
1582
1583 fn new_region_metadata() -> RegionMetadata {
1584 let mut builder = RegionMetadataBuilder::new(RegionId::new(1, 1));
1585 builder
1586 .push_column_metadata(ColumnMetadata {
1587 column_schema: datatypes::schema::ColumnSchema::new(
1588 "ts",
1589 ConcreteDataType::timestamp_millisecond_datatype(),
1590 false,
1591 ),
1592 semantic_type: SemanticType::Timestamp,
1593 column_id: 1,
1594 })
1595 .push_column_metadata(ColumnMetadata {
1596 column_schema: datatypes::schema::ColumnSchema::new(
1597 "k0",
1598 ConcreteDataType::int64_datatype(),
1599 true,
1600 ),
1601 semantic_type: SemanticType::Tag,
1602 column_id: 2,
1603 })
1604 .primary_key(vec![2]);
1605 builder.build().unwrap()
1606 }
1607
1608 #[test]
1609 fn test_check_schema() {
1610 let rows = Rows {
1611 schema: vec![
1612 new_column_schema(
1613 "ts",
1614 ColumnDataType::TimestampMillisecond,
1615 SemanticType::Timestamp,
1616 ),
1617 new_column_schema("k0", ColumnDataType::Int64, SemanticType::Tag),
1618 ],
1619 rows: vec![Row {
1620 values: vec![ts_ms_value(1), i64_value(2)],
1621 }],
1622 };
1623 let metadata = new_region_metadata();
1624
1625 let request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1626 request.check_schema(&metadata).unwrap();
1627 }
1628
1629 #[test]
1630 fn test_column_type() {
1631 let rows = Rows {
1632 schema: vec![
1633 new_column_schema("ts", ColumnDataType::Int64, SemanticType::Timestamp),
1634 new_column_schema("k0", ColumnDataType::Int64, SemanticType::Tag),
1635 ],
1636 rows: vec![Row {
1637 values: vec![i64_value(1), i64_value(2)],
1638 }],
1639 };
1640 let metadata = new_region_metadata();
1641
1642 let request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1643 let err = request.check_schema(&metadata).unwrap_err();
1644 check_invalid_request(
1645 &err,
1646 "column ts expect type Timestamp(Millisecond(TimestampMillisecondType)), given: INT64(4)",
1647 );
1648 }
1649
1650 #[test]
1651 fn test_semantic_type() {
1652 let rows = Rows {
1653 schema: vec![
1654 new_column_schema(
1655 "ts",
1656 ColumnDataType::TimestampMillisecond,
1657 SemanticType::Tag,
1658 ),
1659 new_column_schema("k0", ColumnDataType::Int64, SemanticType::Tag),
1660 ],
1661 rows: vec![Row {
1662 values: vec![ts_ms_value(1), i64_value(2)],
1663 }],
1664 };
1665 let metadata = new_region_metadata();
1666
1667 let request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1668 let err = request.check_schema(&metadata).unwrap_err();
1669 check_invalid_request(&err, "column ts has semantic type Timestamp, given: TAG(0)");
1670 }
1671
1672 #[test]
1673 fn test_column_nullable() {
1674 let rows = Rows {
1675 schema: vec![
1676 new_column_schema(
1677 "ts",
1678 ColumnDataType::TimestampMillisecond,
1679 SemanticType::Timestamp,
1680 ),
1681 new_column_schema("k0", ColumnDataType::Int64, SemanticType::Tag),
1682 ],
1683 rows: vec![Row {
1684 values: vec![Value { value_data: None }, i64_value(2)],
1685 }],
1686 };
1687 let metadata = new_region_metadata();
1688
1689 let request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1690 let err = request.check_schema(&metadata).unwrap_err();
1691 check_invalid_request(&err, "column ts is not null but input has null");
1692 }
1693
1694 #[test]
1695 fn test_column_default() {
1696 let rows = Rows {
1697 schema: vec![new_column_schema(
1698 "k0",
1699 ColumnDataType::Int64,
1700 SemanticType::Tag,
1701 )],
1702 rows: vec![Row {
1703 values: vec![i64_value(1)],
1704 }],
1705 };
1706 let metadata = new_region_metadata();
1707
1708 let request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1709 let err = request.check_schema(&metadata).unwrap_err();
1710 check_invalid_request(&err, "missing column ts");
1711 }
1712
1713 #[test]
1714 fn test_unknown_column() {
1715 let rows = Rows {
1716 schema: vec![
1717 new_column_schema(
1718 "ts",
1719 ColumnDataType::TimestampMillisecond,
1720 SemanticType::Timestamp,
1721 ),
1722 new_column_schema("k0", ColumnDataType::Int64, SemanticType::Tag),
1723 new_column_schema("k1", ColumnDataType::Int64, SemanticType::Tag),
1724 ],
1725 rows: vec![Row {
1726 values: vec![ts_ms_value(1), i64_value(2), i64_value(3)],
1727 }],
1728 };
1729 let metadata = new_region_metadata();
1730
1731 let request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1732 let err = request.check_schema(&metadata).unwrap_err();
1733 check_invalid_request(&err, r#"unknown columns: ["k1"]"#);
1734 }
1735
1736 #[test]
1737 fn test_fill_impure_columns_err() {
1738 let rows = Rows {
1739 schema: vec![new_column_schema(
1740 "k0",
1741 ColumnDataType::Int64,
1742 SemanticType::Tag,
1743 )],
1744 rows: vec![Row {
1745 values: vec![i64_value(1)],
1746 }],
1747 };
1748 let metadata = {
1749 let mut builder = RegionMetadataBuilder::new(RegionId::new(1, 1));
1750 builder
1751 .push_column_metadata(ColumnMetadata {
1752 column_schema: datatypes::schema::ColumnSchema::new(
1753 "ts",
1754 ConcreteDataType::timestamp_millisecond_datatype(),
1755 false,
1756 )
1757 .with_default_constraint(Some(ColumnDefaultConstraint::Function(
1758 "now()".to_string(),
1759 )))
1760 .unwrap(),
1761 semantic_type: SemanticType::Timestamp,
1762 column_id: 1,
1763 })
1764 .push_column_metadata(ColumnMetadata {
1765 column_schema: datatypes::schema::ColumnSchema::new(
1766 "k0",
1767 ConcreteDataType::int64_datatype(),
1768 true,
1769 ),
1770 semantic_type: SemanticType::Tag,
1771 column_id: 2,
1772 })
1773 .primary_key(vec![2]);
1774 builder.build().unwrap()
1775 };
1776
1777 let mut request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1778 let err = request.check_schema(&metadata).unwrap_err();
1779 assert!(err.is_fill_default());
1780 assert!(
1781 request
1782 .fill_missing_columns(&metadata)
1783 .unwrap_err()
1784 .to_string()
1785 .contains("unexpected impure default value with region_id")
1786 );
1787 }
1788
1789 #[test]
1790 fn test_fill_missing_columns() {
1791 let rows = Rows {
1792 schema: vec![new_column_schema(
1793 "ts",
1794 ColumnDataType::TimestampMillisecond,
1795 SemanticType::Timestamp,
1796 )],
1797 rows: vec![Row {
1798 values: vec![ts_ms_value(1)],
1799 }],
1800 };
1801 let metadata = new_region_metadata();
1802
1803 let mut request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1804 let err = request.check_schema(&metadata).unwrap_err();
1805 assert!(err.is_fill_default());
1806 request.fill_missing_columns(&metadata).unwrap();
1807
1808 let expect_rows = Rows {
1809 schema: vec![new_column_schema(
1810 "ts",
1811 ColumnDataType::TimestampMillisecond,
1812 SemanticType::Timestamp,
1813 )],
1814 rows: vec![Row {
1815 values: vec![ts_ms_value(1)],
1816 }],
1817 };
1818 assert_eq!(expect_rows, request.rows);
1819 }
1820
1821 fn builder_with_ts_tag() -> RegionMetadataBuilder {
1822 let mut builder = RegionMetadataBuilder::new(RegionId::new(1, 1));
1823 builder
1824 .push_column_metadata(ColumnMetadata {
1825 column_schema: datatypes::schema::ColumnSchema::new(
1826 "ts",
1827 ConcreteDataType::timestamp_millisecond_datatype(),
1828 false,
1829 ),
1830 semantic_type: SemanticType::Timestamp,
1831 column_id: 1,
1832 })
1833 .push_column_metadata(ColumnMetadata {
1834 column_schema: datatypes::schema::ColumnSchema::new(
1835 "k0",
1836 ConcreteDataType::int64_datatype(),
1837 true,
1838 ),
1839 semantic_type: SemanticType::Tag,
1840 column_id: 2,
1841 })
1842 .primary_key(vec![2]);
1843 builder
1844 }
1845
1846 fn region_metadata_two_fields() -> RegionMetadata {
1847 let mut builder = builder_with_ts_tag();
1848 builder
1849 .push_column_metadata(ColumnMetadata {
1850 column_schema: datatypes::schema::ColumnSchema::new(
1851 "f0",
1852 ConcreteDataType::int64_datatype(),
1853 true,
1854 ),
1855 semantic_type: SemanticType::Field,
1856 column_id: 3,
1857 })
1858 .push_column_metadata(ColumnMetadata {
1860 column_schema: datatypes::schema::ColumnSchema::new(
1861 "f1",
1862 ConcreteDataType::int64_datatype(),
1863 false,
1864 )
1865 .with_default_constraint(Some(ColumnDefaultConstraint::Value(
1866 datatypes::value::Value::Int64(100),
1867 )))
1868 .unwrap(),
1869 semantic_type: SemanticType::Field,
1870 column_id: 4,
1871 });
1872 builder.build().unwrap()
1873 }
1874
1875 #[test]
1876 fn test_fill_missing_for_delete() {
1877 let rows = Rows {
1878 schema: vec![new_column_schema(
1879 "ts",
1880 ColumnDataType::TimestampMillisecond,
1881 SemanticType::Timestamp,
1882 )],
1883 rows: vec![Row {
1884 values: vec![ts_ms_value(1)],
1885 }],
1886 };
1887 let metadata = region_metadata_two_fields();
1888
1889 let mut request =
1890 WriteRequest::new(RegionId::new(1, 1), OpType::Delete, rows, None).unwrap();
1891 let err = request.check_schema(&metadata).unwrap_err();
1892 check_invalid_request(&err, "delete requests need column k0");
1893 let err = request.fill_missing_columns(&metadata).unwrap_err();
1894 check_invalid_request(&err, "delete requests need column k0");
1895
1896 let rows = Rows {
1897 schema: vec![
1898 new_column_schema("k0", ColumnDataType::Int64, SemanticType::Tag),
1899 new_column_schema(
1900 "ts",
1901 ColumnDataType::TimestampMillisecond,
1902 SemanticType::Timestamp,
1903 ),
1904 ],
1905 rows: vec![Row {
1906 values: vec![i64_value(100), ts_ms_value(1)],
1907 }],
1908 };
1909 let mut request =
1910 WriteRequest::new(RegionId::new(1, 1), OpType::Delete, rows, None).unwrap();
1911 let err = request.check_schema(&metadata).unwrap_err();
1912 assert!(err.is_fill_default());
1913 request.fill_missing_columns(&metadata).unwrap();
1914
1915 let expect_rows = Rows {
1916 schema: vec![
1917 new_column_schema("k0", ColumnDataType::Int64, SemanticType::Tag),
1918 new_column_schema(
1919 "ts",
1920 ColumnDataType::TimestampMillisecond,
1921 SemanticType::Timestamp,
1922 ),
1923 new_column_schema("f1", ColumnDataType::Int64, SemanticType::Field),
1924 ],
1925 rows: vec![Row {
1927 values: vec![i64_value(100), ts_ms_value(1), i64_value(0)],
1928 }],
1929 };
1930 assert_eq!(expect_rows, request.rows);
1931 }
1932
1933 #[test]
1934 fn test_fill_missing_without_default_in_delete() {
1935 let mut builder = builder_with_ts_tag();
1936 builder
1937 .push_column_metadata(ColumnMetadata {
1939 column_schema: datatypes::schema::ColumnSchema::new(
1940 "f0",
1941 ConcreteDataType::int64_datatype(),
1942 true,
1943 ),
1944 semantic_type: SemanticType::Field,
1945 column_id: 3,
1946 })
1947 .push_column_metadata(ColumnMetadata {
1949 column_schema: datatypes::schema::ColumnSchema::new(
1950 "f1",
1951 ConcreteDataType::int64_datatype(),
1952 false,
1953 ),
1954 semantic_type: SemanticType::Field,
1955 column_id: 4,
1956 });
1957 let metadata = builder.build().unwrap();
1958
1959 let rows = Rows {
1960 schema: vec![
1961 new_column_schema("k0", ColumnDataType::Int64, SemanticType::Tag),
1962 new_column_schema(
1963 "ts",
1964 ColumnDataType::TimestampMillisecond,
1965 SemanticType::Timestamp,
1966 ),
1967 ],
1968 rows: vec![Row {
1970 values: vec![i64_value(100), ts_ms_value(1)],
1971 }],
1972 };
1973 let mut request =
1974 WriteRequest::new(RegionId::new(1, 1), OpType::Delete, rows, None).unwrap();
1975 let err = request.check_schema(&metadata).unwrap_err();
1976 assert!(err.is_fill_default());
1977 request.fill_missing_columns(&metadata).unwrap();
1978
1979 let expect_rows = Rows {
1980 schema: vec![
1981 new_column_schema("k0", ColumnDataType::Int64, SemanticType::Tag),
1982 new_column_schema(
1983 "ts",
1984 ColumnDataType::TimestampMillisecond,
1985 SemanticType::Timestamp,
1986 ),
1987 new_column_schema("f1", ColumnDataType::Int64, SemanticType::Field),
1988 ],
1989 rows: vec![Row {
1991 values: vec![i64_value(100), ts_ms_value(1), i64_value(0)],
1992 }],
1993 };
1994 assert_eq!(expect_rows, request.rows);
1995 }
1996
1997 #[test]
1998 fn test_no_default() {
1999 let rows = Rows {
2000 schema: vec![new_column_schema(
2001 "k0",
2002 ColumnDataType::Int64,
2003 SemanticType::Tag,
2004 )],
2005 rows: vec![Row {
2006 values: vec![i64_value(1)],
2007 }],
2008 };
2009 let metadata = new_region_metadata();
2010
2011 let mut request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
2012 let err = request.fill_missing_columns(&metadata).unwrap_err();
2013 check_invalid_request(&err, "column ts does not have default value");
2014 }
2015
2016 #[test]
2017 fn test_missing_and_invalid() {
2018 let rows = Rows {
2020 schema: vec![
2021 new_column_schema("k0", ColumnDataType::Int64, SemanticType::Tag),
2022 new_column_schema(
2023 "ts",
2024 ColumnDataType::TimestampMillisecond,
2025 SemanticType::Timestamp,
2026 ),
2027 new_column_schema("f1", ColumnDataType::String, SemanticType::Field),
2028 ],
2029 rows: vec![Row {
2030 values: vec![
2031 i64_value(100),
2032 ts_ms_value(1),
2033 Value {
2034 value_data: Some(ValueData::StringValue("xxxxx".to_string())),
2035 },
2036 ],
2037 }],
2038 };
2039 let metadata = region_metadata_two_fields();
2040
2041 let request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
2042 let err = request.check_schema(&metadata).unwrap_err();
2043 check_invalid_request(
2044 &err,
2045 "column f1 expect type Int64(Int64Type), given: STRING(12)",
2046 );
2047 }
2048
2049 #[test]
2050 fn test_delete_request_defaults_to_writing_wal() {
2051 let (request, _receiver) = WorkerRequest::try_from_region_request(
2052 RegionId::new(1, 1),
2053 RegionRequest::Delete(store_api::region_request::RegionDeleteRequest {
2054 rows: Rows::default(),
2055 hint: None,
2056 partition_expr_version: None,
2057 }),
2058 None,
2059 )
2060 .unwrap();
2061 let WorkerRequest::Write(request) = request else {
2062 panic!("expected a write request");
2063 };
2064 assert_eq!(request.request.op_type, OpType::Delete);
2065 assert!(!request.request.skip_wal);
2066 }
2067
2068 #[test]
2069 fn test_write_request_metadata() {
2070 let rows = Rows {
2071 schema: vec![
2072 new_column_schema("c0", ColumnDataType::Int64, SemanticType::Tag),
2073 new_column_schema("c1", ColumnDataType::Int64, SemanticType::Tag),
2074 ],
2075 rows: vec![Row {
2076 values: vec![i64_value(1), i64_value(2)],
2077 }],
2078 };
2079
2080 let metadata = Arc::new(new_region_metadata());
2081 let request = WriteRequest::new(
2082 RegionId::new(1, 1),
2083 OpType::Put,
2084 rows,
2085 Some(metadata.clone()),
2086 )
2087 .unwrap();
2088
2089 assert!(request.region_metadata.is_some());
2090 assert_eq!(
2091 request.region_metadata.unwrap().region_id,
2092 RegionId::new(1, 1)
2093 );
2094 }
2095}