1use std::sync::Arc;
16
17use itertools::Itertools;
18use risingwave_common::array::Op;
19use risingwave_common::row;
20use risingwave_common::types::{DefaultOrdered, Interval, Timestamptz, ToDatumRef};
21use risingwave_expr::capture_context;
22use risingwave_expr::expr::{
23 EvalErrorReport, InputRefExpression, LiteralExpression, NonStrictExpression,
24 SyncExpressionBoxExt, build_func_non_strict,
25};
26use risingwave_expr::expr_context::TIME_ZONE;
27use tokio::sync::mpsc::UnboundedReceiver;
28use tokio::time::Instant;
29use tokio_stream::wrappers::UnboundedReceiverStream;
30
31use crate::executor::monitor::StreamingMetrics;
32use crate::executor::prelude::*;
33use crate::task::{ActorEvalErrorReport, FragmentId};
34
35pub struct NowExecutor<S: StateStore> {
36 data_types: Vec<DataType>,
37
38 mode: NowMode,
39 eval_error_report: ActorEvalErrorReport,
40
41 barrier_receiver: UnboundedReceiver<Barrier>,
43
44 state_table: StateTable<S>,
45
46 progress_ratio: Option<f32>,
47
48 metrics: Arc<StreamingMetrics>,
50 fragment_id: FragmentId,
51}
52
53pub enum NowMode {
54 UpdateCurrent,
56 GenerateSeries {
59 start_timestamp: Timestamptz,
60 interval: Interval,
61 },
62}
63
64enum ModeVars {
65 UpdateCurrent,
66 GenerateSeries {
67 chunk_builder: StreamChunkBuilder,
68 add_interval_expr: NonStrictExpression,
69 },
70}
71
72impl<S: StateStore> NowExecutor<S> {
73 #[allow(clippy::too_many_arguments)]
74 pub fn new(
75 data_types: Vec<DataType>,
76 mode: NowMode,
77 eval_error_report: ActorEvalErrorReport,
78 barrier_receiver: UnboundedReceiver<Barrier>,
79 state_table: StateTable<S>,
80 progress_ratio: Option<f32>,
81 streaming_metrics: Arc<StreamingMetrics>,
82 fragment_id: FragmentId,
83 ) -> Self {
84 Self {
85 data_types,
86 mode,
87 eval_error_report,
88 barrier_receiver,
89 state_table,
90 progress_ratio,
91 metrics: streaming_metrics,
92 fragment_id,
93 }
94 }
95
96 #[try_stream(ok = Message, error = StreamExecutorError)]
97 async fn execute_inner(self) {
98 let Self {
99 data_types,
100 mode,
101 eval_error_report,
102 barrier_receiver,
103 mut state_table,
104 progress_ratio,
105 metrics,
106 fragment_id,
107 } = self;
108
109 let mut executor_metrics = None;
110
111 info!("NowExecutor started. progress_ratio: {:?}", progress_ratio);
112
113 let max_chunk_size = crate::config::chunk_size();
114
115 let mut paused = false;
117 let mut last_timestamp_datum: Datum = None;
119
120 let mut initialized = false;
122 let mut last_barrier_time = None;
125
126 let mut mode_vars = match &mode {
127 NowMode::UpdateCurrent => ModeVars::UpdateCurrent,
128 NowMode::GenerateSeries { interval, .. } => {
129 let chunk_builder = StreamChunkBuilder::unlimited(data_types.clone(), Some(1));
131 let add_interval_expr =
132 build_add_interval_expr_captured(*interval, eval_error_report)?;
133 ModeVars::GenerateSeries {
134 chunk_builder,
135 add_interval_expr,
136 }
137 }
138 };
139
140 const MAX_MERGE_BARRIER_SIZE: usize = 64;
141
142 #[for_await]
143 for barriers in
144 UnboundedReceiverStream::new(barrier_receiver).ready_chunks(MAX_MERGE_BARRIER_SIZE)
145 {
146 let barrier_time = Instant::now();
147 let elapsed = last_barrier_time
148 .replace(barrier_time)
149 .map(|last| barrier_time.saturating_duration_since(last));
150 let mut curr_timestamp_datum: Datum = None;
151 let mut last_barrier_wall_ms: Option<i64> = None;
154 if barriers.len() > 1 {
155 warn!(
156 "handle multiple barriers at once in now executor: {}",
157 barriers.len()
158 );
159 }
160 for barrier in barriers {
161 let curr_epoch = barrier.get_curr_epoch();
162 let new_timestamp = curr_epoch.as_timestamptz();
163 last_barrier_wall_ms = Some(new_timestamp.timestamp_millis());
164 let pause_mutation =
165 barrier
166 .mutation
167 .as_deref()
168 .and_then(|mutation| match mutation {
169 Mutation::Pause => Some(true),
170 Mutation::Resume => Some(false),
171 _ => None,
172 });
173
174 if !initialized {
175 let first_epoch = barrier.epoch;
176 let is_pause_on_startup = barrier.is_pause_on_startup();
177 yield Message::Barrier(barrier);
178 state_table.init_epoch(first_epoch).await?;
180 last_timestamp_datum = state_table.get_from_one_value_table().await?;
181 paused = is_pause_on_startup;
182 initialized = true;
183 } else {
184 state_table
185 .commit_assert_no_update_vnode_bitmap(barrier.epoch)
186 .await?;
187 yield Message::Barrier(barrier);
188 }
189
190 if let NowMode::UpdateCurrent = &mode
193 && let Some(datum) = &last_timestamp_datum
194 && let Some(progress_ratio) = progress_ratio
195 && progress_ratio > 1.0
196 {
197 let last_timestamp = datum.as_timestamptz();
198 let elapsed_ms = elapsed.map_or(0.0, |elapsed| elapsed.as_secs_f64() * 1000.0);
202 let progress_timestamp = last_timestamp
203 .timestamp_millis()
204 .checked_add((elapsed_ms * f64::from(progress_ratio)).ceil() as i64)
205 .expect("progress_timestamp is out of i64 range");
206 let adjusted_timestamp = if progress_timestamp
207 < new_timestamp.timestamp_millis()
208 {
209 debug!(
210 "adjusted next now timestamp from {} to {}. curr_epoch: {}, elapsed_ms: {}, progress_ratio: {}",
211 new_timestamp.timestamp_millis(),
212 progress_timestamp,
213 curr_epoch,
214 elapsed_ms,
215 progress_ratio
216 );
217 Timestamptz::from_millis(progress_timestamp)
218 .expect("progress_timestamp is out of timestamptz range")
219 } else {
220 new_timestamp
221 };
222 curr_timestamp_datum = Some(adjusted_timestamp.into());
223 } else {
224 curr_timestamp_datum = Some(new_timestamp.into());
225 }
226
227 if let Some(pause_mutation) = pause_mutation {
229 paused = pause_mutation;
230 }
231 }
232
233 if paused {
235 continue;
236 }
237
238 match (&mode, &mut mode_vars) {
239 (NowMode::UpdateCurrent, ModeVars::UpdateCurrent) => {
240 let chunk = if last_timestamp_datum.is_some() {
241 let last_row = row::once(&last_timestamp_datum);
242 let row = row::once(&curr_timestamp_datum);
243 state_table.update(last_row, row);
244
245 StreamChunk::from_rows(
246 &[(Op::Delete, last_row), (Op::Insert, row)],
247 &data_types,
248 )
249 } else {
250 let row = row::once(&curr_timestamp_datum);
251 state_table.insert(row);
252
253 StreamChunk::from_rows(&[(Op::Insert, row)], &data_types)
254 };
255
256 yield Message::Chunk(chunk);
257 last_timestamp_datum.clone_from(&curr_timestamp_datum)
258 }
259 (
260 &NowMode::GenerateSeries {
261 start_timestamp, ..
262 },
263 &mut ModeVars::GenerateSeries {
264 ref mut chunk_builder,
265 ref add_interval_expr,
266 },
267 ) => {
268 if last_timestamp_datum.is_none() {
269 let first = Some(start_timestamp.into());
271 let first_row = row::once(&first);
272 let _ = chunk_builder.append_row(Op::Insert, first_row);
273 state_table.insert(first_row);
274 last_timestamp_datum = first;
275 }
276
277 let mut last_row = OwnedRow::new(vec![last_timestamp_datum.clone()]);
281
282 loop {
283 if chunk_builder.size() >= max_chunk_size {
284 if let Some(chunk) = chunk_builder.take() {
288 yield Message::Chunk(chunk);
289 }
290 }
291
292 let next = add_interval_expr.eval_row_infallible(&last_row).await;
293 if DefaultOrdered(next.to_datum_ref())
294 > DefaultOrdered(curr_timestamp_datum.to_datum_ref())
295 {
296 break;
298 }
299
300 let next_row = OwnedRow::new(vec![next]);
301 let _ = chunk_builder.append_row(Op::Insert, &next_row);
302 last_row = next_row;
303 }
304
305 if let Some(chunk) = chunk_builder.take() {
306 yield Message::Chunk(chunk);
307 }
308
309 state_table.update(row::once(&last_timestamp_datum), &last_row);
311 last_timestamp_datum =
312 Itertools::exactly_one(last_row.into_inner().into_vec().into_iter())
313 .unwrap();
314 }
315 _ => unreachable!(),
316 }
317
318 let curr_timestamp_datum = curr_timestamp_datum.unwrap();
319
320 if let Some(wall_ms) = last_barrier_wall_ms
321 && let ScalarImpl::Timestamptz(ts) = &curr_timestamp_datum
322 {
323 let streaming_now_ms = ts.timestamp_millis();
324 let (streaming_clock_ms, wall_clock_drift_ms) = executor_metrics
325 .get_or_insert_with(|| {
326 let label = fragment_id.to_string();
331 (
332 metrics
333 .now_streaming_clock_ms
334 .with_guarded_label_values(&[&label]),
335 metrics
336 .now_wall_clock_drift_ms
337 .with_guarded_label_values(&[&label]),
338 )
339 });
340 streaming_clock_ms.set(streaming_now_ms);
341 wall_clock_drift_ms.set(wall_ms.saturating_sub(streaming_now_ms));
342 }
343
344 yield Message::Watermark(Watermark::new(
345 0,
346 DataType::Timestamptz,
347 curr_timestamp_datum,
348 ));
349 }
350 }
351}
352
353impl<S: StateStore> Execute for NowExecutor<S> {
354 fn execute(self: Box<Self>) -> BoxedMessageStream {
355 self.execute_inner().boxed()
356 }
357}
358
359#[capture_context(TIME_ZONE)]
360pub fn build_add_interval_expr(
361 time_zone: &str,
362 interval: Interval,
363 eval_error_report: impl EvalErrorReport + 'static,
364) -> risingwave_expr::Result<NonStrictExpression> {
365 let timestamptz_input = InputRefExpression::new(DataType::Timestamptz, 0);
366 let interval = LiteralExpression::new(DataType::Interval, Some(interval.into()));
367 let time_zone = LiteralExpression::new(DataType::Varchar, Some(time_zone.into()));
368
369 use risingwave_pb::expr::expr_node::PbType as PbExprType;
370 build_func_non_strict(
371 PbExprType::AddWithTimeZone,
372 DataType::Timestamptz,
373 vec![
374 timestamptz_input.boxed(),
375 interval.boxed(),
376 time_zone.boxed(),
377 ],
378 eval_error_report,
379 )
380}
381
382#[cfg(test)]
383mod tests {
384 #[cfg(not(madsim))]
385 use std::time::Duration;
386
387 use risingwave_common::catalog::{ColumnDesc, ColumnId, TableId};
388 use risingwave_common::test_prelude::StreamChunkTestExt;
389 use risingwave_common::types::test_utils::IntervalTestExt;
390 use risingwave_common::util::epoch::test_epoch;
391 use risingwave_storage::memory::MemoryStateStore;
392 use tokio::sync::mpsc::{UnboundedSender, unbounded_channel};
393
394 use super::*;
395 use crate::common::table::test_utils::gen_pbtable;
396 use crate::executor::test_utils::StreamExecutorTestExt;
397
398 #[tokio::test]
399 async fn test_now() -> StreamExecutorResult<()> {
400 let state_store = create_state_store();
401 let (tx, mut now) = create_executor(NowMode::UpdateCurrent, &state_store).await;
402
403 tx.send(Barrier::new_test_barrier(test_epoch(1))).unwrap();
405
406 now.next_unwrap_ready_barrier()?;
408
409 let chunk_msg = now.next_unwrap_ready_chunk()?;
411
412 assert_eq!(
413 chunk_msg.compact_vis(),
414 StreamChunk::from_pretty(
415 " TZ
416 + 2021-04-01T00:00:00.001Z"
417 )
418 );
419
420 let watermark = now.next_unwrap_ready_watermark()?;
422
423 assert_eq!(
424 watermark,
425 Watermark::new(
426 0,
427 DataType::Timestamptz,
428 ScalarImpl::Timestamptz("2021-04-01T00:00:00.001Z".parse().unwrap())
429 )
430 );
431
432 tx.send(Barrier::with_prev_epoch_for_test(
433 test_epoch(2),
434 test_epoch(1),
435 ))
436 .unwrap();
437
438 now.next_unwrap_ready_barrier()?;
440
441 let chunk_msg = now.next_unwrap_ready_chunk()?;
443
444 assert_eq!(
445 chunk_msg.compact_vis(),
446 StreamChunk::from_pretty(
447 " TZ
448 - 2021-04-01T00:00:00.001Z
449 + 2021-04-01T00:00:00.002Z"
450 )
451 );
452
453 let watermark = now.next_unwrap_ready_watermark()?;
455
456 assert_eq!(
457 watermark,
458 Watermark::new(
459 0,
460 DataType::Timestamptz,
461 ScalarImpl::Timestamptz("2021-04-01T00:00:00.002Z".parse().unwrap())
462 )
463 );
464
465 now.next_unwrap_pending();
467
468 drop((tx, now));
470 let (tx, mut now) = create_executor(NowMode::UpdateCurrent, &state_store).await;
471 tx.send(Barrier::with_prev_epoch_for_test(
472 test_epoch(3),
473 test_epoch(1),
474 ))
475 .unwrap();
476
477 now.next_unwrap_ready_barrier()?;
479
480 let chunk_msg = now.next_unwrap_ready_chunk()?;
482 assert_eq!(
483 chunk_msg.compact_vis(),
484 StreamChunk::from_pretty(
486 " TZ
487 - 2021-04-01T00:00:00.001Z
488 + 2021-04-01T00:00:00.003Z"
489 )
490 );
491
492 let watermark = now.next_unwrap_ready_watermark()?;
494
495 assert_eq!(
496 watermark,
497 Watermark::new(
498 0,
499 DataType::Timestamptz,
500 ScalarImpl::Timestamptz("2021-04-01T00:00:00.003Z".parse().unwrap())
501 )
502 );
503
504 drop((tx, now));
506 let (tx, mut now) = create_executor(NowMode::UpdateCurrent, &state_store).await;
507 tx.send(
508 Barrier::with_prev_epoch_for_test(test_epoch(4), test_epoch(1))
509 .with_mutation(Mutation::Pause),
510 )
511 .unwrap();
512
513 now.next_unwrap_ready_barrier()?;
515
516 now.next_unwrap_pending();
518
519 tx.send(
521 Barrier::with_prev_epoch_for_test(test_epoch(5), test_epoch(4))
522 .with_mutation(Mutation::Resume),
523 )
524 .unwrap();
525
526 now.next_unwrap_ready_barrier()?;
528
529 let chunk_msg = now.next_unwrap_ready_chunk()?;
531 assert_eq!(
532 chunk_msg.compact_vis(),
533 StreamChunk::from_pretty(
534 " TZ
535 - 2021-04-01T00:00:00.001Z
536 + 2021-04-01T00:00:00.005Z"
537 )
538 );
539
540 let watermark = now.next_unwrap_ready_watermark()?;
542
543 assert_eq!(
544 watermark,
545 Watermark::new(
546 0,
547 DataType::Timestamptz,
548 ScalarImpl::Timestamptz("2021-04-01T00:00:00.005Z".parse().unwrap())
549 )
550 );
551
552 Ok(())
553 }
554
555 #[tokio::test]
556 async fn test_now_start_with_paused() -> StreamExecutorResult<()> {
557 let state_store = create_state_store();
558 let (tx, mut now) = create_executor(NowMode::UpdateCurrent, &state_store).await;
559
560 tx.send(Barrier::new_test_barrier(test_epoch(1)).with_mutation(Mutation::Pause))
562 .unwrap();
563
564 now.next_unwrap_ready_barrier()?;
566
567 now.next_unwrap_pending();
569
570 tx.send(
572 Barrier::with_prev_epoch_for_test(test_epoch(2), test_epoch(1))
573 .with_mutation(Mutation::Resume),
574 )
575 .unwrap();
576
577 now.next_unwrap_ready_barrier()?;
579
580 let chunk_msg = now.next_unwrap_ready_chunk()?;
582
583 assert_eq!(
584 chunk_msg.compact_vis(),
585 StreamChunk::from_pretty(
586 " TZ
587 + 2021-04-01T00:00:00.002Z" )
589 );
590
591 let watermark = now.next_unwrap_ready_watermark()?;
593
594 assert_eq!(
595 watermark,
596 Watermark::new(
597 0,
598 DataType::Timestamptz,
599 ScalarImpl::Timestamptz("2021-04-01T00:00:00.002Z".parse().unwrap())
600 )
601 );
602
603 now.next_unwrap_pending();
605
606 Ok(())
607 }
608
609 #[tokio::test]
610 async fn test_now_generate_series() -> StreamExecutorResult<()> {
611 for progress_ratio in [None, Some(2.0)] {
612 TIME_ZONE::scope(
613 "UTC".to_owned(),
614 test_now_generate_series_inner(progress_ratio),
615 )
616 .await?;
617 }
618 Ok(())
619 }
620
621 #[tokio::test]
622 async fn test_now_generate_series_with_progress_ratio() -> StreamExecutorResult<()> {
623 TIME_ZONE::scope("UTC".to_owned(), async {
624 let state_store = create_state_store();
625 let mode = || NowMode::GenerateSeries {
626 start_timestamp: "2021-04-01T00:00:00Z".parse().unwrap(),
627 interval: Interval::from_millis(10_000),
629 };
630 let (tx, mut now) =
631 create_executor_with_progress_ratio(mode(), &state_store, Some(2.0)).await;
632
633 tx.send(Barrier::new_test_barrier(test_epoch(5000)))
634 .unwrap();
635 now.next_unwrap_ready_barrier()?;
636 assert_eq!(
637 now.next_unwrap_ready_chunk()?.compact_vis(),
638 StreamChunk::from_pretty("TZ\n+ 2021-04-01T00:00:00Z")
639 );
640 assert_eq!(
641 now.next_unwrap_ready_watermark()?,
642 Watermark::new(
643 0,
644 DataType::Timestamptz,
645 "2021-04-01T00:00:05Z"
646 .parse::<Timestamptz>()
647 .unwrap()
648 .into(),
649 )
650 );
651 now.next_unwrap_pending();
652
653 for (curr, prev, expected_watermark) in [
656 (6000, 5000, "2021-04-01T00:00:06Z"),
657 (10_000, 6000, "2021-04-01T00:00:10Z"),
658 (11_000, 10_000, "2021-04-01T00:00:11Z"),
659 ] {
660 tx.send(Barrier::with_prev_epoch_for_test(
661 test_epoch(curr),
662 test_epoch(prev),
663 ))
664 .unwrap();
665 now.next_unwrap_ready_barrier()?;
666 if curr == 10_000 {
667 assert_eq!(
668 now.next_unwrap_ready_chunk()?.compact_vis(),
669 StreamChunk::from_pretty("TZ\n+ 2021-04-01T00:00:10Z")
670 );
671 }
672 assert_eq!(
673 now.next_unwrap_ready_watermark()?,
674 Watermark::new(
675 0,
676 DataType::Timestamptz,
677 expected_watermark.parse::<Timestamptz>().unwrap().into(),
678 )
679 );
680 now.next_unwrap_pending();
681 }
682
683 drop((tx, now));
686 let (tx, mut now) =
687 create_executor_with_progress_ratio(mode(), &state_store, Some(2.0)).await;
688 tx.send(Barrier::with_prev_epoch_for_test(
689 test_epoch(35_000),
690 test_epoch(11_000),
691 ))
692 .unwrap();
693 now.next_unwrap_ready_barrier()?;
694 assert_eq!(
695 now.next_unwrap_ready_chunk()?.compact_vis(),
696 StreamChunk::from_pretty(
697 "TZ
698 + 2021-04-01T00:00:20Z
699 + 2021-04-01T00:00:30Z"
700 )
701 );
702 assert_eq!(
703 now.next_unwrap_ready_watermark()?,
704 Watermark::new(
705 0,
706 DataType::Timestamptz,
707 "2021-04-01T00:00:35Z"
708 .parse::<Timestamptz>()
709 .unwrap()
710 .into(),
711 )
712 );
713 now.next_unwrap_pending();
714 Ok(())
715 })
716 .await
717 }
718
719 #[cfg(not(madsim))]
720 #[tokio::test(start_paused = true)]
721 async fn test_now_with_progress_ratio() -> StreamExecutorResult<()> {
722 let state_store = create_state_store();
723 let progress_ratio = Some(2.0);
724 let (tx, mut now) = create_executor_with_progress_ratio(
725 NowMode::UpdateCurrent,
726 &state_store,
727 progress_ratio,
728 )
729 .await;
730
731 tx.send(Barrier::new_test_barrier(test_epoch(1))).unwrap();
733
734 now.next_unwrap_ready_barrier()?;
736
737 let chunk_msg = now.next_unwrap_ready_chunk()?;
739
740 assert_eq!(
741 chunk_msg.compact_vis(),
742 StreamChunk::from_pretty(
743 " TZ
744 + 2021-04-01T00:00:00.001Z"
745 )
746 );
747
748 let watermark = now.next_unwrap_ready_watermark()?;
750
751 assert_eq!(
752 watermark,
753 Watermark::new(
754 0,
755 DataType::Timestamptz,
756 ScalarImpl::Timestamptz("2021-04-01T00:00:00.001Z".parse().unwrap())
757 )
758 );
759
760 tokio::time::advance(Duration::from_secs(1)).await;
765 tx.send(Barrier::with_prev_epoch_for_test(
766 test_epoch(5000),
767 test_epoch(1),
768 ))
769 .unwrap();
770
771 now.next_unwrap_ready_barrier()?;
773
774 let chunk_msg = now.next_unwrap_ready_chunk()?;
776
777 assert_eq!(
778 chunk_msg.compact_vis(),
779 StreamChunk::from_pretty(
780 " TZ
781 - 2021-04-01T00:00:00.001Z
782 + 2021-04-01T00:00:02.001Z" )
784 );
785
786 let watermark = now.next_unwrap_ready_watermark()?;
788
789 assert_eq!(
790 watermark,
791 Watermark::new(
792 0,
793 DataType::Timestamptz,
794 ScalarImpl::Timestamptz("2021-04-01T00:00:02.001Z".parse().unwrap())
795 )
796 );
797
798 tokio::time::advance(Duration::from_secs(1)).await;
802 tx.send(Barrier::with_prev_epoch_for_test(
803 test_epoch(10000),
804 test_epoch(5000),
805 ))
806 .unwrap();
807
808 now.next_unwrap_ready_barrier()?;
810
811 let chunk_msg = now.next_unwrap_ready_chunk()?;
813
814 assert_eq!(
815 chunk_msg.compact_vis(),
816 StreamChunk::from_pretty(
817 " TZ
818 - 2021-04-01T00:00:02.001Z
819 + 2021-04-01T00:00:04.001Z" )
821 );
822
823 let watermark = now.next_unwrap_ready_watermark()?;
825
826 assert_eq!(
827 watermark,
828 Watermark::new(
829 0,
830 DataType::Timestamptz,
831 ScalarImpl::Timestamptz("2021-04-01T00:00:04.001Z".parse().unwrap())
832 )
833 );
834
835 tokio::time::advance(Duration::from_secs(1)).await;
839 tx.send(Barrier::with_prev_epoch_for_test(
840 test_epoch(15000),
841 test_epoch(10000),
842 ))
843 .unwrap();
844
845 now.next_unwrap_ready_barrier()?;
847
848 let chunk_msg = now.next_unwrap_ready_chunk()?;
850
851 assert_eq!(
852 chunk_msg.compact_vis(),
853 StreamChunk::from_pretty(
854 " TZ
855 - 2021-04-01T00:00:04.001Z
856 + 2021-04-01T00:00:06.001Z" )
858 );
859
860 let watermark = now.next_unwrap_ready_watermark()?;
862
863 assert_eq!(
864 watermark,
865 Watermark::new(
866 0,
867 DataType::Timestamptz,
868 ScalarImpl::Timestamptz("2021-04-01T00:00:06.001Z".parse().unwrap())
869 )
870 );
871
872 tokio::time::advance(Duration::from_secs(1)).await;
876 tx.send(Barrier::with_prev_epoch_for_test(
877 test_epoch(20000),
878 test_epoch(15000),
879 ))
880 .unwrap();
881
882 now.next_unwrap_ready_barrier()?;
884
885 let chunk_msg = now.next_unwrap_ready_chunk()?;
887
888 assert_eq!(
889 chunk_msg.compact_vis(),
890 StreamChunk::from_pretty(
891 " TZ
892 - 2021-04-01T00:00:06.001Z
893 + 2021-04-01T00:00:08.001Z" )
895 );
896
897 let watermark = now.next_unwrap_ready_watermark()?;
899
900 assert_eq!(
901 watermark,
902 Watermark::new(
903 0,
904 DataType::Timestamptz,
905 ScalarImpl::Timestamptz("2021-04-01T00:00:08.001Z".parse().unwrap())
906 )
907 );
908
909 tokio::time::advance(Duration::from_secs(1)).await;
914 tx.send(Barrier::with_prev_epoch_for_test(
915 test_epoch(25000),
916 test_epoch(20000),
917 ))
918 .unwrap();
919
920 now.next_unwrap_ready_barrier()?;
922
923 let chunk_msg = now.next_unwrap_ready_chunk()?;
925
926 assert_eq!(
927 chunk_msg.compact_vis(),
928 StreamChunk::from_pretty(
929 " TZ
930 - 2021-04-01T00:00:08.001Z
931 + 2021-04-01T00:00:10.001Z" )
933 );
934
935 let watermark = now.next_unwrap_ready_watermark()?;
937
938 assert_eq!(
939 watermark,
940 Watermark::new(
941 0,
942 DataType::Timestamptz,
943 ScalarImpl::Timestamptz("2021-04-01T00:00:10.001Z".parse().unwrap())
944 )
945 );
946
947 tokio::time::advance(Duration::from_secs(1)).await;
952 tx.send(Barrier::with_prev_epoch_for_test(
953 test_epoch(30000),
954 test_epoch(25000),
955 ))
956 .unwrap();
957
958 now.next_unwrap_ready_barrier()?;
960
961 let chunk_msg = now.next_unwrap_ready_chunk()?;
963
964 assert_eq!(
965 chunk_msg.compact_vis(),
966 StreamChunk::from_pretty(
967 " TZ
968 - 2021-04-01T00:00:10.001Z
969 + 2021-04-01T00:00:12.001Z" )
971 );
972
973 let watermark = now.next_unwrap_ready_watermark()?;
975
976 assert_eq!(
977 watermark,
978 Watermark::new(
979 0,
980 DataType::Timestamptz,
981 ScalarImpl::Timestamptz("2021-04-01T00:00:12.001Z".parse().unwrap())
982 )
983 );
984
985 Ok(())
986 }
987
988 #[cfg(not(madsim))]
989 #[tokio::test(start_paused = true)]
990 async fn test_now_progress_ratio_uses_elapsed_time() -> StreamExecutorResult<()> {
991 let state_store = create_state_store();
992 let (tx, mut now) =
993 create_executor_with_progress_ratio(NowMode::UpdateCurrent, &state_store, Some(2.0))
994 .await;
995
996 tx.send(Barrier::new_test_barrier(test_epoch(1))).unwrap();
997 now.next_unwrap_ready_barrier()?;
998 now.next_unwrap_ready_chunk()?;
999 now.next_unwrap_ready_watermark()?;
1000
1001 tokio::time::advance(Duration::from_secs(5)).await;
1002 tx.send(Barrier::with_prev_epoch_for_test(
1003 test_epoch(20000),
1004 test_epoch(1),
1005 ))
1006 .unwrap();
1007
1008 now.next_unwrap_ready_barrier()?;
1009 let chunk = now.next_unwrap_ready_chunk()?;
1010 assert_eq!(
1011 chunk.compact_vis(),
1012 StreamChunk::from_pretty(
1013 " TZ
1014 - 2021-04-01T00:00:00.001Z
1015 + 2021-04-01T00:00:10.001Z"
1016 )
1017 );
1018
1019 Ok(())
1020 }
1021
1022 async fn test_now_generate_series_inner(
1023 progress_ratio: Option<f32>,
1024 ) -> StreamExecutorResult<()> {
1025 let start_timestamp = Timestamptz::from_secs(1617235190).unwrap(); let interval = Interval::from_millis(1000); let state_store = create_state_store();
1029 let (tx, mut now) = create_executor_with_progress_ratio(
1030 NowMode::GenerateSeries {
1031 start_timestamp,
1032 interval,
1033 },
1034 &state_store,
1035 progress_ratio,
1036 )
1037 .await;
1038
1039 tx.send(Barrier::new_test_barrier(test_epoch(1000)))
1041 .unwrap();
1042 now.next_unwrap_ready_barrier()?;
1043
1044 let chunk = now.next_unwrap_ready_chunk()?;
1046 assert_eq!(chunk.cardinality(), 12); assert_eq!(
1049 now.next_unwrap_ready_watermark()?,
1050 Watermark::new(
1051 0,
1052 DataType::Timestamptz,
1053 ScalarImpl::Timestamptz("2021-04-01T00:00:01.000Z".parse().unwrap())
1054 )
1055 );
1056
1057 tx.send(Barrier::with_prev_epoch_for_test(
1058 test_epoch(2000),
1059 test_epoch(1000),
1060 ))
1061 .unwrap();
1062 tx.send(Barrier::with_prev_epoch_for_test(
1063 test_epoch(3000),
1064 test_epoch(2000),
1065 ))
1066 .unwrap();
1067
1068 now.next_unwrap_ready_barrier()?;
1069 now.next_unwrap_ready_barrier()?;
1070
1071 let chunk = now.next_unwrap_ready_chunk()?;
1072 assert_eq!(
1073 chunk.compact_vis(),
1074 StreamChunk::from_pretty(
1075 " TZ
1076 + 2021-04-01T00:00:02.000Z
1077 + 2021-04-01T00:00:03.000Z"
1078 )
1079 );
1080
1081 let watermark = now.next_unwrap_ready_watermark()?;
1082 assert_eq!(
1083 watermark,
1084 Watermark::new(
1085 0,
1086 DataType::Timestamptz,
1087 ScalarImpl::Timestamptz("2021-04-01T00:00:03.000Z".parse().unwrap())
1088 )
1089 );
1090
1091 drop((tx, now));
1093 let (tx, mut now) = create_executor_with_progress_ratio(
1094 NowMode::GenerateSeries {
1095 start_timestamp,
1096 interval,
1097 },
1098 &state_store,
1099 progress_ratio,
1100 )
1101 .await;
1102
1103 tx.send(Barrier::with_prev_epoch_for_test(
1104 test_epoch(4000),
1105 test_epoch(2000),
1106 ))
1107 .unwrap();
1108
1109 now.next_unwrap_ready_barrier()?;
1110
1111 let chunk = now.next_unwrap_ready_chunk()?;
1112 assert_eq!(
1113 chunk.compact_vis(),
1114 StreamChunk::from_pretty(
1115 " TZ
1116 + 2021-04-01T00:00:02.000Z
1117 + 2021-04-01T00:00:03.000Z
1118 + 2021-04-01T00:00:04.000Z"
1119 )
1120 );
1121
1122 let watermark = now.next_unwrap_ready_watermark()?;
1123 assert_eq!(
1124 watermark,
1125 Watermark::new(
1126 0,
1127 DataType::Timestamptz,
1128 ScalarImpl::Timestamptz("2021-04-01T00:00:04.000Z".parse().unwrap())
1129 )
1130 );
1131
1132 Ok(())
1133 }
1134
1135 fn create_state_store() -> MemoryStateStore {
1136 MemoryStateStore::new()
1137 }
1138
1139 async fn build_executor(
1140 mode: NowMode,
1141 state_store: &MemoryStateStore,
1142 progress_ratio: Option<f32>,
1143 ) -> (UnboundedSender<Barrier>, NowExecutor<MemoryStateStore>) {
1144 let table_id = TableId::new(1);
1145 let column_descs = vec![ColumnDesc::unnamed(ColumnId::new(0), DataType::Timestamptz)];
1146 let state_table = StateTable::from_table_catalog(
1147 &gen_pbtable(table_id, column_descs, vec![], vec![], 0),
1148 state_store.clone(),
1149 None,
1150 )
1151 .await;
1152
1153 let (sender, barrier_receiver) = unbounded_channel();
1154
1155 let eval_error_report = ActorEvalErrorReport {
1156 actor_context: ActorContext::for_test(123),
1157 identity: "NowExecutor".into(),
1158 };
1159 let now_executor = NowExecutor::new(
1160 vec![DataType::Timestamptz],
1161 mode,
1162 eval_error_report,
1163 barrier_receiver,
1164 state_table,
1165 progress_ratio,
1166 Arc::new(StreamingMetrics::unused()),
1167 0.into(),
1168 );
1169 (sender, now_executor)
1170 }
1171
1172 async fn create_executor_with_progress_ratio(
1173 mode: NowMode,
1174 state_store: &MemoryStateStore,
1175 progress_ratio: Option<f32>,
1176 ) -> (UnboundedSender<Barrier>, BoxedMessageStream) {
1177 let (sender, executor) = build_executor(mode, state_store, progress_ratio).await;
1178 (sender, executor.boxed().execute())
1179 }
1180
1181 async fn create_executor(
1182 mode: NowMode,
1183 state_store: &MemoryStateStore,
1184 ) -> (UnboundedSender<Barrier>, BoxedMessageStream) {
1185 create_executor_with_progress_ratio(mode, state_store, None).await
1186 }
1187}