1use std::collections::{BTreeMap, BTreeSet, VecDeque};
19use std::pin::Pin;
20use std::slice::from_ref;
21use std::sync::Arc;
22use std::task::{Context, Poll};
23
24use arrow::array::{Array, ArrayRef};
25use arrow::compute::SortColumn;
26use arrow_schema::{DataType, SchemaRef, SortOptions};
27use common_error::ext::{BoxedError, PlainError};
28use common_error::status_code::StatusCode;
29use common_recordbatch::{DfRecordBatch, DfSendableRecordBatchStream};
30use common_telemetry::error;
31use common_time::Timestamp;
32use common_time::timestamp::TimeUnit as TimestampUnit;
33use datafusion::execution::memory_pool::{MemoryConsumer, MemoryPool};
34use datafusion::execution::{RecordBatchStream, TaskContext};
35use datafusion::physical_plan::memory::MemoryStream;
36use datafusion::physical_plan::metrics::{BaselineMetrics, ExecutionPlanMetricsSet, MetricsSet};
37use datafusion::physical_plan::sorts::streaming_merge::StreamingMergeBuilder;
38use datafusion::physical_plan::{
39 DisplayAs, DisplayFormatType, ExecutionPlan, ExecutionPlanProperties, PlanProperties,
40 apply_expression_roots,
41};
42use datafusion_common::tree_node::TreeNodeRecursion;
43use datafusion_common::utils::bisect;
44use datafusion_common::{DataFusionError, internal_err};
45use datafusion_physical_expr::{PhysicalExpr, PhysicalSortExpr};
46use datatypes::value::Value;
47use futures::Stream;
48use itertools::Itertools;
49use snafu::ResultExt;
50use store_api::region_engine::PartitionRange;
51
52use crate::error::{QueryExecutionSnafu, Result};
53
54#[derive(Debug, Clone)]
69pub struct WindowedSortExec {
70 expression: PhysicalSortExpr,
72 fetch: Option<usize>,
74 ranges: Vec<Vec<PartitionRange>>,
78 all_avail_working_range: Vec<Vec<(TimeRange, BTreeSet<usize>)>>,
83 input: Arc<dyn ExecutionPlan>,
84 metrics: ExecutionPlanMetricsSet,
86 properties: Arc<PlanProperties>,
87}
88
89pub fn check_partition_range_monotonicity(
93 ranges: &[Vec<PartitionRange>],
94 descending: bool,
95) -> Result<()> {
96 let is_valid = ranges.iter().all(|r| {
97 if descending {
98 r.windows(2)
100 .all(|w| w[0].end > w[1].end || (w[0].end == w[1].end && w[0].start >= w[1].start))
101 } else {
102 r.windows(2).all(|w| {
104 w[0].start < w[1].start || (w[0].start == w[1].start && w[0].end <= w[1].end)
105 })
106 }
107 });
108
109 if !is_valid {
110 let msg = if descending {
111 "Input `PartitionRange`s are not sorted by (end DESC, start DESC)"
112 } else {
113 "Input `PartitionRange`s are not sorted by (start ASC, end ASC)"
114 };
115 let plain_error = PlainError::new(msg.to_string(), StatusCode::Unexpected);
116 Err(BoxedError::new(plain_error)).context(QueryExecutionSnafu {})
117 } else {
118 Ok(())
119 }
120}
121
122impl WindowedSortExec {
123 pub fn try_new(
124 expression: PhysicalSortExpr,
125 fetch: Option<usize>,
126 ranges: Vec<Vec<PartitionRange>>,
127 input: Arc<dyn ExecutionPlan>,
128 ) -> Result<Self> {
129 check_partition_range_monotonicity(&ranges, expression.options.descending)?;
130
131 let mut eq_properties = input.equivalence_properties().clone();
132 eq_properties.reorder(vec![expression.clone()])?;
133
134 let properties = input.properties();
135 let properties = Arc::new(PlanProperties::new(
136 eq_properties,
137 input.output_partitioning().clone(),
138 properties.emission_type,
139 properties.boundedness,
140 ));
141
142 let mut all_avail_working_range = Vec::with_capacity(ranges.len());
143 for r in &ranges {
144 let overlap_counts = split_overlapping_ranges(r);
145 let working_ranges =
146 compute_all_working_ranges(&overlap_counts, expression.options.descending);
147 all_avail_working_range.push(working_ranges);
148 }
149
150 Ok(Self {
151 expression,
152 fetch,
153 ranges,
154 all_avail_working_range,
155 input,
156 metrics: ExecutionPlanMetricsSet::new(),
157 properties,
158 })
159 }
160
161 pub fn to_stream(
165 &self,
166 context: Arc<TaskContext>,
167 partition: usize,
168 ) -> datafusion_common::Result<DfSendableRecordBatchStream> {
169 let input_stream: DfSendableRecordBatchStream =
170 self.input.execute(partition, context.clone())?;
171
172 let df_stream = Box::pin(WindowedSortStream::new(
173 context,
174 self,
175 input_stream,
176 partition,
177 )) as _;
178
179 Ok(df_stream)
180 }
181}
182
183impl DisplayAs for WindowedSortExec {
184 fn fmt_as(&self, _t: DisplayFormatType, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
185 write!(
186 f,
187 "WindowedSortExec: expr={} num_ranges={}",
188 self.expression,
189 self.ranges.len()
190 )?;
191 if let Some(fetch) = self.fetch {
192 write!(f, " fetch={}", fetch)?;
193 }
194 Ok(())
195 }
196}
197
198impl ExecutionPlan for WindowedSortExec {
199 fn schema(&self) -> SchemaRef {
200 self.input.schema()
201 }
202
203 fn properties(&self) -> &Arc<PlanProperties> {
204 &self.properties
205 }
206
207 fn children(&self) -> Vec<&Arc<dyn ExecutionPlan>> {
208 vec![&self.input]
209 }
210
211 fn apply_expressions(
212 &self,
213 f: &mut dyn FnMut(&Arc<dyn PhysicalExpr>) -> datafusion_common::Result<TreeNodeRecursion>,
214 ) -> datafusion_common::Result<TreeNodeRecursion> {
215 apply_expression_roots([&self.expression.expr], f)
216 }
217
218 fn with_new_children(
219 self: Arc<Self>,
220 children: Vec<Arc<dyn ExecutionPlan>>,
221 ) -> datafusion_common::Result<Arc<dyn ExecutionPlan>> {
222 let new_input = if let Some(first) = children.first() {
223 first
224 } else {
225 internal_err!("No children found")?
226 };
227 let new = Self::try_new(
228 self.expression.clone(),
229 self.fetch,
230 self.ranges.clone(),
231 new_input.clone(),
232 )?;
233 Ok(Arc::new(new))
234 }
235
236 fn execute(
237 &self,
238 partition: usize,
239 context: Arc<TaskContext>,
240 ) -> datafusion_common::Result<DfSendableRecordBatchStream> {
241 self.to_stream(context, partition)
242 }
243
244 fn metrics(&self) -> Option<MetricsSet> {
245 Some(self.metrics.clone_inner())
246 }
247
248 fn benefits_from_input_partitioning(&self) -> Vec<bool> {
254 vec![false]
255 }
256
257 fn name(&self) -> &str {
258 "WindowedSortExec"
259 }
260}
261
262pub struct WindowedSortStream {
269 memory_pool: Arc<dyn MemoryPool>,
271 in_progress: Vec<DfRecordBatch>,
273 last_value: Option<Timestamp>,
275 sorted_input_runs: Vec<DfSendableRecordBatchStream>,
277 merge_stream: VecDeque<DfSendableRecordBatchStream>,
279 merge_count: usize,
281 working_idx: usize,
283 input: DfSendableRecordBatchStream,
285 is_terminated: bool,
287 schema: SchemaRef,
289 expression: PhysicalSortExpr,
291 fetch: Option<usize>,
293 produced: usize,
295 batch_size: usize,
297 all_avail_working_range: Vec<(TimeRange, BTreeSet<usize>)>,
301 #[allow(dead_code)] ranges: Vec<PartitionRange>,
304 metrics: BaselineMetrics,
306}
307
308impl WindowedSortStream {
309 pub fn new(
310 context: Arc<TaskContext>,
311 exec: &WindowedSortExec,
312 input: DfSendableRecordBatchStream,
313 partition: usize,
314 ) -> Self {
315 Self {
316 memory_pool: context.runtime_env().memory_pool.clone(),
317 in_progress: Vec::new(),
318 last_value: None,
319 sorted_input_runs: Vec::new(),
320 merge_stream: VecDeque::new(),
321 merge_count: 0,
322 working_idx: 0,
323 schema: input.schema(),
324 input,
325 is_terminated: false,
326 expression: exec.expression.clone(),
327 fetch: exec.fetch,
328 produced: 0,
329 batch_size: context.session_config().batch_size(),
330 all_avail_working_range: exec.all_avail_working_range[partition].clone(),
331 ranges: exec.ranges[partition].clone(),
332 metrics: BaselineMetrics::new(&exec.metrics, partition),
333 }
334 }
335}
336
337impl WindowedSortStream {
338 #[cfg(debug_assertions)]
339 fn check_subset_ranges(&self, cur_range: &TimeRange) {
340 let cur_is_subset_to = self
341 .ranges
342 .iter()
343 .filter(|r| cur_range.is_subset(&TimeRange::from(*r)))
344 .collect_vec();
345 if cur_is_subset_to.is_empty() {
346 error!("Current range is not a subset of any PartitionRange");
347 let subset_ranges = self
349 .ranges
350 .iter()
351 .filter(|r| TimeRange::from(*r).is_subset(cur_range))
352 .collect_vec();
353 let only_overlap = self
354 .ranges
355 .iter()
356 .filter(|r| {
357 let r = TimeRange::from(*r);
358 r.is_overlapping(cur_range) && !r.is_subset(cur_range)
359 })
360 .collect_vec();
361 error!(
362 "Bad input, found {} ranges that are subset of current range, also found {} ranges that only overlap, subset ranges are: {:?}; overlap ranges are: {:?}",
363 subset_ranges.len(),
364 only_overlap.len(),
365 subset_ranges,
366 only_overlap
367 );
368 } else {
369 let only_overlap = self
370 .ranges
371 .iter()
372 .filter(|r| {
373 let r = TimeRange::from(*r);
374 r.is_overlapping(cur_range) && !cur_range.is_subset(&r)
375 })
376 .collect_vec();
377 error!(
378 "Found current range to be subset of {} ranges, also found {} ranges that only overlap, of subset ranges are:{:?}; overlap ranges are: {:?}",
379 cur_is_subset_to.len(),
380 only_overlap.len(),
381 cur_is_subset_to,
382 only_overlap
383 );
384 }
385 let all_overlap_working_range = self
386 .all_avail_working_range
387 .iter()
388 .filter(|(range, _)| range.is_overlapping(cur_range))
389 .map(|(range, _)| range)
390 .collect_vec();
391 error!(
392 "Found {} working ranges that overlap with current range: {:?}",
393 all_overlap_working_range.len(),
394 all_overlap_working_range
395 );
396 }
397
398 fn poll_result_stream(
400 &mut self,
401 cx: &mut Context<'_>,
402 ) -> Poll<Option<datafusion_common::Result<DfRecordBatch>>> {
403 while let Some(merge_stream) = &mut self.merge_stream.front_mut() {
404 match merge_stream.as_mut().poll_next(cx) {
405 Poll::Ready(Some(Ok(batch))) => {
406 let ret = if let Some(remaining) = self.remaining_fetch() {
407 if remaining == 0 {
408 self.is_terminated = true;
409 None
410 } else if remaining < batch.num_rows() {
411 self.produced += remaining;
412 Some(Ok(batch.slice(0, remaining)))
413 } else {
414 self.produced += batch.num_rows();
415 Some(Ok(batch))
416 }
417 } else {
418 self.produced += batch.num_rows();
419 Some(Ok(batch))
420 };
421 return Poll::Ready(ret);
422 }
423 Poll::Ready(Some(Err(e))) => {
424 return Poll::Ready(Some(Err(e)));
425 }
426 Poll::Ready(None) => {
427 self.merge_stream.pop_front();
430 continue;
431 }
432 Poll::Pending => {
433 return Poll::Pending;
434 }
435 }
436 }
437 Poll::Ready(None)
439 }
440
441 pub fn poll_next_inner(
445 mut self: Pin<&mut Self>,
446 cx: &mut Context<'_>,
447 ) -> Poll<Option<datafusion_common::Result<DfRecordBatch>>> {
448 match self.poll_result_stream(cx) {
450 Poll::Ready(None) => {
451 if self.is_terminated {
452 return Poll::Ready(None);
453 }
454 }
455 x => return x,
456 };
457
458 while !self.is_terminated {
460 let SortedRunSet {
462 runs_with_batch,
463 sort_column,
464 } = match self.input.as_mut().poll_next(cx) {
465 Poll::Ready(Some(Ok(batch))) => split_batch_to_sorted_run(batch, &self.expression)?,
466 Poll::Ready(Some(Err(e))) => {
467 return Poll::Ready(Some(Err(e)));
468 }
469 Poll::Ready(None) => {
470 self.is_terminated = true;
472 self.build_sorted_stream()?;
473 self.start_new_merge_sort()?;
474 break;
475 }
476 Poll::Pending => return Poll::Pending,
477 };
478
479 let mut last_remaining = None;
485 let mut run_iter = runs_with_batch.into_iter();
486 loop {
487 let Some((sorted_rb, run_info)) = last_remaining.take().or(run_iter.next()) else {
488 break;
489 };
490 if sorted_rb.num_rows() == 0 {
491 continue;
492 }
493 let Some(cur_range) = run_info.get_time_range() else {
495 internal_err!("Found NULL in time index column")?
496 };
497 let Some(working_range) = self.get_working_range() else {
498 internal_err!("No working range found")?
499 };
500
501 if sort_column.options.unwrap_or_default().descending {
503 if cur_range.end > working_range.end {
504 error!("Invalid range: {:?} > {:?}", cur_range, working_range);
505 #[cfg(debug_assertions)]
506 self.check_subset_ranges(&cur_range);
507 internal_err!(
508 "Current batch have data on the right side of working range, something is very wrong"
509 )?;
510 }
511 } else if cur_range.start < working_range.start {
512 error!("Invalid range: {:?} < {:?}", cur_range, working_range);
513 #[cfg(debug_assertions)]
514 self.check_subset_ranges(&cur_range);
515 internal_err!(
516 "Current batch have data on the left side of working range, something is very wrong"
517 )?;
518 }
519
520 if cur_range.is_subset(&working_range) {
521 self.try_concat_batch(sorted_rb.clone(), &run_info, sort_column.options)?;
524 } else if let Some(intersection) = cur_range.intersection(&working_range) {
525 let cur_sort_column = sort_column.values.slice(run_info.offset, run_info.len);
527 let (offset, len) = find_slice_from_range(
528 &SortColumn {
529 values: cur_sort_column.clone(),
530 options: sort_column.options,
531 },
532 &intersection,
533 )?;
534
535 if offset != 0 {
536 internal_err!(
537 "Current batch have data on the left side of working range, something is very wrong"
538 )?;
539 }
540
541 let sliced_rb = sorted_rb.slice(offset, len);
542
543 self.try_concat_batch(sliced_rb, &run_info, sort_column.options)?;
545 self.build_sorted_stream()?;
547
548 self.start_new_merge_sort()?;
550
551 let (r_offset, r_len) = (offset + len, sorted_rb.num_rows() - offset - len);
552 if r_len != 0 {
553 let remaining_rb = sorted_rb.slice(r_offset, r_len);
555 let new_first_val = get_timestamp_from_idx(&cur_sort_column, r_offset)?;
556 let new_run_info = SucRun {
557 offset: run_info.offset + r_offset,
558 len: r_len,
559 first_val: new_first_val,
560 last_val: run_info.last_val,
561 };
562 last_remaining = Some((remaining_rb, new_run_info));
563 }
564 } else {
570 self.build_sorted_stream()?;
573 self.start_new_merge_sort()?;
574
575 last_remaining = Some((sorted_rb, run_info));
577 }
578 }
579
580 match self.poll_result_stream(cx) {
582 Poll::Ready(None) => {
583 if self.is_terminated {
584 return Poll::Ready(None);
585 }
586 }
587 x => return x,
588 };
589 }
590 self.poll_result_stream(cx)
592 }
593
594 fn push_batch(&mut self, batch: DfRecordBatch) {
595 self.in_progress.push(batch);
596 }
597
598 fn try_concat_batch(
602 &mut self,
603 batch: DfRecordBatch,
604 run_info: &SucRun<Timestamp>,
605 opt: Option<SortOptions>,
606 ) -> datafusion_common::Result<()> {
607 let is_ok_to_concat =
608 cmp_with_opts(&self.last_value, &run_info.first_val, &opt) <= std::cmp::Ordering::Equal;
609
610 if is_ok_to_concat {
611 self.push_batch(batch);
612 } else {
614 self.build_sorted_stream()?;
616 self.push_batch(batch);
617 }
618 self.last_value = run_info.last_val;
619 Ok(())
620 }
621
622 fn get_working_range(&self) -> Option<TimeRange> {
624 self.all_avail_working_range
625 .get(self.working_idx)
626 .map(|(range, _)| *range)
627 }
628
629 fn set_next_working_range(&mut self) {
631 self.working_idx += 1;
632 }
633
634 fn build_sorted_stream(&mut self) -> datafusion_common::Result<()> {
636 if self.in_progress.is_empty() {
637 return Ok(());
638 }
639 let data = std::mem::take(&mut self.in_progress);
640
641 let new_stream = MemoryStream::try_new(data, self.schema(), None)?;
642 self.sorted_input_runs.push(Box::pin(new_stream));
643 Ok(())
644 }
645
646 fn start_new_merge_sort(&mut self) -> datafusion_common::Result<()> {
648 if !self.in_progress.is_empty() {
649 return internal_err!("Starting a merge sort when in_progress is not empty")?;
650 }
651
652 self.set_next_working_range();
653
654 let streams = std::mem::take(&mut self.sorted_input_runs);
655 if streams.is_empty() {
656 return Ok(());
657 } else if streams.len() == 1 {
658 self.merge_stream
659 .push_back(streams.into_iter().next().unwrap());
660 return Ok(());
661 }
662
663 let fetch = self.remaining_fetch();
664 let reservation = MemoryConsumer::new(format!("WindowedSortStream[{}]", self.merge_count))
665 .register(&self.memory_pool);
666 self.merge_count += 1;
667
668 let resulting_stream = StreamingMergeBuilder::new()
669 .with_streams(streams)
670 .with_schema(self.schema())
671 .with_expressions(&[self.expression.clone()].into())
672 .with_metrics(self.metrics.clone())
673 .with_batch_size(self.batch_size)
674 .with_fetch(fetch)
675 .with_reservation(reservation)
676 .build()?;
677 self.merge_stream.push_back(resulting_stream);
678 Ok(())
680 }
681
682 fn remaining_fetch(&self) -> Option<usize> {
685 let total_now = self.produced;
686 self.fetch.map(|p| p.saturating_sub(total_now))
687 }
688}
689
690impl Stream for WindowedSortStream {
691 type Item = datafusion_common::Result<DfRecordBatch>;
692
693 fn poll_next(
694 mut self: Pin<&mut Self>,
695 cx: &mut Context<'_>,
696 ) -> Poll<Option<datafusion_common::Result<DfRecordBatch>>> {
697 let result = self.as_mut().poll_next_inner(cx);
698 self.metrics.record_poll(result)
699 }
700}
701
702impl RecordBatchStream for WindowedSortStream {
703 fn schema(&self) -> SchemaRef {
704 self.schema.clone()
705 }
706}
707
708fn split_batch_to_sorted_run(
710 batch: DfRecordBatch,
711 expression: &PhysicalSortExpr,
712) -> datafusion_common::Result<SortedRunSet<Timestamp>> {
713 let sort_column = expression.evaluate_to_sort_column(&batch)?;
715 let sorted_runs_offset = get_sorted_runs(sort_column.clone())?;
716 if let Some(run) = sorted_runs_offset.first()
717 && sorted_runs_offset.len() == 1
718 {
719 if !(run.offset == 0 && run.len == batch.num_rows()) {
720 internal_err!(
721 "Invalid run offset and length: offset = {:?}, len = {:?}, num_rows = {:?}",
722 run.offset,
723 run.len,
724 batch.num_rows()
725 )?;
726 }
727 Ok(SortedRunSet {
729 runs_with_batch: vec![(batch, run.clone())],
730 sort_column,
731 })
732 } else {
733 let mut ret = Vec::with_capacity(sorted_runs_offset.len());
735 for run in sorted_runs_offset {
736 if run.offset + run.len > batch.num_rows() {
737 internal_err!(
738 "Invalid run offset and length: offset = {:?}, len = {:?}, num_rows = {:?}",
739 run.offset,
740 run.len,
741 batch.num_rows()
742 )?;
743 }
744 let new_rb = batch.slice(run.offset, run.len);
745 ret.push((new_rb, run));
746 }
747 Ok(SortedRunSet {
748 runs_with_batch: ret,
749 sort_column,
750 })
751 }
752}
753
754#[macro_export]
758macro_rules! downcast_ts_array {
759 ($data_type:expr => ($m:path $(, $args:tt)*), $($p:pat => $fallback:expr $(,)*)*) =>
760 {
761 match $data_type {
762 arrow_schema::DataType::Timestamp(arrow_schema::TimeUnit::Second, _) => {
763 $m!(arrow::datatypes::TimestampSecondType, arrow_schema::TimeUnit::Second $(, $args)*)
764 }
765 arrow_schema::DataType::Timestamp(arrow_schema::TimeUnit::Millisecond, _) => {
766 $m!(arrow::datatypes::TimestampMillisecondType, arrow_schema::TimeUnit::Millisecond $(, $args)*)
767 }
768 arrow_schema::DataType::Timestamp(arrow_schema::TimeUnit::Microsecond, _) => {
769 $m!(arrow::datatypes::TimestampMicrosecondType, arrow_schema::TimeUnit::Microsecond $(, $args)*)
770 }
771 arrow_schema::DataType::Timestamp(arrow_schema::TimeUnit::Nanosecond, _) => {
772 $m!(arrow::datatypes::TimestampNanosecondType, arrow_schema::TimeUnit::Nanosecond $(, $args)*)
773 }
774 $($p => $fallback,)*
775 }
776 };
777}
778
779fn find_slice_from_range(
783 sort_column: &SortColumn,
784 range: &TimeRange,
785) -> datafusion_common::Result<(usize, usize)> {
786 let time_unit = sort_timestamp_unit(sort_column.values.data_type())?;
787 let array = &sort_column.values;
788 let opt = &sort_column.options.unwrap_or_default();
789 let descending = opt.descending;
790 let range = convert_time_range_for_sort(range, time_unit)?;
791
792 let typed_sorted_range = [range.start, range.end]
793 .iter()
794 .map(|t| {
795 t.convert_to(time_unit.into())
796 .ok_or_else(|| {
797 DataFusionError::Internal(format!(
798 "Failed to convert timestamp from {:?} to {:?}",
799 t.unit(),
800 time_unit
801 ))
802 })
803 .and_then(|typed_ts| {
804 let value = Value::Timestamp(typed_ts);
805 value
806 .try_to_scalar_value(&value.data_type())
807 .map_err(|e| DataFusionError::External(Box::new(e) as _))
808 })
809 })
810 .collect::<std::result::Result<Vec<_>, _>>()?;
811
812 let (min_val, max_val) = (typed_sorted_range[0].clone(), typed_sorted_range[1].clone());
813
814 let (start, end) = if descending {
816 let start = bisect::<false>(from_ref(array), from_ref(&max_val), &[*opt])?;
820 let end = bisect::<false>(from_ref(array), from_ref(&min_val), &[*opt])?;
823 (start, end)
824 } else {
825 let start = bisect::<true>(from_ref(array), from_ref(&min_val), &[*opt])?;
828 let end = bisect::<true>(from_ref(array), from_ref(&max_val), &[*opt])?;
831 (start, end)
832 };
833
834 Ok((start, end - start))
835}
836
837fn sort_timestamp_unit(data_type: &DataType) -> datafusion_common::Result<arrow_schema::TimeUnit> {
838 if let DataType::Timestamp(unit, _) = data_type {
839 Ok(*unit)
840 } else {
841 Err(DataFusionError::Internal(format!(
842 "Unsupported sort column type: {data_type}"
843 )))
844 }
845}
846
847#[derive(Debug, Clone, Copy)]
848enum RangeBoundKind {
849 InclusiveStart,
850 ExclusiveEnd,
851}
852
853fn convert_time_range_for_sort(
854 range: &TimeRange,
855 time_unit: arrow_schema::TimeUnit,
856) -> datafusion_common::Result<TimeRange> {
857 let target_unit = time_unit.into();
858 Ok(TimeRange::new(
859 convert_timestamp_range_bound(range.start, target_unit, RangeBoundKind::InclusiveStart)?,
860 convert_timestamp_range_bound(range.end, target_unit, RangeBoundKind::ExclusiveEnd)?,
861 ))
862}
863
864fn convert_timestamp_range_bound(
865 timestamp: Timestamp,
866 target_unit: TimestampUnit,
867 bound_kind: RangeBoundKind,
868) -> datafusion_common::Result<Timestamp> {
869 let converted = match bound_kind {
870 RangeBoundKind::InclusiveStart => timestamp.convert_to(target_unit),
871 RangeBoundKind::ExclusiveEnd => timestamp.convert_to_ceil(target_unit),
872 };
873
874 converted.ok_or_else(|| {
875 DataFusionError::Internal(format!(
876 "Failed to convert timestamp from {:?} to {:?}",
877 timestamp.unit(),
878 target_unit
879 ))
880 })
881}
882
883pub(crate) fn project_partition_range_for_sort(
884 range: PartitionRange,
885 sort_data_type: &DataType,
886) -> datafusion_common::Result<PartitionRange> {
887 let target_unit = sort_timestamp_unit(sort_data_type)?.into();
888 Ok(PartitionRange {
889 start: convert_timestamp_range_bound(
890 range.start,
891 target_unit,
892 RangeBoundKind::InclusiveStart,
893 )?,
894 end: convert_timestamp_range_bound(range.end, target_unit, RangeBoundKind::ExclusiveEnd)?,
895 ..range
896 })
897}
898
899fn discrete_exclusive_end(timestamp: Timestamp) -> Timestamp {
900 Timestamp::new(timestamp.value() + 1, timestamp.unit())
901}
902
903#[macro_export]
907macro_rules! array_iter_helper {
908 ($t:ty, $unit:expr, $arr:expr) => {{
909 let typed = $arr
910 .as_any()
911 .downcast_ref::<arrow::array::PrimitiveArray<$t>>()
912 .unwrap();
913 let iter = typed.iter().enumerate();
914 Box::new(iter) as Box<dyn Iterator<Item = (usize, Option<i64>)>>
915 }};
916}
917
918fn cmp_with_opts<T: Ord>(
922 a: &Option<T>,
923 b: &Option<T>,
924 opt: &Option<SortOptions>,
925) -> std::cmp::Ordering {
926 let opt = opt.unwrap_or_default();
927
928 if let (Some(a), Some(b)) = (a, b) {
929 if opt.descending { b.cmp(a) } else { a.cmp(b) }
930 } else if opt.nulls_first {
931 a.cmp(b)
934 } else {
935 match (a, b) {
936 (Some(a), Some(b)) => a.cmp(b),
937 (Some(_), None) => std::cmp::Ordering::Less,
938 (None, Some(_)) => std::cmp::Ordering::Greater,
939 (None, None) => std::cmp::Ordering::Equal,
940 }
941 }
942}
943
944#[derive(Debug, Clone)]
945struct SortedRunSet<N: Ord> {
946 runs_with_batch: Vec<(DfRecordBatch, SucRun<N>)>,
948 sort_column: SortColumn,
950}
951
952#[derive(Debug, Clone, PartialEq)]
954struct SucRun<N: Ord> {
955 offset: usize,
957 len: usize,
959 first_val: Option<N>,
961 last_val: Option<N>,
963}
964
965impl SucRun<Timestamp> {
966 fn get_time_range(&self) -> Option<TimeRange> {
968 let start = self.first_val.min(self.last_val);
969 let end = self
970 .first_val
971 .max(self.last_val)
972 .map(discrete_exclusive_end);
973 start.zip(end).map(|(s, e)| TimeRange::new(s, e))
974 }
975}
976
977fn find_successive_runs<T: Iterator<Item = (usize, Option<N>)>, N: Ord + Copy>(
979 iter: T,
980 sort_opts: &Option<SortOptions>,
981) -> Vec<SucRun<N>> {
982 let mut runs = Vec::new();
983 let mut last_value = None;
984 let mut iter_len = None;
985
986 let mut last_offset = 0;
987 let mut first_val: Option<N> = None;
988 let mut last_val: Option<N> = None;
989
990 for (idx, t) in iter {
991 if let Some(last_value) = &last_value
992 && cmp_with_opts(last_value, &t, sort_opts) == std::cmp::Ordering::Greater
993 {
994 let len = idx - last_offset;
996 let run = SucRun {
997 offset: last_offset,
998 len,
999 first_val,
1000 last_val,
1001 };
1002 runs.push(run);
1003 first_val = None;
1004 last_val = None;
1005
1006 last_offset = idx;
1007 }
1008 last_value = Some(t);
1009 if let Some(t) = t {
1010 first_val = first_val.or(Some(t));
1011 last_val = Some(t).or(last_val);
1012 }
1013 iter_len = Some(idx);
1014 }
1015 let run = SucRun {
1016 offset: last_offset,
1017 len: iter_len.map(|l| l - last_offset + 1).unwrap_or(0),
1018 first_val,
1019 last_val,
1020 };
1021 runs.push(run);
1022
1023 runs
1024}
1025
1026fn get_sorted_runs(sort_column: SortColumn) -> datafusion_common::Result<Vec<SucRun<Timestamp>>> {
1030 let ty = sort_column.values.data_type();
1031 if let DataType::Timestamp(unit, _) = ty {
1032 let array = &sort_column.values;
1033 let iter = downcast_ts_array!(
1034 array.data_type() => (array_iter_helper, array),
1035 _ => internal_err!("Unsupported sort column type: {ty}")?
1036 );
1037
1038 let raw = find_successive_runs(iter, &sort_column.options);
1039 let ts_runs = raw
1040 .into_iter()
1041 .map(|run| SucRun {
1042 offset: run.offset,
1043 len: run.len,
1044 first_val: run.first_val.map(|v| Timestamp::new(v, unit.into())),
1045 last_val: run.last_val.map(|v| Timestamp::new(v, unit.into())),
1046 })
1047 .collect_vec();
1048 Ok(ts_runs)
1049 } else {
1050 Err(DataFusionError::Internal(format!(
1051 "Unsupported sort column type: {ty}"
1052 )))
1053 }
1054}
1055
1056#[derive(Debug, Clone, Default, Copy, PartialEq, Eq, PartialOrd, Ord)]
1060struct TimeRange {
1061 start: Timestamp,
1062 end: Timestamp,
1063}
1064
1065impl From<&PartitionRange> for TimeRange {
1066 fn from(range: &PartitionRange) -> Self {
1067 Self::new(range.start, range.end)
1068 }
1069}
1070
1071impl From<(Timestamp, Timestamp)> for TimeRange {
1072 fn from(range: (Timestamp, Timestamp)) -> Self {
1073 Self::new(range.0, range.1)
1074 }
1075}
1076
1077impl From<&(Timestamp, Timestamp)> for TimeRange {
1078 fn from(range: &(Timestamp, Timestamp)) -> Self {
1079 Self::new(range.0, range.1)
1080 }
1081}
1082
1083impl TimeRange {
1084 fn new(start: Timestamp, end: Timestamp) -> Self {
1086 if start > end {
1087 Self {
1088 start: end,
1089 end: start,
1090 }
1091 } else {
1092 Self { start, end }
1093 }
1094 }
1095
1096 fn is_subset(&self, other: &Self) -> bool {
1097 self.start >= other.start && self.end <= other.end
1098 }
1099
1100 fn is_overlapping(&self, other: &Self) -> bool {
1102 !(self.start >= other.end || self.end <= other.start)
1103 }
1104
1105 fn intersection(&self, other: &Self) -> Option<Self> {
1106 if self.is_overlapping(other) {
1107 Some(Self::new(
1108 self.start.max(other.start),
1109 self.end.min(other.end),
1110 ))
1111 } else {
1112 None
1113 }
1114 }
1115
1116 fn difference(&self, other: &Self) -> Vec<Self> {
1117 if !self.is_overlapping(other) {
1118 vec![*self]
1119 } else {
1120 let mut ret = Vec::new();
1121 if self.start < other.start && self.end > other.end {
1122 ret.push(Self::new(self.start, other.start));
1123 ret.push(Self::new(other.end, self.end));
1124 } else if self.start < other.start {
1125 ret.push(Self::new(self.start, other.start));
1126 } else if self.end > other.end {
1127 ret.push(Self::new(other.end, self.end));
1128 }
1129 ret
1130 }
1131 }
1132}
1133
1134fn split_range_by(
1136 input_range: &TimeRange,
1137 input_parts: &[usize],
1138 split_by: &TimeRange,
1139 split_idx: usize,
1140) -> Vec<Action> {
1141 let mut ret = Vec::new();
1142 if input_range.is_overlapping(split_by) {
1143 let input_parts = input_parts.to_vec();
1144 let new_parts = {
1145 let mut new_parts = input_parts.clone();
1146 new_parts.push(split_idx);
1147 new_parts
1148 };
1149
1150 ret.push(Action::Pop(*input_range));
1151 if let Some(intersection) = input_range.intersection(split_by) {
1152 ret.push(Action::Push(intersection, new_parts.clone()));
1153 }
1154 for diff in input_range.difference(split_by) {
1155 ret.push(Action::Push(diff, input_parts.clone()));
1156 }
1157 }
1158 ret
1159}
1160
1161#[derive(Debug, Clone, PartialEq, Eq)]
1162enum Action {
1163 Pop(TimeRange),
1164 Push(TimeRange, Vec<usize>),
1165}
1166
1167fn compute_all_working_ranges(
1175 overlap_counts: &BTreeMap<TimeRange, Vec<usize>>,
1176 descending: bool,
1177) -> Vec<(TimeRange, BTreeSet<usize>)> {
1178 let mut ret = Vec::new();
1179 let mut cur_range_set: Option<(TimeRange, BTreeSet<usize>)> = None;
1180 let overlap_iter: Box<dyn Iterator<Item = (&TimeRange, &Vec<usize>)>> = if descending {
1181 Box::new(overlap_counts.iter().rev()) as _
1182 } else {
1183 Box::new(overlap_counts.iter()) as _
1184 };
1185 for (range, set) in overlap_iter {
1186 match &mut cur_range_set {
1187 None => cur_range_set = Some((*range, BTreeSet::from_iter(set.iter().cloned()))),
1188 Some((working_range, working_set)) => {
1189 let need_expand = {
1194 let last_part = working_set.last();
1195 let inter: BTreeSet<usize> = working_set
1196 .intersection(&BTreeSet::from_iter(set.iter().cloned()))
1197 .cloned()
1198 .collect();
1199 if let Some(one) = inter.first()
1200 && inter.len() == 1
1201 && Some(one) == last_part
1202 {
1203 if set.iter().all(|p| Some(p) >= last_part) {
1205 false
1207 } else {
1208 true
1210 }
1211 } else if inter.is_empty() {
1212 false
1214 } else {
1215 true
1217 }
1218 };
1219
1220 if need_expand {
1221 if descending {
1222 working_range.start = range.start;
1223 } else {
1224 working_range.end = range.end;
1225 }
1226 working_set.extend(set.iter().cloned());
1227 } else {
1228 ret.push((*working_range, std::mem::take(working_set)));
1229 cur_range_set = Some((*range, BTreeSet::from_iter(set.iter().cloned())));
1230 }
1231 }
1232 }
1233 }
1234
1235 if let Some(cur_range_set) = cur_range_set {
1236 ret.push(cur_range_set)
1237 }
1238
1239 ret
1240}
1241
1242fn split_overlapping_ranges(ranges: &[PartitionRange]) -> BTreeMap<TimeRange, Vec<usize>> {
1245 let mut ret: BTreeMap<TimeRange, Vec<usize>> = BTreeMap::new();
1247 for (idx, range) in ranges.iter().enumerate() {
1248 let key: TimeRange = (range.start, range.end).into();
1249 let mut actions = Vec::new();
1250 let mut untouched = vec![key];
1251 let forward_iter = ret
1255 .range(key..)
1256 .take_while(|(range, _)| range.is_overlapping(&key));
1257 let backward_iter = ret
1258 .range(..key)
1259 .rev()
1260 .take_while(|(range, _)| range.is_overlapping(&key));
1261
1262 for (range, parts) in forward_iter.chain(backward_iter) {
1263 untouched = untouched.iter().flat_map(|r| r.difference(range)).collect();
1264 let act = split_range_by(range, parts, &key, idx);
1265 actions.extend(act);
1266 }
1267
1268 for action in actions {
1269 match action {
1270 Action::Pop(range) => {
1271 ret.remove(&range);
1272 }
1273 Action::Push(range, parts) => {
1274 ret.insert(range, parts);
1275 }
1276 }
1277 }
1278
1279 for range in untouched {
1281 ret.insert(range, vec![idx]);
1282 }
1283 }
1284 ret
1285}
1286
1287fn get_timestamp_from_idx(
1289 array: &ArrayRef,
1290 offset: usize,
1291) -> datafusion_common::Result<Option<Timestamp>> {
1292 let time_unit = if let DataType::Timestamp(unit, _) = array.data_type() {
1293 unit
1294 } else {
1295 return Err(DataFusionError::Internal(format!(
1296 "Unsupported sort column type: {}",
1297 array.data_type()
1298 )));
1299 };
1300 let ty = array.data_type();
1301 let array = array.slice(offset, 1);
1302 let mut iter = downcast_ts_array!(
1303 array.data_type() => (array_iter_helper, array),
1304 _ => internal_err!("Unsupported sort column type: {ty}")?
1305 );
1306 let (_idx, val) = iter.next().ok_or_else(|| {
1307 DataFusionError::Internal("Empty array in get_timestamp_from".to_string())
1308 })?;
1309 let val = if let Some(val) = val {
1310 val
1311 } else {
1312 return Ok(None);
1313 };
1314 let gt_timestamp = Timestamp::new(val, time_unit.into());
1315 Ok(Some(gt_timestamp))
1316}
1317
1318#[cfg(test)]
1319mod test {
1320 use std::io::Write;
1321 use std::sync::Arc;
1322
1323 use arrow::array::{ArrayRef, TimestampMillisecondArray};
1324 use arrow::compute::concat_batches;
1325 use arrow::json::ArrayWriter;
1326 use arrow_schema::{Field, Schema, TimeUnit};
1327 use futures::StreamExt;
1328 use pretty_assertions::assert_eq;
1329 use serde_json::json;
1330
1331 use super::*;
1332 use crate::test_util::{MockInputExec, new_ts_array};
1333
1334 mod helpers {
1336 use datafusion::physical_plan::expressions::Column;
1337
1338 use super::*;
1339
1340 pub fn default_sort_opts(descending: bool) -> SortOptions {
1341 SortOptions {
1342 descending,
1343 nulls_first: true,
1344 }
1345 }
1346
1347 pub fn ts_field(unit: TimeUnit) -> Field {
1348 Field::new("ts", DataType::Timestamp(unit, None), false)
1349 }
1350
1351 pub fn ts_column() -> Column {
1352 Column::new("ts", 0)
1353 }
1354
1355 pub fn partition_range(start: i64, end: i64, num_rows: usize, id: usize) -> PartitionRange {
1356 PartitionRange {
1357 start: Timestamp::new_millisecond(start),
1358 end: Timestamp::new_millisecond(end),
1359 num_rows,
1360 identifier: id,
1361 }
1362 }
1363
1364 pub fn ts_array(values: impl IntoIterator<Item = i64>) -> ArrayRef {
1365 Arc::new(TimestampMillisecondArray::from_iter_values(values))
1366 }
1367 }
1368
1369 #[test]
1370 fn test_overlapping() {
1371 let testcases = [
1372 (
1373 (Timestamp::new_second(1), Timestamp::new_millisecond(1001)),
1374 (Timestamp::new_second(0), Timestamp::new_millisecond(1)),
1375 false,
1376 ),
1377 (
1378 (Timestamp::new_second(1), Timestamp::new_millisecond(1001)),
1379 (Timestamp::new_second(0), Timestamp::new_millisecond(1001)),
1380 true,
1381 ),
1382 (
1383 (Timestamp::new_second(1), Timestamp::new_millisecond(1001)),
1384 (Timestamp::new_second(0), Timestamp::new_millisecond(1002)),
1385 true,
1386 ),
1387 (
1388 (Timestamp::new_second(1), Timestamp::new_millisecond(1001)),
1389 (
1390 Timestamp::new_millisecond(1000),
1391 Timestamp::new_millisecond(1002),
1392 ),
1393 true,
1394 ),
1395 (
1396 (Timestamp::new_second(1), Timestamp::new_millisecond(1001)),
1397 (
1398 Timestamp::new_millisecond(1001),
1399 Timestamp::new_millisecond(1002),
1400 ),
1401 false,
1402 ),
1403 (
1404 (Timestamp::new_second(1), Timestamp::new_millisecond(1001)),
1405 (
1406 Timestamp::new_millisecond(1002),
1407 Timestamp::new_millisecond(1003),
1408 ),
1409 false,
1410 ),
1411 ];
1412
1413 for (range1, range2, expected) in testcases.iter() {
1414 assert_eq!(
1415 TimeRange::from(range1).is_overlapping(&range2.into()),
1416 *expected,
1417 "range1: {:?}, range2: {:?}",
1418 range1,
1419 range2
1420 );
1421 }
1422 }
1423
1424 #[test]
1425 fn test_split() {
1426 let testcases = [
1427 (
1429 (Timestamp::new_second(1), Timestamp::new_millisecond(1001)),
1430 vec![0],
1431 (Timestamp::new_second(0), Timestamp::new_millisecond(1)),
1432 1,
1433 vec![],
1434 ),
1435 (
1437 (Timestamp::new_second(1), Timestamp::new_millisecond(1001)),
1438 vec![0],
1439 (Timestamp::new_second(0), Timestamp::new_millisecond(1001)),
1440 1,
1441 vec![
1442 Action::Pop(
1443 (Timestamp::new_second(1), Timestamp::new_millisecond(1001)).into(),
1444 ),
1445 Action::Push(
1446 (Timestamp::new_second(1), Timestamp::new_millisecond(1001)).into(),
1447 vec![0, 1],
1448 ),
1449 ],
1450 ),
1451 (
1452 (Timestamp::new_second(1), Timestamp::new_millisecond(1001)),
1453 vec![0],
1454 (Timestamp::new_second(0), Timestamp::new_millisecond(1002)),
1455 1,
1456 vec![
1457 Action::Pop(
1458 (Timestamp::new_second(1), Timestamp::new_millisecond(1001)).into(),
1459 ),
1460 Action::Push(
1461 (Timestamp::new_second(1), Timestamp::new_millisecond(1001)).into(),
1462 vec![0, 1],
1463 ),
1464 ],
1465 ),
1466 (
1467 (Timestamp::new_second(1), Timestamp::new_millisecond(1001)),
1468 vec![0],
1469 (
1470 Timestamp::new_millisecond(1000),
1471 Timestamp::new_millisecond(1002),
1472 ),
1473 1,
1474 vec![
1475 Action::Pop(
1476 (Timestamp::new_second(1), Timestamp::new_millisecond(1001)).into(),
1477 ),
1478 Action::Push(
1479 (
1480 Timestamp::new_millisecond(1000),
1481 Timestamp::new_millisecond(1001),
1482 )
1483 .into(),
1484 vec![0, 1],
1485 ),
1486 ],
1487 ),
1488 (
1490 (Timestamp::new_second(1), Timestamp::new_millisecond(1002)),
1491 vec![0],
1492 (
1493 Timestamp::new_millisecond(1001),
1494 Timestamp::new_millisecond(1002),
1495 ),
1496 1,
1497 vec![
1498 Action::Pop(
1499 (Timestamp::new_second(1), Timestamp::new_millisecond(1002)).into(),
1500 ),
1501 Action::Push(
1502 (
1503 Timestamp::new_millisecond(1001),
1504 Timestamp::new_millisecond(1002),
1505 )
1506 .into(),
1507 vec![0, 1],
1508 ),
1509 Action::Push(
1510 (Timestamp::new_second(1), Timestamp::new_millisecond(1001)).into(),
1511 vec![0],
1512 ),
1513 ],
1514 ),
1515 (
1517 (Timestamp::new_second(1), Timestamp::new_millisecond(1004)),
1518 vec![0],
1519 (
1520 Timestamp::new_millisecond(1001),
1521 Timestamp::new_millisecond(1002),
1522 ),
1523 1,
1524 vec![
1525 Action::Pop(
1526 (Timestamp::new_second(1), Timestamp::new_millisecond(1004)).into(),
1527 ),
1528 Action::Push(
1529 (
1530 Timestamp::new_millisecond(1001),
1531 Timestamp::new_millisecond(1002),
1532 )
1533 .into(),
1534 vec![0, 1],
1535 ),
1536 Action::Push(
1537 (Timestamp::new_second(1), Timestamp::new_millisecond(1001)).into(),
1538 vec![0],
1539 ),
1540 Action::Push(
1541 (
1542 Timestamp::new_millisecond(1002),
1543 Timestamp::new_millisecond(1004),
1544 )
1545 .into(),
1546 vec![0],
1547 ),
1548 ],
1549 ),
1550 ];
1551
1552 for (range, parts, split_by, split_idx, expected) in testcases.iter() {
1553 assert_eq!(
1554 split_range_by(&(*range).into(), parts, &split_by.into(), *split_idx),
1555 *expected,
1556 "range: {:?}, parts: {:?}, split_by: {:?}, split_idx: {}",
1557 range,
1558 parts,
1559 split_by,
1560 split_idx
1561 );
1562 }
1563 }
1564
1565 #[test]
1566 fn test_project_partition_range_for_sort_uses_ceil_on_exclusive_end() {
1567 let range = PartitionRange {
1568 start: Timestamp::new_nanosecond(1_000_000),
1569 end: Timestamp::new_nanosecond(1_000_001),
1570 num_rows: 1,
1571 identifier: 0,
1572 };
1573
1574 let projected = project_partition_range_for_sort(
1575 range,
1576 &DataType::Timestamp(TimeUnit::Millisecond, None),
1577 )
1578 .unwrap();
1579
1580 assert_eq!(Timestamp::new_millisecond(1), projected.start);
1581 assert_eq!(Timestamp::new_millisecond(2), projected.end);
1582 }
1583
1584 #[test]
1585 fn test_find_slice_from_range_preserves_last_row_after_precision_drop() {
1586 let sort_column = SortColumn {
1587 values: Arc::new(TimestampMillisecondArray::from_iter_values([1])) as ArrayRef,
1588 options: Some(SortOptions::default()),
1589 };
1590 let range = TimeRange::new(
1591 Timestamp::new_nanosecond(1_000_000),
1592 Timestamp::new_nanosecond(1_000_001),
1593 );
1594
1595 assert_eq!((0, 1), find_slice_from_range(&sort_column, &range).unwrap());
1596 }
1597
1598 #[test]
1599 fn test_discrete_exclusive_end_creates_half_open_upper_bound() {
1600 let timestamp = Timestamp::new_millisecond(42);
1601
1602 assert_eq!(
1603 Timestamp::new_millisecond(43),
1604 discrete_exclusive_end(timestamp)
1605 );
1606 }
1607
1608 #[allow(clippy::type_complexity)]
1609 fn run_compute_working_ranges_test(
1610 testcases: Vec<(
1611 BTreeMap<(Timestamp, Timestamp), Vec<usize>>,
1612 Vec<((Timestamp, Timestamp), BTreeSet<usize>)>,
1613 )>,
1614 descending: bool,
1615 ) {
1616 for (input, expected) in testcases {
1617 let expected = expected
1618 .into_iter()
1619 .map(|(r, s)| (r.into(), s))
1620 .collect_vec();
1621 let input = input.into_iter().map(|(r, s)| (r.into(), s)).collect();
1622 assert_eq!(
1623 compute_all_working_ranges(&input, descending),
1624 expected,
1625 "input: {:?}, descending: {}",
1626 input,
1627 descending
1628 );
1629 }
1630 }
1631
1632 #[test]
1633 fn test_compute_working_ranges_descending() {
1634 let testcases = vec![
1635 (
1636 BTreeMap::from([(
1637 (Timestamp::new_second(1), Timestamp::new_second(2)),
1638 vec![0],
1639 )]),
1640 vec![(
1641 (Timestamp::new_second(1), Timestamp::new_second(2)),
1642 BTreeSet::from([0]),
1643 )],
1644 ),
1645 (
1646 BTreeMap::from([(
1647 (Timestamp::new_second(1), Timestamp::new_second(2)),
1648 vec![0, 1],
1649 )]),
1650 vec![(
1651 (Timestamp::new_second(1), Timestamp::new_second(2)),
1652 BTreeSet::from([0, 1]),
1653 )],
1654 ),
1655 (
1656 BTreeMap::from([
1657 (
1658 (Timestamp::new_second(2), Timestamp::new_second(3)),
1659 vec![0],
1660 ),
1661 (
1662 (Timestamp::new_second(1), Timestamp::new_second(2)),
1663 vec![0, 1],
1664 ),
1665 ]),
1666 vec![
1667 (
1668 (Timestamp::new_second(2), Timestamp::new_second(3)),
1669 BTreeSet::from([0]),
1670 ),
1671 (
1672 (Timestamp::new_second(1), Timestamp::new_second(2)),
1673 BTreeSet::from([0, 1]),
1674 ),
1675 ],
1676 ),
1677 (
1678 BTreeMap::from([
1679 (
1680 (Timestamp::new_second(2), Timestamp::new_second(3)),
1681 vec![0, 1],
1682 ),
1683 (
1684 (Timestamp::new_second(1), Timestamp::new_second(2)),
1685 vec![1],
1686 ),
1687 ]),
1688 vec![
1689 (
1690 (Timestamp::new_second(2), Timestamp::new_second(3)),
1691 BTreeSet::from([0, 1]),
1692 ),
1693 (
1694 (Timestamp::new_second(1), Timestamp::new_second(2)),
1695 BTreeSet::from([1]),
1696 ),
1697 ],
1698 ),
1699 (
1700 BTreeMap::from([
1701 (
1702 (Timestamp::new_second(3), Timestamp::new_second(4)),
1703 vec![0],
1704 ),
1705 (
1706 (Timestamp::new_second(2), Timestamp::new_second(3)),
1707 vec![0, 1],
1708 ),
1709 (
1710 (Timestamp::new_second(1), Timestamp::new_second(2)),
1711 vec![1],
1712 ),
1713 ]),
1714 vec![
1715 (
1716 (Timestamp::new_second(3), Timestamp::new_second(4)),
1717 BTreeSet::from([0]),
1718 ),
1719 (
1720 (Timestamp::new_second(2), Timestamp::new_second(3)),
1721 BTreeSet::from([0, 1]),
1722 ),
1723 (
1724 (Timestamp::new_second(1), Timestamp::new_second(2)),
1725 BTreeSet::from([1]),
1726 ),
1727 ],
1728 ),
1729 (
1730 BTreeMap::from([
1731 (
1732 (Timestamp::new_second(3), Timestamp::new_second(4)),
1733 vec![0, 2],
1734 ),
1735 (
1736 (Timestamp::new_second(2), Timestamp::new_second(3)),
1737 vec![0, 1, 2],
1738 ),
1739 (
1740 (Timestamp::new_second(1), Timestamp::new_second(2)),
1741 vec![1, 2],
1742 ),
1743 ]),
1744 vec![(
1745 (Timestamp::new_second(1), Timestamp::new_second(4)),
1746 BTreeSet::from([0, 1, 2]),
1747 )],
1748 ),
1749 (
1750 BTreeMap::from([
1751 (
1752 (Timestamp::new_second(2), Timestamp::new_second(3)),
1753 vec![0, 2],
1754 ),
1755 (
1756 (Timestamp::new_second(1), Timestamp::new_second(2)),
1757 vec![1, 2],
1758 ),
1759 ]),
1760 vec![(
1761 (Timestamp::new_second(1), Timestamp::new_second(3)),
1762 BTreeSet::from([0, 1, 2]),
1763 )],
1764 ),
1765 (
1766 BTreeMap::from([
1767 (
1768 (Timestamp::new_second(3), Timestamp::new_second(4)),
1769 vec![0, 1],
1770 ),
1771 (
1772 (Timestamp::new_second(2), Timestamp::new_second(3)),
1773 vec![0, 1, 2],
1774 ),
1775 (
1776 (Timestamp::new_second(1), Timestamp::new_second(2)),
1777 vec![1, 2],
1778 ),
1779 ]),
1780 vec![(
1781 (Timestamp::new_second(1), Timestamp::new_second(4)),
1782 BTreeSet::from([0, 1, 2]),
1783 )],
1784 ),
1785 (
1786 BTreeMap::from([
1787 (
1788 (Timestamp::new_second(2), Timestamp::new_second(3)),
1789 vec![0, 1],
1790 ),
1791 (
1792 (Timestamp::new_second(1), Timestamp::new_second(2)),
1793 vec![1, 2],
1794 ),
1795 ]),
1796 vec![
1797 (
1798 (Timestamp::new_second(2), Timestamp::new_second(3)),
1799 BTreeSet::from([0, 1]),
1800 ),
1801 (
1802 (Timestamp::new_second(1), Timestamp::new_second(2)),
1803 BTreeSet::from([1, 2]),
1804 ),
1805 ],
1806 ),
1807 (
1809 BTreeMap::from([
1810 (
1811 (Timestamp::new_second(2), Timestamp::new_second(3)),
1812 vec![0],
1813 ),
1814 (
1815 (Timestamp::new_second(1), Timestamp::new_second(2)),
1816 vec![1, 2],
1817 ),
1818 ]),
1819 vec![
1820 (
1821 (Timestamp::new_second(2), Timestamp::new_second(3)),
1822 BTreeSet::from([0]),
1823 ),
1824 (
1825 (Timestamp::new_second(1), Timestamp::new_second(2)),
1826 BTreeSet::from([1, 2]),
1827 ),
1828 ],
1829 ),
1830 ];
1831
1832 run_compute_working_ranges_test(testcases, true);
1833 }
1834
1835 #[test]
1836 fn test_compute_working_ranges_ascending() {
1837 let testcases = vec![
1838 (
1839 BTreeMap::from([(
1840 (Timestamp::new_second(1), Timestamp::new_second(2)),
1841 vec![0],
1842 )]),
1843 vec![(
1844 (Timestamp::new_second(1), Timestamp::new_second(2)),
1845 BTreeSet::from([0]),
1846 )],
1847 ),
1848 (
1849 BTreeMap::from([(
1850 (Timestamp::new_second(1), Timestamp::new_second(2)),
1851 vec![0, 1],
1852 )]),
1853 vec![(
1854 (Timestamp::new_second(1), Timestamp::new_second(2)),
1855 BTreeSet::from([0, 1]),
1856 )],
1857 ),
1858 (
1859 BTreeMap::from([
1860 (
1861 (Timestamp::new_second(1), Timestamp::new_second(2)),
1862 vec![0, 1],
1863 ),
1864 (
1865 (Timestamp::new_second(2), Timestamp::new_second(3)),
1866 vec![1],
1867 ),
1868 ]),
1869 vec![
1870 (
1871 (Timestamp::new_second(1), Timestamp::new_second(2)),
1872 BTreeSet::from([0, 1]),
1873 ),
1874 (
1875 (Timestamp::new_second(2), Timestamp::new_second(3)),
1876 BTreeSet::from([1]),
1877 ),
1878 ],
1879 ),
1880 (
1881 BTreeMap::from([
1882 (
1883 (Timestamp::new_second(1), Timestamp::new_second(2)),
1884 vec![0],
1885 ),
1886 (
1887 (Timestamp::new_second(2), Timestamp::new_second(3)),
1888 vec![0, 1],
1889 ),
1890 ]),
1891 vec![
1892 (
1893 (Timestamp::new_second(1), Timestamp::new_second(2)),
1894 BTreeSet::from([0]),
1895 ),
1896 (
1897 (Timestamp::new_second(2), Timestamp::new_second(3)),
1898 BTreeSet::from([0, 1]),
1899 ),
1900 ],
1901 ),
1902 (
1904 BTreeMap::from([
1905 (
1906 (Timestamp::new_second(1), Timestamp::new_second(2)),
1907 vec![0],
1908 ),
1909 (
1910 (Timestamp::new_second(2), Timestamp::new_second(3)),
1911 vec![0, 1],
1912 ),
1913 (
1914 (Timestamp::new_second(3), Timestamp::new_second(4)),
1915 vec![1],
1916 ),
1917 ]),
1918 vec![
1919 (
1920 (Timestamp::new_second(1), Timestamp::new_second(2)),
1921 BTreeSet::from([0]),
1922 ),
1923 (
1924 (Timestamp::new_second(2), Timestamp::new_second(3)),
1925 BTreeSet::from([0, 1]),
1926 ),
1927 (
1928 (Timestamp::new_second(3), Timestamp::new_second(4)),
1929 BTreeSet::from([1]),
1930 ),
1931 ],
1932 ),
1933 (
1934 BTreeMap::from([
1935 (
1936 (Timestamp::new_second(1), Timestamp::new_second(2)),
1937 vec![0, 2],
1938 ),
1939 (
1940 (Timestamp::new_second(2), Timestamp::new_second(3)),
1941 vec![0, 1, 2],
1942 ),
1943 (
1944 (Timestamp::new_second(3), Timestamp::new_second(4)),
1945 vec![1, 2],
1946 ),
1947 ]),
1948 vec![(
1949 (Timestamp::new_second(1), Timestamp::new_second(4)),
1950 BTreeSet::from([0, 1, 2]),
1951 )],
1952 ),
1953 (
1954 BTreeMap::from([
1955 (
1956 (Timestamp::new_second(1), Timestamp::new_second(2)),
1957 vec![0, 2],
1958 ),
1959 (
1960 (Timestamp::new_second(2), Timestamp::new_second(3)),
1961 vec![1, 2],
1962 ),
1963 ]),
1964 vec![(
1965 (Timestamp::new_second(1), Timestamp::new_second(3)),
1966 BTreeSet::from([0, 1, 2]),
1967 )],
1968 ),
1969 (
1970 BTreeMap::from([
1971 (
1972 (Timestamp::new_second(1), Timestamp::new_second(2)),
1973 vec![0, 1],
1974 ),
1975 (
1976 (Timestamp::new_second(2), Timestamp::new_second(3)),
1977 vec![0, 1, 2],
1978 ),
1979 (
1980 (Timestamp::new_second(3), Timestamp::new_second(4)),
1981 vec![1, 2],
1982 ),
1983 ]),
1984 vec![(
1985 (Timestamp::new_second(1), Timestamp::new_second(4)),
1986 BTreeSet::from([0, 1, 2]),
1987 )],
1988 ),
1989 (
1990 BTreeMap::from([
1991 (
1992 (Timestamp::new_second(1), Timestamp::new_second(2)),
1993 vec![0, 1],
1994 ),
1995 (
1996 (Timestamp::new_second(2), Timestamp::new_second(3)),
1997 vec![1, 2],
1998 ),
1999 ]),
2000 vec![
2001 (
2002 (Timestamp::new_second(1), Timestamp::new_second(2)),
2003 BTreeSet::from([0, 1]),
2004 ),
2005 (
2006 (Timestamp::new_second(2), Timestamp::new_second(3)),
2007 BTreeSet::from([1, 2]),
2008 ),
2009 ],
2010 ),
2011 (
2013 BTreeMap::from([
2014 (
2015 (Timestamp::new_second(1), Timestamp::new_second(2)),
2016 vec![0, 1],
2017 ),
2018 (
2019 (Timestamp::new_second(2), Timestamp::new_second(3)),
2020 vec![2],
2021 ),
2022 ]),
2023 vec![
2024 (
2025 (Timestamp::new_second(1), Timestamp::new_second(2)),
2026 BTreeSet::from([0, 1]),
2027 ),
2028 (
2029 (Timestamp::new_second(2), Timestamp::new_second(3)),
2030 BTreeSet::from([2]),
2031 ),
2032 ],
2033 ),
2034 ];
2035
2036 run_compute_working_ranges_test(testcases, false);
2037 }
2038
2039 #[test]
2040 fn test_split_overlap_range() {
2041 let testcases = vec![
2042 (
2044 vec![PartitionRange {
2045 start: Timestamp::new_second(1),
2046 end: Timestamp::new_second(2),
2047 num_rows: 2,
2048 identifier: 0,
2049 }],
2050 BTreeMap::from_iter(
2051 vec![(
2052 (Timestamp::new_second(1), Timestamp::new_second(2)),
2053 vec![0],
2054 )]
2055 .into_iter(),
2056 ),
2057 ),
2058 (
2060 vec![
2061 PartitionRange {
2062 start: Timestamp::new_second(1),
2063 end: Timestamp::new_second(2),
2064 num_rows: 2,
2065 identifier: 0,
2066 },
2067 PartitionRange {
2068 start: Timestamp::new_second(1),
2069 end: Timestamp::new_second(2),
2070 num_rows: 2,
2071 identifier: 1,
2072 },
2073 ],
2074 BTreeMap::from_iter(
2075 vec![(
2076 (Timestamp::new_second(1), Timestamp::new_second(2)),
2077 vec![0, 1],
2078 )]
2079 .into_iter(),
2080 ),
2081 ),
2082 (
2083 vec![
2084 PartitionRange {
2085 start: Timestamp::new_second(1),
2086 end: Timestamp::new_second(3),
2087 num_rows: 2,
2088 identifier: 0,
2089 },
2090 PartitionRange {
2091 start: Timestamp::new_second(2),
2092 end: Timestamp::new_second(4),
2093 num_rows: 2,
2094 identifier: 1,
2095 },
2096 ],
2097 BTreeMap::from_iter(
2098 vec![
2099 (
2100 (Timestamp::new_second(1), Timestamp::new_second(2)),
2101 vec![0],
2102 ),
2103 (
2104 (Timestamp::new_second(2), Timestamp::new_second(3)),
2105 vec![0, 1],
2106 ),
2107 (
2108 (Timestamp::new_second(3), Timestamp::new_second(4)),
2109 vec![1],
2110 ),
2111 ]
2112 .into_iter(),
2113 ),
2114 ),
2115 (
2117 vec![
2118 PartitionRange {
2119 start: Timestamp::new_second(1),
2120 end: Timestamp::new_second(3),
2121 num_rows: 2,
2122 identifier: 0,
2123 },
2124 PartitionRange {
2125 start: Timestamp::new_second(2),
2126 end: Timestamp::new_second(4),
2127 num_rows: 2,
2128 identifier: 1,
2129 },
2130 PartitionRange {
2131 start: Timestamp::new_second(1),
2132 end: Timestamp::new_second(4),
2133 num_rows: 2,
2134 identifier: 2,
2135 },
2136 ],
2137 BTreeMap::from_iter(
2138 vec![
2139 (
2140 (Timestamp::new_second(1), Timestamp::new_second(2)),
2141 vec![0, 2],
2142 ),
2143 (
2144 (Timestamp::new_second(2), Timestamp::new_second(3)),
2145 vec![0, 1, 2],
2146 ),
2147 (
2148 (Timestamp::new_second(3), Timestamp::new_second(4)),
2149 vec![1, 2],
2150 ),
2151 ]
2152 .into_iter(),
2153 ),
2154 ),
2155 (
2156 vec![
2157 PartitionRange {
2158 start: Timestamp::new_second(1),
2159 end: Timestamp::new_second(3),
2160 num_rows: 2,
2161 identifier: 0,
2162 },
2163 PartitionRange {
2164 start: Timestamp::new_second(1),
2165 end: Timestamp::new_second(4),
2166 num_rows: 2,
2167 identifier: 1,
2168 },
2169 PartitionRange {
2170 start: Timestamp::new_second(2),
2171 end: Timestamp::new_second(4),
2172 num_rows: 2,
2173 identifier: 2,
2174 },
2175 ],
2176 BTreeMap::from_iter(
2177 vec![
2178 (
2179 (Timestamp::new_second(1), Timestamp::new_second(2)),
2180 vec![0, 1],
2181 ),
2182 (
2183 (Timestamp::new_second(2), Timestamp::new_second(3)),
2184 vec![0, 1, 2],
2185 ),
2186 (
2187 (Timestamp::new_second(3), Timestamp::new_second(4)),
2188 vec![1, 2],
2189 ),
2190 ]
2191 .into_iter(),
2192 ),
2193 ),
2194 ];
2195
2196 for (input, expected) in testcases {
2197 let expected = expected.into_iter().map(|(r, s)| (r.into(), s)).collect();
2198 assert_eq!(split_overlapping_ranges(&input), expected);
2199 }
2200 }
2201
2202 impl From<(i32, i32, Option<i32>, Option<i32>)> for SucRun<i32> {
2203 fn from((offset, len, min_val, max_val): (i32, i32, Option<i32>, Option<i32>)) -> Self {
2204 Self {
2205 offset: offset as usize,
2206 len: len as usize,
2207 first_val: min_val,
2208 last_val: max_val,
2209 }
2210 }
2211 }
2212
2213 #[test]
2214 fn test_find_successive_runs() {
2215 let testcases = vec![
2216 (
2217 vec![Some(1), Some(1), Some(2), Some(1), Some(3)],
2218 Some(SortOptions {
2219 descending: false,
2220 nulls_first: false,
2221 }),
2222 vec![(0, 3, Some(1), Some(2)), (3, 2, Some(1), Some(3))],
2223 ),
2224 (
2225 vec![Some(1), Some(2), Some(2), Some(1), Some(3)],
2226 Some(SortOptions {
2227 descending: false,
2228 nulls_first: false,
2229 }),
2230 vec![(0, 3, Some(1), Some(2)), (3, 2, Some(1), Some(3))],
2231 ),
2232 (
2233 vec![Some(1), Some(2), None, None, Some(1), Some(3)],
2234 Some(SortOptions {
2235 descending: false,
2236 nulls_first: false,
2237 }),
2238 vec![(0, 4, Some(1), Some(2)), (4, 2, Some(1), Some(3))],
2239 ),
2240 (
2241 vec![Some(1), Some(2), Some(1), Some(3)],
2242 Some(SortOptions {
2243 descending: false,
2244 nulls_first: false,
2245 }),
2246 vec![(0, 2, Some(1), Some(2)), (2, 2, Some(1), Some(3))],
2247 ),
2248 (
2249 vec![Some(1), Some(2), Some(1), Some(3)],
2250 Some(SortOptions {
2251 descending: true,
2252 nulls_first: false,
2253 }),
2254 vec![
2255 (0, 1, Some(1), Some(1)),
2256 (1, 2, Some(2), Some(1)),
2257 (3, 1, Some(3), Some(3)),
2258 ],
2259 ),
2260 (
2261 vec![Some(1), Some(2), None, Some(3)],
2262 Some(SortOptions {
2263 descending: false,
2264 nulls_first: true,
2265 }),
2266 vec![(0, 2, Some(1), Some(2)), (2, 2, Some(3), Some(3))],
2267 ),
2268 (
2269 vec![Some(1), Some(2), None, Some(3)],
2270 Some(SortOptions {
2271 descending: false,
2272 nulls_first: false,
2273 }),
2274 vec![(0, 3, Some(1), Some(2)), (3, 1, Some(3), Some(3))],
2275 ),
2276 (
2277 vec![Some(2), Some(1), None, Some(3)],
2278 Some(SortOptions {
2279 descending: true,
2280 nulls_first: true,
2281 }),
2282 vec![(0, 2, Some(2), Some(1)), (2, 2, Some(3), Some(3))],
2283 ),
2284 (
2285 vec![],
2286 Some(SortOptions {
2287 descending: false,
2288 nulls_first: true,
2289 }),
2290 vec![(0, 0, None, None)],
2291 ),
2292 (
2293 vec![None, None, Some(2), Some(2), Some(1), Some(5), Some(4)],
2294 Some(SortOptions {
2295 descending: true,
2296 nulls_first: true,
2297 }),
2298 vec![(0, 5, Some(2), Some(1)), (5, 2, Some(5), Some(4))],
2299 ),
2300 (
2301 vec![None, None, Some(2), Some(2), Some(1), Some(5), Some(4)],
2302 Some(SortOptions {
2303 descending: true,
2304 nulls_first: false,
2305 }),
2306 vec![
2307 (0, 2, None, None),
2308 (2, 3, Some(2), Some(1)),
2309 (5, 2, Some(5), Some(4)),
2310 ],
2311 ),
2312 ];
2313 for (input, sort_opts, expected) in testcases {
2314 let ret = find_successive_runs(input.clone().into_iter().enumerate(), &sort_opts);
2315 let expected = expected.into_iter().map(SucRun::<i32>::from).collect_vec();
2316 assert_eq!(
2317 ret, expected,
2318 "input: {:?}, opt: {:?},expected: {:?}",
2319 input, sort_opts, expected
2320 );
2321 }
2322 }
2323
2324 #[test]
2325 fn test_cmp_with_opts() {
2326 let testcases = vec![
2327 (
2329 Some(1),
2330 Some(2),
2331 Some(SortOptions {
2332 descending: false,
2333 nulls_first: false,
2334 }),
2335 std::cmp::Ordering::Less,
2336 ),
2337 (
2338 Some(1),
2339 Some(2),
2340 Some(SortOptions {
2341 descending: true,
2342 nulls_first: false,
2343 }),
2344 std::cmp::Ordering::Greater,
2345 ),
2346 (
2348 Some(1),
2349 None,
2350 Some(SortOptions {
2351 descending: false,
2352 nulls_first: true,
2353 }),
2354 std::cmp::Ordering::Greater,
2355 ),
2356 (
2357 Some(1),
2358 None,
2359 Some(SortOptions {
2360 descending: true,
2361 nulls_first: true,
2362 }),
2363 std::cmp::Ordering::Greater,
2364 ),
2365 (
2367 Some(1),
2368 None,
2369 Some(SortOptions {
2370 descending: true,
2371 nulls_first: false,
2372 }),
2373 std::cmp::Ordering::Less,
2374 ),
2375 (
2376 Some(1),
2377 None,
2378 Some(SortOptions {
2379 descending: false,
2380 nulls_first: false,
2381 }),
2382 std::cmp::Ordering::Less,
2383 ),
2384 (
2386 None,
2387 None,
2388 Some(SortOptions {
2389 descending: false,
2390 nulls_first: true,
2391 }),
2392 std::cmp::Ordering::Equal,
2393 ),
2394 ];
2395 for (a, b, opts, expected) in testcases {
2396 assert_eq!(
2397 cmp_with_opts(&a, &b, &opts),
2398 expected,
2399 "a: {:?}, b: {:?}, opts: {:?}",
2400 a,
2401 b,
2402 opts
2403 );
2404 }
2405 }
2406
2407 #[test]
2408 fn test_find_slice_from_range() {
2409 let test_cases = vec![
2410 (
2412 Arc::new(TimestampMillisecondArray::from_iter_values([1, 2, 3, 4, 5])) as ArrayRef,
2413 false,
2414 TimeRange {
2415 start: Timestamp::new_millisecond(2),
2416 end: Timestamp::new_millisecond(4),
2417 },
2418 Ok((1, 2)),
2419 ),
2420 (
2421 Arc::new(TimestampMillisecondArray::from_iter_values([
2422 -2, -1, 0, 1, 2, 3, 4, 5,
2423 ])) as ArrayRef,
2424 false,
2425 TimeRange {
2426 start: Timestamp::new_millisecond(-1),
2427 end: Timestamp::new_millisecond(4),
2428 },
2429 Ok((1, 5)),
2430 ),
2431 (
2432 Arc::new(TimestampMillisecondArray::from_iter_values([1, 3, 4, 6])) as ArrayRef,
2433 false,
2434 TimeRange {
2435 start: Timestamp::new_millisecond(2),
2436 end: Timestamp::new_millisecond(5),
2437 },
2438 Ok((1, 2)),
2439 ),
2440 (
2441 Arc::new(TimestampMillisecondArray::from_iter_values([1, 2, 3, 4, 6])) as ArrayRef,
2442 false,
2443 TimeRange {
2444 start: Timestamp::new_millisecond(2),
2445 end: Timestamp::new_millisecond(5),
2446 },
2447 Ok((1, 3)),
2448 ),
2449 (
2450 Arc::new(TimestampMillisecondArray::from_iter_values([1, 3, 4, 5, 6])) as ArrayRef,
2451 false,
2452 TimeRange {
2453 start: Timestamp::new_millisecond(2),
2454 end: Timestamp::new_millisecond(5),
2455 },
2456 Ok((1, 2)),
2457 ),
2458 (
2459 Arc::new(TimestampMillisecondArray::from_iter_values([1, 2, 3, 4, 5])) as ArrayRef,
2460 false,
2461 TimeRange {
2462 start: Timestamp::new_millisecond(6),
2463 end: Timestamp::new_millisecond(7),
2464 },
2465 Ok((5, 0)),
2466 ),
2467 (
2469 Arc::new(TimestampMillisecondArray::from_iter_values([5, 3, 2, 1])) as ArrayRef,
2470 true,
2471 TimeRange {
2472 end: Timestamp::new_millisecond(4),
2473 start: Timestamp::new_millisecond(1),
2474 },
2475 Ok((1, 3)),
2476 ),
2477 (
2478 Arc::new(TimestampMillisecondArray::from_iter_values([
2479 5, 4, 3, 2, 1, 0,
2480 ])) as ArrayRef,
2481 true,
2482 TimeRange {
2483 end: Timestamp::new_millisecond(4),
2484 start: Timestamp::new_millisecond(1),
2485 },
2486 Ok((2, 3)),
2487 ),
2488 (
2489 Arc::new(TimestampMillisecondArray::from_iter_values([5, 3, 2, 0])) as ArrayRef,
2490 true,
2491 TimeRange {
2492 end: Timestamp::new_millisecond(4),
2493 start: Timestamp::new_millisecond(1),
2494 },
2495 Ok((1, 2)),
2496 ),
2497 (
2498 Arc::new(TimestampMillisecondArray::from_iter_values([5, 4, 3, 2, 0])) as ArrayRef,
2499 true,
2500 TimeRange {
2501 end: Timestamp::new_millisecond(4),
2502 start: Timestamp::new_millisecond(1),
2503 },
2504 Ok((2, 2)),
2505 ),
2506 (
2507 Arc::new(TimestampMillisecondArray::from_iter_values([5, 4, 3, 2, 1])) as ArrayRef,
2508 true,
2509 TimeRange {
2510 end: Timestamp::new_millisecond(5),
2511 start: Timestamp::new_millisecond(2),
2512 },
2513 Ok((1, 3)),
2514 ),
2515 (
2516 Arc::new(TimestampMillisecondArray::from_iter_values([5, 4, 3, 1])) as ArrayRef,
2517 true,
2518 TimeRange {
2519 end: Timestamp::new_millisecond(5),
2520 start: Timestamp::new_millisecond(2),
2521 },
2522 Ok((1, 2)),
2523 ),
2524 (
2525 Arc::new(TimestampMillisecondArray::from_iter_values([6, 4, 3, 2, 1])) as ArrayRef,
2526 true,
2527 TimeRange {
2528 end: Timestamp::new_millisecond(5),
2529 start: Timestamp::new_millisecond(2),
2530 },
2531 Ok((1, 3)),
2532 ),
2533 (
2534 Arc::new(TimestampMillisecondArray::from_iter_values([6, 4, 3, 1])) as ArrayRef,
2535 true,
2536 TimeRange {
2537 end: Timestamp::new_millisecond(5),
2538 start: Timestamp::new_millisecond(2),
2539 },
2540 Ok((1, 2)),
2541 ),
2542 (
2543 Arc::new(TimestampMillisecondArray::from_iter_values([
2544 10, 9, 8, 7, 6,
2545 ])) as ArrayRef,
2546 true,
2547 TimeRange {
2548 end: Timestamp::new_millisecond(5),
2549 start: Timestamp::new_millisecond(2),
2550 },
2551 Ok((5, 0)),
2552 ),
2553 (
2555 Arc::new(TimestampMillisecondArray::from_iter_values([3, 2, 1, 0])) as ArrayRef,
2556 true,
2557 TimeRange {
2558 end: Timestamp::new_millisecond(4),
2559 start: Timestamp::new_millisecond(3),
2560 },
2561 Ok((0, 1)),
2562 ),
2563 (
2564 Arc::new(TimestampMillisecondArray::from_iter_values([5, 3, 2])) as ArrayRef,
2565 true,
2566 TimeRange {
2567 end: Timestamp::new_millisecond(4),
2568 start: Timestamp::new_millisecond(3),
2569 },
2570 Ok((1, 1)),
2571 ),
2572 (
2573 Arc::new(TimestampMillisecondArray::from_iter_values([5, 4, 3, 2])) as ArrayRef,
2574 true,
2575 TimeRange {
2576 end: Timestamp::new_millisecond(4),
2577 start: Timestamp::new_millisecond(3),
2578 },
2579 Ok((2, 1)),
2580 ),
2581 ];
2582
2583 for (sort_vals, descending, range, expected) in test_cases {
2584 let sort_column = SortColumn {
2585 values: sort_vals,
2586 options: Some(SortOptions {
2587 descending,
2588 ..Default::default()
2589 }),
2590 };
2591 let ret = find_slice_from_range(&sort_column, &range);
2592 match (ret, expected) {
2593 (Ok(ret), Ok(expected)) => {
2594 assert_eq!(
2595 ret, expected,
2596 "sort_vals: {:?}, range: {:?}",
2597 sort_column, range
2598 )
2599 }
2600 (Err(err), Err(expected)) => {
2601 let expected: &str = expected;
2602 assert!(
2603 err.to_string().contains(expected),
2604 "err: {:?}, expected: {:?}",
2605 err,
2606 expected
2607 );
2608 }
2609 (r, e) => panic!("unexpected result: {:?}, expected: {:?}", r, e),
2610 }
2611 }
2612 }
2613
2614 #[derive(Debug)]
2615 struct TestStream {
2616 expression: PhysicalSortExpr,
2617 fetch: Option<usize>,
2618 input: Vec<(PartitionRange, DfRecordBatch)>,
2619 output: Vec<DfRecordBatch>,
2620 schema: SchemaRef,
2621 }
2622
2623 impl TestStream {
2624 fn new(
2625 opt: SortOptions,
2626 fetch: Option<usize>,
2627 unit: TimeUnit,
2628 input: Vec<(PartitionRange, Vec<ArrayRef>)>,
2629 expected: Vec<Vec<ArrayRef>>,
2630 ) -> Self {
2631 let expression = PhysicalSortExpr {
2632 expr: Arc::new(helpers::ts_column()),
2633 options: opt,
2634 };
2635 let schema = Schema::new(vec![helpers::ts_field(unit)]);
2636 let schema = Arc::new(schema);
2637 let input = input
2638 .into_iter()
2639 .map(|(k, v)| (k, DfRecordBatch::try_new(schema.clone(), v).unwrap()))
2640 .collect_vec();
2641 let output_batchs = expected
2642 .into_iter()
2643 .map(|v| DfRecordBatch::try_new(schema.clone(), v).unwrap())
2644 .collect_vec();
2645 Self {
2646 expression,
2647 fetch,
2648 input,
2649 output: output_batchs,
2650 schema,
2651 }
2652 }
2653
2654 fn new_simple(
2655 descending: bool,
2656 fetch: Option<usize>,
2657 input: Vec<(PartitionRange, Vec<ArrayRef>)>,
2658 expected: Vec<Vec<ArrayRef>>,
2659 ) -> Self {
2660 Self::new(
2661 helpers::default_sort_opts(descending),
2662 fetch,
2663 TimeUnit::Millisecond,
2664 input,
2665 expected,
2666 )
2667 }
2668
2669 async fn run_test(&self) -> Vec<DfRecordBatch> {
2670 let (ranges, batches): (Vec<_>, Vec<_>) = self.input.clone().into_iter().unzip();
2671
2672 let mock_input = MockInputExec::new(vec![batches], self.schema.clone());
2673
2674 let exec = WindowedSortExec::try_new(
2675 self.expression.clone(),
2676 self.fetch,
2677 vec![ranges],
2678 Arc::new(mock_input),
2679 )
2680 .unwrap();
2681
2682 let exec_stream = exec.execute(0, Arc::new(TaskContext::default())).unwrap();
2683
2684 let real_output = exec_stream.collect::<Vec<_>>().await;
2685 let real_output: Vec<_> = real_output
2686 .into_iter()
2687 .collect::<std::result::Result<Vec<_>, _>>()
2688 .unwrap();
2689 real_output
2690 }
2691 }
2692
2693 #[tokio::test]
2694 async fn test_window_sort_empty_and_minimal() {
2695 use helpers::*;
2696 let test_cases = [
2697 TestStream::new_simple(false, None, vec![], vec![]),
2699 TestStream::new_simple(
2701 false,
2702 None,
2703 vec![
2704 (partition_range(1, 2, 1, 0), vec![ts_array([])]),
2705 (partition_range(1, 3, 1, 0), vec![ts_array([2])]),
2706 ],
2707 vec![vec![ts_array([2])]],
2708 ),
2709 TestStream::new_simple(
2711 false,
2712 None,
2713 vec![
2714 (partition_range(1, 2, 1, 0), vec![ts_array([])]),
2715 (partition_range(1, 3, 1, 0), vec![ts_array([])]),
2716 ],
2717 vec![],
2718 ),
2719 TestStream::new_simple(
2721 false,
2722 None,
2723 vec![
2724 (partition_range(1, 2, 1, 0), vec![ts_array([1])]),
2725 (partition_range(1, 3, 1, 0), vec![ts_array([2])]),
2726 ],
2727 vec![vec![ts_array([1])], vec![ts_array([2])]],
2728 ),
2729 ];
2730
2731 for (idx, testcase) in test_cases.iter().enumerate() {
2732 let output = testcase.run_test().await;
2733 assert_eq!(output, testcase.output, "empty/minimal case {idx} failed");
2734 }
2735 }
2736
2737 #[tokio::test]
2738 async fn test_window_sort_overlapping() {
2739 use helpers::*;
2740 let test_cases = [
2741 TestStream::new_simple(
2743 false,
2744 None,
2745 vec![
2746 (partition_range(1, 3, 1, 0), vec![ts_array([1, 2])]),
2747 (partition_range(1, 4, 1, 0), vec![ts_array([2, 3])]),
2748 ],
2749 vec![
2750 vec![ts_array([1, 2])],
2751 vec![ts_array([2])],
2752 vec![ts_array([3])],
2753 ],
2754 ),
2755 TestStream::new_simple(
2757 false,
2758 None,
2759 vec![
2760 (partition_range(1, 3, 1, 0), vec![ts_array([1, 2])]),
2761 (partition_range(1, 4, 1, 1), vec![ts_array([1, 2, 3])]),
2762 ],
2763 vec![vec![ts_array([1, 1, 2, 2])], vec![ts_array([3])]],
2764 ),
2765 TestStream::new_simple(
2767 false,
2768 None,
2769 vec![
2770 (partition_range(1, 3, 1, 0), vec![ts_array([1, 2])]),
2771 (partition_range(1, 4, 1, 1), vec![ts_array([1, 2, 3])]),
2772 (partition_range(4, 6, 1, 1), vec![ts_array([4, 5])]),
2773 ],
2774 vec![
2775 vec![ts_array([1, 1, 2, 2])],
2776 vec![ts_array([3])],
2777 vec![ts_array([4, 5])],
2778 ],
2779 ),
2780 ];
2781
2782 for (idx, testcase) in test_cases.iter().enumerate() {
2783 let output = testcase.run_test().await;
2784 assert_eq!(output, testcase.output, "overlapping case {idx} failed");
2785 }
2786 }
2787
2788 #[tokio::test]
2789 async fn test_window_sort_with_fetch() {
2790 use helpers::*;
2791 let test_cases = [
2792 TestStream::new_simple(
2794 false,
2795 Some(6),
2796 vec![
2797 (partition_range(1, 3, 1, 0), vec![ts_array([1, 2])]),
2798 (partition_range(1, 4, 1, 1), vec![ts_array([1, 2, 3])]),
2799 (partition_range(3, 6, 1, 1), vec![ts_array([4, 5])]),
2800 ],
2801 vec![
2802 vec![ts_array([1, 1, 2, 2])],
2803 vec![ts_array([3])],
2804 vec![ts_array([4])],
2805 ],
2806 ),
2807 TestStream::new_simple(
2809 false,
2810 Some(3),
2811 vec![
2812 (partition_range(1, 3, 1, 0), vec![ts_array([1, 2])]),
2813 (partition_range(1, 4, 1, 1), vec![ts_array([1, 2, 3])]),
2814 (partition_range(3, 6, 1, 1), vec![ts_array([4, 5])]),
2815 ],
2816 vec![vec![ts_array([1, 1, 2])]],
2817 ),
2818 ];
2819
2820 for (idx, testcase) in test_cases.iter().enumerate() {
2821 let output = testcase.run_test().await;
2822 assert_eq!(output, testcase.output, "fetch case {idx} failed");
2823 }
2824 }
2825
2826 #[tokio::test]
2827 async fn test_window_sort_descending() {
2828 use helpers::*;
2829 let test_cases = [
2830 TestStream::new_simple(
2832 true,
2833 None,
2834 vec![
2835 (partition_range(3, 6, 1, 1), vec![ts_array([5, 4])]),
2836 (partition_range(1, 4, 1, 1), vec![ts_array([3, 2, 1])]),
2837 (partition_range(1, 3, 1, 0), vec![ts_array([2, 1])]),
2838 ],
2839 vec![
2840 vec![ts_array([5, 4])],
2841 vec![ts_array([3])],
2842 vec![ts_array([2, 2, 1, 1])],
2843 ],
2844 ),
2845 ];
2846
2847 for (idx, testcase) in test_cases.iter().enumerate() {
2848 let output = testcase.run_test().await;
2849 assert_eq!(output, testcase.output, "descending case {idx} failed");
2850 }
2851 }
2852
2853 #[tokio::test]
2854 async fn test_window_sort_complex() {
2855 use helpers::*;
2856 let test_cases = [
2857 TestStream::new_simple(
2859 false,
2860 None,
2861 vec![
2862 (partition_range(1, 10, 1, 0), vec![ts_array([1, 5, 9])]),
2863 (partition_range(3, 7, 1, 1), vec![ts_array([3, 4, 5, 6])]),
2864 ],
2865 vec![vec![ts_array([1])], vec![ts_array([3, 4, 5, 5, 6, 9])]],
2866 ),
2867 TestStream::new_simple(
2869 false,
2870 None,
2871 vec![
2872 (partition_range(1, 3, 1, 0), vec![ts_array([1, 2])]),
2873 (
2874 partition_range(1, 10, 1, 1),
2875 vec![ts_array([1, 3, 4, 5, 6, 8])],
2876 ),
2877 (partition_range(7, 10, 1, 1), vec![ts_array([7, 8, 9])]),
2878 ],
2879 vec![
2880 vec![ts_array([1, 1, 2])],
2881 vec![ts_array([3, 4, 5, 6])],
2882 vec![ts_array([7, 8, 8, 9])],
2883 ],
2884 ),
2885 TestStream::new_simple(
2887 false,
2888 None,
2889 vec![
2890 (
2891 partition_range(1, 11, 1, 0),
2892 vec![ts_array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])],
2893 ),
2894 (partition_range(5, 7, 1, 1), vec![ts_array([5, 6])]),
2895 ],
2896 vec![
2897 vec![ts_array([1, 2, 3, 4])],
2898 vec![ts_array([5, 5, 6, 6, 7, 8, 9, 10])],
2899 ],
2900 ),
2901 ];
2902
2903 for (idx, testcase) in test_cases.iter().enumerate() {
2904 let output = testcase.run_test().await;
2905 assert_eq!(output, testcase.output, "complex case {idx} failed");
2906 }
2907 }
2908
2909 #[tokio::test]
2910 async fn fuzzy_ish_test_window_sort_stream() {
2911 let test_cnt = 100;
2912 let part_cnt_bound = 100;
2913 let range_size_bound = 100;
2914 let range_offset_bound = 100;
2915 let in_range_datapoint_cnt_bound = 100;
2916 let fetch_bound = 100;
2917
2918 let mut rng = fastrand::Rng::new();
2919 let rng_seed = rng.u64(..);
2920 rng.seed(rng_seed);
2921 let mut bound_val = None;
2922 type CmpFn<T> = Box<dyn FnMut(&T, &T) -> std::cmp::Ordering>;
2924 let mut full_testcase_list = Vec::new();
2925 for _case_id in 0..test_cnt {
2926 let descending = rng.bool();
2927 fn ret_cmp_fn<T: Ord>(descending: bool) -> CmpFn<T> {
2928 if descending {
2929 return Box::new(|a: &T, b: &T| b.cmp(a));
2930 }
2931 Box::new(|a: &T, b: &T| a.cmp(b))
2932 }
2933 let unit = match rng.u8(0..3) {
2934 0 => TimeUnit::Second,
2935 1 => TimeUnit::Millisecond,
2936 2 => TimeUnit::Microsecond,
2937 _ => TimeUnit::Nanosecond,
2938 };
2939 let fetch = if rng.bool() {
2940 Some(rng.usize(0..fetch_bound))
2941 } else {
2942 None
2943 };
2944
2945 let mut input_ranged_data = vec![];
2946 let mut output_data: Vec<i64> = vec![];
2947 for part_id in 0..rng.usize(0..part_cnt_bound) {
2949 let (start, end) = if descending {
2950 let end = bound_val
2952 .map(|i| i - rng.i64(1..=range_offset_bound))
2953 .unwrap_or_else(|| rng.i64(..));
2954 bound_val = Some(end);
2955 let start = end - rng.i64(1..range_size_bound);
2956 let start = Timestamp::new(start, unit.into());
2957 let end = Timestamp::new(end, unit.into());
2958 (start, end)
2959 } else {
2960 let start = bound_val
2962 .map(|i| i + rng.i64(1..=range_offset_bound))
2963 .unwrap_or_else(|| rng.i64(..));
2964 bound_val = Some(start);
2965 let end = start + rng.i64(1..range_size_bound);
2966 let start = Timestamp::new(start, unit.into());
2967 let end = Timestamp::new(end, unit.into());
2968 (start, end)
2969 };
2970
2971 let iter = 0..rng.usize(0..in_range_datapoint_cnt_bound);
2972 let data_gen = iter
2973 .map(|_| rng.i64(start.value()..end.value()))
2974 .sorted_by(ret_cmp_fn(descending))
2975 .collect_vec();
2976 output_data.extend(data_gen.clone());
2977 let arr = new_ts_array(unit, data_gen);
2978 let range = PartitionRange {
2979 start,
2980 end,
2981 num_rows: arr.len(),
2982 identifier: part_id,
2983 };
2984 input_ranged_data.push((range, vec![arr]));
2985 }
2986
2987 output_data.sort_by(ret_cmp_fn(descending));
2988 if let Some(fetch) = fetch {
2989 output_data.truncate(fetch);
2990 }
2991 let output_arr = new_ts_array(unit, output_data);
2992
2993 let test_stream = TestStream::new(
2994 helpers::default_sort_opts(descending),
2995 fetch,
2996 unit,
2997 input_ranged_data.clone(),
2998 vec![vec![output_arr]],
2999 );
3000 full_testcase_list.push(test_stream);
3001 }
3002
3003 for (case_id, test_stream) in full_testcase_list.into_iter().enumerate() {
3004 let res = test_stream.run_test().await;
3005 let res_concat = concat_batches(&test_stream.schema, &res).unwrap();
3006 let expected = test_stream.output;
3007 let expected_concat = concat_batches(&test_stream.schema, &expected).unwrap();
3008
3009 if res_concat != expected_concat {
3010 {
3011 let mut f_input = std::io::stderr();
3012 f_input.write_all(b"[").unwrap();
3013 for (input_range, input_arr) in test_stream.input {
3014 let range_json = json!({
3015 "start": input_range.start.to_chrono_datetime().unwrap().to_string(),
3016 "end": input_range.end.to_chrono_datetime().unwrap().to_string(),
3017 "num_rows": input_range.num_rows,
3018 "identifier": input_range.identifier,
3019 });
3020 let buf = Vec::new();
3021 let mut input_writer = ArrayWriter::new(buf);
3022 input_writer.write(&input_arr).unwrap();
3023 input_writer.finish().unwrap();
3024 let res_str =
3025 String::from_utf8_lossy(&input_writer.into_inner()).to_string();
3026 let whole_json =
3027 format!(r#"{{"range": {}, "data": {}}},"#, range_json, res_str);
3028 f_input.write_all(whole_json.as_bytes()).unwrap();
3029 }
3030 f_input.write_all(b"]").unwrap();
3031 }
3032 {
3033 let mut f_res = std::io::stderr();
3034 f_res.write_all(b"[").unwrap();
3035 for batch in &res {
3036 let mut res_writer = ArrayWriter::new(f_res);
3037 res_writer.write(batch).unwrap();
3038 res_writer.finish().unwrap();
3039 f_res = res_writer.into_inner();
3040 f_res.write_all(b",").unwrap();
3041 }
3042 f_res.write_all(b"]").unwrap();
3043
3044 let f_res_concat = std::io::stderr();
3045 let mut res_writer = ArrayWriter::new(f_res_concat);
3046 res_writer.write(&res_concat).unwrap();
3047 res_writer.finish().unwrap();
3048
3049 let f_expected = std::io::stderr();
3050 let mut expected_writer = ArrayWriter::new(f_expected);
3051 expected_writer.write(&expected_concat).unwrap();
3052 expected_writer.finish().unwrap();
3053 }
3054 panic!(
3055 "case failed, case id: {0}, output and expected output to stderr",
3056 case_id
3057 );
3058 }
3059 assert_eq!(
3060 res_concat, expected_concat,
3061 "case failed, case id: {}, rng seed: {}",
3062 case_id, rng_seed
3063 );
3064 }
3065 }
3066}