1use std::collections::{HashMap, HashSet};
18use std::sync::{Arc, Mutex, MutexGuard};
19use std::time::Duration;
20
21use common_telemetry::debug;
22use common_time::Timestamp;
23use common_time::timestamp::TimeUnit;
24use common_time::timestamp_millis::BucketAligned;
25use datatypes::arrow;
26use datatypes::arrow::array::{
27 ArrayRef, BooleanArray, RecordBatch, RecordBatchOptions, TimestampMicrosecondArray,
28 TimestampMillisecondArray, TimestampNanosecondArray, TimestampSecondArray,
29};
30use datatypes::arrow::buffer::{BooleanBuffer, MutableBuffer};
31use datatypes::arrow::datatypes::{DataType, Int64Type, SchemaRef};
32use mito_codec::key_values::KeyValue;
33use mito_codec::row_converter::{PrimaryKeyCodec, build_primary_key_codec};
34use smallvec::{SmallVec, smallvec};
35use snafu::{OptionExt, ResultExt};
36use store_api::metadata::RegionMetadataRef;
37
38use crate::error;
39use crate::error::{InvalidRequestSnafu, Result};
40use crate::memtable::bulk::part::{BulkPart, BulkPartConverter};
41use crate::memtable::version::SmallMemtableVec;
42use crate::memtable::{KeyValues, MemtableBuilderRef, MemtableId, MemtableRef};
43use crate::sst::{FlatSchemaOptions, to_flat_sst_arrow_schema};
44
45const INITIAL_TIME_WINDOW: Duration = Duration::from_days(1);
47
48#[derive(Debug, Clone)]
50pub struct TimePartition {
51 memtable: MemtableRef,
53 time_range: PartTimeRange,
55}
56
57impl TimePartition {
58 fn contains_timestamp(&self, ts: Timestamp) -> bool {
60 self.time_range.contains_timestamp(ts)
61 }
62
63 fn write(&self, kvs: &KeyValues) -> Result<()> {
65 self.memtable.write(kvs)
66 }
67
68 fn write_record_batch(&self, rb: BulkPart) -> Result<()> {
70 self.memtable.write_bulk(rb)
71 }
72
73 fn write_record_batch_partial(&self, part: &BulkPart) -> Result<()> {
75 let Some(filtered) = filter_record_batch(
76 part,
77 self.time_range.min_timestamp.value(),
78 self.time_range.max_timestamp.value(),
79 )?
80 else {
81 return Ok(());
82 };
83 self.write_record_batch(filtered)
84 }
85}
86
87macro_rules! create_filter_buffer {
88 ($ts_array:expr, $min:expr, $max:expr) => {{
89 let len = $ts_array.len();
90 let mut buffer = MutableBuffer::new(len.div_ceil(64) * 8);
91
92 let f = |idx: usize| -> bool {
93 unsafe {
95 let val = $ts_array.value_unchecked(idx);
96 val >= $min && val < $max
97 }
98 };
99
100 let chunks = len / 64;
101 let remainder = len % 64;
102
103 for chunk in 0..chunks {
104 let mut packed = 0;
105 for bit_idx in 0..64 {
106 let i = bit_idx + chunk * 64;
107 packed |= (f(i) as u64) << bit_idx;
108 }
109 unsafe { buffer.push_unchecked(packed) }
111 }
112
113 if remainder != 0 {
114 let mut packed = 0;
115 for bit_idx in 0..remainder {
116 let i = bit_idx + chunks * 64;
117 packed |= (f(i) as u64) << bit_idx;
118 }
119 unsafe { buffer.push_unchecked(packed) }
121 }
122
123 BooleanArray::new(BooleanBuffer::new(buffer.into(), 0, len), None)
124 }};
125}
126
127macro_rules! handle_timestamp_array {
128 ($ts_array:expr, $array_type:ty, $min:expr, $max:expr) => {{
129 let ts_array = $ts_array.as_any().downcast_ref::<$array_type>().unwrap();
130 let filter = create_filter_buffer!(ts_array, $min, $max);
131
132 let res = arrow::compute::filter(ts_array, &filter).context(error::ComputeArrowSnafu)?;
133 if res.is_empty() {
134 return Ok(None);
135 }
136
137 let i64array = res.as_any().downcast_ref::<$array_type>().unwrap();
138 let max_ts = arrow::compute::max(i64array).unwrap();
140 let min_ts = arrow::compute::min(i64array).unwrap();
141
142 (res, filter, min_ts, max_ts)
143 }};
144}
145
146pub fn filter_record_batch(part: &BulkPart, min: i64, max: i64) -> Result<Option<BulkPart>> {
149 let ts_array = part.timestamps();
150 let (ts_array, filter, min_ts, max_ts) = match ts_array.data_type() {
151 DataType::Timestamp(unit, _) => match unit {
152 arrow::datatypes::TimeUnit::Second => {
153 handle_timestamp_array!(ts_array, TimestampSecondArray, min, max)
154 }
155 arrow::datatypes::TimeUnit::Millisecond => {
156 handle_timestamp_array!(ts_array, TimestampMillisecondArray, min, max)
157 }
158 arrow::datatypes::TimeUnit::Microsecond => {
159 handle_timestamp_array!(ts_array, TimestampMicrosecondArray, min, max)
160 }
161 arrow::datatypes::TimeUnit::Nanosecond => {
162 handle_timestamp_array!(ts_array, TimestampNanosecondArray, min, max)
163 }
164 },
165 _ => {
166 unreachable!("Got data type: {:?}", ts_array.data_type());
167 }
168 };
169
170 let num_rows = ts_array.len();
171 let arrays = part
172 .batch
173 .columns()
174 .iter()
175 .enumerate()
176 .map(|(index, array)| {
177 if index == part.timestamp_index {
178 Ok(ts_array.clone())
179 } else {
180 arrow::compute::filter(&array, &filter).context(error::ComputeArrowSnafu)
181 }
182 })
183 .collect::<Result<Vec<_>>>()?;
184 let batch = RecordBatch::try_new_with_options(
185 part.batch.schema(),
186 arrays,
187 &RecordBatchOptions::default().with_row_count(Some(num_rows)),
188 )
189 .context(error::NewRecordBatchSnafu)?;
190 Ok(Some(BulkPart {
191 batch,
192 max_timestamp: max_ts,
193 min_timestamp: min_ts,
194 sequence: part.sequence,
195 timestamp_index: part.timestamp_index,
196 raw_data: None,
197 }))
198}
199
200type PartitionVec = SmallVec<[TimePartition; 2]>;
201
202#[derive(Debug)]
204pub struct TimePartitions {
205 inner: Mutex<PartitionsInner>,
207 part_duration: Duration,
209 metadata: RegionMetadataRef,
211 builder: MemtableBuilderRef,
213 primary_key_codec: Arc<dyn PrimaryKeyCodec>,
215
216 bulk_schema: Option<SchemaRef>,
219}
220
221pub type TimePartitionsRef = Arc<TimePartitions>;
222
223impl TimePartitions {
224 pub fn new(
226 metadata: RegionMetadataRef,
227 builder: MemtableBuilderRef,
228 next_memtable_id: MemtableId,
229 part_duration: Option<Duration>,
230 ) -> Self {
231 let inner = PartitionsInner::new(next_memtable_id);
232 let primary_key_codec = build_primary_key_codec(&metadata);
233 let bulk_schema = builder.use_bulk_insert(&metadata).then(|| {
234 let opts = FlatSchemaOptions::from_encoding(metadata.primary_key_encoding);
235 to_flat_sst_arrow_schema(&metadata, &opts)
236 });
237
238 Self {
239 inner: Mutex::new(inner),
240 part_duration: part_duration.unwrap_or(INITIAL_TIME_WINDOW),
241 metadata,
242 builder,
243 primary_key_codec,
244 bulk_schema,
245 }
246 }
247
248 pub fn write(&self, kvs: &KeyValues) -> Result<()> {
252 if let Some(bulk_schema) = &self.bulk_schema {
253 let mut converter = BulkPartConverter::new(
254 &self.metadata,
255 bulk_schema.clone(),
256 kvs.num_rows(),
257 self.primary_key_codec.clone(),
258 true,
260 );
261 converter.append_key_values(kvs)?;
262 let part = converter.convert()?;
263
264 return self.write_bulk_inner(part);
265 }
266
267 let parts = self.list_partitions();
269
270 for part in parts.iter().rev() {
273 let mut all_in_partition = true;
274 for kv in kvs.iter() {
275 let ts = kv.timestamp().try_into_timestamp().unwrap().unwrap();
277 if !part.contains_timestamp(ts) {
278 all_in_partition = false;
279 break;
280 }
281 }
282 if !all_in_partition {
283 continue;
284 }
285
286 return part.write(kvs);
288 }
289
290 self.write_multi_parts(kvs, &parts)
292 }
293
294 pub fn write_bulk(&self, part: BulkPart) -> Result<()> {
296 let part = if let Some(bulk_schema) = &self.bulk_schema {
298 let converted = crate::memtable::bulk::part::convert_bulk_part(
299 part,
300 &self.metadata,
301 self.primary_key_codec.clone(),
302 bulk_schema.clone(),
303 true,
305 )?;
306 match converted {
307 Some(p) => p,
308 None => return Ok(()),
309 }
310 } else {
311 part
312 };
313
314 self.write_bulk_inner(part)
315 }
316
317 fn write_bulk_inner(&self, part: BulkPart) -> Result<()> {
319 let time_type = self
320 .metadata
321 .time_index_column()
322 .column_schema
323 .data_type
324 .as_timestamp()
325 .unwrap();
326
327 let parts = self.list_partitions();
329 let (matching_parts, missing_parts) = self.find_partitions_by_time_range(
330 part.timestamps(),
331 &parts,
332 time_type.create_timestamp(part.min_timestamp),
333 time_type.create_timestamp(part.max_timestamp),
334 )?;
335
336 if matching_parts.len() == 1 && missing_parts.is_empty() {
337 return matching_parts[0].write_record_batch(part);
339 }
340
341 for matching in matching_parts {
342 matching.write_record_batch_partial(&part)?
343 }
344
345 for missing in missing_parts {
346 let new_part = {
347 let mut inner = self.inner.lock().unwrap();
348 self.get_or_create_time_partition(missing, &mut inner)?
349 };
350 new_part.write_record_batch_partial(&part)?;
351 }
352 Ok(())
353 }
354
355 fn get_or_create_time_partition(
358 &self,
359 part_start: Timestamp,
360 inner: &mut MutexGuard<PartitionsInner>,
361 ) -> Result<TimePartition> {
362 let part_pos = match inner
363 .parts
364 .iter()
365 .position(|part| part.time_range.min_timestamp == part_start)
366 {
367 Some(pos) => pos,
368 None => {
369 let range = PartTimeRange::from_start_duration(part_start, self.part_duration)
370 .with_context(|| InvalidRequestSnafu {
371 region_id: self.metadata.region_id,
372 reason: format!(
373 "Partition time range for {part_start:?} is out of bound, bucket size: {:?}", self.part_duration
374 ),
375 })?;
376 let memtable = self
377 .builder
378 .build(inner.alloc_memtable_id(), &self.metadata);
379 debug!(
380 "Create time partition {:?} for region {}, duration: {:?}, memtable_id: {}, parts_total: {}, metadata: {:?}",
381 range,
382 self.metadata.region_id,
383 self.part_duration,
384 memtable.id(),
385 inner.parts.len() + 1,
386 self.metadata,
387 );
388 let pos = inner.parts.len();
389 inner.parts.push(TimePartition {
390 memtable,
391 time_range: range,
392 });
393 pos
394 }
395 };
396 Ok(inner.parts[part_pos].clone())
397 }
398
399 pub fn list_memtables(&self, memtables: &mut Vec<MemtableRef>) {
401 let inner = self.inner.lock().unwrap();
402 memtables.extend(inner.parts.iter().map(|part| part.memtable.clone()));
403 }
404
405 pub fn num_partitions(&self) -> usize {
407 let inner = self.inner.lock().unwrap();
408 inner.parts.len()
409 }
410
411 pub fn is_empty(&self) -> bool {
413 let inner = self.inner.lock().unwrap();
414 inner.parts.iter().all(|part| part.memtable.is_empty())
415 }
416
417 pub fn freeze(&self) -> Result<()> {
419 let inner = self.inner.lock().unwrap();
420 for part in &*inner.parts {
421 part.memtable.freeze()?;
422 }
423 Ok(())
424 }
425
426 pub fn fork(&self, metadata: &RegionMetadataRef, part_duration: Option<Duration>) -> Self {
428 let part_duration = part_duration.unwrap_or(self.part_duration);
430
431 let mut inner = self.inner.lock().unwrap();
432 let latest_part = inner
433 .parts
434 .iter()
435 .max_by_key(|part| part.time_range.min_timestamp)
436 .cloned();
437
438 let Some(old_part) = latest_part else {
439 return Self::new(
441 metadata.clone(),
442 self.builder.clone(),
443 inner.next_memtable_id,
444 Some(part_duration),
445 );
446 };
447
448 let old_stats = old_part.memtable.stats();
449 let partitions_inner = old_stats
451 .time_range()
452 .and_then(|(_, old_stats_end_timestamp)| {
453 partition_start_timestamp(old_stats_end_timestamp, part_duration)
454 .and_then(|start| PartTimeRange::from_start_duration(start, part_duration))
455 })
456 .map(|part_time_range| {
457 let memtable = old_part.memtable.fork(inner.alloc_memtable_id(), metadata);
459 let part = TimePartition {
460 memtable,
461 time_range: part_time_range,
462 };
463 PartitionsInner::with_partition(part, inner.next_memtable_id)
464 })
465 .unwrap_or_else(|| PartitionsInner::new(inner.next_memtable_id));
466
467 Self {
468 inner: Mutex::new(partitions_inner),
469 part_duration,
470 metadata: metadata.clone(),
471 builder: self.builder.clone(),
472 primary_key_codec: self.primary_key_codec.clone(),
473 bulk_schema: self.bulk_schema.clone(),
474 }
475 }
476
477 pub(crate) fn part_duration(&self) -> Duration {
479 self.part_duration
480 }
481
482 pub(crate) fn memtable_builder(&self) -> &MemtableBuilderRef {
484 &self.builder
485 }
486
487 pub(crate) fn memory_usage(&self) -> usize {
489 let inner = self.inner.lock().unwrap();
490 inner
491 .parts
492 .iter()
493 .map(|part| part.memtable.stats().estimated_bytes)
494 .sum()
495 }
496
497 pub(crate) fn num_rows(&self) -> u64 {
499 let inner = self.inner.lock().unwrap();
500 inner
501 .parts
502 .iter()
503 .map(|part| part.memtable.stats().num_rows as u64)
504 .sum()
505 }
506
507 pub(crate) fn list_memtables_to_small_vec(&self, memtables: &mut SmallMemtableVec) {
509 let inner = self.inner.lock().unwrap();
510 memtables.extend(inner.parts.iter().map(|part| part.memtable.clone()));
511 }
512
513 pub(crate) fn next_memtable_id(&self) -> MemtableId {
515 let inner = self.inner.lock().unwrap();
516 inner.next_memtable_id
517 }
518
519 pub(crate) fn new_with_part_duration(
522 &self,
523 part_duration: Option<Duration>,
524 memtable_builder: Option<MemtableBuilderRef>,
525 ) -> Self {
526 debug_assert!(self.is_empty());
527
528 Self::new(
529 self.metadata.clone(),
530 memtable_builder.unwrap_or_else(|| self.builder.clone()),
531 self.next_memtable_id(),
532 Some(part_duration.unwrap_or(self.part_duration)),
533 )
534 }
535
536 fn list_partitions(&self) -> PartitionVec {
538 let inner = self.inner.lock().unwrap();
539 inner.parts.clone()
540 }
541
542 fn find_partitions_by_time_range<'a>(
545 &self,
546 ts_array: &ArrayRef,
547 existing_parts: &'a [TimePartition],
548 min: Timestamp,
549 max: Timestamp,
550 ) -> Result<(Vec<&'a TimePartition>, Vec<Timestamp>)> {
551 let mut matching = Vec::new();
552
553 let mut present = HashSet::new();
554 for part in existing_parts {
556 let part_time_range = &part.time_range;
557 if !(max < part_time_range.min_timestamp || min >= part_time_range.max_timestamp) {
558 matching.push(part);
559 present.insert(part_time_range.min_timestamp.value());
560 }
561 }
562
563 let part_duration = self.part_duration_or_default();
565 let timestamp_unit = self.metadata.time_index_type().unit();
566
567 let part_duration_sec = part_duration.as_secs() as i64;
568 let start_bucket = min
570 .convert_to(TimeUnit::Second)
571 .unwrap()
572 .value()
573 .div_euclid(part_duration_sec);
574 let end_bucket = max
575 .convert_to(TimeUnit::Second)
576 .unwrap()
577 .value()
578 .div_euclid(part_duration_sec);
579 let bucket_num = (end_bucket - start_bucket + 1) as usize;
580
581 let num_timestamps = ts_array.len();
582 let missing = if bucket_num <= num_timestamps {
583 (start_bucket..=end_bucket)
584 .filter_map(|start_sec| {
585 let Some(timestamp) = Timestamp::new_second(start_sec * part_duration_sec)
586 .convert_to(timestamp_unit)
587 else {
588 return Some(
589 InvalidRequestSnafu {
590 region_id: self.metadata.region_id,
591 reason: format!("Timestamp out of range: {}", start_sec),
592 }
593 .fail(),
594 );
595 };
596 if present.insert(timestamp.value()) {
597 Some(Ok(timestamp))
598 } else {
599 None
600 }
601 })
602 .collect::<Result<Vec<_>>>()?
603 } else {
604 let ts_primitive = match ts_array.data_type() {
605 DataType::Timestamp(unit, _) => match unit {
606 arrow::datatypes::TimeUnit::Second => ts_array
607 .as_any()
608 .downcast_ref::<TimestampSecondArray>()
609 .unwrap()
610 .reinterpret_cast::<Int64Type>(),
611 arrow::datatypes::TimeUnit::Millisecond => ts_array
612 .as_any()
613 .downcast_ref::<TimestampMillisecondArray>()
614 .unwrap()
615 .reinterpret_cast::<Int64Type>(),
616 arrow::datatypes::TimeUnit::Microsecond => ts_array
617 .as_any()
618 .downcast_ref::<TimestampMicrosecondArray>()
619 .unwrap()
620 .reinterpret_cast::<Int64Type>(),
621 arrow::datatypes::TimeUnit::Nanosecond => ts_array
622 .as_any()
623 .downcast_ref::<TimestampNanosecondArray>()
624 .unwrap()
625 .reinterpret_cast::<Int64Type>(),
626 },
627 _ => unreachable!(),
628 };
629
630 ts_primitive
631 .values()
632 .iter()
633 .filter_map(|ts| {
634 let ts = self.metadata.time_index_type().create_timestamp(*ts);
635 let Some(bucket_start) = ts
636 .convert_to(TimeUnit::Second)
637 .and_then(|ts| ts.align_by_bucket(part_duration_sec))
638 .and_then(|ts| ts.convert_to(timestamp_unit))
639 else {
640 return Some(
641 InvalidRequestSnafu {
642 region_id: self.metadata.region_id,
643 reason: format!("Timestamp out of range: {:?}", ts),
644 }
645 .fail(),
646 );
647 };
648 if present.insert(bucket_start.value()) {
649 Some(Ok(bucket_start))
650 } else {
651 None
652 }
653 })
654 .collect::<Result<Vec<_>>>()?
655 };
656 Ok((matching, missing))
657 }
658
659 fn part_duration_or_default(&self) -> Duration {
661 self.part_duration
662 }
663
664 fn write_multi_parts(&self, kvs: &KeyValues, parts: &PartitionVec) -> Result<()> {
666 let mut parts_to_write = HashMap::new();
667 let mut missing_parts = HashMap::new();
668 for kv in kvs.iter() {
669 let mut part_found = false;
670 let ts = kv.timestamp().try_into_timestamp().unwrap().unwrap();
672 for part in parts {
673 if part.contains_timestamp(ts) {
674 parts_to_write
675 .entry(part.time_range.min_timestamp)
676 .or_insert_with(|| PartitionToWrite {
677 partition: part.clone(),
678 key_values: Vec::new(),
679 })
680 .key_values
681 .push(kv);
682 part_found = true;
683 break;
684 }
685 }
686
687 if !part_found {
688 let part_duration = self.part_duration_or_default();
691 let part_start =
692 partition_start_timestamp(ts, part_duration).with_context(|| {
693 InvalidRequestSnafu {
694 region_id: self.metadata.region_id,
695 reason: format!(
696 "timestamp {ts:?} and bucket {part_duration:?} are out of range"
697 ),
698 }
699 })?;
700 missing_parts
701 .entry(part_start)
702 .or_insert_with(Vec::new)
703 .push(kv);
704 }
705 }
706
707 for part_to_write in parts_to_write.into_values() {
709 for kv in part_to_write.key_values {
710 part_to_write.partition.memtable.write_one(kv)?;
711 }
712 }
713
714 let mut inner = self.inner.lock().unwrap();
717 for (part_start, key_values) in missing_parts {
718 let partition = self.get_or_create_time_partition(part_start, &mut inner)?;
719 for kv in key_values {
720 partition.memtable.write_one(kv)?;
721 }
722 }
723
724 Ok(())
725 }
726
727 pub(crate) fn series_count(&self) -> usize {
729 self.inner.lock().unwrap().series_count()
730 }
731}
732
733fn partition_start_timestamp(ts: Timestamp, bucket: Duration) -> Option<Timestamp> {
737 let ts_sec = ts.convert_to(TimeUnit::Second).unwrap();
739 let bucket_sec: i64 = bucket.as_secs().try_into().ok()?;
740 let start_sec = ts_sec.align_by_bucket(bucket_sec)?;
741 start_sec.convert_to(ts.unit())
742}
743
744#[derive(Debug)]
745struct PartitionsInner {
746 parts: PartitionVec,
748 next_memtable_id: MemtableId,
750}
751
752impl PartitionsInner {
753 fn new(next_memtable_id: MemtableId) -> Self {
754 Self {
755 parts: Default::default(),
756 next_memtable_id,
757 }
758 }
759
760 fn with_partition(part: TimePartition, next_memtable_id: MemtableId) -> Self {
761 Self {
762 parts: smallvec![part],
763 next_memtable_id,
764 }
765 }
766
767 fn alloc_memtable_id(&mut self) -> MemtableId {
768 let id = self.next_memtable_id;
769 self.next_memtable_id += 1;
770 id
771 }
772
773 pub(crate) fn series_count(&self) -> usize {
774 self.parts
775 .iter()
776 .map(|p| p.memtable.stats().series_count)
777 .sum()
778 }
779}
780
781#[derive(Debug, Clone, Copy)]
783struct PartTimeRange {
784 min_timestamp: Timestamp,
786 max_timestamp: Timestamp,
788}
789
790impl PartTimeRange {
791 fn from_start_duration(start: Timestamp, duration: Duration) -> Option<Self> {
792 let start_sec = start.convert_to(TimeUnit::Second)?;
793 let end_sec = start_sec.add_duration(duration).ok()?;
794 let min_timestamp = start_sec.convert_to(start.unit())?;
795 let max_timestamp = end_sec.convert_to(start.unit())?;
796
797 Some(Self {
798 min_timestamp,
799 max_timestamp,
800 })
801 }
802
803 fn contains_timestamp(&self, ts: Timestamp) -> bool {
805 self.min_timestamp <= ts && ts < self.max_timestamp
806 }
807}
808
809struct PartitionToWrite<'a> {
810 partition: TimePartition,
811 key_values: Vec<KeyValue<'a>>,
812}
813
814#[cfg(test)]
815mod tests {
816 use std::sync::Arc;
817
818 use api::v1::SemanticType;
819 use datatypes::arrow::array::{ArrayRef, StringArray, TimestampMillisecondArray};
820 use datatypes::arrow::datatypes::{DataType, Field, Schema};
821 use datatypes::arrow::record_batch::RecordBatch;
822 use datatypes::prelude::ConcreteDataType;
823 use datatypes::schema::ColumnSchema;
824 use store_api::metadata::{ColumnMetadata, RegionMetadataBuilder};
825 use store_api::storage::SequenceNumber;
826
827 use super::*;
828 use crate::memtable::time_series::TimeSeriesMemtableBuilder;
829 use crate::memtable::{IterBuilder, RangesOptions};
830 use crate::test_util::memtable_util::{self, collect_iter_timestamps};
831
832 #[test]
833 fn test_no_duration() {
834 let metadata = memtable_util::metadata_for_test();
835 let builder = Arc::new(TimeSeriesMemtableBuilder::default());
836 let partitions = TimePartitions::new(metadata.clone(), builder, 0, None);
837 assert_eq!(0, partitions.num_partitions());
838 assert!(partitions.is_empty());
839
840 let kvs = memtable_util::build_key_values(
841 &metadata,
842 "hello".to_string(),
843 0,
844 &[1000, 3000, 7000, 5000, 6000],
845 0, );
847 partitions.write(&kvs).unwrap();
848
849 assert_eq!(1, partitions.num_partitions());
850 assert!(!partitions.is_empty());
851 let mut memtables = Vec::new();
852 partitions.list_memtables(&mut memtables);
853 assert_eq!(0, memtables[0].id());
854
855 let iter = memtables[0]
856 .ranges(None, RangesOptions::default())
857 .unwrap()
858 .build(None)
859 .unwrap();
860 let timestamps = collect_iter_timestamps(iter);
861 assert_eq!(&[1000, 3000, 5000, 6000, 7000], ×tamps[..]);
862 }
863
864 #[test]
865 fn test_write_single_part() {
866 let metadata = memtable_util::metadata_for_test();
867 let builder = Arc::new(TimeSeriesMemtableBuilder::default());
868 let partitions =
869 TimePartitions::new(metadata.clone(), builder, 0, Some(Duration::from_secs(10)));
870 assert_eq!(0, partitions.num_partitions());
871
872 let kvs = memtable_util::build_key_values(
873 &metadata,
874 "hello".to_string(),
875 0,
876 &[5000, 2000, 0],
877 0, );
879 partitions.write(&kvs).unwrap();
881 assert_eq!(1, partitions.num_partitions());
882 assert!(!partitions.is_empty());
883
884 let kvs = memtable_util::build_key_values(
885 &metadata,
886 "hello".to_string(),
887 0,
888 &[3000, 7000, 4000],
889 3, );
891 partitions.write(&kvs).unwrap();
893 assert_eq!(1, partitions.num_partitions());
894
895 let mut memtables = Vec::new();
896 partitions.list_memtables(&mut memtables);
897 let iter = memtables[0]
898 .ranges(None, RangesOptions::default())
899 .unwrap()
900 .build(None)
901 .unwrap();
902 let timestamps = collect_iter_timestamps(iter);
903 assert_eq!(&[0, 2000, 3000, 4000, 5000, 7000], ×tamps[..]);
904 let parts = partitions.list_partitions();
905 assert_eq!(
906 Timestamp::new_millisecond(0),
907 parts[0].time_range.min_timestamp
908 );
909 assert_eq!(
910 Timestamp::new_millisecond(10000),
911 parts[0].time_range.max_timestamp
912 );
913 }
914
915 #[cfg(test)]
916 fn new_multi_partitions(metadata: &RegionMetadataRef) -> TimePartitions {
917 let builder = Arc::new(TimeSeriesMemtableBuilder::default());
918 let partitions =
919 TimePartitions::new(metadata.clone(), builder, 0, Some(Duration::from_secs(5)));
920 assert_eq!(0, partitions.num_partitions());
921
922 let kvs = memtable_util::build_key_values(
923 metadata,
924 "hello".to_string(),
925 0,
926 &[2000, 0],
927 0, );
929 partitions.write(&kvs).unwrap();
931 assert_eq!(1, partitions.num_partitions());
932 assert!(!partitions.is_empty());
933
934 let kvs = memtable_util::build_key_values(
935 metadata,
936 "hello".to_string(),
937 0,
938 &[3000, 7000, 4000, 5000],
939 2, );
941 partitions.write(&kvs).unwrap();
943 assert_eq!(2, partitions.num_partitions());
944
945 partitions
946 }
947
948 #[test]
949 fn test_write_multi_parts() {
950 let metadata = memtable_util::metadata_for_test();
951 let partitions = new_multi_partitions(&metadata);
952
953 let parts = partitions.list_partitions();
954 let iter = parts[0]
955 .memtable
956 .ranges(None, RangesOptions::default())
957 .unwrap()
958 .build(None)
959 .unwrap();
960 let timestamps = collect_iter_timestamps(iter);
961 assert_eq!(0, parts[0].memtable.id());
962 assert_eq!(
963 Timestamp::new_millisecond(0),
964 parts[0].time_range.min_timestamp
965 );
966 assert_eq!(
967 Timestamp::new_millisecond(5000),
968 parts[0].time_range.max_timestamp
969 );
970 assert_eq!(&[0, 2000, 3000, 4000], ×tamps[..]);
971 let iter = parts[1]
972 .memtable
973 .ranges(None, RangesOptions::default())
974 .unwrap()
975 .build(None)
976 .unwrap();
977 assert_eq!(1, parts[1].memtable.id());
978 let timestamps = collect_iter_timestamps(iter);
979 assert_eq!(&[5000, 7000], ×tamps[..]);
980 assert_eq!(
981 Timestamp::new_millisecond(5000),
982 parts[1].time_range.min_timestamp
983 );
984 assert_eq!(
985 Timestamp::new_millisecond(10000),
986 parts[1].time_range.max_timestamp
987 );
988 }
989
990 #[test]
991 fn test_new_with_part_duration() {
992 let metadata = memtable_util::metadata_for_test();
993 let builder = Arc::new(TimeSeriesMemtableBuilder::default());
994 let partitions = TimePartitions::new(metadata.clone(), builder.clone(), 0, None);
995
996 let new_parts = partitions.new_with_part_duration(Some(Duration::from_secs(5)), None);
997 assert_eq!(Duration::from_secs(5), new_parts.part_duration());
998 assert_eq!(0, new_parts.next_memtable_id());
999
1000 let new_parts = new_parts.new_with_part_duration(None, None);
1002 assert_eq!(Duration::from_secs(5), new_parts.part_duration());
1003 assert_eq!(0, new_parts.next_memtable_id());
1005
1006 let new_parts = new_parts.new_with_part_duration(Some(Duration::from_secs(10)), None);
1007 assert_eq!(Duration::from_secs(10), new_parts.part_duration());
1008 assert_eq!(0, new_parts.next_memtable_id());
1010
1011 let builder = Arc::new(TimeSeriesMemtableBuilder::default());
1012 let partitions = TimePartitions::new(metadata.clone(), builder.clone(), 0, None);
1013 let new_parts = partitions.new_with_part_duration(None, None);
1015 assert_eq!(INITIAL_TIME_WINDOW, new_parts.part_duration());
1016 assert_eq!(0, new_parts.next_memtable_id());
1017 }
1018
1019 #[test]
1020 fn test_fork_empty() {
1021 let metadata = memtable_util::metadata_for_test();
1022 let builder = Arc::new(TimeSeriesMemtableBuilder::default());
1023 let partitions = TimePartitions::new(metadata.clone(), builder, 0, None);
1024 partitions.freeze().unwrap();
1025 let new_parts = partitions.fork(&metadata, None);
1026 assert_eq!(INITIAL_TIME_WINDOW, new_parts.part_duration());
1027 assert!(new_parts.list_partitions().is_empty());
1028 assert_eq!(0, new_parts.next_memtable_id());
1029
1030 new_parts.freeze().unwrap();
1031 let new_parts = new_parts.fork(&metadata, Some(Duration::from_secs(5)));
1032 assert_eq!(Duration::from_secs(5), new_parts.part_duration());
1033 assert!(new_parts.list_partitions().is_empty());
1034 assert_eq!(0, new_parts.next_memtable_id());
1035
1036 new_parts.freeze().unwrap();
1037 let new_parts = new_parts.fork(&metadata, None);
1038 assert_eq!(Duration::from_secs(5), new_parts.part_duration());
1040 assert!(new_parts.list_partitions().is_empty());
1041 assert_eq!(0, new_parts.next_memtable_id());
1042
1043 new_parts.freeze().unwrap();
1044 let new_parts = new_parts.fork(&metadata, Some(Duration::from_secs(10)));
1045 assert_eq!(Duration::from_secs(10), new_parts.part_duration());
1046 assert!(new_parts.list_partitions().is_empty());
1047 assert_eq!(0, new_parts.next_memtable_id());
1048 }
1049
1050 #[test]
1051 fn test_fork_non_empty_none() {
1052 let metadata = memtable_util::metadata_for_test();
1053 let partitions = new_multi_partitions(&metadata);
1054 partitions.freeze().unwrap();
1055
1056 let new_parts = partitions.fork(&metadata, None);
1058 assert!(new_parts.is_empty());
1059 assert_eq!(Duration::from_secs(5), new_parts.part_duration());
1060 assert_eq!(2, new_parts.list_partitions()[0].memtable.id());
1061 assert_eq!(3, new_parts.next_memtable_id());
1062
1063 let new_parts = partitions.fork(&metadata, Some(Duration::from_secs(10)));
1065 assert!(new_parts.is_empty());
1066 assert_eq!(Duration::from_secs(10), new_parts.part_duration());
1067 assert_eq!(3, new_parts.list_partitions()[0].memtable.id());
1068 assert_eq!(4, new_parts.next_memtable_id());
1069 }
1070
1071 #[test]
1072 fn test_find_partitions_by_time_range() {
1073 let metadata = memtable_util::metadata_for_test();
1074 let builder = Arc::new(TimeSeriesMemtableBuilder::default());
1075
1076 let partitions = TimePartitions::new(metadata.clone(), builder.clone(), 0, None);
1078 let parts = partitions.list_partitions();
1079 let (matching, missing) = partitions
1080 .find_partitions_by_time_range(
1081 &(Arc::new(TimestampMillisecondArray::from_iter_values(1000..=2000)) as ArrayRef),
1082 &parts,
1083 Timestamp::new_millisecond(1000),
1084 Timestamp::new_millisecond(2000),
1085 )
1086 .unwrap();
1087 assert_eq!(matching.len(), 0);
1088 assert_eq!(missing.len(), 1);
1089 assert_eq!(missing[0], Timestamp::new_millisecond(0));
1090
1091 let partitions = TimePartitions::new(
1093 metadata.clone(),
1094 builder.clone(),
1095 0,
1096 Some(Duration::from_secs(5)),
1097 );
1098
1099 let kvs =
1101 memtable_util::build_key_values(&metadata, "hello".to_string(), 0, &[2000, 4000], 0);
1102 partitions.write(&kvs).unwrap();
1103 let kvs =
1104 memtable_util::build_key_values(&metadata, "hello".to_string(), 0, &[7000, 8000], 2);
1105 partitions.write(&kvs).unwrap();
1106
1107 let parts = partitions.list_partitions();
1108 assert_eq!(2, parts.len());
1109
1110 let (matching, missing) = partitions
1112 .find_partitions_by_time_range(
1113 &(Arc::new(TimestampMillisecondArray::from_iter_values(2000..=4000)) as ArrayRef),
1114 &parts,
1115 Timestamp::new_millisecond(2000),
1116 Timestamp::new_millisecond(4000),
1117 )
1118 .unwrap();
1119 assert_eq!(matching.len(), 1);
1120 assert!(missing.is_empty());
1121 assert_eq!(matching[0].time_range.min_timestamp.value(), 0);
1122
1123 let (matching, missing) = partitions
1125 .find_partitions_by_time_range(
1126 &(Arc::new(TimestampMillisecondArray::from_iter_values(3000..=8000)) as ArrayRef),
1127 &parts,
1128 Timestamp::new_millisecond(3000),
1129 Timestamp::new_millisecond(8000),
1130 )
1131 .unwrap();
1132 assert_eq!(matching.len(), 2);
1133 assert!(missing.is_empty());
1134 assert_eq!(matching[0].time_range.min_timestamp.value(), 0);
1135 assert_eq!(matching[1].time_range.min_timestamp.value(), 5000);
1136
1137 let (matching, missing) = partitions
1139 .find_partitions_by_time_range(
1140 &(Arc::new(TimestampMillisecondArray::from_iter_values(12000..=13000)) as ArrayRef),
1141 &parts,
1142 Timestamp::new_millisecond(12000),
1143 Timestamp::new_millisecond(13000),
1144 )
1145 .unwrap();
1146 assert!(matching.is_empty());
1147 assert_eq!(missing.len(), 1);
1148 assert_eq!(missing[0].value(), 10000);
1149
1150 let (matching, missing) = partitions
1152 .find_partitions_by_time_range(
1153 &(Arc::new(TimestampMillisecondArray::from_iter_values(4000..=6000)) as ArrayRef),
1154 &parts,
1155 Timestamp::new_millisecond(4000),
1156 Timestamp::new_millisecond(6000),
1157 )
1158 .unwrap();
1159 assert_eq!(matching.len(), 2);
1160 assert!(missing.is_empty());
1161 assert_eq!(matching[0].time_range.min_timestamp.value(), 0);
1162 assert_eq!(matching[1].time_range.min_timestamp.value(), 5000);
1163
1164 let (matching, missing) = partitions
1166 .find_partitions_by_time_range(
1167 &(Arc::new(TimestampMillisecondArray::from_iter_values(4999..=5000)) as ArrayRef),
1168 &parts,
1169 Timestamp::new_millisecond(4999),
1170 Timestamp::new_millisecond(5000),
1171 )
1172 .unwrap();
1173 assert_eq!(matching.len(), 2);
1174 assert!(missing.is_empty());
1175 assert_eq!(matching[0].time_range.min_timestamp.value(), 0);
1176 assert_eq!(matching[1].time_range.min_timestamp.value(), 5000);
1177
1178 let (matching, missing) = partitions
1180 .find_partitions_by_time_range(
1181 &(Arc::new(TimestampMillisecondArray::from_iter_values(9999..=10000)) as ArrayRef),
1182 &parts,
1183 Timestamp::new_millisecond(9999),
1184 Timestamp::new_millisecond(10000),
1185 )
1186 .unwrap();
1187 assert_eq!(matching.len(), 1);
1188 assert_eq!(1, missing.len());
1189 assert_eq!(matching[0].time_range.min_timestamp.value(), 5000);
1190 assert_eq!(missing[0].value(), 10000);
1191
1192 let (matching, missing) = partitions
1194 .find_partitions_by_time_range(
1195 &(Arc::new(TimestampMillisecondArray::from_iter_values(-1000..=1000)) as ArrayRef),
1196 &parts,
1197 Timestamp::new_millisecond(-1000),
1198 Timestamp::new_millisecond(1000),
1199 )
1200 .unwrap();
1201 assert_eq!(matching.len(), 1);
1202 assert_eq!(matching[0].time_range.min_timestamp.value(), 0);
1203 assert_eq!(1, missing.len());
1204 assert_eq!(missing[0].value(), -5000);
1205
1206 let (matching, missing) = partitions
1208 .find_partitions_by_time_range(
1209 &(Arc::new(TimestampMillisecondArray::from(vec![
1210 -100000000000,
1211 0,
1212 100000000000,
1213 ])) as ArrayRef),
1214 &parts,
1215 Timestamp::new_millisecond(-100000000000),
1216 Timestamp::new_millisecond(100000000000),
1217 )
1218 .unwrap();
1219 assert_eq!(2, matching.len());
1220 assert_eq!(matching[0].time_range.min_timestamp.value(), 0);
1221 assert_eq!(matching[1].time_range.min_timestamp.value(), 5000);
1222 assert_eq!(2, missing.len());
1223 assert_eq!(missing[0].value(), -100000000000);
1224 assert_eq!(missing[1].value(), 100000000000);
1225 }
1226
1227 fn build_part(ts: &[i64], sequence: SequenceNumber) -> BulkPart {
1228 let schema = Arc::new(Schema::new(vec![
1229 Field::new(
1230 "ts",
1231 DataType::Timestamp(arrow::datatypes::TimeUnit::Millisecond, None),
1232 false,
1233 ),
1234 Field::new("val", DataType::Utf8, true),
1235 ]));
1236 let ts_data = ts.to_vec();
1237 let ts_array = Arc::new(TimestampMillisecondArray::from(ts_data));
1238 let val_array = Arc::new(StringArray::from_iter_values(
1239 ts.iter().map(|v| v.to_string()),
1240 ));
1241 let batch = RecordBatch::try_new(
1242 schema,
1243 vec![ts_array.clone() as ArrayRef, val_array.clone() as ArrayRef],
1244 )
1245 .unwrap();
1246 let max_ts = ts.iter().max().copied().unwrap();
1247 let min_ts = ts.iter().min().copied().unwrap();
1248 BulkPart {
1249 batch,
1250 max_timestamp: max_ts,
1251 min_timestamp: min_ts,
1252 sequence,
1253 timestamp_index: 0,
1254 raw_data: None,
1255 }
1256 }
1257
1258 #[test]
1259 fn test_write_bulk() {
1260 let mut metadata_builder = RegionMetadataBuilder::new(0.into());
1261 metadata_builder
1262 .push_column_metadata(ColumnMetadata {
1263 column_schema: ColumnSchema::new(
1264 "ts",
1265 ConcreteDataType::timestamp_millisecond_datatype(),
1266 false,
1267 ),
1268 semantic_type: SemanticType::Timestamp,
1269 column_id: 0,
1270 })
1271 .push_column_metadata(ColumnMetadata {
1272 column_schema: ColumnSchema::new("val", ConcreteDataType::string_datatype(), false),
1273 semantic_type: SemanticType::Field,
1274 column_id: 1,
1275 })
1276 .primary_key(vec![]);
1277 let metadata = Arc::new(metadata_builder.build().unwrap());
1278
1279 let builder = Arc::new(TimeSeriesMemtableBuilder::default());
1280 let partitions = TimePartitions::new(
1281 metadata.clone(),
1282 builder.clone(),
1283 0,
1284 Some(Duration::from_secs(5)),
1285 );
1286
1287 partitions
1289 .write_bulk(build_part(&[1000, 2000, 3000], 0))
1290 .unwrap();
1291
1292 let parts = partitions.list_partitions();
1293 assert_eq!(1, parts.len());
1294 let iter = parts[0]
1295 .memtable
1296 .ranges(None, RangesOptions::default())
1297 .unwrap()
1298 .build(None)
1299 .unwrap();
1300 let timestamps = collect_iter_timestamps(iter);
1301 assert_eq!(&[1000, 2000, 3000], ×tamps[..]);
1302
1303 partitions
1305 .write_bulk(build_part(&[4000, 5000, 6000], 1))
1306 .unwrap();
1307 let parts = partitions.list_partitions();
1308 assert_eq!(2, parts.len());
1309 let iter = parts[0]
1311 .memtable
1312 .ranges(None, RangesOptions::default())
1313 .unwrap()
1314 .build(None)
1315 .unwrap();
1316 let timestamps = collect_iter_timestamps(iter);
1317 assert_eq!(&[1000, 2000, 3000, 4000], ×tamps[..]);
1318 let iter = parts[1]
1320 .memtable
1321 .ranges(None, RangesOptions::default())
1322 .unwrap()
1323 .build(None)
1324 .unwrap();
1325 let timestamps = collect_iter_timestamps(iter);
1326 assert_eq!(&[5000, 6000], ×tamps[..]);
1327
1328 partitions
1330 .write_bulk(build_part(&[11000, 12000], 3))
1331 .unwrap();
1332
1333 let parts = partitions.list_partitions();
1334 assert_eq!(3, parts.len());
1335
1336 let iter = parts[2]
1338 .memtable
1339 .ranges(None, RangesOptions::default())
1340 .unwrap()
1341 .build(None)
1342 .unwrap();
1343 let timestamps = collect_iter_timestamps(iter);
1344 assert_eq!(&[11000, 12000], ×tamps[..]);
1345
1346 let partitions = TimePartitions::new(metadata.clone(), builder, 3, None);
1348
1349 partitions
1350 .write_bulk(build_part(&[1000, 5000, 9000], 4))
1351 .unwrap();
1352
1353 let parts = partitions.list_partitions();
1354 assert_eq!(1, parts.len());
1355 let iter = parts[0]
1356 .memtable
1357 .ranges(None, RangesOptions::default())
1358 .unwrap()
1359 .build(None)
1360 .unwrap();
1361 let timestamps = collect_iter_timestamps(iter);
1362 assert_eq!(&[1000, 5000, 9000], ×tamps[..]);
1363 }
1364
1365 #[test]
1366 fn test_split_record_batch() {
1367 let schema = Arc::new(Schema::new(vec![
1368 Field::new(
1369 "ts",
1370 DataType::Timestamp(TimeUnit::Millisecond.as_arrow_time_unit(), None),
1371 false,
1372 ),
1373 Field::new("val", DataType::Utf8, true),
1374 ]));
1375
1376 let ts_array = Arc::new(TimestampMillisecondArray::from(vec![
1377 1000, 2000, 5000, 7000, 8000,
1378 ]));
1379 let val_array = Arc::new(StringArray::from(vec!["a", "b", "c", "d", "e"]));
1380 let batch = RecordBatch::try_new(
1381 schema.clone(),
1382 vec![ts_array as ArrayRef, val_array as ArrayRef],
1383 )
1384 .unwrap();
1385
1386 let part = BulkPart {
1387 batch,
1388 max_timestamp: 8000,
1389 min_timestamp: 1000,
1390 sequence: 0,
1391 timestamp_index: 0,
1392 raw_data: None,
1393 };
1394
1395 let result = filter_record_batch(&part, 1000, 2000).unwrap();
1396 assert!(result.is_some());
1397 let filtered = result.unwrap();
1398 assert_eq!(filtered.num_rows(), 1);
1399 assert_eq!(filtered.min_timestamp, 1000);
1400 assert_eq!(filtered.max_timestamp, 1000);
1401
1402 let result = filter_record_batch(&part, 3000, 6000).unwrap();
1404 assert!(result.is_some());
1405 let filtered = result.unwrap();
1406 assert_eq!(filtered.num_rows(), 1);
1407 assert_eq!(filtered.min_timestamp, 5000);
1408 assert_eq!(filtered.max_timestamp, 5000);
1409
1410 let result = filter_record_batch(&part, 3000, 4000).unwrap();
1412 assert!(result.is_none());
1413
1414 let result = filter_record_batch(&part, 0, 9000).unwrap();
1416 assert!(result.is_some());
1417 let filtered = result.unwrap();
1418 assert_eq!(filtered.num_rows(), 5);
1419 assert_eq!(filtered.min_timestamp, 1000);
1420 assert_eq!(filtered.max_timestamp, 8000);
1421 }
1422}