1use std::collections::BTreeMap;
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::RegionMetadataRef;
34use store_api::storage::{ColumnId, SequenceNumber, SequenceRange};
35
36use crate::config::MitoConfig;
37use crate::error::{Result, UnsupportedOperationSnafu};
38use crate::flush::WriteBufferManagerRef;
39use crate::memtable::bulk::{BulkMemtableBuilder, 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 type MemtableId = u32;
71
72#[derive(Clone)]
74pub struct RangesOptions {
75 pub for_flush: bool,
77 pub pre_filter_mode: PreFilterMode,
79 pub predicate: PredicateGroup,
81 pub sequence: Option<SequenceRange>,
83 pub batch_size: usize,
85}
86
87impl Default for RangesOptions {
88 fn default() -> Self {
89 Self {
90 for_flush: false,
91 pre_filter_mode: PreFilterMode::All,
92 predicate: PredicateGroup::default(),
93 sequence: None,
94 batch_size: crate::sst::parquet::DEFAULT_READ_BATCH_SIZE,
95 }
96 }
97}
98
99impl RangesOptions {
100 pub fn for_flush() -> Self {
102 Self {
103 for_flush: true,
104 pre_filter_mode: PreFilterMode::All,
105 predicate: PredicateGroup::default(),
106 sequence: None,
107 batch_size: crate::sst::parquet::DEFAULT_READ_BATCH_SIZE,
108 }
109 }
110
111 #[must_use]
113 pub fn with_pre_filter_mode(mut self, pre_filter_mode: PreFilterMode) -> Self {
114 self.pre_filter_mode = pre_filter_mode;
115 self
116 }
117
118 #[must_use]
120 pub fn with_predicate(mut self, predicate: PredicateGroup) -> Self {
121 self.predicate = predicate;
122 self
123 }
124
125 #[must_use]
127 pub fn with_sequence(mut self, sequence: Option<SequenceRange>) -> Self {
128 self.sequence = sequence;
129 self
130 }
131
132 #[must_use]
134 pub fn with_batch_size(mut self, batch_size: usize) -> Self {
135 self.batch_size = batch_size.clamp(1, crate::sst::parquet::DEFAULT_READ_BATCH_SIZE);
136 self
137 }
138}
139
140#[derive(Debug, Default, Clone)]
141pub struct MemtableStats {
142 pub estimated_bytes: usize,
144 pub time_range: Option<(Timestamp, Timestamp)>,
147 pub num_rows: usize,
149 pub num_ranges: usize,
151 pub max_sequence: SequenceNumber,
153 pub series_count: usize,
155}
156
157impl MemtableStats {
158 #[cfg(any(test, feature = "test"))]
160 pub fn with_time_range(mut self, time_range: Option<(Timestamp, Timestamp)>) -> Self {
161 self.time_range = time_range;
162 self
163 }
164
165 #[cfg(feature = "test")]
166 pub fn with_max_sequence(mut self, max_sequence: SequenceNumber) -> Self {
167 self.max_sequence = max_sequence;
168 self
169 }
170
171 pub fn bytes_allocated(&self) -> usize {
173 self.estimated_bytes
174 }
175
176 pub fn time_range(&self) -> Option<(Timestamp, Timestamp)> {
178 self.time_range
179 }
180
181 pub fn num_rows(&self) -> usize {
183 self.num_rows
184 }
185
186 pub fn num_ranges(&self) -> usize {
188 self.num_ranges
189 }
190
191 pub fn max_sequence(&self) -> SequenceNumber {
193 self.max_sequence
194 }
195
196 pub fn series_count(&self) -> usize {
198 self.series_count
199 }
200}
201
202pub type BoxedBatchIterator = Box<dyn Iterator<Item = Result<Batch>> + Send>;
203
204pub type BoxedRecordBatchIterator = Box<dyn Iterator<Item = Result<RecordBatch>> + Send>;
205
206#[derive(Default)]
208pub struct MemtableRanges {
209 pub ranges: BTreeMap<usize, MemtableRange>,
211}
212
213impl MemtableRanges {
214 pub fn num_rows(&self) -> usize {
216 self.ranges.values().map(|r| r.stats().num_rows()).sum()
217 }
218
219 pub fn series_count(&self) -> usize {
221 self.ranges.values().map(|r| r.stats().series_count()).sum()
222 }
223
224 pub fn max_sequence(&self) -> SequenceNumber {
226 self.ranges
227 .values()
228 .map(|r| r.stats().max_sequence())
229 .max()
230 .unwrap_or(0)
231 }
232}
233
234impl IterBuilder for MemtableRanges {
235 fn build(&self, _metrics: Option<MemScanMetrics>) -> Result<BoxedBatchIterator> {
236 ensure!(
237 self.ranges.len() == 1,
238 UnsupportedOperationSnafu {
239 err_msg: format!(
240 "Building an iterator from MemtableRanges expects 1 range, but got {}",
241 self.ranges.len()
242 ),
243 }
244 );
245
246 self.ranges.values().next().unwrap().build_iter()
247 }
248
249 fn is_record_batch(&self) -> bool {
250 self.ranges.values().all(|range| range.is_record_batch())
251 }
252}
253
254pub trait Memtable: Send + Sync + fmt::Debug {
256 fn id(&self) -> MemtableId;
258
259 fn write(&self, kvs: &KeyValues) -> Result<()>;
261
262 fn write_one(&self, key_value: KeyValue) -> Result<()>;
264
265 fn write_bulk(&self, part: crate::memtable::bulk::part::BulkPart) -> Result<()>;
267
268 fn ranges(
272 &self,
273 projection: Option<&[ColumnId]>,
274 options: RangesOptions,
275 ) -> Result<MemtableRanges>;
276
277 fn is_empty(&self) -> bool;
279
280 fn freeze(&self) -> Result<()>;
282
283 fn stats(&self) -> MemtableStats;
285
286 fn fork(&self, id: MemtableId, metadata: &RegionMetadataRef) -> MemtableRef;
290
291 fn compact(&self, for_flush: bool) -> Result<()> {
295 let _ = for_flush;
296 Ok(())
297 }
298}
299
300pub type MemtableRef = Arc<dyn Memtable>;
301
302pub trait MemtableBuilder: Send + Sync + fmt::Debug {
304 fn build(&self, id: MemtableId, metadata: &RegionMetadataRef) -> MemtableRef;
306
307 fn use_bulk_insert(&self, metadata: &RegionMetadataRef) -> bool {
309 let _metadata = metadata;
310 false
311 }
312}
313
314pub type MemtableBuilderRef = Arc<dyn MemtableBuilder>;
315
316#[derive(Default)]
318pub struct AllocTracker {
319 write_buffer_manager: Option<WriteBufferManagerRef>,
320 bytes_allocated: AtomicUsize,
322 is_done_allocating: AtomicBool,
324}
325
326impl fmt::Debug for AllocTracker {
327 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
328 f.debug_struct("AllocTracker")
329 .field("bytes_allocated", &self.bytes_allocated)
330 .field("is_done_allocating", &self.is_done_allocating)
331 .finish()
332 }
333}
334
335impl AllocTracker {
336 pub fn new(write_buffer_manager: Option<WriteBufferManagerRef>) -> AllocTracker {
338 AllocTracker {
339 write_buffer_manager,
340 bytes_allocated: AtomicUsize::new(0),
341 is_done_allocating: AtomicBool::new(false),
342 }
343 }
344
345 pub(crate) fn on_allocation(&self, bytes: usize) {
347 self.bytes_allocated.fetch_add(bytes, Ordering::Relaxed);
348 WRITE_BUFFER_BYTES.add(bytes as i64);
349 if let Some(write_buffer_manager) = &self.write_buffer_manager {
350 write_buffer_manager.reserve_mem(bytes);
351 }
352 }
353
354 pub(crate) fn done_allocating(&self) {
359 if let Some(write_buffer_manager) = &self.write_buffer_manager
360 && self
361 .is_done_allocating
362 .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
363 .is_ok()
364 {
365 write_buffer_manager.schedule_free_mem(self.bytes_allocated.load(Ordering::Relaxed));
366 }
367 }
368
369 pub(crate) fn bytes_allocated(&self) -> usize {
371 self.bytes_allocated.load(Ordering::Relaxed)
372 }
373
374 pub(crate) fn write_buffer_manager(&self) -> Option<WriteBufferManagerRef> {
376 self.write_buffer_manager.clone()
377 }
378}
379
380impl Drop for AllocTracker {
381 fn drop(&mut self) {
382 if !self.is_done_allocating.load(Ordering::Relaxed) {
383 self.done_allocating();
384 }
385
386 let bytes_allocated = self.bytes_allocated.load(Ordering::Relaxed);
387 WRITE_BUFFER_BYTES.sub(bytes_allocated as i64);
388
389 if let Some(write_buffer_manager) = &self.write_buffer_manager {
391 write_buffer_manager.free_mem(bytes_allocated);
392 }
393 }
394}
395
396#[derive(Clone)]
398pub(crate) struct MemtableBuilderProvider {
399 write_buffer_manager: Option<WriteBufferManagerRef>,
400 config: Arc<MitoConfig>,
401 compact_dispatcher: Arc<CompactDispatcher>,
402}
403
404impl MemtableBuilderProvider {
405 pub(crate) fn new(
406 write_buffer_manager: Option<WriteBufferManagerRef>,
407 config: Arc<MitoConfig>,
408 ) -> Self {
409 let compact_dispatcher =
410 Arc::new(CompactDispatcher::new(config.max_background_compactions));
411
412 Self {
413 write_buffer_manager,
414 config,
415 compact_dispatcher,
416 }
417 }
418
419 pub(crate) fn builder_for_options(&self, options: &RegionOptions) -> MemtableBuilderRef {
420 let dedup = options.need_dedup();
421 let merge_mode = options.merge_mode();
422 let primary_key_encoding = options.primary_key_encoding();
423 let flat_format = options
424 .sst_format
425 .map(|format| format == FormatType::Flat)
426 .unwrap_or(self.config.default_flat_format);
427 if flat_format {
428 if options.memtable.is_some()
429 && !matches!(&options.memtable, Some(MemtableOptions::Bulk(_)))
430 {
431 common_telemetry::info!(
432 "Overriding memtable config, use BulkMemtable under flat format"
433 );
434 }
435
436 return Arc::new(self.bulk_memtable_builder(dedup, merge_mode, options));
437 }
438
439 if primary_key_encoding == PrimaryKeyEncoding::Sparse {
440 if options.memtable.is_some()
441 && !matches!(&options.memtable, Some(MemtableOptions::Bulk(_)))
442 {
443 common_telemetry::info!(
444 "Overriding memtable config, use BulkMemtable for sparse primary key encoding"
445 );
446 }
447 return Arc::new(self.bulk_memtable_builder(dedup, merge_mode, options));
448 }
449
450 match &options.memtable {
452 Some(MemtableOptions::Bulk(config)) => Arc::new(
453 BulkMemtableBuilder::new(self.write_buffer_manager.clone(), !dedup, merge_mode)
454 .with_config(config.clone())
455 .with_row_group_size(options.row_group_size())
456 .with_compact_dispatcher(self.compact_dispatcher.clone()),
457 ),
458 Some(MemtableOptions::TimeSeries) => Arc::new(TimeSeriesMemtableBuilder::new(
459 self.write_buffer_manager.clone(),
460 dedup,
461 merge_mode,
462 )),
463 None => self.default_primary_key_memtable_builder(dedup, merge_mode),
464 }
465 }
466
467 fn bulk_memtable_builder(
468 &self,
469 dedup: bool,
470 merge_mode: MergeMode,
471 options: &RegionOptions,
472 ) -> BulkMemtableBuilder {
473 let mut builder = BulkMemtableBuilder::new(
474 self.write_buffer_manager.clone(),
475 !dedup, merge_mode,
477 )
478 .with_row_group_size(options.row_group_size())
479 .with_compact_dispatcher(self.compact_dispatcher.clone());
480
481 if let Some(MemtableOptions::Bulk(config)) = &options.memtable {
482 builder = builder.with_config(config.clone());
483 }
484
485 builder
486 }
487
488 fn default_primary_key_memtable_builder(
489 &self,
490 dedup: bool,
491 merge_mode: MergeMode,
492 ) -> MemtableBuilderRef {
493 Arc::new(TimeSeriesMemtableBuilder::new(
494 self.write_buffer_manager.clone(),
495 dedup,
496 merge_mode,
497 ))
498 }
499}
500
501#[derive(Clone, Default)]
503pub struct MemScanMetrics(Arc<Mutex<MemScanMetricsData>>);
504
505impl MemScanMetrics {
506 pub(crate) fn merge_inner(&self, inner: &MemScanMetricsData) {
508 let mut metrics = self.0.lock().unwrap();
509 metrics.total_series += inner.total_series;
510 metrics.num_rows += inner.num_rows;
511 metrics.num_batches += inner.num_batches;
512 metrics.scan_cost += inner.scan_cost;
513 metrics.prefilter_cost += inner.prefilter_cost;
514 metrics.prefilter_rows_filtered += inner.prefilter_rows_filtered;
515 }
516
517 pub(crate) fn data(&self) -> MemScanMetricsData {
519 self.0.lock().unwrap().clone()
520 }
521}
522
523#[derive(Clone, Default)]
524pub(crate) struct MemScanMetricsData {
525 pub(crate) total_series: usize,
527 pub(crate) num_rows: usize,
529 pub(crate) num_batches: usize,
531 pub(crate) scan_cost: Duration,
533 pub(crate) prefilter_cost: Duration,
535 pub(crate) prefilter_rows_filtered: usize,
537}
538
539pub struct EncodedRange {
541 pub data: Bytes,
543 pub sst_info: SstInfo,
545}
546
547pub trait IterBuilder: Send + Sync {
550 fn build(&self, metrics: Option<MemScanMetrics>) -> Result<BoxedBatchIterator>;
552
553 fn is_record_batch(&self) -> bool {
555 false
556 }
557
558 fn build_record_batch(
562 &self,
563 time_range: Option<(Timestamp, Timestamp)>,
564 metrics: Option<MemScanMetrics>,
565 ) -> Result<BoxedRecordBatchIterator> {
566 let _metrics = metrics;
567 let _ = time_range;
568 UnsupportedOperationSnafu {
569 err_msg: "Record batch iterator is not supported by this memtable",
570 }
571 .fail()
572 }
573
574 fn record_batch_schema_hint(&self) -> Option<SchemaRef> {
576 None
577 }
578
579 fn encoded_range(&self) -> Option<EncodedRange> {
581 None
582 }
583}
584
585pub type BoxedIterBuilder = Box<dyn IterBuilder>;
586
587pub fn read_column_ids_from_projection(
592 metadata: &RegionMetadataRef,
593 projection: Option<&[ColumnId]>,
594) -> Vec<ColumnId> {
595 if let Some(projection) = projection {
596 projection.to_vec()
597 } else {
598 metadata
599 .column_metadatas
600 .iter()
601 .map(|c| c.column_id)
602 .collect()
603 }
604}
605
606pub struct BatchToRecordBatchContext {
608 metadata: RegionMetadataRef,
609 codec: Arc<dyn PrimaryKeyCodec>,
610 read_column_ids: Vec<ColumnId>,
611}
612
613impl BatchToRecordBatchContext {
614 pub fn new(metadata: RegionMetadataRef, mut read_column_ids: Vec<ColumnId>) -> Self {
616 if read_column_ids.is_empty() {
617 read_column_ids.push(metadata.time_index_column().column_id);
618 }
619
620 let codec = build_primary_key_codec(&metadata);
621 Self {
622 metadata,
623 codec,
624 read_column_ids,
625 }
626 }
627
628 fn adapt_iter(&self, iter: BoxedBatchIterator) -> BoxedRecordBatchIterator {
629 Box::new(BatchToRecordBatchAdapter::new(
630 iter,
631 self.metadata.clone(),
632 self.codec.clone(),
633 &self.read_column_ids,
634 ))
635 }
636}
637
638pub struct MemtableRangeContext {
640 id: MemtableId,
642 builder: BoxedIterBuilder,
644 predicate: PredicateGroup,
646 batch_to_record_batch: Option<Arc<BatchToRecordBatchContext>>,
648}
649
650pub type MemtableRangeContextRef = Arc<MemtableRangeContext>;
651
652impl MemtableRangeContext {
653 pub fn new(id: MemtableId, builder: BoxedIterBuilder, predicate: PredicateGroup) -> Self {
655 Self::new_with_batch_to_record_batch(id, builder, predicate, None)
656 }
657
658 pub fn new_with_batch_to_record_batch(
660 id: MemtableId,
661 builder: BoxedIterBuilder,
662 predicate: PredicateGroup,
663 batch_to_record_batch: Option<Arc<BatchToRecordBatchContext>>,
664 ) -> Self {
665 Self {
666 id,
667 builder,
668 predicate,
669 batch_to_record_batch,
670 }
671 }
672}
673
674#[derive(Clone)]
676pub struct MemtableRange {
677 context: MemtableRangeContextRef,
679 stats: MemtableStats,
681}
682
683impl MemtableRange {
684 pub fn new(context: MemtableRangeContextRef, stats: MemtableStats) -> Self {
686 Self { context, stats }
687 }
688
689 pub fn stats(&self) -> &MemtableStats {
691 &self.stats
692 }
693
694 pub fn id(&self) -> MemtableId {
696 self.context.id
697 }
698
699 pub fn build_prune_iter(
703 &self,
704 time_range: FileTimeRange,
705 metrics: Option<MemScanMetrics>,
706 ) -> Result<BoxedBatchIterator> {
707 let iter = self.context.builder.build(metrics)?;
708 let time_filters = self.context.predicate.time_filters();
709 Ok(Box::new(PruneTimeIterator::new(
710 iter,
711 time_range,
712 time_filters,
713 )))
714 }
715
716 pub fn build_iter(&self) -> Result<BoxedBatchIterator> {
718 self.context.builder.build(None)
719 }
720
721 pub fn build_record_batch_iter(
726 &self,
727 time_range: Option<FileTimeRange>,
728 metrics: Option<MemScanMetrics>,
729 ) -> Result<BoxedRecordBatchIterator> {
730 if self.context.builder.is_record_batch() {
731 return self.context.builder.build_record_batch(time_range, metrics);
732 }
733
734 if let Some(context) = self.context.batch_to_record_batch.as_ref() {
735 let iter = self.context.builder.build(metrics)?;
736 let iter: BoxedBatchIterator = if let Some(time_range) = time_range {
737 let time_filters = self.context.predicate.time_filters();
738 Box::new(PruneTimeIterator::new(iter, time_range, time_filters))
739 } else {
740 iter
741 };
742 return Ok(context.adapt_iter(iter));
743 }
744
745 UnsupportedOperationSnafu {
746 err_msg: "Record batch iterator is not supported by this memtable",
747 }
748 .fail()
749 }
750
751 pub fn record_batch_schema_hint(&self) -> Option<SchemaRef> {
753 self.context.builder.record_batch_schema_hint()
754 }
755
756 pub fn is_record_batch(&self) -> bool {
758 self.context.builder.is_record_batch()
759 }
760
761 pub fn num_rows(&self) -> usize {
762 self.stats.num_rows
763 }
764
765 pub fn encoded(&self) -> Option<EncodedRange> {
767 self.context.builder.encoded_range()
768 }
769}
770
771#[cfg(test)]
772mod tests {
773 use std::sync::Arc;
774
775 use super::*;
776 use crate::flush::{WriteBufferManager, WriteBufferManagerImpl};
777 use crate::memtable::bulk::BulkMemtableConfig;
778
779 #[test]
780 fn test_alloc_tracker_without_manager() {
781 let tracker = AllocTracker::new(None);
782 assert_eq!(0, tracker.bytes_allocated());
783 tracker.on_allocation(100);
784 assert_eq!(100, tracker.bytes_allocated());
785 tracker.on_allocation(200);
786 assert_eq!(300, tracker.bytes_allocated());
787
788 tracker.done_allocating();
789 assert_eq!(300, tracker.bytes_allocated());
790 }
791
792 #[test]
793 fn test_alloc_tracker_with_manager() {
794 let manager = Arc::new(WriteBufferManagerImpl::new(1000));
795 {
796 let tracker = AllocTracker::new(Some(manager.clone() as WriteBufferManagerRef));
797
798 tracker.on_allocation(100);
799 assert_eq!(100, tracker.bytes_allocated());
800 assert_eq!(100, manager.memory_usage());
801 assert_eq!(100, manager.mutable_usage());
802
803 for _ in 0..2 {
804 tracker.done_allocating();
806 assert_eq!(100, manager.memory_usage());
807 assert_eq!(0, manager.mutable_usage());
808 }
809 }
810
811 assert_eq!(0, manager.memory_usage());
812 assert_eq!(0, manager.mutable_usage());
813 }
814
815 #[test]
816 fn test_alloc_tracker_without_done_allocating() {
817 let manager = Arc::new(WriteBufferManagerImpl::new(1000));
818 {
819 let tracker = AllocTracker::new(Some(manager.clone() as WriteBufferManagerRef));
820
821 tracker.on_allocation(100);
822 assert_eq!(100, tracker.bytes_allocated());
823 assert_eq!(100, manager.memory_usage());
824 assert_eq!(100, manager.mutable_usage());
825 }
826
827 assert_eq!(0, manager.memory_usage());
828 assert_eq!(0, manager.mutable_usage());
829 }
830
831 #[test]
832 fn test_forced_bulk_memtable_preserves_bulk_config() {
833 let provider = MemtableBuilderProvider::new(None, Arc::new(MitoConfig::default()));
834 let config = BulkMemtableConfig {
835 merge_threshold: 7,
836 encode_row_threshold: 11,
837 encode_bytes_threshold: 13,
838 max_merge_groups: 17,
839 };
840 let options = RegionOptions {
841 memtable: Some(MemtableOptions::Bulk(config.clone())),
842 primary_key_encoding: Some(PrimaryKeyEncoding::Sparse),
843 ..Default::default()
844 };
845
846 let builder =
847 provider.bulk_memtable_builder(options.need_dedup(), options.merge_mode(), &options);
848
849 assert_eq!(&config, builder.config());
850 }
851}