1use std::collections::VecDeque;
16use std::ops::Range;
17
18use educe::Educe;
19use risingwave_common::array::Op;
20use risingwave_common::types::Sentinelled;
21use risingwave_common::util::memcmp_encoding::{self, MemcmpEncoded};
22use risingwave_expr::window_function::{
23 FrameExclusion, RangeFrameBounds, Readiness, RowsFrameBounds, SessionFrameBounds, StateKey,
24 WatermarkBound,
25};
26
27use super::range_utils::{range_diff, range_except};
28
29pub(super) struct WindowBuffer<W: WindowImpl> {
31 window_impl: W,
32 frame_exclusion: FrameExclusion,
33 buffer: VecDeque<Entry<W::Key, W::Value>>,
34 curr_idx: usize,
35 left_idx: usize, right_excl_idx: usize, curr_delta: Option<Vec<(Op, W::Value)>>,
38}
39
40struct Entry<K: Ord, V> {
42 key: K,
43 value: V,
44}
45
46pub(super) struct CurrWindow<'a, K> {
48 pub key: Option<&'a K>,
49
50 #[cfg_attr(not(test), expect(dead_code))]
52 pub preceding_saturated: bool,
54 pub following_saturated: bool,
56}
57
58impl<W: WindowImpl> WindowBuffer<W> {
59 pub fn new(window_impl: W, frame_exclusion: FrameExclusion, enable_delta: bool) -> Self {
60 if enable_delta {
61 assert!(frame_exclusion.is_no_others());
63 }
64
65 Self {
66 window_impl,
67 frame_exclusion,
68 buffer: Default::default(),
69 curr_idx: 0,
70 left_idx: 0,
71 right_excl_idx: 0,
72 curr_delta: if enable_delta {
73 Some(Default::default())
74 } else {
75 None
76 },
77 }
78 }
79
80 pub fn smallest_key(&self) -> Option<&W::Key> {
83 self.buffer.front().map(|Entry { key, .. }| key)
84 }
85
86 pub fn curr_key(&self) -> Option<&W::Key> {
88 self.buffer.get(self.curr_idx).map(|Entry { key, .. }| key)
89 }
90
91 fn buffer_ref(&self) -> BufferRef<'_, W::Key, W::Value> {
92 BufferRef {
93 buffer: &self.buffer,
94 curr_idx: self.curr_idx,
95 left_idx: self.left_idx,
96 right_excl_idx: self.right_excl_idx,
97 }
98 }
99
100 pub fn curr_window(&self) -> CurrWindow<'_, W::Key> {
102 let window = self.buffer_ref();
103 CurrWindow {
104 key: self.curr_key(),
105 preceding_saturated: self.window_impl.preceding_saturated(window),
106 following_saturated: self.window_impl.following_saturated(window),
107 }
108 }
109
110 pub fn readiness(&self) -> Readiness {
112 let window = self.buffer_ref();
113 if self.curr_key().is_none() {
114 Readiness::WaitForInput
115 } else if self.window_impl.closed_by_input(window) {
116 Readiness::Ready
117 } else if let Some(bound) = self.window_impl.watermark_bound(window) {
118 Readiness::OnWatermark(bound)
119 } else {
120 Readiness::WaitForInput
121 }
122 }
123
124 pub fn is_empty(&self) -> bool {
125 self.buffer.is_empty()
126 }
127
128 fn curr_window_outer(&self) -> Range<usize> {
129 self.left_idx..std::cmp::max(self.right_excl_idx, self.left_idx)
130 }
131
132 fn curr_window_exclusion(&self) -> Range<usize> {
133 match self.frame_exclusion {
135 FrameExclusion::CurrentRow => self.curr_idx..self.curr_idx + 1,
136 FrameExclusion::NoOthers => self.curr_idx..self.curr_idx,
137 }
138 }
139
140 fn curr_window_ranges(&self) -> (Range<usize>, Range<usize>) {
141 let selection = self.curr_window_outer();
142 let exclusion = self.curr_window_exclusion();
143 range_except(selection, exclusion)
144 }
145
146 pub fn curr_window_values(&self) -> impl DoubleEndedIterator<Item = &W::Value> {
148 assert!(self.left_idx <= self.buffer.len()); assert!(self.right_excl_idx <= self.buffer.len());
150
151 let (left, right) = self.curr_window_ranges();
152 self.buffer
153 .range(left)
154 .chain(self.buffer.range(right))
155 .map(|Entry { value, .. }| value)
156 }
157
158 pub fn consume_curr_window_values_delta(
161 &mut self,
162 ) -> impl Iterator<Item = (Op, W::Value)> + '_ {
163 self.curr_delta
164 .as_mut()
165 .expect("delta mode should be enabled")
166 .drain(..)
167 }
168
169 pub fn append(&mut self, key: W::Key, value: W::Value) {
171 let old_outer = self.curr_window_outer();
172
173 self.buffer.push_back(Entry { key, value });
174 self.recalculate_left_right(RecalculateHint::Append);
175
176 if self.curr_delta.is_some() {
177 self.maintain_delta(old_outer, self.curr_window_outer());
178 }
179 }
180
181 pub fn slide(&mut self) -> impl Iterator<Item = (W::Key, W::Value)> + '_ {
184 let old_outer = self.curr_window_outer();
185
186 self.curr_idx += 1;
187 self.recalculate_left_right(RecalculateHint::Slide);
188
189 if self.curr_delta.is_some() {
190 self.maintain_delta(old_outer, self.curr_window_outer());
191 }
192
193 let min_needed_idx = [self.left_idx, self.curr_idx, self.right_excl_idx]
194 .iter()
195 .min()
196 .copied()
197 .unwrap();
198 self.curr_idx -= min_needed_idx;
199 self.left_idx -= min_needed_idx;
200 self.right_excl_idx -= min_needed_idx;
201
202 self.window_impl.shift_indices(min_needed_idx);
203
204 self.buffer
205 .drain(0..min_needed_idx)
206 .map(|Entry { key, value }| (key, value))
207 }
208
209 fn maintain_delta(&mut self, old_outer: Range<usize>, new_outer: Range<usize>) {
210 debug_assert!(self.frame_exclusion.is_no_others());
211
212 let (outer_removed, outer_added) = range_diff(old_outer, new_outer);
213 let delta = self.curr_delta.as_mut().unwrap();
214 for idx in outer_removed.iter().cloned().flatten() {
215 delta.push((Op::Delete, self.buffer[idx].value.clone()));
216 }
217 for idx in outer_added.iter().cloned().flatten() {
218 delta.push((Op::Insert, self.buffer[idx].value.clone()));
219 }
220 }
221
222 fn recalculate_left_right(&mut self, hint: RecalculateHint) {
223 let window = BufferRefMut {
224 buffer: &self.buffer,
225 curr_idx: &mut self.curr_idx,
226 left_idx: &mut self.left_idx,
227 right_excl_idx: &mut self.right_excl_idx,
228 };
229 self.window_impl.recalculate_left_right(window, hint);
230 }
231}
232
233#[derive(Educe)]
235#[educe(Clone, Copy)]
236pub(super) struct BufferRef<'a, K: Ord, V: Clone> {
237 buffer: &'a VecDeque<Entry<K, V>>,
238 curr_idx: usize,
239 left_idx: usize,
240 right_excl_idx: usize,
241}
242
243pub(super) struct BufferRefMut<'a, K: Ord, V: Clone> {
245 buffer: &'a VecDeque<Entry<K, V>>,
246 curr_idx: &'a mut usize,
247 left_idx: &'a mut usize,
248 right_excl_idx: &'a mut usize,
249}
250
251#[derive(Clone, Copy, PartialEq, Eq)]
252pub(super) enum RecalculateHint {
253 Append,
254 Slide,
255}
256
257pub(super) trait WindowImpl {
260 type Key: Ord;
261 type Value: Clone;
262
263 fn preceding_saturated(&self, window: BufferRef<'_, Self::Key, Self::Value>) -> bool;
267
268 fn following_saturated(&self, window: BufferRef<'_, Self::Key, Self::Value>) -> bool;
270
271 fn closed_by_input(&self, window: BufferRef<'_, Self::Key, Self::Value>) -> bool {
274 self.following_saturated(window)
275 }
276
277 fn watermark_bound(
282 &self,
283 _window: BufferRef<'_, Self::Key, Self::Value>,
284 ) -> Option<WatermarkBound> {
285 None
286 }
287
288 fn recalculate_left_right(
291 &mut self,
292 window: BufferRefMut<'_, Self::Key, Self::Value>,
293 hint: RecalculateHint,
294 );
295
296 fn shift_indices(&mut self, n: usize);
299}
300
301pub(super) struct RowsWindow<K: Ord, V: Clone> {
303 frame_bounds: RowsFrameBounds,
304 _phantom: std::marker::PhantomData<K>,
305 _phantom2: std::marker::PhantomData<V>,
306}
307
308impl<K: Ord, V: Clone> RowsWindow<K, V> {
309 pub fn new(frame_bounds: RowsFrameBounds) -> Self {
310 Self {
311 frame_bounds,
312 _phantom: std::marker::PhantomData,
313 _phantom2: std::marker::PhantomData,
314 }
315 }
316}
317
318impl<K: Ord, V: Clone> WindowImpl for RowsWindow<K, V> {
319 type Key = K;
320 type Value = V;
321
322 fn preceding_saturated(&self, window: BufferRef<'_, Self::Key, Self::Value>) -> bool {
323 window.curr_idx < window.buffer.len() && {
324 let start_off = self.frame_bounds.start.to_offset();
325 if let Some(start_off) = start_off {
326 if start_off >= 0 {
327 true } else {
329 {
333 assert!(window.curr_idx >= window.left_idx);
334 }
335 window.curr_idx - window.left_idx >= start_off.unsigned_abs()
336 }
337 } else {
338 false }
340 }
341 }
342
343 fn following_saturated(&self, window: BufferRef<'_, Self::Key, Self::Value>) -> bool {
344 window.curr_idx < window.buffer.len() && {
345 let end_off = self.frame_bounds.end.to_offset();
346 if let Some(end_off) = end_off {
347 if end_off <= 0 {
348 true } else {
350 {
353 assert!(window.right_excl_idx > 0);
354 assert!(window.right_excl_idx > window.curr_idx);
355 assert!(window.right_excl_idx <= window.buffer.len());
356 }
357 window.right_excl_idx - 1 - window.curr_idx >= end_off as usize
358 }
359 } else {
360 false }
362 }
363 }
364
365 fn recalculate_left_right(
366 &mut self,
367 window: BufferRefMut<'_, Self::Key, Self::Value>,
368 _hint: RecalculateHint,
369 ) {
370 if window.buffer.is_empty() {
371 *window.left_idx = 0;
372 *window.right_excl_idx = 0;
373 }
374
375 let start_off = self.frame_bounds.start.to_offset();
376 let end_off = self.frame_bounds.end.to_offset();
377 if let Some(start_off) = start_off {
378 let logical_left_idx = *window.curr_idx as isize + start_off;
379 if logical_left_idx >= 0 {
380 *window.left_idx = std::cmp::min(logical_left_idx as usize, window.buffer.len());
381 } else {
382 *window.left_idx = 0;
383 }
384 } else {
385 *window.left_idx = 0;
387 }
388 if let Some(end_off) = end_off {
389 let logical_right_excl_idx = *window.curr_idx as isize + end_off + 1;
390 if logical_right_excl_idx >= 0 {
391 *window.right_excl_idx =
392 std::cmp::min(logical_right_excl_idx as usize, window.buffer.len());
393 } else {
394 *window.right_excl_idx = 0;
395 }
396 } else {
397 *window.right_excl_idx = window.buffer.len();
399 }
400 }
401
402 fn shift_indices(&mut self, _n: usize) {}
403}
404
405pub(super) struct RangeWindow<V: Clone> {
407 frame_bounds: RangeFrameBounds,
408 curr_frame_end: Option<MemcmpEncoded>,
411 _phantom: std::marker::PhantomData<V>,
412}
413
414impl<V: Clone> RangeWindow<V> {
415 pub fn new(frame_bounds: RangeFrameBounds) -> Self {
416 Self {
417 frame_bounds,
418 curr_frame_end: None,
419 _phantom: std::marker::PhantomData,
420 }
421 }
422}
423
424impl<V: Clone> WindowImpl for RangeWindow<V> {
425 type Key = StateKey;
426 type Value = V;
427
428 fn preceding_saturated(&self, window: BufferRef<'_, Self::Key, Self::Value>) -> bool {
429 window.curr_idx < window.buffer.len() && {
430 true
432 }
433 }
434
435 fn following_saturated(&self, window: BufferRef<'_, Self::Key, Self::Value>) -> bool {
436 window.curr_idx < window.buffer.len()
437 && {
438 window.left_idx < window.buffer.len() - 1
444 }
445 && {
446 window.right_excl_idx < window.buffer.len()
448 }
449 }
450
451 fn closed_by_input(&self, window: BufferRef<'_, Self::Key, Self::Value>) -> bool {
452 window.curr_idx < window.buffer.len() && window.right_excl_idx < window.buffer.len()
454 }
455
456 fn watermark_bound(
457 &self,
458 _window: BufferRef<'_, Self::Key, Self::Value>,
459 ) -> Option<WatermarkBound> {
460 if !self.frame_bounds.order_type.is_ascending() {
461 return None;
462 }
463 self.curr_frame_end.clone().map(|value| WatermarkBound {
465 value,
466 exclusive: true,
467 })
468 }
469
470 fn recalculate_left_right(
471 &mut self,
472 window: BufferRefMut<'_, Self::Key, Self::Value>,
473 _hint: RecalculateHint,
474 ) {
475 if window.buffer.is_empty() {
476 *window.left_idx = 0;
477 *window.right_excl_idx = 0;
478 }
479
480 let Some(entry) = window.buffer.get(*window.curr_idx) else {
481 return;
485 };
486 let curr_key = &entry.key;
487
488 let curr_order_value = memcmp_encoding::decode_value(
489 &self.frame_bounds.order_data_type,
490 &curr_key.order_key,
491 self.frame_bounds.order_type,
492 )
493 .expect("no reason to fail here because we just encoded it in memory");
494
495 match self.frame_bounds.frame_start_of(&curr_order_value) {
496 Sentinelled::Smallest => {
497 assert_eq!(
499 *window.left_idx, 0,
500 "for unbounded start, left index should always be 0"
501 );
502 }
503 Sentinelled::Normal(value) => {
504 let value_enc = memcmp_encoding::encode_value(value, self.frame_bounds.order_type)
506 .expect("no reason to fail here");
507 *window.left_idx = window
508 .buffer
509 .partition_point(|elem| elem.key.order_key < value_enc);
510 }
511 Sentinelled::Largest => unreachable!("frame start never be UNBOUNDED FOLLOWING"),
512 }
513
514 match self.frame_bounds.frame_end_of(curr_order_value) {
515 Sentinelled::Largest => {
516 *window.right_excl_idx = window.buffer.len();
518 self.curr_frame_end = None;
519 }
520 Sentinelled::Normal(value) => {
521 let value_enc = memcmp_encoding::encode_value(value, self.frame_bounds.order_type)
523 .expect("no reason to fail here");
524 *window.right_excl_idx = window
525 .buffer
526 .partition_point(|elem| elem.key.order_key <= value_enc);
527 self.curr_frame_end = Some(value_enc);
528 }
529 Sentinelled::Smallest => unreachable!("frame end never be UNBOUNDED PRECEDING"),
530 }
531 }
532
533 fn shift_indices(&mut self, _n: usize) {}
534}
535
536pub(super) struct SessionWindow<V: Clone> {
537 frame_bounds: SessionFrameBounds,
538 latest_session: Option<LatestSession>,
540 recognized_session_sizes: VecDeque<usize>,
544 _phantom: std::marker::PhantomData<V>,
545}
546
547#[derive(Debug)]
548struct LatestSession {
549 start_idx: usize,
551
552 minimal_next_start: MemcmpEncoded,
555}
556
557impl<V: Clone> SessionWindow<V> {
558 pub fn new(frame_bounds: SessionFrameBounds) -> Self {
559 Self {
560 frame_bounds,
561 latest_session: None,
562 recognized_session_sizes: Default::default(),
563 _phantom: std::marker::PhantomData,
564 }
565 }
566}
567
568impl<V: Clone> WindowImpl for SessionWindow<V> {
569 type Key = StateKey;
570 type Value = V;
571
572 fn preceding_saturated(&self, window: BufferRef<'_, Self::Key, Self::Value>) -> bool {
573 window.curr_idx < window.buffer.len() && {
574 true
576 }
577 }
578
579 fn following_saturated(&self, window: BufferRef<'_, Self::Key, Self::Value>) -> bool {
580 window.curr_idx < window.buffer.len() && {
581 assert!(window.left_idx <= window.curr_idx);
583 assert!(window.curr_idx < window.right_excl_idx);
584
585 self.latest_session
589 .as_ref()
590 .is_some_and(|LatestSession { start_idx, .. }| window.left_idx < *start_idx)
591 }
592 }
593
594 fn watermark_bound(
595 &self,
596 _window: BufferRef<'_, Self::Key, Self::Value>,
597 ) -> Option<WatermarkBound> {
598 if !self.frame_bounds.order_type.is_ascending() {
599 return None;
600 }
601 self.latest_session.as_ref().map(
604 |LatestSession {
605 minimal_next_start, ..
606 }| WatermarkBound {
607 value: minimal_next_start.clone(),
608 exclusive: false,
609 },
610 )
611 }
612
613 fn recalculate_left_right(
614 &mut self,
615 window: BufferRefMut<'_, Self::Key, Self::Value>,
616 hint: RecalculateHint,
617 ) {
618 match hint {
627 RecalculateHint::Append => {
628 assert!(!window.buffer.is_empty()); let appended_idx = window.buffer.len() - 1;
630 let appended_key = &window.buffer[appended_idx].key;
631
632 let minimal_next_start_of_appended = self.frame_bounds.minimal_next_start_of(
633 memcmp_encoding::decode_value(
634 &self.frame_bounds.order_data_type,
635 &appended_key.order_key,
636 self.frame_bounds.order_type,
637 )
638 .expect("no reason to fail here because we just encoded it in memory"),
639 );
640 let minimal_next_start_enc_of_appended = memcmp_encoding::encode_value(
641 minimal_next_start_of_appended,
642 self.frame_bounds.order_type,
643 )
644 .expect("no reason to fail here");
645
646 if let Some(&mut LatestSession {
647 ref start_idx,
648 ref mut minimal_next_start,
649 }) = self.latest_session.as_mut()
650 {
651 if &appended_key.order_key >= minimal_next_start {
652 self.recognized_session_sizes
654 .push_back(appended_idx - start_idx);
655 self.latest_session = Some(LatestSession {
656 start_idx: appended_idx,
657 minimal_next_start: minimal_next_start_enc_of_appended,
658 });
659 } else {
662 *minimal_next_start = minimal_next_start_enc_of_appended;
664
665 if *start_idx == *window.left_idx {
666 *window.right_excl_idx = appended_idx + 1;
668 }
669 }
670 } else {
671 let left_idx = *window.left_idx;
673 let curr_idx = *window.curr_idx;
674 let old_right_excl_idx = *window.right_excl_idx;
675 assert_eq!(left_idx, curr_idx);
676 assert_eq!(left_idx, old_right_excl_idx);
677 assert_eq!(old_right_excl_idx, window.buffer.len() - 1);
678
679 *window.right_excl_idx = window.buffer.len();
681
682 self.latest_session = Some(LatestSession {
684 start_idx: left_idx,
685 minimal_next_start: minimal_next_start_enc_of_appended,
686 });
687 }
688 }
689 RecalculateHint::Slide => {
690 let old_left_idx = *window.left_idx;
691 let new_curr_idx = *window.curr_idx;
692 let old_right_excl_idx = *window.right_excl_idx;
693
694 if new_curr_idx < old_right_excl_idx {
695 } else {
697 let old_session_size = self.recognized_session_sizes.pop_front();
698 let next_session_size = self.recognized_session_sizes.front().copied();
699
700 if let Some(old_session_size) = old_session_size {
701 assert_eq!(old_session_size, old_right_excl_idx - old_left_idx);
702
703 if let Some(next_session_size) = next_session_size {
705 *window.left_idx = old_right_excl_idx;
707 *window.right_excl_idx = old_right_excl_idx + next_session_size;
708 } else {
709 *window.left_idx = old_right_excl_idx;
711 *window.right_excl_idx = window.buffer.len();
712 }
713 } else {
714 assert_eq!(old_right_excl_idx, window.buffer.len());
716 *window.left_idx = old_right_excl_idx;
717 *window.right_excl_idx = old_right_excl_idx;
718 self.latest_session = None;
719 }
720 }
721 }
722 }
723 }
724
725 fn shift_indices(&mut self, n: usize) {
726 if let Some(LatestSession { start_idx, .. }) = self.latest_session.as_mut() {
727 *start_idx -= n;
728 }
729 }
730}
731
732#[cfg(test)]
733mod tests {
734 use itertools::Itertools;
735 use risingwave_common::row::OwnedRow;
736 use risingwave_common::types::{DataType, ScalarImpl};
737 use risingwave_common::util::sort_util::OrderType;
738 use risingwave_expr::window_function::FrameBound::{
739 CurrentRow, Following, Preceding, UnboundedFollowing, UnboundedPreceding,
740 };
741 use risingwave_expr::window_function::{FrameBound, RangeFrameOffset, SessionFrameGap};
742
743 use super::*;
744
745 #[test]
746 fn test_rows_frame_unbounded_preceding_to_current_row() {
747 let mut buffer = WindowBuffer::<RowsWindow<_, _>>::new(
748 RowsWindow::new(RowsFrameBounds {
749 start: UnboundedPreceding,
750 end: CurrentRow,
751 }),
752 FrameExclusion::NoOthers,
753 true,
754 );
755
756 let window = buffer.curr_window();
757 assert!(window.key.is_none());
758 assert!(!window.preceding_saturated);
759 assert!(!window.following_saturated);
760 buffer.append(1, "hello");
761 let window = buffer.curr_window();
762 assert_eq!(window.key, Some(&1));
763 assert!(!window.preceding_saturated); assert!(window.following_saturated);
765 buffer.append(2, "world");
766 let window = buffer.curr_window();
767 assert_eq!(window.key, Some(&1));
768 assert!(!window.preceding_saturated);
769 assert!(window.following_saturated);
770 assert_eq!(
771 buffer.curr_window_values().cloned().collect_vec(),
772 vec!["hello"]
773 );
774 let removed_keys = buffer.slide().map(|(k, _)| k).collect_vec();
775 assert!(removed_keys.is_empty()); let window = buffer.curr_window();
777 assert_eq!(window.key, Some(&2));
778 assert!(!window.preceding_saturated);
779 assert!(window.following_saturated);
780 assert_eq!(buffer.smallest_key(), Some(&1));
781 }
782
783 #[test]
784 fn test_rows_frame_preceding_to_current_row() {
785 let mut buffer = WindowBuffer::<RowsWindow<_, _>>::new(
786 RowsWindow::new(RowsFrameBounds {
787 start: Preceding(1),
788 end: CurrentRow,
789 }),
790 FrameExclusion::NoOthers,
791 true,
792 );
793
794 let window = buffer.curr_window();
795 assert!(window.key.is_none());
796 assert!(!window.preceding_saturated);
797 assert!(!window.following_saturated);
798 buffer.append(1, "hello");
799 let window = buffer.curr_window();
800 assert_eq!(window.key, Some(&1));
801 assert!(!window.preceding_saturated);
802 assert!(window.following_saturated);
803 assert_eq!(
804 buffer.curr_window_values().cloned().collect_vec(),
805 vec!["hello"]
806 );
807 buffer.append(2, "world");
808 let window = buffer.curr_window();
809 assert_eq!(window.key, Some(&1));
810 assert!(!window.preceding_saturated);
811 assert!(window.following_saturated);
812 let removed_keys = buffer.slide().map(|(k, _)| k).collect_vec();
813 assert!(removed_keys.is_empty());
814 let window = buffer.curr_window();
815 assert_eq!(window.key, Some(&2));
816 assert!(window.preceding_saturated);
817 assert!(window.following_saturated);
818 assert_eq!(buffer.smallest_key(), Some(&1));
819 buffer.append(3, "!");
820 let window = buffer.curr_window();
821 assert_eq!(window.key, Some(&2));
822 let removed_keys = buffer.slide().map(|(k, _)| k).collect_vec();
823 assert_eq!(removed_keys, vec![1]);
824 }
825
826 #[test]
827 fn test_rows_frame_preceding_to_preceding() {
828 let mut buffer = WindowBuffer::<RowsWindow<_, _>>::new(
829 RowsWindow::new(RowsFrameBounds {
830 start: Preceding(2),
831 end: Preceding(1),
832 }),
833 FrameExclusion::NoOthers,
834 true,
835 );
836
837 buffer.append(1, "RisingWave");
838 let window = buffer.curr_window();
839 assert_eq!(window.key, Some(&1));
840 assert!(!window.preceding_saturated);
841 assert!(window.following_saturated);
842 assert!(buffer.curr_window_values().collect_vec().is_empty());
843 let removed_keys = buffer.slide().map(|(k, _)| k).collect_vec();
844 assert!(removed_keys.is_empty());
845 assert_eq!(buffer.smallest_key(), Some(&1));
846 buffer.append(2, "is the best");
847 let window = buffer.curr_window();
848 assert_eq!(window.key, Some(&2));
849 assert!(!window.preceding_saturated);
850 assert!(window.following_saturated);
851 assert_eq!(
852 buffer.curr_window_values().cloned().collect_vec(),
853 vec!["RisingWave"]
854 );
855 let removed_keys = buffer.slide().map(|(k, _)| k).collect_vec();
856 assert!(removed_keys.is_empty());
857 assert_eq!(buffer.smallest_key(), Some(&1));
858 buffer.append(3, "streaming platform");
859 let window = buffer.curr_window();
860 assert_eq!(window.key, Some(&3));
861 assert!(window.preceding_saturated);
862 assert!(window.following_saturated);
863 assert_eq!(
864 buffer.curr_window_values().cloned().collect_vec(),
865 vec!["RisingWave", "is the best"]
866 );
867 let removed_keys = buffer.slide().map(|(k, _)| k).collect_vec();
868 assert_eq!(removed_keys, vec![1]);
869 assert_eq!(buffer.smallest_key(), Some(&2));
870 }
871
872 #[test]
873 fn test_rows_frame_current_row_to_unbounded_following() {
874 let mut buffer = WindowBuffer::<RowsWindow<_, _>>::new(
875 RowsWindow::new(RowsFrameBounds {
876 start: CurrentRow,
877 end: UnboundedFollowing,
878 }),
879 FrameExclusion::NoOthers,
880 true,
881 );
882
883 buffer.append(1, "RisingWave");
884 let window = buffer.curr_window();
885 assert_eq!(window.key, Some(&1));
886 assert!(window.preceding_saturated);
887 assert!(!window.following_saturated);
888 assert_eq!(
889 buffer.curr_window_values().cloned().collect_vec(),
890 vec!["RisingWave"]
891 );
892 buffer.append(2, "is the best");
893 let window = buffer.curr_window();
894 assert_eq!(window.key, Some(&1));
895 assert!(window.preceding_saturated);
896 assert!(!window.following_saturated);
897 assert_eq!(
898 buffer.curr_window_values().cloned().collect_vec(),
899 vec!["RisingWave", "is the best"]
900 );
901 let removed_keys = buffer.slide().map(|(k, _)| k).collect_vec();
902 assert_eq!(removed_keys, vec![1]);
903 assert_eq!(buffer.smallest_key(), Some(&2));
904 let window = buffer.curr_window();
905 assert_eq!(window.key, Some(&2));
906 assert!(window.preceding_saturated);
907 assert!(!window.following_saturated);
908 assert_eq!(
909 buffer.curr_window_values().cloned().collect_vec(),
910 vec!["is the best"]
911 );
912 }
913
914 #[test]
915 fn test_rows_frame_current_row_to_following() {
916 let mut buffer = WindowBuffer::<RowsWindow<_, _>>::new(
917 RowsWindow::new(RowsFrameBounds {
918 start: CurrentRow,
919 end: Following(1),
920 }),
921 FrameExclusion::NoOthers,
922 true,
923 );
924
925 buffer.append(1, "RisingWave");
926 let window = buffer.curr_window();
927 assert_eq!(window.key, Some(&1));
928 assert!(window.preceding_saturated);
929 assert!(!window.following_saturated);
930 assert_eq!(
931 buffer.curr_window_values().cloned().collect_vec(),
932 vec!["RisingWave"]
933 );
934 buffer.append(2, "is the best");
935 let window = buffer.curr_window();
936 assert_eq!(window.key, Some(&1));
937 assert!(window.preceding_saturated);
938 assert!(window.following_saturated);
939 assert_eq!(
940 buffer.curr_window_values().cloned().collect_vec(),
941 vec!["RisingWave", "is the best"]
942 );
943 buffer.append(3, "streaming platform");
944 let window = buffer.curr_window();
945 assert_eq!(window.key, Some(&1));
946 assert!(window.preceding_saturated);
947 assert!(window.following_saturated);
948 assert_eq!(
949 buffer.curr_window_values().cloned().collect_vec(),
950 vec!["RisingWave", "is the best"]
951 );
952 let removed_keys = buffer.slide().map(|(k, _)| k).collect_vec();
953 assert_eq!(removed_keys, vec![1]);
954 let window = buffer.curr_window();
955 assert_eq!(window.key, Some(&2));
956 assert!(window.preceding_saturated);
957 assert!(window.following_saturated);
958 assert_eq!(
959 buffer.curr_window_values().cloned().collect_vec(),
960 vec!["is the best", "streaming platform"]
961 );
962 }
963
964 #[test]
965 fn test_rows_frame_following_to_following() {
966 let mut buffer = WindowBuffer::<RowsWindow<_, _>>::new(
967 RowsWindow::new(RowsFrameBounds {
968 start: Following(1),
969 end: Following(2),
970 }),
971 FrameExclusion::NoOthers,
972 true,
973 );
974
975 buffer.append(1, "RisingWave");
976 let window = buffer.curr_window();
977 assert_eq!(window.key, Some(&1));
978 assert!(window.preceding_saturated);
979 assert!(!window.following_saturated);
980 assert!(buffer.curr_window_values().collect_vec().is_empty());
981 buffer.append(2, "is the best");
982 let window = buffer.curr_window();
983 assert_eq!(window.key, Some(&1));
984 assert!(window.preceding_saturated);
985 assert!(!window.following_saturated);
986 assert_eq!(
987 buffer.curr_window_values().cloned().collect_vec(),
988 vec!["is the best"]
989 );
990 buffer.append(3, "streaming platform");
991 let window = buffer.curr_window();
992 assert_eq!(window.key, Some(&1));
993 assert!(window.preceding_saturated);
994 assert!(window.following_saturated);
995 assert_eq!(
996 buffer.curr_window_values().cloned().collect_vec(),
997 vec!["is the best", "streaming platform"]
998 );
999 let removed_keys = buffer.slide().map(|(k, _)| k).collect_vec();
1000 assert_eq!(removed_keys, vec![1]);
1001 let window = buffer.curr_window();
1002 assert_eq!(window.key, Some(&2));
1003 assert!(window.preceding_saturated);
1004 assert!(!window.following_saturated);
1005 assert_eq!(
1006 buffer.curr_window_values().cloned().collect_vec(),
1007 vec!["streaming platform"]
1008 );
1009 }
1010
1011 #[test]
1012 fn test_rows_frame_exclude_current_row() {
1013 let mut buffer = WindowBuffer::<RowsWindow<_, _>>::new(
1014 RowsWindow::new(RowsFrameBounds {
1015 start: UnboundedPreceding,
1016 end: CurrentRow,
1017 }),
1018 FrameExclusion::CurrentRow,
1019 false,
1020 );
1021
1022 buffer.append(1, "hello");
1023 assert!(
1024 buffer
1025 .curr_window_values()
1026 .cloned()
1027 .collect_vec()
1028 .is_empty()
1029 );
1030 buffer.append(2, "world");
1031 let _ = buffer.slide();
1032 assert_eq!(
1033 buffer.curr_window_values().cloned().collect_vec(),
1034 vec!["hello"]
1035 );
1036 }
1037
1038 #[test]
1039 fn test_session_frame() {
1040 let order_data_type = DataType::Int64;
1041 let order_type = OrderType::ascending();
1042 let gap_data_type = DataType::Int64;
1043
1044 let mut buffer = WindowBuffer::<SessionWindow<_>>::new(
1045 SessionWindow::new(SessionFrameBounds {
1046 order_data_type: order_data_type.clone(),
1047 order_type,
1048 gap_data_type: gap_data_type.clone(),
1049 gap: SessionFrameGap::new_for_test(
1050 ScalarImpl::Int64(5),
1051 &order_data_type,
1052 &gap_data_type,
1053 ),
1054 }),
1055 FrameExclusion::NoOthers,
1056 true,
1057 );
1058
1059 let key = |key: i64| -> StateKey {
1060 StateKey {
1061 order_key: memcmp_encoding::encode_value(Some(ScalarImpl::from(key)), order_type)
1062 .unwrap(),
1063 pk: OwnedRow::empty().into(),
1064 }
1065 };
1066
1067 assert!(buffer.curr_key().is_none());
1068
1069 buffer.append(key(1), "hello");
1070 buffer.append(key(3), "session");
1071 let window = buffer.curr_window();
1072 assert_eq!(window.key, Some(&key(1)));
1073 assert!(window.preceding_saturated);
1074 assert!(!window.following_saturated);
1075 assert_eq!(
1076 buffer.curr_window_values().cloned().collect_vec(),
1077 vec!["hello", "session"]
1078 );
1079
1080 buffer.append(key(8), "window"); let window = buffer.curr_window();
1082 assert!(window.following_saturated);
1083 assert_eq!(
1084 buffer.curr_window_values().cloned().collect_vec(),
1085 vec!["hello", "session"]
1086 );
1087
1088 buffer.append(key(15), "and");
1089 buffer.append(key(16), "world");
1090 assert_eq!(
1091 buffer.curr_window_values().cloned().collect_vec(),
1092 vec!["hello", "session"]
1093 );
1094
1095 let removed_keys = buffer.slide().map(|(k, _)| k).collect_vec();
1096 assert!(removed_keys.is_empty());
1097 let window = buffer.curr_window();
1098 assert_eq!(window.key, Some(&key(3)));
1099 assert!(window.preceding_saturated);
1100 assert!(window.following_saturated);
1101 assert_eq!(
1102 buffer.curr_window_values().cloned().collect_vec(),
1103 vec!["hello", "session"]
1104 );
1105
1106 let removed_keys = buffer.slide().map(|(k, _)| k).collect_vec();
1107 assert_eq!(removed_keys, vec![key(1), key(3)]);
1108 assert_eq!(buffer.smallest_key(), Some(&key(8)));
1109 let window = buffer.curr_window();
1110 assert_eq!(window.key, Some(&key(8)));
1111 assert!(window.preceding_saturated);
1112 assert!(window.following_saturated);
1113 assert_eq!(
1114 buffer.curr_window_values().cloned().collect_vec(),
1115 vec!["window"]
1116 );
1117
1118 let removed_keys = buffer.slide().map(|(k, _)| k).collect_vec();
1119 assert_eq!(removed_keys, vec![key(8)]);
1120 assert_eq!(buffer.smallest_key(), Some(&key(15)));
1121 let window = buffer.curr_window();
1122 assert_eq!(window.key, Some(&key(15)));
1123 assert!(window.preceding_saturated);
1124 assert!(!window.following_saturated);
1125 assert_eq!(
1126 buffer.curr_window_values().cloned().collect_vec(),
1127 vec!["and", "world"]
1128 );
1129
1130 let removed_keys = buffer.slide().map(|(k, _)| k).collect_vec();
1131 assert!(removed_keys.is_empty());
1132 assert_eq!(buffer.curr_key(), Some(&key(16)));
1133 assert_eq!(
1134 buffer.curr_window_values().cloned().collect_vec(),
1135 vec!["and", "world"]
1136 );
1137
1138 let removed_keys = buffer.slide().map(|(k, _)| k).collect_vec();
1139 assert_eq!(removed_keys, vec![key(15), key(16)]);
1140 assert!(buffer.curr_key().is_none());
1141 assert!(
1142 buffer
1143 .curr_window_values()
1144 .cloned()
1145 .collect_vec()
1146 .is_empty()
1147 );
1148 }
1149
1150 fn key_of(order: ScalarImpl) -> StateKey {
1151 StateKey {
1152 order_key: memcmp_encoding::encode_value(Some(order), OrderType::ascending()).unwrap(),
1153 pk: OwnedRow::empty().into(),
1154 }
1155 }
1156
1157 fn key(order: i64) -> StateKey {
1158 key_of(order.into())
1159 }
1160
1161 fn range_buffer_of(
1162 data_type: DataType,
1163 start: FrameBound<ScalarImpl>,
1164 end: FrameBound<ScalarImpl>,
1165 ) -> WindowBuffer<RangeWindow<&'static str>> {
1166 let offset = |bound: FrameBound<ScalarImpl>| {
1167 bound.map(|offset| RangeFrameOffset::new_for_test(offset, &data_type, &data_type))
1168 };
1169 WindowBuffer::new(
1170 RangeWindow::new(RangeFrameBounds {
1171 order_data_type: data_type.clone(),
1172 order_type: OrderType::ascending(),
1173 offset_data_type: data_type.clone(),
1174 start: offset(start),
1175 end: offset(end),
1176 }),
1177 FrameExclusion::NoOthers,
1178 true,
1179 )
1180 }
1181
1182 fn range_buffer(
1183 start: FrameBound<i64>,
1184 end: FrameBound<i64>,
1185 ) -> WindowBuffer<RangeWindow<&'static str>> {
1186 range_buffer_of(
1187 DataType::Int64,
1188 start.map(ScalarImpl::from),
1189 end.map(ScalarImpl::from),
1190 )
1191 }
1192
1193 #[test]
1194 fn test_range_frame_readiness() {
1195 let mut buffer = range_buffer(Preceding(10), Preceding(5));
1198 buffer.append(key(102), "a");
1199 assert_eq!(buffer.readiness(), Readiness::Ready);
1200 assert!(!buffer.curr_window().following_saturated);
1201
1202 let mut buffer = range_buffer(CurrentRow, UnboundedFollowing);
1203 buffer.append(key(1), "a");
1204 buffer.append(key(2), "b");
1205 assert_eq!(buffer.readiness(), Readiness::WaitForInput);
1206
1207 let bound = |order: i64| {
1209 Readiness::OnWatermark(WatermarkBound {
1210 value: key(order).order_key,
1211 exclusive: true,
1212 })
1213 };
1214 let mut buffer = range_buffer(CurrentRow, Following(2));
1215 buffer.append(key(1), "a");
1216 buffer.append(key(2), "b");
1217 assert_eq!(buffer.readiness(), bound(3));
1218 buffer.append(key(4), "c");
1219 assert_eq!(buffer.readiness(), Readiness::Ready);
1220 let _ = buffer.slide();
1221 assert_eq!(buffer.readiness(), bound(4));
1222
1223 let x = ScalarImpl::from(2f64.powi(54));
1226 let one = ScalarImpl::from(1.0f64);
1227 let mut buffer = range_buffer_of(DataType::Float64, Preceding(one.clone()), Preceding(one));
1228 buffer.append(key_of(x.clone()), "a");
1229 assert_eq!(
1230 buffer.readiness(),
1231 Readiness::OnWatermark(WatermarkBound {
1232 value: key_of(x).order_key,
1233 exclusive: true,
1234 })
1235 );
1236 }
1237}