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, ResultMpscSender};
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 let num_columns = self.name_to_index.len();
247 if self.rows.schema.len() > num_columns {
248 self.rows.schema.truncate(num_columns);
249 for row in &mut self.rows.rows {
250 row.values.truncate(num_columns);
251 }
252 }
253 if let Err(e) = self.check_schema(metadata) {
254 if e.is_fill_default() {
255 self.fill_missing_columns(metadata)?;
259 } else {
260 return Err(e);
261 }
262 }
263
264 Ok(())
265 }
266
267 fn fill_columns(&mut self, columns: Vec<&ColumnMetadata>) -> Result<()> {
269 let mut default_values = Vec::with_capacity(columns.len());
270 let mut columns_to_fill = Vec::with_capacity(columns.len());
271 for column in columns {
272 let default_value = self.column_default_value(column)?;
273 if default_value.value_data.is_some() {
274 default_values.push(default_value);
275 columns_to_fill.push(column);
276 }
277 }
278
279 for row in &mut self.rows.rows {
280 row.values.extend(default_values.iter().cloned());
281 }
282
283 for column in columns_to_fill {
284 let (datatype, datatype_ext) =
285 ColumnDataTypeWrapper::try_from(column.column_schema.data_type.clone())
286 .with_context(|_| ConvertColumnDataTypeSnafu {
287 reason: format!(
288 "no protobuf type for column {} ({:?})",
289 column.column_schema.name, column.column_schema.data_type
290 ),
291 })?
292 .to_parts();
293 self.rows.schema.push(ColumnSchema {
294 column_name: column.column_schema.name.clone(),
295 datatype: datatype as i32,
296 semantic_type: column.semantic_type as i32,
297 datatype_extension: datatype_ext,
298 options: options_from_column_schema(&column.column_schema),
299 });
300 }
301
302 Ok(())
303 }
304
305 fn check_missing_column(&self, column: &ColumnMetadata) -> Result<()> {
307 if self.op_type == OpType::Delete {
308 if column.semantic_type == SemanticType::Field {
309 return Ok(());
312 } else {
313 return InvalidRequestSnafu {
314 region_id: self.region_id,
315 reason: format!("delete requests need column {}", column.column_schema.name),
316 }
317 .fail();
318 }
319 }
320
321 check_column_can_be_filled(self.region_id, column)
323 }
324
325 fn column_default_value(&self, column: &ColumnMetadata) -> Result<Value> {
327 let default_value = match self.op_type {
328 OpType::Delete => {
329 ensure!(
330 column.semantic_type == SemanticType::Field,
331 InvalidRequestSnafu {
332 region_id: self.region_id,
333 reason: format!(
334 "delete requests need column {}",
335 column.column_schema.name
336 ),
337 }
338 );
339
340 if column.column_schema.is_nullable() {
345 datatypes::value::Value::Null
346 } else {
347 column.column_schema.data_type.default_value()
348 }
349 }
350 OpType::Put => {
351 if column.column_schema.is_default_impure() {
353 UnexpectedSnafu {
354 reason: format!(
355 "unexpected impure default value with region_id: {}, column: {}, default_value: {:?}",
356 self.region_id,
357 column.column_schema.name,
358 column.column_schema.default_constraint(),
359 ),
360 }
361 .fail()?
362 }
363 column
364 .column_schema
365 .create_default()
366 .context(CreateDefaultSnafu {
367 region_id: self.region_id,
368 column: &column.column_schema.name,
369 })?
370 .with_context(|| InvalidRequestSnafu {
372 region_id: self.region_id,
373 reason: format!(
374 "column {} does not have default value",
375 column.column_schema.name
376 ),
377 })?
378 }
379 };
380
381 Ok(api::helper::to_grpc_value(default_value))
383 }
384}
385
386trait RequestColumn {
388 fn has_type_of(&self, column: &ColumnMetadata) -> bool;
390
391 fn type_name(&self) -> String;
393
394 fn semantic_type(&self) -> Option<i32>;
396
397 fn has_null(&self) -> bool;
399}
400
401fn check_request_columns<C: RequestColumn>(
407 region_id: RegionId,
408 metadata: &RegionMetadata,
409 mut columns: HashMap<&str, C>,
410 mut check_missing: impl FnMut(&ColumnMetadata) -> Result<()>,
411) -> Result<bool> {
412 let mut has_missing = false;
413 for column in &metadata.column_metadatas {
414 let Some(input_col) = columns.remove(column.column_schema.name.as_str()) else {
415 check_missing(column)?;
416 has_missing = true;
417 continue;
418 };
419 ensure!(
421 input_col.has_type_of(column),
422 InvalidRequestSnafu {
423 region_id,
424 reason: format!(
425 "column {} expect type {:?}, given: {}",
426 column.column_schema.name,
427 column.column_schema.data_type,
428 input_col.type_name(),
429 )
430 }
431 );
432
433 if let Some(semantic_type) = input_col.semantic_type() {
435 ensure!(
436 is_semantic_type_eq(semantic_type, column.semantic_type),
437 InvalidRequestSnafu {
438 region_id,
439 reason: format!(
440 "column {} has semantic type {:?}, given: {}({})",
441 column.column_schema.name,
442 column.semantic_type,
443 api::v1::SemanticType::try_from(semantic_type)
444 .map(|v| v.as_str_name())
445 .unwrap_or("Unknown"),
446 semantic_type
447 ),
448 }
449 );
450 }
451
452 ensure!(
454 !input_col.has_null() || column.column_schema.is_nullable(),
455 InvalidRequestSnafu {
456 region_id,
457 reason: format!(
458 "column {} is not null but input has null",
459 column.column_schema.name
460 ),
461 }
462 );
463 }
464
465 if !columns.is_empty() {
467 let names: Vec<_> = columns.into_keys().collect();
468 return InvalidRequestSnafu {
469 region_id,
470 reason: format!("unknown columns: {:?}", names),
471 }
472 .fail();
473 }
474
475 Ok(has_missing)
476}
477
478fn check_column_can_be_filled(region_id: RegionId, column: &ColumnMetadata) -> Result<()> {
481 ensure!(
482 column.column_schema.is_nullable() || column.column_schema.default_constraint().is_some(),
483 InvalidRequestSnafu {
484 region_id,
485 reason: format!("missing column {}", column.column_schema.name),
486 }
487 );
488 Ok(())
489}
490
491struct RowColumn<'a> {
493 request: &'a WriteRequest,
494 schema: &'a ColumnSchema,
495}
496
497impl RequestColumn for RowColumn<'_> {
498 fn has_type_of(&self, column: &ColumnMetadata) -> bool {
499 is_column_type_value_eq(
500 self.schema.datatype,
501 self.schema.datatype_extension.clone(),
502 &column.column_schema.data_type,
503 )
504 }
505
506 fn type_name(&self) -> String {
507 format!(
508 "{}({})",
509 ColumnDataType::try_from(self.schema.datatype)
510 .map(|v| v.as_str_name())
511 .unwrap_or("Unknown"),
512 self.schema.datatype,
513 )
514 }
515
516 fn semantic_type(&self) -> Option<i32> {
517 Some(self.schema.semantic_type)
518 }
519
520 fn has_null(&self) -> bool {
521 self.request.has_null[self.request.name_to_index[&self.schema.column_name]]
523 }
524}
525
526struct BulkColumn<'a> {
528 array: &'a ArrayRef,
529 field: &'a datatypes::arrow::datatypes::Field,
530}
531
532impl RequestColumn for BulkColumn<'_> {
533 fn has_type_of(&self, column: &ColumnMetadata) -> bool {
534 let actual = self.array.data_type();
535 let data_type = &column.column_schema.data_type;
536 if column.semantic_type == SemanticType::Tag && data_type.is_string() {
538 return match actual {
539 ArrowDataType::Dictionary(key, value) => key.is_integer() && value.is_string(),
540 actual => actual.is_string(),
541 };
542 }
543 if data_type.is_json2() && datatypes::extension::json::is_json2_extension_type(self.field) {
544 return matches!(actual, ArrowDataType::Struct(_) | ArrowDataType::Null)
545 && datatypes::extension::json::json2_remainder_field(self.field).is_ok()
546 && datatypes::types::json_type::JsonNativeType::try_from(actual).is_ok();
547 }
548 *actual == data_type.as_arrow_type()
549 }
550
551 fn type_name(&self) -> String {
552 self.array.data_type().to_string()
553 }
554
555 fn semantic_type(&self) -> Option<i32> {
556 None
557 }
558
559 fn has_null(&self) -> bool {
560 self.array.logical_null_count() > 0
561 }
562}
563
564pub fn check_bulk_insert_batch(metadata: &RegionMetadata, batch: &RecordBatch) -> Result<bool> {
572 let region_id = metadata.region_id;
573 let sparse = metadata.primary_key_encoding == PrimaryKeyEncoding::Sparse;
574 let mut primary_key = None;
575 let mut columns = HashMap::with_capacity(batch.num_columns());
576 for (field, array) in batch.schema_ref().fields().iter().zip(batch.columns()) {
577 let duplicate = if sparse && field.name() == PRIMARY_KEY_COLUMN_NAME {
578 primary_key.replace(array).is_some()
579 } else {
580 columns
581 .insert(field.name().as_str(), BulkColumn { array, field })
582 .is_some()
583 };
584 ensure!(
585 !duplicate,
586 InvalidRequestSnafu {
587 region_id,
588 reason: format!("duplicate column {}", field.name()),
589 }
590 );
591 }
592 if let Some(primary_key) = primary_key {
593 let type_matches = match primary_key.data_type() {
595 ArrowDataType::Binary => true,
596 ArrowDataType::Dictionary(key, value) => {
597 key.is_integer() && **value == ArrowDataType::Binary
598 }
599 _ => false,
600 };
601 ensure!(
602 type_matches && primary_key.logical_null_count() == 0,
603 InvalidRequestSnafu {
604 region_id,
605 reason: format!(
606 "column {PRIMARY_KEY_COLUMN_NAME} must be binary without nulls, given: {}",
607 primary_key.data_type()
608 ),
609 }
610 );
611 }
612 let mut needs_fill = false;
613 check_request_columns(region_id, metadata, columns, |column| {
614 if primary_key.is_some() && column.semantic_type == SemanticType::Tag {
615 Ok(())
616 } else {
617 needs_fill = true;
618 check_column_can_be_filled(region_id, column)
619 }
620 })?;
621 Ok(needs_fill)
622}
623
624pub(crate) fn validate_proto_value(
626 region_id: RegionId,
627 value: &Value,
628 column_schema: &ColumnSchema,
629) -> Result<()> {
630 if let Some(value_type) = proto_value_type(value) {
631 let column_type = ColumnDataType::try_from(column_schema.datatype).map_err(|_| {
632 InvalidRequestSnafu {
633 region_id,
634 reason: format!(
635 "column {} has unknown type {}",
636 column_schema.column_name, column_schema.datatype
637 ),
638 }
639 .build()
640 })?;
641 ensure!(
642 proto_value_type_match(column_type, value_type),
643 InvalidRequestSnafu {
644 region_id,
645 reason: format!(
646 "value has type {:?}, but column {} has type {:?}({})",
647 value_type, column_schema.column_name, column_type, column_schema.datatype,
648 ),
649 }
650 );
651 }
652
653 Ok(())
654}
655
656#[derive(Debug)]
658pub struct OutputTx(Sender<Result<AffectedRows>>);
659
660impl OutputTx {
661 pub(crate) fn new(sender: Sender<Result<AffectedRows>>) -> OutputTx {
663 OutputTx(sender)
664 }
665
666 pub(crate) fn send(self, result: Result<AffectedRows>) {
668 let _ = self.0.send(result);
670 }
671}
672
673#[derive(Debug)]
675pub(crate) struct OptionOutputTx(Option<OutputTx>);
676
677impl OptionOutputTx {
678 pub(crate) fn new(sender: Option<OutputTx>) -> OptionOutputTx {
680 OptionOutputTx(sender)
681 }
682
683 pub(crate) fn none() -> OptionOutputTx {
685 OptionOutputTx(None)
686 }
687
688 pub(crate) fn send_mut(&mut self, result: Result<AffectedRows>) {
690 if let Some(sender) = self.0.take() {
691 sender.send(result);
692 }
693 }
694
695 pub(crate) fn send(mut self, result: Result<AffectedRows>) {
697 if let Some(sender) = self.0.take() {
698 sender.send(result);
699 }
700 }
701
702 pub(crate) fn take_inner(&mut self) -> Option<OutputTx> {
704 self.0.take()
705 }
706}
707
708impl From<Sender<Result<AffectedRows>>> for OptionOutputTx {
709 fn from(sender: Sender<Result<AffectedRows>>) -> Self {
710 Self::new(Some(OutputTx::new(sender)))
711 }
712}
713
714impl OnFailure for OptionOutputTx {
715 fn on_failure(&mut self, err: Error) {
716 self.send_mut(Err(err));
717 }
718}
719
720pub(crate) trait OnFailure {
722 fn on_failure(&mut self, err: Error);
724}
725
726#[derive(Debug)]
728pub(crate) struct SenderWriteRequest {
729 pub(crate) sender: OptionOutputTx,
731 pub(crate) request: WriteRequest,
732}
733
734pub(crate) struct SenderBulkRequest {
735 pub(crate) skip_wal: bool,
736 pub(crate) sender: OptionOutputTx,
737 pub(crate) region_id: RegionId,
738 pub(crate) request: BulkPart,
739 pub(crate) region_metadata: Option<RegionMetadataRef>,
740 pub(crate) partition_expr_version: Option<u64>,
741}
742
743#[derive(Debug)]
744pub(crate) struct BulkInsertRequest {
745 pub(crate) metadata: Option<RegionMetadataRef>,
746 pub(crate) request: RegionBulkInsertsRequest,
747 pub(crate) sender: OptionOutputTx,
748}
749
750#[derive(Debug)]
752pub(crate) struct WorkerRequestWithTime {
753 pub(crate) request: WorkerRequest,
754 pub(crate) created_at: Instant,
755}
756
757impl WorkerRequestWithTime {
758 pub(crate) fn new(request: WorkerRequest) -> Self {
759 Self {
760 request,
761 created_at: Instant::now(),
762 }
763 }
764}
765
766#[derive(Debug)]
768pub(crate) enum WorkerRequest {
769 Write(SenderWriteRequest),
771
772 BatchWrite(Vec<SenderWriteRequest>),
774
775 Ddl(SenderDdlRequest),
777
778 Background {
780 region_id: RegionId,
782 notify: BackgroundNotify,
784 },
785
786 SetRegionRoleStateGracefully {
788 region_id: RegionId,
790 region_role_state: SettableRegionRoleState,
792 sender: Sender<SetRegionRoleStateResponse>,
794 },
795
796 Stop,
798
799 EditRegion(RegionEditRequest),
801
802 SyncRegion(RegionSyncRequest),
804
805 BulkInserts(BulkInsertRequest),
807
808 RemapManifests(RemapManifestsRequest),
810
811 CopyRegionFrom(CopyRegionFromRequest),
813}
814
815impl WorkerRequest {
816 pub(crate) fn new_open_region_request(
818 region_id: RegionId,
819 request: RegionOpenRequest,
820 entry_receiver: Option<WalEntryReceiver>,
821 ) -> (WorkerRequest, Receiver<Result<AffectedRows>>) {
822 let (sender, receiver) = oneshot::channel();
823
824 let worker_request = WorkerRequest::Ddl(SenderDdlRequest {
825 region_id,
826 sender: sender.into(),
827 request: DdlRequest::Open((request, entry_receiver)),
828 });
829
830 (worker_request, receiver)
831 }
832
833 pub(crate) fn new_catchup_region_request(
835 region_id: RegionId,
836 request: RegionCatchupRequest,
837 entry_receiver: Option<WalEntryReceiver>,
838 ) -> (WorkerRequest, Receiver<Result<AffectedRows>>) {
839 let (sender, receiver) = oneshot::channel();
840 let worker_request = WorkerRequest::Ddl(SenderDdlRequest {
841 region_id,
842 sender: sender.into(),
843 request: DdlRequest::Catchup((request, entry_receiver)),
844 });
845 (worker_request, receiver)
846 }
847
848 pub(crate) fn try_from_region_request(
850 region_id: RegionId,
851 value: RegionRequest,
852 region_metadata: Option<RegionMetadataRef>,
853 ) -> Result<(WorkerRequest, Receiver<Result<AffectedRows>>)> {
854 let (sender, receiver) = oneshot::channel();
855 let worker_request = match value {
856 RegionRequest::Put(v) => {
857 let mut write_request =
858 WriteRequest::new(region_id, OpType::Put, v.rows, region_metadata.clone())?
859 .with_hint(v.hint)
860 .with_skip_wal(v.skip_wal)
861 .with_partition_expr_version(v.partition_expr_version);
862 if write_request.primary_key_encoding() == PrimaryKeyEncoding::Dense
863 && let Some(region_metadata) = ®ion_metadata
864 {
865 write_request.maybe_fill_missing_columns(region_metadata)?;
866 }
867 WorkerRequest::Write(SenderWriteRequest {
868 sender: sender.into(),
869 request: write_request,
870 })
871 }
872 RegionRequest::Delete(v) => {
873 let mut write_request =
874 WriteRequest::new(region_id, OpType::Delete, v.rows, region_metadata.clone())?
875 .with_hint(v.hint)
876 .with_partition_expr_version(v.partition_expr_version);
877 if write_request.primary_key_encoding() == PrimaryKeyEncoding::Dense
878 && let Some(region_metadata) = ®ion_metadata
879 {
880 write_request.maybe_fill_missing_columns(region_metadata)?;
881 }
882 WorkerRequest::Write(SenderWriteRequest {
883 sender: sender.into(),
884 request: write_request,
885 })
886 }
887 RegionRequest::Create(v) => WorkerRequest::Ddl(SenderDdlRequest {
888 region_id,
889 sender: sender.into(),
890 request: DdlRequest::Create(v),
891 }),
892 RegionRequest::Drop(v) => WorkerRequest::Ddl(SenderDdlRequest {
893 region_id,
894 sender: sender.into(),
895 request: DdlRequest::Drop(v),
896 }),
897 RegionRequest::Open(v) => WorkerRequest::Ddl(SenderDdlRequest {
898 region_id,
899 sender: sender.into(),
900 request: DdlRequest::Open((v, None)),
901 }),
902 RegionRequest::CleanUp(v) => WorkerRequest::Ddl(SenderDdlRequest {
903 region_id,
904 sender: sender.into(),
905 request: DdlRequest::OfflineCleanup(v),
906 }),
907 RegionRequest::Close(v) => WorkerRequest::Ddl(SenderDdlRequest {
908 region_id,
909 sender: sender.into(),
910 request: DdlRequest::Close(v),
911 }),
912 RegionRequest::Alter(v) => WorkerRequest::Ddl(SenderDdlRequest {
913 region_id,
914 sender: sender.into(),
915 request: DdlRequest::Alter(v),
916 }),
917 RegionRequest::Flush(v) => WorkerRequest::Ddl(SenderDdlRequest {
918 region_id,
919 sender: sender.into(),
920 request: DdlRequest::Flush(v),
921 }),
922 RegionRequest::Compact(v) => WorkerRequest::Ddl(SenderDdlRequest {
923 region_id,
924 sender: sender.into(),
925 request: DdlRequest::Compact(v),
926 }),
927 RegionRequest::BuildIndex(v) => WorkerRequest::Ddl(SenderDdlRequest {
928 region_id,
929 sender: sender.into(),
930 request: DdlRequest::BuildIndex(v),
931 }),
932 RegionRequest::Truncate(v) => WorkerRequest::Ddl(SenderDdlRequest {
933 region_id,
934 sender: sender.into(),
935 request: DdlRequest::Truncate(v),
936 }),
937 RegionRequest::Catchup(v) => WorkerRequest::Ddl(SenderDdlRequest {
938 region_id,
939 sender: sender.into(),
940 request: DdlRequest::Catchup((v, None)),
941 }),
942 RegionRequest::EnterStaging(v) => WorkerRequest::Ddl(SenderDdlRequest {
943 region_id,
944 sender: sender.into(),
945 request: DdlRequest::EnterStaging(v),
946 }),
947 RegionRequest::BulkInserts(mut region_bulk_inserts_request) => {
948 if let Some(region_metadata) = ®ion_metadata
950 && region_bulk_inserts_request.payload.num_rows() > 0
951 && check_bulk_insert_batch(
952 region_metadata,
953 ®ion_bulk_inserts_request.payload,
954 )?
955 {
956 region_bulk_inserts_request.aligned_schema_version = None;
958 }
959 WorkerRequest::BulkInserts(BulkInsertRequest {
960 metadata: region_metadata,
961 sender: sender.into(),
962 request: region_bulk_inserts_request,
963 })
964 }
965 RegionRequest::ApplyStagingManifest(v) => WorkerRequest::Ddl(SenderDdlRequest {
966 region_id,
967 sender: sender.into(),
968 request: DdlRequest::ApplyStagingManifest(v),
969 }),
970 };
971
972 Ok((worker_request, receiver))
973 }
974
975 pub(crate) fn new_set_readonly_gracefully(
976 region_id: RegionId,
977 region_role_state: SettableRegionRoleState,
978 ) -> (WorkerRequest, Receiver<SetRegionRoleStateResponse>) {
979 let (sender, receiver) = oneshot::channel();
980
981 (
982 WorkerRequest::SetRegionRoleStateGracefully {
983 region_id,
984 region_role_state,
985 sender,
986 },
987 receiver,
988 )
989 }
990
991 pub(crate) fn new_sync_region_request(
992 region_id: RegionId,
993 manifest_version: ManifestVersion,
994 ) -> (WorkerRequest, Receiver<Result<(ManifestVersion, bool)>>) {
995 let (sender, receiver) = oneshot::channel();
996 (
997 WorkerRequest::SyncRegion(RegionSyncRequest {
998 region_id,
999 manifest_version,
1000 sender,
1001 }),
1002 receiver,
1003 )
1004 }
1005
1006 #[allow(clippy::type_complexity)]
1013 pub(crate) fn try_from_remap_manifests_request(
1014 store_api::region_engine::RemapManifestsRequest {
1015 region_id,
1016 input_regions,
1017 region_mapping,
1018 new_partition_exprs,
1019 }: store_api::region_engine::RemapManifestsRequest,
1020 ) -> Result<(WorkerRequest, Receiver<Result<HashMap<RegionId, String>>>)> {
1021 let (sender, receiver) = oneshot::channel();
1022 let new_partition_exprs = new_partition_exprs
1023 .into_iter()
1024 .map(|(k, v)| {
1025 Ok((
1026 k,
1027 PartitionExpr::from_json_str(&v)
1028 .context(InvalidPartitionExprSnafu { expr: v })?
1029 .context(MissingPartitionExprSnafu { region_id: k })?,
1030 ))
1031 })
1032 .collect::<Result<HashMap<_, _>>>()?;
1033
1034 let request = RemapManifestsRequest {
1035 region_id,
1036 input_regions,
1037 region_mapping,
1038 new_partition_exprs,
1039 sender,
1040 };
1041
1042 Ok((WorkerRequest::RemapManifests(request), receiver))
1043 }
1044
1045 pub(crate) fn try_from_copy_region_from_request(
1047 region_id: RegionId,
1048 store_api::region_engine::MitoCopyRegionFromRequest {
1049 source_region_id,
1050 parallelism,
1051 }: store_api::region_engine::MitoCopyRegionFromRequest,
1052 ) -> Result<(WorkerRequest, Receiver<Result<MitoCopyRegionFromResponse>>)> {
1053 let (sender, receiver) = oneshot::channel();
1054 let request = CopyRegionFromRequest {
1055 region_id,
1056 source_region_id,
1057 parallelism,
1058 sender,
1059 };
1060 Ok((WorkerRequest::CopyRegionFrom(request), receiver))
1061 }
1062}
1063
1064#[derive(Debug)]
1066pub(crate) enum DdlRequest {
1067 Create(RegionCreateRequest),
1068 Drop(RegionDropRequest),
1069 Open((RegionOpenRequest, Option<WalEntryReceiver>)),
1070 OfflineCleanup(RegionCleanUpRequest),
1071 Close(RegionCloseRequest),
1072 Alter(RegionAlterRequest),
1073 Flush(RegionFlushRequest),
1074 Compact(RegionCompactRequest),
1075 BuildIndex(RegionBuildIndexRequest),
1076 Truncate(RegionTruncateRequest),
1077 Catchup((RegionCatchupRequest, Option<WalEntryReceiver>)),
1078 EnterStaging(EnterStagingRequest),
1079 ApplyStagingManifest(ApplyStagingManifestRequest),
1080}
1081
1082#[derive(Debug)]
1084pub(crate) struct SenderDdlRequest {
1085 pub(crate) region_id: RegionId,
1087 pub(crate) sender: OptionOutputTx,
1089 pub(crate) request: DdlRequest,
1091}
1092
1093#[derive(Debug)]
1095pub(crate) enum BackgroundNotify {
1096 RegionOpened {
1098 region: MitoRegionRef,
1099 registered: Sender<()>,
1100 },
1101 CompactionUnit(CompactionUnitNotification),
1103 CompactionDdlComplete {
1105 generation: u64,
1106 request_index: usize,
1107 },
1108 CompactionPickFinished(CompactionPickFinished),
1110 FlushFinished(FlushFinished),
1112 FlushFailed(FlushFailed),
1114 IndexBuildFinished(IndexBuildFinished),
1116 IndexBuildStopped(IndexBuildStopped),
1118 IndexBuildRetry(BuildIndexRequest),
1120 CompactionFinished(CompactionFinished),
1122 CompactionFailed(CompactionFailed),
1124 Truncate(TruncateResult),
1126 DiscardUnflushed(DiscardUnflushedResult),
1128 RegionChange(RegionChangeResult),
1130 RegionEdit(RegionEditResult),
1132 EnterStaging(EnterStagingResult),
1134 CopyRegionFromFinished(CopyRegionFromFinished),
1136}
1137
1138#[derive(Debug)]
1140pub(crate) struct FlushFinished {
1141 pub(crate) region_id: RegionId,
1143 pub(crate) flush_reason: FlushReason,
1145 pub(crate) flushed_entry_id: EntryId,
1147 pub(crate) senders: Vec<OutputTx>,
1149 pub(crate) _timer: HistogramTimer,
1151 pub(crate) edit: RegionEdit,
1153 pub(crate) memtables_to_remove: SmallVec<[MemtableId; 2]>,
1155 pub(crate) is_staging: bool,
1157}
1158
1159impl FlushFinished {
1160 pub(crate) fn on_success(self) {
1162 for sender in self.senders {
1163 sender.send(Ok(0));
1164 }
1165 }
1166}
1167
1168impl OnFailure for FlushFinished {
1169 fn on_failure(&mut self, err: Error) {
1170 let err = Arc::new(err);
1171 for sender in self.senders.drain(..) {
1172 sender.send(Err(err.clone()).context(FlushRegionSnafu {
1173 region_id: self.region_id,
1174 }));
1175 }
1176 }
1177}
1178
1179#[derive(Debug)]
1181pub(crate) struct FlushFailed {
1182 pub(crate) err: Arc<Error>,
1184}
1185
1186impl FlushFailed {
1187 pub(crate) fn is_cancelled(&self) -> bool {
1189 matches!(self.err.as_ref(), Error::FlushCancelled { .. })
1190 }
1191}
1192
1193#[derive(Debug)]
1194pub(crate) struct IndexBuildFinished {
1195 pub(crate) manifest_version: ManifestVersion,
1196 pub(crate) file_meta: FileMeta,
1197 pub(crate) result_senders: Vec<ResultMpscSender>,
1199}
1200
1201#[derive(Debug)]
1203pub(crate) struct IndexBuildStopped {
1204 pub(crate) file_id: FileId,
1205}
1206
1207#[derive(Debug)]
1209pub(crate) enum CompactionUnitNotification {
1210 Finished {
1212 plan_id: u64,
1213 result: std::result::Result<RegionEdit, Arc<Error>>,
1214 applied: tokio::sync::oneshot::Sender<()>,
1215 },
1216 Released {
1218 plan_id: u64,
1220 },
1221}
1222
1223#[derive(Debug)]
1225pub(crate) struct CompactionFinished {
1226 pub(crate) region_id: RegionId,
1228 pub(crate) execution: CompactionExecution,
1230 pub(crate) senders: Vec<OutputTx>,
1232 pub(crate) start_time: Instant,
1234 pub(crate) edit: RegionEdit,
1236}
1237
1238impl CompactionFinished {
1239 pub fn on_success(self) {
1240 COMPACTION_ELAPSED_TOTAL
1242 .with_label_values(&["remote"])
1243 .observe(self.start_time.elapsed().as_secs_f64());
1244
1245 for sender in self.senders {
1246 sender.send(Ok(0));
1247 }
1248 info!("Successfully compacted region: {}", self.region_id);
1249 }
1250}
1251
1252impl OnFailure for CompactionFinished {
1253 fn on_failure(&mut self, err: Error) {
1255 let err = Arc::new(err);
1256 for sender in self.senders.drain(..) {
1257 sender.send(Err(err.clone()).context(CompactRegionSnafu {
1258 region_id: self.region_id,
1259 }));
1260 }
1261 }
1262}
1263
1264#[derive(Debug)]
1266pub(crate) struct CompactionFailed {
1267 pub(crate) region_id: RegionId,
1268 pub(crate) execution: CompactionExecution,
1270 pub(crate) err: Arc<Error>,
1272}
1273
1274#[derive(Debug)]
1276pub(crate) struct TruncateResult {
1277 pub(crate) region_id: RegionId,
1279 pub(crate) sender: OptionOutputTx,
1281 pub(crate) result: Result<()>,
1283 pub(crate) kind: TruncateKind,
1284}
1285
1286#[derive(Debug)]
1288pub(crate) struct DiscardUnflushedResult {
1289 pub(crate) region_id: RegionId,
1291 pub(crate) sender: OptionOutputTx,
1293 pub(crate) result: Result<()>,
1295 pub(crate) discarded_entry_id: EntryId,
1297 pub(crate) discarded_sequence: SequenceNumber,
1299 pub(crate) discarded_rows: u64,
1301 pub(crate) discarded_bytes: u64,
1303}
1304
1305#[derive(Debug)]
1307pub(crate) struct RegionChangeResult {
1308 pub(crate) region_id: RegionId,
1310 pub(crate) new_meta: RegionMetadataRef,
1312 pub(crate) sender: OptionOutputTx,
1314 pub(crate) result: Result<()>,
1316 pub(crate) need_index: bool,
1318 pub(crate) new_options: Option<RegionOptions>,
1320}
1321
1322#[derive(Debug)]
1324pub(crate) struct EnterStagingResult {
1325 pub(crate) region_id: RegionId,
1327 pub(crate) partition_directive: StagingPartitionDirective,
1329 pub(crate) sender: OptionOutputTx,
1331 pub(crate) result: Result<()>,
1333}
1334
1335#[derive(Debug)]
1336pub(crate) struct CopyRegionFromFinished {
1337 pub(crate) region_id: RegionId,
1339 pub(crate) edit: RegionEdit,
1341 pub(crate) sender: Sender<Result<MitoCopyRegionFromResponse>>,
1343}
1344
1345#[derive(Debug, Default)]
1346pub(crate) struct Waiters(SmallVec<[Sender<Result<()>>; 1]>);
1347
1348impl Waiters {
1349 pub(crate) fn one(waiter: Sender<Result<()>>) -> Self {
1350 let mut waiters = SmallVec::new();
1351 waiters.push(waiter);
1352 Self(waiters)
1353 }
1354
1355 pub(crate) fn reply_with<F: Fn() -> Result<()>>(self, f: F) {
1356 for tx in self.0 {
1357 let _ = tx.send(f());
1358 }
1359 }
1360
1361 pub(crate) fn merge(&mut self, other: Self) {
1362 self.0.extend(other.0);
1363 }
1364}
1365
1366#[derive(Debug)]
1368pub(crate) struct RegionEditRequest {
1369 pub(crate) region_id: RegionId,
1370 pub(crate) edit: RegionEdit,
1371 pub(crate) preload_sst_cache: bool,
1373 pub(crate) waiters: Waiters,
1375}
1376
1377impl RegionEditRequest {
1378 pub(crate) fn new(
1379 region_id: RegionId,
1380 edit: RegionEdit,
1381 preload_sst_cache: bool,
1382 waiter: Sender<Result<()>>,
1383 ) -> Self {
1384 Self {
1385 region_id,
1386 edit,
1387 preload_sst_cache,
1388 waiters: Waiters::one(waiter),
1389 }
1390 }
1391}
1392
1393#[derive(Debug)]
1395pub(crate) struct RegionEditResult {
1396 pub(crate) region_id: RegionId,
1398 pub(crate) waiters: Waiters,
1400 pub(crate) edit: RegionEdit,
1402 pub(crate) result: std::result::Result<(), Arc<Error>>,
1404 pub(crate) update_region_state: bool,
1406 pub(crate) is_staging: bool,
1408}
1409
1410#[derive(Debug)]
1411pub(crate) struct BuildIndexRequest {
1412 pub(crate) region_id: RegionId,
1413 pub(crate) build_type: IndexBuildType,
1414 pub(crate) file_metas: Vec<FileMeta>,
1416 pub(crate) result_senders: Vec<ResultMpscSender>,
1418}
1419
1420#[derive(Debug)]
1421pub(crate) struct RegionSyncRequest {
1422 pub(crate) region_id: RegionId,
1423 pub(crate) manifest_version: ManifestVersion,
1424 pub(crate) sender: Sender<Result<(ManifestVersion, bool)>>,
1426}
1427
1428#[derive(Debug)]
1429pub(crate) struct RemapManifestsRequest {
1430 pub(crate) region_id: RegionId,
1432 pub(crate) input_regions: Vec<RegionId>,
1434 pub(crate) region_mapping: HashMap<RegionId, Vec<RegionId>>,
1436 pub(crate) new_partition_exprs: HashMap<RegionId, PartitionExpr>,
1438 pub(crate) sender: Sender<Result<HashMap<RegionId, String>>>,
1442}
1443
1444#[derive(Debug)]
1445pub(crate) struct CopyRegionFromRequest {
1446 pub(crate) region_id: RegionId,
1448 pub(crate) source_region_id: RegionId,
1450 pub(crate) parallelism: usize,
1452 pub(crate) sender: Sender<Result<MitoCopyRegionFromResponse>>,
1454}
1455
1456#[cfg(test)]
1457mod tests {
1458 use api::v1::value::ValueData;
1459 use api::v1::{Row, SemanticType};
1460 use datatypes::prelude::ConcreteDataType;
1461 use datatypes::schema::ColumnDefaultConstraint;
1462 use mito_codec::test_util::i64_value;
1463 use store_api::metadata::RegionMetadataBuilder;
1464 use tokio::sync::oneshot;
1465
1466 use super::*;
1467 use crate::error::Error;
1468 use crate::test_util::ts_ms_value;
1469
1470 fn new_column_schema(
1471 name: &str,
1472 data_type: ColumnDataType,
1473 semantic_type: SemanticType,
1474 ) -> ColumnSchema {
1475 ColumnSchema {
1476 column_name: name.to_string(),
1477 datatype: data_type as i32,
1478 semantic_type: semantic_type as i32,
1479 ..Default::default()
1480 }
1481 }
1482
1483 fn check_invalid_request(err: &Error, expect: &str) {
1484 if let Error::InvalidRequest {
1485 region_id: _,
1486 reason,
1487 location: _,
1488 } = err
1489 {
1490 assert_eq!(reason, expect);
1491 } else {
1492 panic!("Unexpected error {err}")
1493 }
1494 }
1495
1496 fn waiter() -> (Sender<Result<()>>, Receiver<Result<()>>) {
1497 oneshot::channel()
1498 }
1499
1500 fn assert_waiter_ok(rx: &mut Receiver<Result<()>>) {
1501 rx.try_recv().unwrap().unwrap();
1502 }
1503
1504 #[test]
1505 fn test_waiters_reply_with_single_waiter() {
1506 let (tx, mut rx) = waiter();
1507 Waiters::one(tx).reply_with(|| Ok(()));
1508 assert_waiter_ok(&mut rx);
1509 }
1510
1511 #[test]
1512 fn test_waiters_reply_with_many_waiters() {
1513 let (tx1, mut rx1) = waiter();
1514 let (tx2, mut rx2) = waiter();
1515 let (tx3, mut rx3) = waiter();
1516
1517 let waiters = Waiters(vec![tx1, tx2, tx3].into());
1518 waiters.reply_with(|| Ok(()));
1519
1520 assert_waiter_ok(&mut rx1);
1521 assert_waiter_ok(&mut rx2);
1522 assert_waiter_ok(&mut rx3);
1523 }
1524
1525 #[test]
1526 fn test_waiters_merge() {
1527 let (tx1, mut rx1) = waiter();
1528 let (tx2, mut rx2) = waiter();
1529 let (tx3, mut rx3) = waiter();
1530 let (tx4, mut rx4) = waiter();
1531
1532 let mut waiters = Waiters::one(tx1);
1533 waiters.merge(Waiters::one(tx2));
1534 waiters.merge(Waiters(vec![tx3, tx4].into()));
1535 assert_eq!(4, waiters.0.len());
1536
1537 waiters.reply_with(|| Ok(()));
1538
1539 assert_waiter_ok(&mut rx1);
1540 assert_waiter_ok(&mut rx2);
1541 assert_waiter_ok(&mut rx3);
1542 assert_waiter_ok(&mut rx4);
1543 }
1544
1545 #[test]
1546 fn test_write_request_duplicate_column() {
1547 let rows = Rows {
1548 schema: vec![
1549 new_column_schema("c0", ColumnDataType::Int64, SemanticType::Tag),
1550 new_column_schema("c0", ColumnDataType::Int64, SemanticType::Tag),
1551 ],
1552 rows: vec![],
1553 };
1554
1555 let err = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap_err();
1556 check_invalid_request(&err, "duplicate column c0");
1557 }
1558
1559 #[test]
1560 fn test_valid_write_request() {
1561 let rows = Rows {
1562 schema: vec![
1563 new_column_schema("c0", ColumnDataType::Int64, SemanticType::Tag),
1564 new_column_schema("c1", ColumnDataType::Int64, SemanticType::Tag),
1565 ],
1566 rows: vec![Row {
1567 values: vec![i64_value(1), i64_value(2)],
1568 }],
1569 };
1570
1571 let request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1572 assert_eq!(0, request.column_index_by_name("c0").unwrap());
1573 assert_eq!(1, request.column_index_by_name("c1").unwrap());
1574 assert_eq!(None, request.column_index_by_name("c2"));
1575 }
1576
1577 #[test]
1578 fn test_write_request_column_num() {
1579 let rows = Rows {
1580 schema: vec![
1581 new_column_schema("c0", ColumnDataType::Int64, SemanticType::Tag),
1582 new_column_schema("c1", ColumnDataType::Int64, SemanticType::Tag),
1583 ],
1584 rows: vec![Row {
1585 values: vec![i64_value(1), i64_value(2), i64_value(3)],
1586 }],
1587 };
1588
1589 let err = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap_err();
1590 check_invalid_request(&err, "row has 3 columns but schema has 2");
1591 }
1592
1593 fn new_region_metadata() -> RegionMetadata {
1594 let mut builder = RegionMetadataBuilder::new(RegionId::new(1, 1));
1595 builder
1596 .push_column_metadata(ColumnMetadata {
1597 column_schema: datatypes::schema::ColumnSchema::new(
1598 "ts",
1599 ConcreteDataType::timestamp_millisecond_datatype(),
1600 false,
1601 ),
1602 semantic_type: SemanticType::Timestamp,
1603 column_id: 1,
1604 })
1605 .push_column_metadata(ColumnMetadata {
1606 column_schema: datatypes::schema::ColumnSchema::new(
1607 "k0",
1608 ConcreteDataType::int64_datatype(),
1609 true,
1610 ),
1611 semantic_type: SemanticType::Tag,
1612 column_id: 2,
1613 })
1614 .primary_key(vec![2]);
1615 builder.build().unwrap()
1616 }
1617
1618 #[test]
1619 fn test_check_schema() {
1620 let rows = Rows {
1621 schema: vec![
1622 new_column_schema(
1623 "ts",
1624 ColumnDataType::TimestampMillisecond,
1625 SemanticType::Timestamp,
1626 ),
1627 new_column_schema("k0", ColumnDataType::Int64, SemanticType::Tag),
1628 ],
1629 rows: vec![Row {
1630 values: vec![ts_ms_value(1), i64_value(2)],
1631 }],
1632 };
1633 let metadata = new_region_metadata();
1634
1635 let request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1636 request.check_schema(&metadata).unwrap();
1637 }
1638
1639 #[test]
1640 fn test_column_type() {
1641 let rows = Rows {
1642 schema: vec![
1643 new_column_schema("ts", ColumnDataType::Int64, SemanticType::Timestamp),
1644 new_column_schema("k0", ColumnDataType::Int64, SemanticType::Tag),
1645 ],
1646 rows: vec![Row {
1647 values: vec![i64_value(1), i64_value(2)],
1648 }],
1649 };
1650 let metadata = new_region_metadata();
1651
1652 let request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1653 let err = request.check_schema(&metadata).unwrap_err();
1654 check_invalid_request(
1655 &err,
1656 "column ts expect type Timestamp(Millisecond(TimestampMillisecondType)), given: INT64(4)",
1657 );
1658 }
1659
1660 #[test]
1661 fn test_semantic_type() {
1662 let rows = Rows {
1663 schema: vec![
1664 new_column_schema(
1665 "ts",
1666 ColumnDataType::TimestampMillisecond,
1667 SemanticType::Tag,
1668 ),
1669 new_column_schema("k0", ColumnDataType::Int64, SemanticType::Tag),
1670 ],
1671 rows: vec![Row {
1672 values: vec![ts_ms_value(1), i64_value(2)],
1673 }],
1674 };
1675 let metadata = new_region_metadata();
1676
1677 let request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1678 let err = request.check_schema(&metadata).unwrap_err();
1679 check_invalid_request(&err, "column ts has semantic type Timestamp, given: TAG(0)");
1680 }
1681
1682 #[test]
1683 fn test_column_nullable() {
1684 let rows = Rows {
1685 schema: vec![
1686 new_column_schema(
1687 "ts",
1688 ColumnDataType::TimestampMillisecond,
1689 SemanticType::Timestamp,
1690 ),
1691 new_column_schema("k0", ColumnDataType::Int64, SemanticType::Tag),
1692 ],
1693 rows: vec![Row {
1694 values: vec![Value { value_data: None }, i64_value(2)],
1695 }],
1696 };
1697 let metadata = new_region_metadata();
1698
1699 let request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1700 let err = request.check_schema(&metadata).unwrap_err();
1701 check_invalid_request(&err, "column ts is not null but input has null");
1702 }
1703
1704 #[test]
1705 fn test_column_default() {
1706 let rows = Rows {
1707 schema: vec![new_column_schema(
1708 "k0",
1709 ColumnDataType::Int64,
1710 SemanticType::Tag,
1711 )],
1712 rows: vec![Row {
1713 values: vec![i64_value(1)],
1714 }],
1715 };
1716 let metadata = new_region_metadata();
1717
1718 let request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1719 let err = request.check_schema(&metadata).unwrap_err();
1720 check_invalid_request(&err, "missing column ts");
1721 }
1722
1723 #[test]
1724 fn test_unknown_column() {
1725 let rows = Rows {
1726 schema: vec![
1727 new_column_schema(
1728 "ts",
1729 ColumnDataType::TimestampMillisecond,
1730 SemanticType::Timestamp,
1731 ),
1732 new_column_schema("k0", ColumnDataType::Int64, SemanticType::Tag),
1733 new_column_schema("k1", ColumnDataType::Int64, SemanticType::Tag),
1734 ],
1735 rows: vec![Row {
1736 values: vec![ts_ms_value(1), i64_value(2), i64_value(3)],
1737 }],
1738 };
1739 let metadata = new_region_metadata();
1740
1741 let request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1742 let err = request.check_schema(&metadata).unwrap_err();
1743 check_invalid_request(&err, r#"unknown columns: ["k1"]"#);
1744 }
1745
1746 #[test]
1747 fn test_fill_impure_columns_err() {
1748 let rows = Rows {
1749 schema: vec![new_column_schema(
1750 "k0",
1751 ColumnDataType::Int64,
1752 SemanticType::Tag,
1753 )],
1754 rows: vec![Row {
1755 values: vec![i64_value(1)],
1756 }],
1757 };
1758 let metadata = {
1759 let mut builder = RegionMetadataBuilder::new(RegionId::new(1, 1));
1760 builder
1761 .push_column_metadata(ColumnMetadata {
1762 column_schema: datatypes::schema::ColumnSchema::new(
1763 "ts",
1764 ConcreteDataType::timestamp_millisecond_datatype(),
1765 false,
1766 )
1767 .with_default_constraint(Some(ColumnDefaultConstraint::Function(
1768 "now()".to_string(),
1769 )))
1770 .unwrap(),
1771 semantic_type: SemanticType::Timestamp,
1772 column_id: 1,
1773 })
1774 .push_column_metadata(ColumnMetadata {
1775 column_schema: datatypes::schema::ColumnSchema::new(
1776 "k0",
1777 ConcreteDataType::int64_datatype(),
1778 true,
1779 ),
1780 semantic_type: SemanticType::Tag,
1781 column_id: 2,
1782 })
1783 .primary_key(vec![2]);
1784 builder.build().unwrap()
1785 };
1786
1787 let mut request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1788 let err = request.check_schema(&metadata).unwrap_err();
1789 assert!(err.is_fill_default());
1790 assert!(
1791 request
1792 .fill_missing_columns(&metadata)
1793 .unwrap_err()
1794 .to_string()
1795 .contains("unexpected impure default value with region_id")
1796 );
1797 }
1798
1799 #[test]
1800 fn test_fill_missing_columns() {
1801 let rows = Rows {
1802 schema: vec![new_column_schema(
1803 "ts",
1804 ColumnDataType::TimestampMillisecond,
1805 SemanticType::Timestamp,
1806 )],
1807 rows: vec![Row {
1808 values: vec![ts_ms_value(1)],
1809 }],
1810 };
1811 let metadata = new_region_metadata();
1812
1813 let mut request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
1814 let err = request.check_schema(&metadata).unwrap_err();
1815 assert!(err.is_fill_default());
1816 request.fill_missing_columns(&metadata).unwrap();
1817
1818 let expect_rows = Rows {
1819 schema: vec![new_column_schema(
1820 "ts",
1821 ColumnDataType::TimestampMillisecond,
1822 SemanticType::Timestamp,
1823 )],
1824 rows: vec![Row {
1825 values: vec![ts_ms_value(1)],
1826 }],
1827 };
1828 assert_eq!(expect_rows, request.rows);
1829 }
1830
1831 fn builder_with_ts_tag() -> RegionMetadataBuilder {
1832 let mut builder = RegionMetadataBuilder::new(RegionId::new(1, 1));
1833 builder
1834 .push_column_metadata(ColumnMetadata {
1835 column_schema: datatypes::schema::ColumnSchema::new(
1836 "ts",
1837 ConcreteDataType::timestamp_millisecond_datatype(),
1838 false,
1839 ),
1840 semantic_type: SemanticType::Timestamp,
1841 column_id: 1,
1842 })
1843 .push_column_metadata(ColumnMetadata {
1844 column_schema: datatypes::schema::ColumnSchema::new(
1845 "k0",
1846 ConcreteDataType::int64_datatype(),
1847 true,
1848 ),
1849 semantic_type: SemanticType::Tag,
1850 column_id: 2,
1851 })
1852 .primary_key(vec![2]);
1853 builder
1854 }
1855
1856 fn region_metadata_two_fields() -> RegionMetadata {
1857 let mut builder = builder_with_ts_tag();
1858 builder
1859 .push_column_metadata(ColumnMetadata {
1860 column_schema: datatypes::schema::ColumnSchema::new(
1861 "f0",
1862 ConcreteDataType::int64_datatype(),
1863 true,
1864 ),
1865 semantic_type: SemanticType::Field,
1866 column_id: 3,
1867 })
1868 .push_column_metadata(ColumnMetadata {
1870 column_schema: datatypes::schema::ColumnSchema::new(
1871 "f1",
1872 ConcreteDataType::int64_datatype(),
1873 false,
1874 )
1875 .with_default_constraint(Some(ColumnDefaultConstraint::Value(
1876 datatypes::value::Value::Int64(100),
1877 )))
1878 .unwrap(),
1879 semantic_type: SemanticType::Field,
1880 column_id: 4,
1881 });
1882 builder.build().unwrap()
1883 }
1884
1885 #[test]
1886 fn test_fill_missing_for_delete() {
1887 let rows = Rows {
1888 schema: vec![new_column_schema(
1889 "ts",
1890 ColumnDataType::TimestampMillisecond,
1891 SemanticType::Timestamp,
1892 )],
1893 rows: vec![Row {
1894 values: vec![ts_ms_value(1)],
1895 }],
1896 };
1897 let metadata = region_metadata_two_fields();
1898
1899 let mut request =
1900 WriteRequest::new(RegionId::new(1, 1), OpType::Delete, rows, None).unwrap();
1901 let err = request.check_schema(&metadata).unwrap_err();
1902 check_invalid_request(&err, "delete requests need column k0");
1903 let err = request.fill_missing_columns(&metadata).unwrap_err();
1904 check_invalid_request(&err, "delete requests need column k0");
1905
1906 let rows = Rows {
1907 schema: vec![
1908 new_column_schema("k0", ColumnDataType::Int64, SemanticType::Tag),
1909 new_column_schema(
1910 "ts",
1911 ColumnDataType::TimestampMillisecond,
1912 SemanticType::Timestamp,
1913 ),
1914 ],
1915 rows: vec![Row {
1916 values: vec![i64_value(100), ts_ms_value(1)],
1917 }],
1918 };
1919 let mut request =
1920 WriteRequest::new(RegionId::new(1, 1), OpType::Delete, rows, None).unwrap();
1921 let err = request.check_schema(&metadata).unwrap_err();
1922 assert!(err.is_fill_default());
1923 request.fill_missing_columns(&metadata).unwrap();
1924
1925 let expect_rows = Rows {
1926 schema: vec![
1927 new_column_schema("k0", ColumnDataType::Int64, SemanticType::Tag),
1928 new_column_schema(
1929 "ts",
1930 ColumnDataType::TimestampMillisecond,
1931 SemanticType::Timestamp,
1932 ),
1933 new_column_schema("f1", ColumnDataType::Int64, SemanticType::Field),
1934 ],
1935 rows: vec![Row {
1937 values: vec![i64_value(100), ts_ms_value(1), i64_value(0)],
1938 }],
1939 };
1940 assert_eq!(expect_rows, request.rows);
1941 }
1942
1943 #[test]
1944 fn test_fill_missing_without_default_in_delete() {
1945 let mut builder = builder_with_ts_tag();
1946 builder
1947 .push_column_metadata(ColumnMetadata {
1949 column_schema: datatypes::schema::ColumnSchema::new(
1950 "f0",
1951 ConcreteDataType::int64_datatype(),
1952 true,
1953 ),
1954 semantic_type: SemanticType::Field,
1955 column_id: 3,
1956 })
1957 .push_column_metadata(ColumnMetadata {
1959 column_schema: datatypes::schema::ColumnSchema::new(
1960 "f1",
1961 ConcreteDataType::int64_datatype(),
1962 false,
1963 ),
1964 semantic_type: SemanticType::Field,
1965 column_id: 4,
1966 });
1967 let metadata = builder.build().unwrap();
1968
1969 let rows = Rows {
1970 schema: vec![
1971 new_column_schema("k0", ColumnDataType::Int64, SemanticType::Tag),
1972 new_column_schema(
1973 "ts",
1974 ColumnDataType::TimestampMillisecond,
1975 SemanticType::Timestamp,
1976 ),
1977 ],
1978 rows: vec![Row {
1980 values: vec![i64_value(100), ts_ms_value(1)],
1981 }],
1982 };
1983 let mut request =
1984 WriteRequest::new(RegionId::new(1, 1), OpType::Delete, rows, None).unwrap();
1985 let err = request.check_schema(&metadata).unwrap_err();
1986 assert!(err.is_fill_default());
1987 request.fill_missing_columns(&metadata).unwrap();
1988
1989 let expect_rows = Rows {
1990 schema: vec![
1991 new_column_schema("k0", ColumnDataType::Int64, SemanticType::Tag),
1992 new_column_schema(
1993 "ts",
1994 ColumnDataType::TimestampMillisecond,
1995 SemanticType::Timestamp,
1996 ),
1997 new_column_schema("f1", ColumnDataType::Int64, SemanticType::Field),
1998 ],
1999 rows: vec![Row {
2001 values: vec![i64_value(100), ts_ms_value(1), i64_value(0)],
2002 }],
2003 };
2004 assert_eq!(expect_rows, request.rows);
2005 }
2006
2007 #[test]
2008 fn test_no_default() {
2009 let rows = Rows {
2010 schema: vec![new_column_schema(
2011 "k0",
2012 ColumnDataType::Int64,
2013 SemanticType::Tag,
2014 )],
2015 rows: vec![Row {
2016 values: vec![i64_value(1)],
2017 }],
2018 };
2019 let metadata = new_region_metadata();
2020
2021 let mut request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
2022 let err = request.fill_missing_columns(&metadata).unwrap_err();
2023 check_invalid_request(&err, "column ts does not have default value");
2024 }
2025
2026 #[test]
2027 fn test_missing_and_invalid() {
2028 let rows = Rows {
2030 schema: vec![
2031 new_column_schema("k0", ColumnDataType::Int64, SemanticType::Tag),
2032 new_column_schema(
2033 "ts",
2034 ColumnDataType::TimestampMillisecond,
2035 SemanticType::Timestamp,
2036 ),
2037 new_column_schema("f1", ColumnDataType::String, SemanticType::Field),
2038 ],
2039 rows: vec![Row {
2040 values: vec![
2041 i64_value(100),
2042 ts_ms_value(1),
2043 Value {
2044 value_data: Some(ValueData::StringValue("xxxxx".to_string())),
2045 },
2046 ],
2047 }],
2048 };
2049 let metadata = region_metadata_two_fields();
2050
2051 let request = WriteRequest::new(RegionId::new(1, 1), OpType::Put, rows, None).unwrap();
2052 let err = request.check_schema(&metadata).unwrap_err();
2053 check_invalid_request(
2054 &err,
2055 "column f1 expect type Int64(Int64Type), given: STRING(12)",
2056 );
2057 }
2058
2059 #[test]
2060 fn test_delete_request_defaults_to_writing_wal() {
2061 let (request, _receiver) = WorkerRequest::try_from_region_request(
2062 RegionId::new(1, 1),
2063 RegionRequest::Delete(store_api::region_request::RegionDeleteRequest {
2064 rows: Rows::default(),
2065 hint: None,
2066 partition_expr_version: None,
2067 }),
2068 None,
2069 )
2070 .unwrap();
2071 let WorkerRequest::Write(request) = request else {
2072 panic!("expected a write request");
2073 };
2074 assert_eq!(request.request.op_type, OpType::Delete);
2075 assert!(!request.request.skip_wal);
2076 }
2077
2078 #[test]
2079 fn test_write_request_metadata() {
2080 let rows = Rows {
2081 schema: vec![
2082 new_column_schema("c0", ColumnDataType::Int64, SemanticType::Tag),
2083 new_column_schema("c1", ColumnDataType::Int64, SemanticType::Tag),
2084 ],
2085 rows: vec![Row {
2086 values: vec![i64_value(1), i64_value(2)],
2087 }],
2088 };
2089
2090 let metadata = Arc::new(new_region_metadata());
2091 let request = WriteRequest::new(
2092 RegionId::new(1, 1),
2093 OpType::Put,
2094 rows,
2095 Some(metadata.clone()),
2096 )
2097 .unwrap();
2098
2099 assert!(request.region_metadata.is_some());
2100 assert_eq!(
2101 request.region_metadata.unwrap().region_id,
2102 RegionId::new(1, 1)
2103 );
2104 }
2105}