risingwave_stream/executor/
chain.rs1use crate::executor::prelude::*;
16use crate::task::CreateMviewProgressReporter;
17
18pub struct ChainExecutor {
23 upstream: Executor,
24
25 progress: CreateMviewProgressReporter,
26}
27
28impl ChainExecutor {
29 pub fn new(upstream: Executor, progress: CreateMviewProgressReporter) -> Self {
30 Self { upstream, progress }
31 }
32
33 #[try_stream(ok = Message, error = StreamExecutorError)]
34 async fn execute_inner(mut self) {
35 let mut upstream = self.upstream.execute();
36
37 let barrier = expect_first_barrier(&mut upstream).await?;
39
40 yield Message::Barrier(barrier);
42
43 let mut progress_finished = false;
46 #[for_await]
47 for msg in upstream {
48 let msg = msg?;
49 if !progress_finished && let Message::Barrier(barrier) = &msg {
50 self.progress.finish(barrier.epoch, 0);
51 progress_finished = true;
52 }
53 yield msg;
54 }
55 }
56}
57
58impl Execute for ChainExecutor {
59 fn execute(self: Box<Self>) -> super::BoxedMessageStream {
60 self.execute_inner().boxed()
61 }
62}
63
64#[cfg(test)]
65mod test {
66
67 use futures::StreamExt;
68 use risingwave_common::array::StreamChunk;
69 use risingwave_common::array::stream_chunk::StreamChunkTestExt;
70 use risingwave_common::catalog::{Field, Schema};
71 use risingwave_common::types::DataType;
72 use risingwave_common::util::epoch::test_epoch;
73 use risingwave_pb::stream_plan::Dispatcher;
74
75 use super::ChainExecutor;
76 use crate::executor::test_utils::MockSource;
77 use crate::executor::{AddMutation, Barrier, Execute, Message, Mutation, StreamKey};
78 use crate::task::CreateMviewProgressReporter;
79 use crate::task::barrier_test_utils::LocalBarrierTestEnv;
80
81 #[tokio::test]
82 async fn test_basic() {
83 let test_env = LocalBarrierTestEnv::for_test().await;
84 let barrier_manager = test_env.local_barrier_manager.clone();
85 let progress = CreateMviewProgressReporter::for_test(barrier_manager);
86 let actor_id = progress.actor_id();
87
88 let schema = Schema::new(vec![Field::unnamed(DataType::Int64)]);
89 let upstream = MockSource::with_messages(vec![
90 Message::Barrier(Barrier::new_test_barrier(test_epoch(1)).with_mutation(
91 Mutation::Add(AddMutation {
92 adds: maplit::hashmap! {
93 0.into() => vec![Dispatcher {
94 downstream_actor_id: vec![actor_id],
95 ..Default::default()
96 }],
97 },
98 added_actors: maplit::hashset! { actor_id },
99 ..Default::default()
100 }),
101 )),
102 Message::Chunk(StreamChunk::from_pretty("I\n + 3")),
103 Message::Chunk(StreamChunk::from_pretty("I\n + 4")),
104 Message::Barrier(Barrier::new_test_barrier(test_epoch(2))),
105 ])
106 .into_executor(schema.clone(), StreamKey::new());
107
108 let chain = ChainExecutor::new(upstream, progress);
109
110 let mut chain = chain.boxed().execute();
111 chain.next().await;
112
113 assert_eq!(
114 chain.next().await.transpose().unwrap(),
115 Some(Message::Chunk(StreamChunk::from_pretty("I\n + 3")))
116 );
117 assert_eq!(
118 chain.next().await.transpose().unwrap(),
119 Some(Message::Chunk(StreamChunk::from_pretty("I\n + 4")))
120 );
121 assert!(matches!(
122 chain.next().await.transpose().unwrap(),
123 Some(Message::Barrier(_))
124 ));
125 }
126}