1use std::collections::{BTreeMap, HashMap};
18use std::fmt;
19use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
20use std::sync::{Arc, Mutex};
21use std::time::Duration;
22
23pub use bulk::part::EncodedBulkPart;
24use bytes::Bytes;
25use common_time::Timestamp;
26use datatypes::arrow::datatypes::SchemaRef;
27use datatypes::arrow::record_batch::RecordBatch;
28use mito_codec::key_values::KeyValue;
29pub use mito_codec::key_values::KeyValues;
30use mito_codec::row_converter::{PrimaryKeyCodec, build_primary_key_codec};
31use snafu::ensure;
32use store_api::codec::PrimaryKeyEncoding;
33use store_api::metadata::{RegionMetadata, RegionMetadataRef};
34use store_api::storage::{ColumnId, RegionId, SequenceNumber, SequenceRange};
35
36use crate::config::MitoConfig;
37use crate::error::{InvalidRegionOptionsSnafu, Result, UnsupportedOperationSnafu};
38use crate::flush::WriteBufferManagerRef;
39use crate::memtable::bulk::{BulkMemtableBuilder, BulkMemtableConfig, CompactDispatcher};
40use crate::memtable::time_series::TimeSeriesMemtableBuilder;
41use crate::metrics::WRITE_BUFFER_BYTES;
42use crate::read::Batch;
43use crate::read::batch_adapter::BatchToRecordBatchAdapter;
44use crate::read::prune::PruneTimeIterator;
45use crate::read::scan_region::PredicateGroup;
46use crate::region::options::{MemtableOptions, MergeMode, RegionOptions};
47use crate::sst::FormatType;
48use crate::sst::file::FileTimeRange;
49use crate::sst::parquet::SstInfo;
50use crate::sst::parquet::file_range::PreFilterMode;
51
52mod builder;
53pub mod bulk;
54pub mod simple_bulk_memtable;
55mod stats;
56pub mod time_partition;
57pub mod time_series;
58pub(crate) mod version;
59
60pub use bulk::part::{
61 BulkPart, BulkPartEncoder, BulkPartMeta, UnorderedPart, record_batch_estimated_size,
62 sort_primary_key_record_batch,
63};
64#[cfg(any(test, feature = "test"))]
65pub use time_partition::filter_record_batch;
66
67pub(crate) fn group_by_sequence<T>(
71 mut parts: Vec<T>,
72 bounds: impl Fn(&T) -> (SequenceNumber, SequenceNumber),
73) -> Vec<Vec<T>> {
74 parts.sort_by_key(&bounds);
75 let mut groups: Vec<Vec<T>> = Vec::new();
76 let mut group_max = 0;
77 for part in parts {
78 let (min, max) = bounds(&part);
79 match groups.last_mut() {
80 Some(group) if min <= group_max => {
81 group.push(part);
82 group_max = group_max.max(max);
83 }
84 _ => {
85 groups.push(vec![part]);
86 group_max = max;
87 }
88 }
89 }
90 groups
91}
92
93pub type MemtableId = u32;
97
98#[derive(Clone)]
100pub struct RangesOptions {
101 pub for_flush: bool,
103 pub pre_filter_mode: PreFilterMode,
105 pub predicate: PredicateGroup,
107 pub sequence: Option<SequenceRange>,
109 pub batch_size: usize,
111}
112
113impl Default for RangesOptions {
114 fn default() -> Self {
115 Self {
116 for_flush: false,
117 pre_filter_mode: PreFilterMode::All,
118 predicate: PredicateGroup::default(),
119 sequence: None,
120 batch_size: crate::sst::parquet::DEFAULT_READ_BATCH_SIZE,
121 }
122 }
123}
124
125impl RangesOptions {
126 pub fn for_flush() -> Self {
128 Self {
129 for_flush: true,
130 pre_filter_mode: PreFilterMode::All,
131 predicate: PredicateGroup::default(),
132 sequence: None,
133 batch_size: crate::sst::parquet::DEFAULT_READ_BATCH_SIZE,
134 }
135 }
136
137 #[must_use]
139 pub fn with_pre_filter_mode(mut self, pre_filter_mode: PreFilterMode) -> Self {
140 self.pre_filter_mode = pre_filter_mode;
141 self
142 }
143
144 #[must_use]
146 pub fn with_predicate(mut self, predicate: PredicateGroup) -> Self {
147 self.predicate = predicate;
148 self
149 }
150
151 #[must_use]
153 pub fn with_sequence(mut self, sequence: Option<SequenceRange>) -> Self {
154 self.sequence = sequence;
155 self
156 }
157
158 #[must_use]
160 pub fn with_batch_size(mut self, batch_size: usize) -> Self {
161 self.batch_size = batch_size.clamp(1, crate::sst::parquet::DEFAULT_READ_BATCH_SIZE);
162 self
163 }
164}
165
166#[derive(Debug, Default, Clone)]
167pub struct MemtableStats {
168 pub estimated_bytes: usize,
170 pub time_range: Option<(Timestamp, Timestamp)>,
173 pub num_rows: usize,
175 pub num_ranges: usize,
177 pub max_sequence: SequenceNumber,
179 pub min_sequence: SequenceNumber,
183 pub series_count: usize,
185}
186
187impl MemtableStats {
188 #[cfg(any(test, feature = "test"))]
190 pub fn with_time_range(mut self, time_range: Option<(Timestamp, Timestamp)>) -> Self {
191 self.time_range = time_range;
192 self
193 }
194
195 #[cfg(feature = "test")]
196 pub fn with_max_sequence(mut self, max_sequence: SequenceNumber) -> Self {
197 self.max_sequence = max_sequence;
198 self
199 }
200
201 pub fn bytes_allocated(&self) -> usize {
203 self.estimated_bytes
204 }
205
206 pub fn time_range(&self) -> Option<(Timestamp, Timestamp)> {
208 self.time_range
209 }
210
211 pub fn num_rows(&self) -> usize {
213 self.num_rows
214 }
215
216 pub fn num_ranges(&self) -> usize {
218 self.num_ranges
219 }
220
221 pub fn max_sequence(&self) -> SequenceNumber {
223 self.max_sequence
224 }
225
226 pub fn series_count(&self) -> usize {
228 self.series_count
229 }
230}
231
232pub type BoxedBatchIterator = Box<dyn Iterator<Item = Result<Batch>> + Send>;
233
234pub type BoxedRecordBatchIterator = Box<dyn Iterator<Item = Result<RecordBatch>> + Send>;
235
236#[derive(Default)]
238pub struct MemtableRanges {
239 pub ranges: BTreeMap<usize, MemtableRange>,
241}
242
243impl MemtableRanges {
244 pub fn num_rows(&self) -> usize {
246 self.ranges.values().map(|r| r.stats().num_rows()).sum()
247 }
248
249 pub fn series_count(&self) -> usize {
251 self.ranges.values().map(|r| r.stats().series_count()).sum()
252 }
253
254 pub fn max_sequence(&self) -> SequenceNumber {
256 self.ranges
257 .values()
258 .map(|r| r.stats().max_sequence())
259 .max()
260 .unwrap_or(0)
261 }
262}
263
264impl IterBuilder for MemtableRanges {
265 fn build(&self, _metrics: Option<MemScanMetrics>) -> Result<BoxedBatchIterator> {
266 ensure!(
267 self.ranges.len() == 1,
268 UnsupportedOperationSnafu {
269 err_msg: format!(
270 "Building an iterator from MemtableRanges expects 1 range, but got {}",
271 self.ranges.len()
272 ),
273 }
274 );
275
276 self.ranges.values().next().unwrap().build_iter()
277 }
278
279 fn is_record_batch(&self) -> bool {
280 self.ranges.values().all(|range| range.is_record_batch())
281 }
282}
283
284pub trait Memtable: Send + Sync + fmt::Debug {
286 fn id(&self) -> MemtableId;
288
289 fn write(&self, kvs: &KeyValues) -> Result<()>;
291
292 fn write_one(&self, key_value: KeyValue) -> Result<()>;
294
295 fn write_bulk(&self, part: crate::memtable::bulk::part::BulkPart) -> Result<()>;
297
298 fn ranges(
302 &self,
303 projection: Option<&[ColumnId]>,
304 options: RangesOptions,
305 ) -> Result<MemtableRanges>;
306
307 fn is_empty(&self) -> bool;
309
310 fn freeze(&self) -> Result<()>;
312
313 fn stats(&self) -> MemtableStats;
315
316 fn min_sequence(&self) -> SequenceNumber;
320
321 fn fork(&self, id: MemtableId, metadata: &RegionMetadataRef) -> MemtableRef;
325
326 fn compact(&self, for_flush: bool) -> Result<()> {
330 let _ = for_flush;
331 Ok(())
332 }
333}
334
335pub type MemtableRef = Arc<dyn Memtable>;
336
337pub trait MemtableBuilder: Send + Sync + fmt::Debug {
339 fn build(&self, id: MemtableId, metadata: &RegionMetadataRef) -> MemtableRef;
341
342 fn use_bulk_insert(&self, metadata: &RegionMetadataRef) -> bool {
344 let _metadata = metadata;
345 false
346 }
347}
348
349pub type MemtableBuilderRef = Arc<dyn MemtableBuilder>;
350
351#[derive(Default)]
353pub struct AllocTracker {
354 write_buffer_manager: Option<WriteBufferManagerRef>,
355 bytes_allocated: AtomicUsize,
357 is_done_allocating: AtomicBool,
359}
360
361impl fmt::Debug for AllocTracker {
362 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
363 f.debug_struct("AllocTracker")
364 .field("bytes_allocated", &self.bytes_allocated)
365 .field("is_done_allocating", &self.is_done_allocating)
366 .finish()
367 }
368}
369
370impl AllocTracker {
371 pub fn new(write_buffer_manager: Option<WriteBufferManagerRef>) -> AllocTracker {
373 AllocTracker {
374 write_buffer_manager,
375 bytes_allocated: AtomicUsize::new(0),
376 is_done_allocating: AtomicBool::new(false),
377 }
378 }
379
380 pub(crate) fn on_allocation(&self, bytes: usize) {
382 self.bytes_allocated.fetch_add(bytes, Ordering::Relaxed);
383 WRITE_BUFFER_BYTES.add(bytes as i64);
384 if let Some(write_buffer_manager) = &self.write_buffer_manager {
385 write_buffer_manager.reserve_mem(bytes);
386 }
387 }
388
389 pub(crate) fn done_allocating(&self) {
394 if let Some(write_buffer_manager) = &self.write_buffer_manager
395 && self
396 .is_done_allocating
397 .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
398 .is_ok()
399 {
400 write_buffer_manager.schedule_free_mem(self.bytes_allocated.load(Ordering::Relaxed));
401 }
402 }
403
404 pub(crate) fn bytes_allocated(&self) -> usize {
406 self.bytes_allocated.load(Ordering::Relaxed)
407 }
408
409 pub(crate) fn write_buffer_manager(&self) -> Option<WriteBufferManagerRef> {
411 self.write_buffer_manager.clone()
412 }
413}
414
415impl Drop for AllocTracker {
416 fn drop(&mut self) {
417 if !self.is_done_allocating.load(Ordering::Relaxed) {
418 self.done_allocating();
419 }
420
421 let bytes_allocated = self.bytes_allocated.load(Ordering::Relaxed);
422 WRITE_BUFFER_BYTES.sub(bytes_allocated as i64);
423
424 if let Some(write_buffer_manager) = &self.write_buffer_manager {
426 write_buffer_manager.free_mem(bytes_allocated);
427 }
428 }
429}
430
431#[derive(Clone)]
433pub(crate) struct MemtableBuilderProvider {
434 write_buffer_manager: Option<WriteBufferManagerRef>,
435 config: Arc<MitoConfig>,
436 default_bulk_memtable_config: BulkMemtableConfig,
437 compact_dispatcher: Arc<CompactDispatcher>,
438}
439
440pub(crate) fn ensure_json2_uses_flat_format(
442 metadata: &RegionMetadata,
443 options: &RegionOptions,
444) -> Result<()> {
445 if metadata
446 .column_metadatas
447 .iter()
448 .any(|x| x.column_schema.data_type.is_json2())
449 {
450 ensure!(
452 options.sst_format == Some(FormatType::Flat),
453 InvalidRegionOptionsSnafu {
454 reason: "JSON2 columns require sst_format=flat",
455 }
456 );
457 }
458 Ok(())
459}
460
461impl MemtableBuilderProvider {
462 pub(crate) fn new(
463 write_buffer_manager: Option<WriteBufferManagerRef>,
464 config: Arc<MitoConfig>,
465 compact_dispatcher: Arc<CompactDispatcher>,
466 ) -> Self {
467 let default_bulk_memtable_config = BulkMemtableConfig::default_for_write_buffer_size(
468 config.global_write_buffer_size.as_bytes() as usize,
469 );
470
471 Self {
472 write_buffer_manager,
473 config,
474 default_bulk_memtable_config,
475 compact_dispatcher,
476 }
477 }
478
479 pub(crate) fn parse_options(
481 &self,
482 region_id: RegionId,
483 options: &HashMap<String, String>,
484 ) -> Result<RegionOptions> {
485 RegionOptions::try_from_options_with_bulk_config(
486 region_id,
487 options,
488 &self.default_bulk_memtable_config,
489 )
490 }
491
492 pub(crate) fn builder_for_options(&self, options: &RegionOptions) -> MemtableBuilderRef {
493 let dedup = options.need_dedup();
494 let merge_mode = options.merge_mode();
495 let primary_key_encoding = options.primary_key_encoding();
496 let flat_format = options
497 .sst_format
498 .map(|format| format == FormatType::Flat)
499 .unwrap_or(self.config.default_flat_format);
500 if flat_format {
501 if options.memtable.is_some()
502 && !matches!(&options.memtable, Some(MemtableOptions::Bulk(_)))
503 {
504 common_telemetry::info!(
505 "Overriding memtable config, use BulkMemtable under flat format"
506 );
507 }
508
509 return Arc::new(self.bulk_memtable_builder(dedup, merge_mode, options));
510 }
511
512 if primary_key_encoding == PrimaryKeyEncoding::Sparse {
513 if options.memtable.is_some()
514 && !matches!(&options.memtable, Some(MemtableOptions::Bulk(_)))
515 {
516 common_telemetry::info!(
517 "Overriding memtable config, use BulkMemtable for sparse primary key encoding"
518 );
519 }
520 return Arc::new(self.bulk_memtable_builder(dedup, merge_mode, options));
521 }
522
523 match &options.memtable {
525 Some(MemtableOptions::Bulk(config)) => Arc::new(
526 BulkMemtableBuilder::new(self.write_buffer_manager.clone(), !dedup, merge_mode)
527 .with_config(config.clone())
528 .with_row_group_size(options.row_group_size())
529 .with_float_field_encoding(options.float_field_encoding)
530 .with_compact_dispatcher(self.compact_dispatcher.clone()),
531 ),
532 Some(MemtableOptions::TimeSeries) => Arc::new(TimeSeriesMemtableBuilder::new(
533 self.write_buffer_manager.clone(),
534 dedup,
535 merge_mode,
536 )),
537 None => self.default_primary_key_memtable_builder(dedup, merge_mode),
538 }
539 }
540
541 fn bulk_memtable_builder(
542 &self,
543 dedup: bool,
544 merge_mode: MergeMode,
545 options: &RegionOptions,
546 ) -> BulkMemtableBuilder {
547 let mut builder = BulkMemtableBuilder::new(
548 self.write_buffer_manager.clone(),
549 !dedup, merge_mode,
551 )
552 .with_config(self.default_bulk_memtable_config.clone())
553 .with_row_group_size(options.row_group_size())
554 .with_float_field_encoding(options.float_field_encoding)
555 .with_compact_dispatcher(self.compact_dispatcher.clone());
556
557 if let Some(MemtableOptions::Bulk(config)) = &options.memtable {
558 builder = builder.with_config(config.clone());
559 }
560
561 builder
562 }
563
564 fn default_primary_key_memtable_builder(
565 &self,
566 dedup: bool,
567 merge_mode: MergeMode,
568 ) -> MemtableBuilderRef {
569 Arc::new(TimeSeriesMemtableBuilder::new(
570 self.write_buffer_manager.clone(),
571 dedup,
572 merge_mode,
573 ))
574 }
575}
576
577#[derive(Clone, Default)]
579pub struct MemScanMetrics(Arc<Mutex<MemScanMetricsData>>);
580
581impl MemScanMetrics {
582 pub(crate) fn merge_inner(&self, inner: &MemScanMetricsData) {
584 let mut metrics = self.0.lock().unwrap();
585 metrics.total_series += inner.total_series;
586 metrics.num_rows += inner.num_rows;
587 metrics.num_batches += inner.num_batches;
588 metrics.scan_cost += inner.scan_cost;
589 metrics.prefilter_cost += inner.prefilter_cost;
590 metrics.prefilter_rows_filtered += inner.prefilter_rows_filtered;
591 }
592
593 pub(crate) fn data(&self) -> MemScanMetricsData {
595 self.0.lock().unwrap().clone()
596 }
597}
598
599#[derive(Clone, Default)]
600pub(crate) struct MemScanMetricsData {
601 pub(crate) total_series: usize,
603 pub(crate) num_rows: usize,
605 pub(crate) num_batches: usize,
607 pub(crate) scan_cost: Duration,
609 pub(crate) prefilter_cost: Duration,
611 pub(crate) prefilter_rows_filtered: usize,
613}
614
615pub struct EncodedRange {
617 pub data: Bytes,
619 pub sst_info: SstInfo,
621}
622
623pub trait IterBuilder: Send + Sync {
626 fn build(&self, metrics: Option<MemScanMetrics>) -> Result<BoxedBatchIterator>;
628
629 fn is_record_batch(&self) -> bool {
631 false
632 }
633
634 fn build_record_batch(
638 &self,
639 time_range: Option<(Timestamp, Timestamp)>,
640 metrics: Option<MemScanMetrics>,
641 ) -> Result<BoxedRecordBatchIterator> {
642 let _metrics = metrics;
643 let _ = time_range;
644 UnsupportedOperationSnafu {
645 err_msg: "Record batch iterator is not supported by this memtable",
646 }
647 .fail()
648 }
649
650 fn record_batch_schema_hint(&self) -> Option<SchemaRef> {
652 None
653 }
654
655 fn encoded_range(&self) -> Option<EncodedRange> {
657 None
658 }
659}
660
661pub type BoxedIterBuilder = Box<dyn IterBuilder>;
662
663pub fn read_column_ids_from_projection(
668 metadata: &RegionMetadataRef,
669 projection: Option<&[ColumnId]>,
670) -> Vec<ColumnId> {
671 if let Some(projection) = projection {
672 projection.to_vec()
673 } else {
674 metadata
675 .column_metadatas
676 .iter()
677 .map(|c| c.column_id)
678 .collect()
679 }
680}
681
682pub struct BatchToRecordBatchContext {
684 metadata: RegionMetadataRef,
685 codec: Arc<dyn PrimaryKeyCodec>,
686 read_column_ids: Vec<ColumnId>,
687}
688
689impl BatchToRecordBatchContext {
690 pub fn new(metadata: RegionMetadataRef, mut read_column_ids: Vec<ColumnId>) -> Self {
692 if read_column_ids.is_empty() {
693 read_column_ids.push(metadata.time_index_column().column_id);
694 }
695
696 let codec = build_primary_key_codec(&metadata);
697 Self {
698 metadata,
699 codec,
700 read_column_ids,
701 }
702 }
703
704 fn adapt_iter(&self, iter: BoxedBatchIterator) -> BoxedRecordBatchIterator {
705 Box::new(BatchToRecordBatchAdapter::new(
706 iter,
707 self.metadata.clone(),
708 self.codec.clone(),
709 &self.read_column_ids,
710 ))
711 }
712}
713
714pub struct MemtableRangeContext {
716 id: MemtableId,
718 builder: BoxedIterBuilder,
720 predicate: PredicateGroup,
722 batch_to_record_batch: Option<Arc<BatchToRecordBatchContext>>,
724}
725
726pub type MemtableRangeContextRef = Arc<MemtableRangeContext>;
727
728impl MemtableRangeContext {
729 pub fn new(id: MemtableId, builder: BoxedIterBuilder, predicate: PredicateGroup) -> Self {
731 Self::new_with_batch_to_record_batch(id, builder, predicate, None)
732 }
733
734 pub fn new_with_batch_to_record_batch(
736 id: MemtableId,
737 builder: BoxedIterBuilder,
738 predicate: PredicateGroup,
739 batch_to_record_batch: Option<Arc<BatchToRecordBatchContext>>,
740 ) -> Self {
741 Self {
742 id,
743 builder,
744 predicate,
745 batch_to_record_batch,
746 }
747 }
748}
749
750#[derive(Clone)]
752pub struct MemtableRange {
753 context: MemtableRangeContextRef,
755 stats: MemtableStats,
757}
758
759impl MemtableRange {
760 pub fn new(context: MemtableRangeContextRef, stats: MemtableStats) -> Self {
762 Self { context, stats }
763 }
764
765 pub fn stats(&self) -> &MemtableStats {
767 &self.stats
768 }
769
770 pub fn id(&self) -> MemtableId {
772 self.context.id
773 }
774
775 pub fn build_prune_iter(
779 &self,
780 time_range: FileTimeRange,
781 metrics: Option<MemScanMetrics>,
782 ) -> Result<BoxedBatchIterator> {
783 let iter = self.context.builder.build(metrics)?;
784 let time_filters = self.context.predicate.time_filters();
785 Ok(Box::new(PruneTimeIterator::new(
786 iter,
787 time_range,
788 time_filters,
789 )))
790 }
791
792 pub fn build_iter(&self) -> Result<BoxedBatchIterator> {
794 self.context.builder.build(None)
795 }
796
797 pub fn build_record_batch_iter(
802 &self,
803 time_range: Option<FileTimeRange>,
804 metrics: Option<MemScanMetrics>,
805 ) -> Result<BoxedRecordBatchIterator> {
806 if self.context.builder.is_record_batch() {
807 return self.context.builder.build_record_batch(time_range, metrics);
808 }
809
810 if let Some(context) = self.context.batch_to_record_batch.as_ref() {
811 let iter = self.context.builder.build(metrics)?;
812 let iter: BoxedBatchIterator = if let Some(time_range) = time_range {
813 let time_filters = self.context.predicate.time_filters();
814 Box::new(PruneTimeIterator::new(iter, time_range, time_filters))
815 } else {
816 iter
817 };
818 return Ok(context.adapt_iter(iter));
819 }
820
821 UnsupportedOperationSnafu {
822 err_msg: "Record batch iterator is not supported by this memtable",
823 }
824 .fail()
825 }
826
827 pub fn record_batch_schema_hint(&self) -> Option<SchemaRef> {
829 self.context.builder.record_batch_schema_hint()
830 }
831
832 pub fn is_record_batch(&self) -> bool {
834 self.context.builder.is_record_batch()
835 }
836
837 pub fn num_rows(&self) -> usize {
838 self.stats.num_rows
839 }
840
841 pub fn encoded(&self) -> Option<EncodedRange> {
843 self.context.builder.encoded_range()
844 }
845}
846
847#[cfg(test)]
848mod tests {
849 use std::collections::HashMap;
850 use std::sync::Arc;
851
852 use common_base::readable_size::ReadableSize;
853 use common_error::ext::WhateverResult;
854 use datatypes::prelude::ConcreteDataType;
855 use datatypes::types::json_type::{JsonNativeType, JsonObjectType};
856 use store_api::metadata::RegionMetadataBuilder;
857 use store_api::storage::RegionId;
858
859 use super::*;
860 use crate::flush::{WriteBufferManager, WriteBufferManagerImpl};
861 use crate::memtable::bulk::BulkMemtableConfig;
862 use crate::test_util::sst_util::sst_region_metadata;
863
864 #[test]
865 fn test_alloc_tracker_without_manager() {
866 let tracker = AllocTracker::new(None);
867 assert_eq!(0, tracker.bytes_allocated());
868 tracker.on_allocation(100);
869 assert_eq!(100, tracker.bytes_allocated());
870 tracker.on_allocation(200);
871 assert_eq!(300, tracker.bytes_allocated());
872
873 tracker.done_allocating();
874 assert_eq!(300, tracker.bytes_allocated());
875 }
876
877 #[test]
878 fn test_alloc_tracker_with_manager() {
879 let manager = Arc::new(WriteBufferManagerImpl::new(1000));
880 {
881 let tracker = AllocTracker::new(Some(manager.clone() as WriteBufferManagerRef));
882
883 tracker.on_allocation(100);
884 assert_eq!(100, tracker.bytes_allocated());
885 assert_eq!(100, manager.memory_usage());
886 assert_eq!(100, manager.mutable_usage());
887
888 for _ in 0..2 {
889 tracker.done_allocating();
891 assert_eq!(100, manager.memory_usage());
892 assert_eq!(0, manager.mutable_usage());
893 }
894 }
895
896 assert_eq!(0, manager.memory_usage());
897 assert_eq!(0, manager.mutable_usage());
898 }
899
900 #[test]
901 fn test_alloc_tracker_without_done_allocating() {
902 let manager = Arc::new(WriteBufferManagerImpl::new(1000));
903 {
904 let tracker = AllocTracker::new(Some(manager.clone() as WriteBufferManagerRef));
905
906 tracker.on_allocation(100);
907 assert_eq!(100, tracker.bytes_allocated());
908 assert_eq!(100, manager.memory_usage());
909 assert_eq!(100, manager.mutable_usage());
910 }
911
912 assert_eq!(0, manager.memory_usage());
913 assert_eq!(0, manager.mutable_usage());
914 }
915
916 #[test]
917 fn test_forced_bulk_memtable_preserves_bulk_config() {
918 let provider = MemtableBuilderProvider::new(
919 None,
920 Arc::new(MitoConfig::default()),
921 Arc::new(CompactDispatcher::new(1)),
922 );
923 let config = BulkMemtableConfig {
924 merge_threshold: 7,
925 encode_row_threshold: 11,
926 encode_bytes_threshold: 13,
927 max_merge_groups: 17,
928 };
929 let options = RegionOptions {
930 memtable: Some(MemtableOptions::Bulk(config.clone())),
931 primary_key_encoding: Some(PrimaryKeyEncoding::Sparse),
932 ..Default::default()
933 };
934
935 let builder =
936 provider.bulk_memtable_builder(options.need_dedup(), options.merge_mode(), &options);
937
938 assert_eq!(&config, builder.config());
939 }
940
941 #[test]
942 fn test_provider_uses_adaptive_config_for_implicit_bulk_builder() {
943 let config = MitoConfig {
944 global_write_buffer_size: ReadableSize::gb(8),
945 ..Default::default()
946 };
947 let provider = MemtableBuilderProvider::new(
948 None,
949 Arc::new(config),
950 Arc::new(CompactDispatcher::new(1)),
951 );
952 let options = RegionOptions::default();
953
954 let builder =
955 provider.bulk_memtable_builder(options.need_dedup(), options.merge_mode(), &options);
956
957 assert_eq!(256 * 1024 * 1024, builder.config().encode_bytes_threshold);
958 }
959
960 #[test]
961 fn test_provider_parses_bulk_memtable_with_adaptive_config() {
962 let config = MitoConfig {
963 global_write_buffer_size: ReadableSize::gb(8),
964 ..Default::default()
965 };
966 let provider = MemtableBuilderProvider::new(
967 None,
968 Arc::new(config),
969 Arc::new(CompactDispatcher::new(1)),
970 );
971 let options = HashMap::from([("memtable.type".to_string(), "bulk".to_string())]);
972
973 let options = provider
974 .parse_options(RegionId::new(0, 0), &options)
975 .unwrap();
976
977 let Some(MemtableOptions::Bulk(config)) = options.memtable else {
978 panic!("expected bulk memtable options");
979 };
980 assert_eq!(256 * 1024 * 1024, config.encode_bytes_threshold);
981 }
982
983 #[test]
984 fn test_provider_preserves_explicit_bulk_encode_bytes_threshold() {
985 let config = MitoConfig {
986 global_write_buffer_size: ReadableSize::gb(8),
987 ..Default::default()
988 };
989 let provider = MemtableBuilderProvider::new(
990 None,
991 Arc::new(config),
992 Arc::new(CompactDispatcher::new(1)),
993 );
994 let options = HashMap::from([
995 ("memtable.type".to_string(), "bulk".to_string()),
996 (
997 "memtable.bulk.encode_bytes_threshold".to_string(),
998 "13".to_string(),
999 ),
1000 ]);
1001
1002 let options = provider
1003 .parse_options(RegionId::new(0, 0), &options)
1004 .unwrap();
1005
1006 let Some(MemtableOptions::Bulk(config)) = options.memtable else {
1007 panic!("expected bulk memtable options");
1008 };
1009 assert_eq!(13, config.encode_bytes_threshold);
1010 }
1011
1012 #[test]
1013 fn test_json2_requires_flat_format() -> WhateverResult<()> {
1014 let mut metadata = sst_region_metadata();
1015 metadata.column_metadatas[2].column_schema.data_type =
1016 ConcreteDataType::json2(JsonNativeType::Object(JsonObjectType::new()));
1017 let metadata = RegionMetadataBuilder::from_existing(metadata).build()?;
1018 let mut options = RegionOptions {
1019 sst_format: Some(FormatType::PrimaryKey),
1020 memtable: Some(MemtableOptions::TimeSeries),
1021 ..Default::default()
1022 };
1023
1024 let err = ensure_json2_uses_flat_format(&metadata, &options).unwrap_err();
1025 assert!(
1026 err.to_string()
1027 .contains("JSON2 columns require sst_format=flat")
1028 );
1029
1030 options.memtable = None;
1031 assert!(ensure_json2_uses_flat_format(&metadata, &options).is_err());
1032
1033 options.memtable = Some(MemtableOptions::Bulk(BulkMemtableConfig::default()));
1034 assert!(ensure_json2_uses_flat_format(&metadata, &options).is_err());
1035
1036 options.memtable = Some(MemtableOptions::TimeSeries);
1037 options.sst_format = Some(FormatType::Flat);
1038 ensure_json2_uses_flat_format(&metadata, &options)?;
1039
1040 options.sst_format = Some(FormatType::PrimaryKey);
1041 options.primary_key_encoding = Some(PrimaryKeyEncoding::Sparse);
1042 assert!(ensure_json2_uses_flat_format(&metadata, &options).is_err());
1043
1044 options.sst_format = Some(FormatType::Flat);
1045 ensure_json2_uses_flat_format(&metadata, &options)?;
1046 Ok(())
1047 }
1048}