1use std::collections::VecDeque;
16use std::pin::Pin;
17use std::task::{Context, Poll};
18
19use risingwave_common::array::StreamChunkBuilder;
20use tokio::sync::mpsc;
21
22use super::exchange::input::BoxedActorInput;
23use super::*;
24use crate::executor::prelude::*;
25use crate::task::LocalBarrierManager;
26
27pub type SelectReceivers = DynamicReceivers<ActorId, ()>;
28
29pub type MergeUpstream = BufferChunks<SelectReceivers>;
30pub type SingletonUpstream = BoxedActorInput;
31
32pub(crate) enum MergeExecutorUpstream {
33 Singleton(SingletonUpstream),
34 Merge(MergeUpstream),
35}
36
37pub(crate) struct MergeExecutorInput {
38 upstream: MergeExecutorUpstream,
39 actor_context: ActorContextRef,
40 upstream_fragment_id: UpstreamFragmentId,
41 local_barrier_manager: LocalBarrierManager,
42 executor_stats: Arc<StreamingMetrics>,
43 pub(crate) info: ExecutorInfo,
44}
45
46impl MergeExecutorInput {
47 pub(crate) fn new(
48 upstream: MergeExecutorUpstream,
49 actor_context: ActorContextRef,
50 upstream_fragment_id: UpstreamFragmentId,
51 local_barrier_manager: LocalBarrierManager,
52 executor_stats: Arc<StreamingMetrics>,
53 info: ExecutorInfo,
54 ) -> Self {
55 Self {
56 upstream,
57 actor_context,
58 upstream_fragment_id,
59 local_barrier_manager,
60 executor_stats,
61 info,
62 }
63 }
64
65 pub(crate) fn into_executor(self, barrier_rx: mpsc::UnboundedReceiver<Barrier>) -> Executor {
66 let fragment_id = self.actor_context.fragment_id;
67 let executor = match self.upstream {
68 MergeExecutorUpstream::Singleton(input) => ReceiverExecutor::new(
69 self.actor_context,
70 fragment_id,
71 self.upstream_fragment_id,
72 input,
73 self.local_barrier_manager,
74 self.executor_stats,
75 barrier_rx,
76 )
77 .boxed(),
78 MergeExecutorUpstream::Merge(inputs) => MergeExecutor::new(
79 self.actor_context,
80 fragment_id,
81 self.upstream_fragment_id,
82 inputs,
83 self.local_barrier_manager,
84 self.executor_stats,
85 barrier_rx,
86 )
87 .boxed(),
88 };
89 (self.info, executor).into()
90 }
91}
92
93impl Stream for MergeExecutorInput {
94 type Item = DispatcherMessageStreamItem;
95
96 fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
97 match &mut self.get_mut().upstream {
98 MergeExecutorUpstream::Singleton(input) => input.poll_next_unpin(cx),
99 MergeExecutorUpstream::Merge(inputs) => inputs.poll_next_unpin(cx),
100 }
101 }
102}
103
104mod upstream {
105 use super::*;
106
107 pub trait Upstream:
110 Stream<Item = StreamExecutorResult<DispatcherMessage>> + Unpin + Send + 'static
111 {
112 fn upstream_input_ids(&self) -> impl Iterator<Item = ActorId> + '_;
113 fn flush_buffered_watermarks(&mut self);
114 fn update(&mut self, to_add: Vec<BoxedActorInput>, to_remove: &HashSet<ActorId>);
115 }
116
117 impl Upstream for MergeUpstream {
118 fn upstream_input_ids(&self) -> impl Iterator<Item = ActorId> + '_ {
119 self.inner.upstream_input_ids()
120 }
121
122 fn flush_buffered_watermarks(&mut self) {
123 self.inner.flush_buffered_watermarks();
124 }
125
126 fn update(&mut self, to_add: Vec<BoxedActorInput>, to_remove: &HashSet<ActorId>) {
127 if !to_add.is_empty() {
128 self.inner.add_upstreams_from(to_add);
129 }
130 if !to_remove.is_empty() {
131 self.inner.remove_upstreams(to_remove);
132 }
133 }
134 }
135
136 impl Upstream for SingletonUpstream {
137 fn upstream_input_ids(&self) -> impl Iterator<Item = ActorId> + '_ {
138 std::iter::once(self.id())
139 }
140
141 fn flush_buffered_watermarks(&mut self) {
142 }
144
145 fn update(&mut self, to_add: Vec<BoxedActorInput>, to_remove: &HashSet<ActorId>) {
146 assert_eq!(
147 to_remove,
148 &HashSet::from_iter([self.id()]),
149 "the removed upstream actor should be the same as the current input"
150 );
151
152 *self = Itertools::exactly_one(to_add.into_iter())
154 .expect("receiver should have exactly one new upstream");
155 }
156 }
157}
158use upstream::Upstream;
159
160pub struct MergeExecutorInner<U> {
162 actor_context: ActorContextRef,
164
165 upstream: U,
167
168 fragment_id: FragmentId,
170
171 upstream_fragment_id: FragmentId,
173
174 local_barrier_manager: LocalBarrierManager,
175
176 metrics: Arc<StreamingMetrics>,
178
179 barrier_rx: mpsc::UnboundedReceiver<Barrier>,
180}
181
182impl<U> MergeExecutorInner<U> {
183 pub fn new(
184 ctx: ActorContextRef,
185 fragment_id: FragmentId,
186 upstream_fragment_id: FragmentId,
187 upstream: U,
188 local_barrier_manager: LocalBarrierManager,
189 metrics: Arc<StreamingMetrics>,
190 barrier_rx: mpsc::UnboundedReceiver<Barrier>,
191 ) -> Self {
192 Self {
193 actor_context: ctx,
194 upstream,
195 fragment_id,
196 upstream_fragment_id,
197 local_barrier_manager,
198 metrics,
199 barrier_rx,
200 }
201 }
202}
203
204pub type MergeExecutor = MergeExecutorInner<MergeUpstream>;
206
207impl MergeExecutor {
208 #[cfg(test)]
209 pub fn for_test(
210 actor_id: impl Into<ActorId>,
211 inputs: Vec<super::exchange::permit::Receiver>,
212 local_barrier_manager: crate::task::LocalBarrierManager,
213 schema: Schema,
214 chunk_size: usize,
215 barrier_rx: Option<mpsc::UnboundedReceiver<Barrier>>,
216 ) -> Self {
217 let actor_id = actor_id.into();
218 use super::exchange::input::LocalInput;
219 use crate::executor::exchange::input::ActorInput;
220
221 let barrier_rx =
222 barrier_rx.unwrap_or_else(|| local_barrier_manager.subscribe_barrier(actor_id));
223
224 let metrics = StreamingMetrics::unused();
225 let actor_ctx = ActorContext::for_test(actor_id);
226 let upstream = Self::new_merge_upstream(
227 inputs
228 .into_iter()
229 .enumerate()
230 .map(|(idx, input)| LocalInput::new(input, ActorId::new(idx as u32)).boxed_input())
231 .collect(),
232 &metrics,
233 &actor_ctx,
234 chunk_size,
235 schema,
236 );
237
238 Self::new(
239 actor_ctx,
240 514.into(),
241 1919.into(),
242 upstream,
243 local_barrier_manager,
244 metrics.into(),
245 barrier_rx,
246 )
247 }
248
249 pub(crate) fn new_merge_upstream(
250 upstreams: Vec<BoxedActorInput>,
251 metrics: &StreamingMetrics,
252 actor_context: &ActorContext,
253 chunk_size: usize,
254 schema: Schema,
255 ) -> MergeUpstream {
256 let merge_barrier_align_duration = Some(
257 metrics
258 .merge_barrier_align_duration
259 .with_guarded_label_values(&[
260 &actor_context.id.to_string(),
261 &actor_context.fragment_id.to_string(),
262 ]),
263 );
264
265 BufferChunks::new(
266 SelectReceivers::new(upstreams, None, merge_barrier_align_duration),
268 chunk_size,
269 schema,
270 )
271 }
272}
273
274impl<U> MergeExecutorInner<U>
275where
276 U: Upstream,
277{
278 #[try_stream(ok = Message, error = StreamExecutorError)]
279 pub(crate) async fn execute_inner(mut self: Box<Self>) {
280 let mut upstream = self.upstream;
281 let actor_id = self.actor_context.id;
282
283 let mut metrics = self.metrics.new_actor_input_metrics(
284 actor_id,
285 self.fragment_id,
286 self.upstream_fragment_id,
287 );
288
289 let mut barrier_buffer = DispatchBarrierBuffer::new(
290 self.barrier_rx,
291 actor_id,
292 self.upstream_fragment_id,
293 self.local_barrier_manager,
294 self.metrics.clone(),
295 self.fragment_id,
296 self.actor_context.config.clone(),
297 );
298
299 loop {
300 let msg = barrier_buffer
301 .await_next_message(&mut upstream, &metrics)
302 .await?;
303 let msg = match msg {
304 DispatcherMessage::Watermark(watermark) => Message::Watermark(watermark),
305 DispatcherMessage::Chunk(chunk) => {
306 metrics.actor_in_record_cnt.inc_by(chunk.cardinality() as _);
307 Message::Chunk(chunk)
308 }
309 DispatcherMessage::Barrier(barrier) => {
310 let (barrier, new_inputs) =
311 barrier_buffer.pop_barrier_with_inputs(barrier).await?;
312
313 if let Some(Mutation::Update(UpdateMutation { dispatchers, .. })) =
314 barrier.mutation.as_deref()
315 && upstream
316 .upstream_input_ids()
317 .any(|actor_id| dispatchers.contains_key(&actor_id))
318 {
319 upstream.flush_buffered_watermarks();
321 }
322
323 if let Some(update) =
324 barrier.as_update_merge(self.actor_context.id, self.upstream_fragment_id)
325 {
326 let new_upstream_fragment_id = update
327 .new_upstream_fragment_id
328 .unwrap_or(self.upstream_fragment_id);
329 let removed_upstream_actor_id: HashSet<_> =
330 if update.new_upstream_fragment_id.is_some() {
331 upstream.upstream_input_ids().collect()
332 } else {
333 update.removed_upstream_actor_id.iter().copied().collect()
334 };
335
336 upstream.flush_buffered_watermarks();
338
339 upstream.update(new_inputs.unwrap_or_default(), &removed_upstream_actor_id);
341
342 self.upstream_fragment_id = new_upstream_fragment_id;
343 metrics = self.metrics.new_actor_input_metrics(
344 actor_id,
345 self.fragment_id,
346 self.upstream_fragment_id,
347 );
348 }
349
350 let is_stop = barrier.is_stop(actor_id);
351 let msg = Message::Barrier(barrier);
352 if is_stop {
353 yield msg;
354 break;
355 }
356
357 msg
358 }
359 };
360
361 yield msg;
362 }
363 }
364}
365
366impl<U> Execute for MergeExecutorInner<U>
367where
368 U: Upstream,
369{
370 fn execute(self: Box<Self>) -> BoxedMessageStream {
371 self.execute_inner().boxed()
372 }
373}
374
375pub struct BufferChunks<S: Stream> {
379 inner: S,
380 chunk_builder: StreamChunkBuilder,
381
382 pending_items: VecDeque<S::Item>,
384}
385
386impl<S: Stream> BufferChunks<S> {
387 pub(super) fn new(inner: S, chunk_size: usize, schema: Schema) -> Self {
388 assert!(chunk_size > 0);
389 let chunk_builder = StreamChunkBuilder::new(chunk_size, schema.data_types());
390 Self {
391 inner,
392 chunk_builder,
393 pending_items: VecDeque::new(),
394 }
395 }
396}
397
398impl<S: Stream> std::ops::Deref for BufferChunks<S> {
399 type Target = S;
400
401 fn deref(&self) -> &Self::Target {
402 &self.inner
403 }
404}
405
406impl<S: Stream> std::ops::DerefMut for BufferChunks<S> {
407 fn deref_mut(&mut self) -> &mut Self::Target {
408 &mut self.inner
409 }
410}
411
412impl<S: Stream> Stream for BufferChunks<S>
413where
414 S: Stream<Item = DispatcherMessageStreamItem> + Unpin,
415{
416 type Item = S::Item;
417
418 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
419 loop {
420 if let Some(item) = self.pending_items.pop_front() {
421 return Poll::Ready(Some(item));
422 }
423
424 match self.inner.poll_next_unpin(cx) {
425 Poll::Pending => {
426 return if let Some(chunk_out) = self.chunk_builder.take() {
427 Poll::Ready(Some(Ok(MessageInner::Chunk(chunk_out))))
428 } else {
429 Poll::Pending
430 };
431 }
432
433 Poll::Ready(Some(result)) => {
434 if let Ok(MessageInner::Chunk(chunk)) = result {
435 for row in chunk.records() {
436 if let Some(chunk_out) = self.chunk_builder.append_record(row) {
437 self.pending_items
438 .push_back(Ok(MessageInner::Chunk(chunk_out)));
439 }
440 }
441 } else {
442 return if let Some(chunk_out) = self.chunk_builder.take() {
443 self.pending_items.push_back(result);
444 Poll::Ready(Some(Ok(MessageInner::Chunk(chunk_out))))
445 } else {
446 Poll::Ready(Some(result))
447 };
448 }
449 }
450
451 Poll::Ready(None) => {
452 unreachable!("Merge should always have upstream inputs");
454 }
455 }
456 }
457 }
458}
459
460#[cfg(test)]
461mod tests {
462 use std::sync::atomic::{AtomicBool, Ordering};
463 use std::time::Duration;
464
465 use assert_matches::assert_matches;
466 use futures::FutureExt;
467 use futures::future::try_join_all;
468 use risingwave_common::array::Op;
469 use risingwave_common::util::epoch::test_epoch;
470 use risingwave_pb::task_service::stream_exchange_service_server::{
471 StreamExchangeService, StreamExchangeServiceServer,
472 };
473 use risingwave_pb::task_service::{GetStreamRequest, GetStreamResponse, PbPermits};
474 use tokio::time::sleep;
475 use tokio_stream::wrappers::ReceiverStream;
476 use tonic::{Request, Response, Status, Streaming};
477
478 use super::*;
479 use crate::executor::exchange::input::{ActorInput, LocalInput, RemoteInput};
480 use crate::executor::exchange::permit::channel_for_test;
481 use crate::executor::{BarrierInner as Barrier, MessageInner as Message};
482 use crate::task::barrier_test_utils::LocalBarrierTestEnv;
483 use crate::task::test_utils::helper_make_local_actor;
484 use crate::task::{NewOutputRequest, TEST_PARTIAL_GRAPH_ID};
485
486 fn build_test_chunk(size: u64) -> StreamChunk {
487 let ops = vec![Op::Insert; size as usize];
488 StreamChunk::new(ops, vec![])
489 }
490
491 #[tokio::test]
492 async fn test_buffer_chunks() {
493 let test_env = LocalBarrierTestEnv::for_test().await;
494
495 let (tx, rx) = channel_for_test();
496 let input = LocalInput::new(rx, 1.into()).boxed_input();
497 let mut buffer = BufferChunks::new(input, 100, Schema::new(vec![]));
498
499 tx.send(Message::Chunk(build_test_chunk(10)).into())
501 .await
502 .unwrap();
503 assert_matches!(buffer.next().await.unwrap().unwrap(), Message::Chunk(chunk) => {
504 assert_eq!(chunk.ops().len() as u64, 10);
505 });
506
507 tx.send(Message::Chunk(build_test_chunk(10)).into())
509 .await
510 .unwrap();
511 tx.send(Message::Chunk(build_test_chunk(10)).into())
512 .await
513 .unwrap();
514 assert_matches!(buffer.next().await.unwrap().unwrap(), Message::Chunk(chunk) => {
515 assert_eq!(chunk.ops().len() as u64, 20);
516 });
517
518 tx.send(
520 Message::Watermark(Watermark {
521 col_idx: 0,
522 data_type: DataType::Int64,
523 val: ScalarImpl::Int64(233),
524 })
525 .into(),
526 )
527 .await
528 .unwrap();
529 assert_matches!(buffer.next().await.unwrap().unwrap(), Message::Watermark(watermark) => {
530 assert_eq!(watermark.val, ScalarImpl::Int64(233));
531 });
532
533 tx.send(Message::Chunk(build_test_chunk(10)).into())
535 .await
536 .unwrap();
537 tx.send(Message::Chunk(build_test_chunk(10)).into())
538 .await
539 .unwrap();
540 tx.send(
541 Message::Watermark(Watermark {
542 col_idx: 0,
543 data_type: DataType::Int64,
544 val: ScalarImpl::Int64(233),
545 })
546 .into(),
547 )
548 .await
549 .unwrap();
550 assert_matches!(buffer.next().await.unwrap().unwrap(), Message::Chunk(chunk) => {
551 assert_eq!(chunk.ops().len() as u64, 20);
552 });
553 assert_matches!(buffer.next().await.unwrap().unwrap(), Message::Watermark(watermark) => {
554 assert_eq!(watermark.val, ScalarImpl::Int64(233));
555 });
556
557 let barrier = Barrier::new_test_barrier(test_epoch(1));
559 test_env.inject_barrier(&barrier, [2.into()]);
560 tx.send(Message::Barrier(barrier.clone().into_dispatcher()).into())
561 .await
562 .unwrap();
563 assert_matches!(buffer.next().await.unwrap().unwrap(), Message::Barrier(Barrier { epoch: barrier_epoch, .. }) => {
564 assert_eq!(barrier_epoch.curr, test_epoch(1));
565 });
566
567 tx.send(Message::Chunk(build_test_chunk(10)).into())
569 .await
570 .unwrap();
571 tx.send(Message::Chunk(build_test_chunk(10)).into())
572 .await
573 .unwrap();
574 let barrier = Barrier::new_test_barrier(test_epoch(2));
575 test_env.inject_barrier(&barrier, [2.into()]);
576 tx.send(Message::Barrier(barrier.clone().into_dispatcher()).into())
577 .await
578 .unwrap();
579 assert_matches!(buffer.next().await.unwrap().unwrap(), Message::Chunk(chunk) => {
580 assert_eq!(chunk.ops().len() as u64, 20);
581 });
582 assert_matches!(buffer.next().await.unwrap().unwrap(), Message::Barrier(Barrier { epoch: barrier_epoch, .. }) => {
583 assert_eq!(barrier_epoch.curr, test_epoch(2));
584 });
585 }
586
587 #[tokio::test]
588 async fn test_merger() {
589 const CHANNEL_NUMBER: usize = 10;
590 let mut txs = Vec::with_capacity(CHANNEL_NUMBER);
591 let mut rxs = Vec::with_capacity(CHANNEL_NUMBER);
592 for _i in 0..CHANNEL_NUMBER {
593 let (tx, rx) = channel_for_test();
594 txs.push(tx);
595 rxs.push(rx);
596 }
597 let barrier_test_env = LocalBarrierTestEnv::for_test().await;
598 let actor_id = 233.into();
599 let mut handles = Vec::with_capacity(CHANNEL_NUMBER);
600
601 let epochs = (10..1000u64)
602 .step_by(10)
603 .map(|idx| (idx, test_epoch(idx)))
604 .collect_vec();
605 let mut prev_epoch = 0;
606 let prev_epoch = &mut prev_epoch;
607 let barriers: HashMap<_, _> = epochs
608 .iter()
609 .map(|(_, epoch)| {
610 let barrier = Barrier::with_prev_epoch_for_test(*epoch, *prev_epoch);
611 *prev_epoch = *epoch;
612 barrier_test_env.inject_barrier(&barrier, [actor_id]);
613 (*epoch, barrier)
614 })
615 .collect();
616 let b2 = Barrier::with_prev_epoch_for_test(test_epoch(1000), *prev_epoch)
617 .with_mutation(Mutation::Stop(StopMutation::default()));
618 barrier_test_env.inject_barrier(&b2, [actor_id]);
619 barrier_test_env.flush_all_events().await;
620
621 for (tx_id, tx) in txs.into_iter().enumerate() {
622 let epochs = epochs.clone();
623 let barriers = barriers.clone();
624 let b2 = b2.clone();
625 let handle = tokio::spawn(async move {
626 for (idx, epoch) in epochs {
627 if idx % 20 == 0 {
628 tx.send(Message::Chunk(build_test_chunk(10)).into())
629 .await
630 .unwrap();
631 } else {
632 tx.send(
633 Message::Watermark(Watermark {
634 col_idx: (idx as usize / 20 + tx_id) % CHANNEL_NUMBER,
635 data_type: DataType::Int64,
636 val: ScalarImpl::Int64(idx as i64),
637 })
638 .into(),
639 )
640 .await
641 .unwrap();
642 }
643 tx.send(Message::Barrier(barriers[&epoch].clone().into_dispatcher()).into())
644 .await
645 .unwrap();
646 sleep(Duration::from_millis(1)).await;
647 }
648 tx.send(Message::Barrier(b2.clone().into_dispatcher()).into())
649 .await
650 .unwrap();
651 });
652 handles.push(handle);
653 }
654
655 let merger = MergeExecutor::for_test(
656 actor_id,
657 rxs,
658 barrier_test_env.local_barrier_manager.clone(),
659 Schema::new(vec![]),
660 100,
661 None,
662 );
663 let mut merger = merger.boxed().execute();
664 for (idx, epoch) in epochs {
665 if idx % 20 == 0 {
666 let mut count = 0usize;
668 while count < 100 {
669 assert_matches!(merger.next().await.unwrap().unwrap(), Message::Chunk(chunk) => {
670 count += chunk.ops().len();
671 });
672 }
673 assert_eq!(count, 100);
674 } else if idx as usize / 20 >= CHANNEL_NUMBER - 1 {
675 for _ in 0..CHANNEL_NUMBER {
677 assert_matches!(merger.next().await.unwrap().unwrap(), Message::Watermark(watermark) => {
678 assert_eq!(watermark.val, ScalarImpl::Int64((idx - 20 * (CHANNEL_NUMBER as u64 - 1)) as i64));
679 });
680 }
681 }
682 assert_matches!(merger.next().await.unwrap().unwrap(), Message::Barrier(Barrier{epoch:barrier_epoch,..}) => {
684 assert_eq!(barrier_epoch.curr, epoch);
685 });
686 }
687 assert_matches!(
688 merger.next().await.unwrap().unwrap(),
689 Message::Barrier(Barrier {
690 mutation,
691 ..
692 }) if mutation.as_deref().unwrap().is_stop_mutation()
693 );
694
695 for handle in handles {
696 handle.await.unwrap();
697 }
698 }
699
700 #[tokio::test]
701 async fn test_configuration_change() {
702 let actor_id = 233.into();
703 let (untouched, old, new) = (234.into(), 235.into(), 238.into()); let barrier_test_env = LocalBarrierTestEnv::for_test().await;
705 let metrics = Arc::new(StreamingMetrics::unused());
706
707 let (upstream_fragment_id, fragment_id) = (10.into(), 18.into());
712
713 let actor_ctx = ActorContext::for_test(actor_id);
714
715 let inputs: Vec<_> =
716 try_join_all([untouched, old].into_iter().map(async |upstream_actor_id| {
717 new_input(
718 &barrier_test_env.local_barrier_manager,
719 metrics.clone(),
720 actor_id,
721 fragment_id,
722 &helper_make_local_actor(upstream_actor_id),
723 upstream_fragment_id,
724 actor_ctx.config.clone(),
725 )
726 .await
727 }))
728 .await
729 .unwrap();
730
731 let merge_updates = maplit::hashmap! {
732 (actor_id, upstream_fragment_id) => MergeUpdate {
733 actor_id,
734 upstream_fragment_id,
735 new_upstream_fragment_id: None,
736 added_upstream_actors: vec![helper_make_local_actor(new)],
737 removed_upstream_actor_id: vec![old],
738 }
739 };
740
741 let b1 = Barrier::new_test_barrier(test_epoch(1)).with_mutation(Mutation::Update(
742 UpdateMutation {
743 merges: merge_updates,
744 ..Default::default()
745 },
746 ));
747 barrier_test_env.inject_barrier(&b1, [actor_id]);
748 barrier_test_env.flush_all_events().await;
749
750 let barrier_rx = barrier_test_env
751 .local_barrier_manager
752 .subscribe_barrier(actor_id);
753 let upstream = MergeExecutor::new_merge_upstream(
754 inputs,
755 &metrics,
756 &actor_ctx,
757 100,
758 Schema::empty().clone(),
759 );
760
761 let mut merge = MergeExecutor::new(
762 actor_ctx,
763 fragment_id,
764 upstream_fragment_id,
765 upstream,
766 barrier_test_env.local_barrier_manager.clone(),
767 metrics.clone(),
768 barrier_rx,
769 )
770 .boxed()
771 .execute();
772
773 let mut txs = HashMap::new();
774 macro_rules! send {
775 ($actors:expr, $msg:expr) => {
776 for actor in $actors {
777 txs.get(&actor).unwrap().send($msg).await.unwrap();
778 }
779 };
780 }
781
782 macro_rules! assert_recv_pending {
783 () => {
784 assert!(
785 merge
786 .next()
787 .now_or_never()
788 .flatten()
789 .transpose()
790 .unwrap()
791 .is_none()
792 );
793 };
794 }
795 macro_rules! recv {
796 () => {
797 merge.next().await.transpose().unwrap()
798 };
799 }
800
801 macro_rules! collect_upstream_tx {
802 ($actors:expr) => {
803 for upstream_id in $actors {
804 let mut output_requests = barrier_test_env
805 .take_pending_new_output_requests(upstream_id)
806 .await;
807 assert_eq!(output_requests.len(), 1);
808 let (downstream_actor_id, request) = output_requests.pop().unwrap();
809 assert_eq!(downstream_actor_id, actor_id);
810 let NewOutputRequest::Local(tx) = request else {
811 unreachable!()
812 };
813 txs.insert(upstream_id, tx);
814 }
815 };
816 }
817
818 assert_recv_pending!();
819 barrier_test_env.flush_all_events().await;
820
821 collect_upstream_tx!([untouched, old]);
823
824 send!([untouched, old], Message::Chunk(build_test_chunk(1)).into());
826 assert_eq!(2, recv!().unwrap().as_chunk().unwrap().cardinality()); assert_recv_pending!();
828
829 send!(
830 [untouched, old],
831 Message::Barrier(b1.clone().into_dispatcher()).into()
832 );
833 assert_recv_pending!(); collect_upstream_tx!([new]);
836
837 send!([new], Message::Barrier(b1.clone().into_dispatcher()).into());
838 recv!().unwrap().as_barrier().unwrap(); send!([untouched, new], Message::Chunk(build_test_chunk(1)).into());
842 assert_eq!(2, recv!().unwrap().as_chunk().unwrap().cardinality()); assert_recv_pending!();
844 }
845
846 struct FakeExchangeService {
847 rpc_called: Arc<AtomicBool>,
848 }
849
850 fn exchange_client_test_barrier() -> crate::executor::Barrier {
851 Barrier::new_test_barrier(test_epoch(1))
852 }
853
854 #[async_trait::async_trait]
855 impl StreamExchangeService for FakeExchangeService {
856 type GetStreamStream = ReceiverStream<std::result::Result<GetStreamResponse, Status>>;
857
858 async fn get_stream(
859 &self,
860 _request: Request<Streaming<GetStreamRequest>>,
861 ) -> std::result::Result<Response<Self::GetStreamStream>, Status> {
862 let (tx, rx) = tokio::sync::mpsc::channel(10);
863 self.rpc_called.store(true, Ordering::SeqCst);
864 let stream_chunk = StreamChunk::default().to_protobuf();
866 tx.send(Ok(GetStreamResponse {
867 message: Some(PbStreamMessageBatch {
868 stream_message_batch: Some(
869 risingwave_pb::stream_plan::stream_message_batch::StreamMessageBatch::StreamChunk(
870 stream_chunk,
871 ),
872 ),
873 }),
874 permits: Some(PbPermits::default()),
875 }))
876 .await
877 .unwrap();
878 let barrier = exchange_client_test_barrier();
880 tx.send(Ok(GetStreamResponse {
881 message: Some(PbStreamMessageBatch {
882 stream_message_batch: Some(
883 risingwave_pb::stream_plan::stream_message_batch::StreamMessageBatch::BarrierBatch(
884 BarrierBatch {
885 barriers: vec![barrier.to_protobuf()],
886 },
887 ),
888 ),
889 }),
890 permits: Some(PbPermits::default()),
891 }))
892 .await
893 .unwrap();
894 Ok(Response::new(ReceiverStream::new(rx)))
895 }
896 }
897
898 #[tokio::test]
899 async fn test_stream_exchange_client() {
900 let rpc_called = Arc::new(AtomicBool::new(false));
901 let server_run = Arc::new(AtomicBool::new(false));
902 let addr = "127.0.0.1:12348".parse().unwrap();
903
904 let (shutdown_send, shutdown_recv) = tokio::sync::oneshot::channel();
906 let exchange_svc = StreamExchangeServiceServer::new(FakeExchangeService {
907 rpc_called: rpc_called.clone(),
908 });
909 let cp_server_run = server_run.clone();
910 let join_handle = tokio::spawn(async move {
911 cp_server_run.store(true, Ordering::SeqCst);
912 tonic::transport::Server::builder()
913 .add_service(exchange_svc)
914 .serve_with_shutdown(addr, async move {
915 shutdown_recv.await.unwrap();
916 })
917 .await
918 .unwrap();
919 });
920
921 sleep(Duration::from_secs(1)).await;
922 assert!(server_run.load(Ordering::SeqCst));
923
924 let test_env = LocalBarrierTestEnv::for_test().await;
925
926 let remote_input = {
927 RemoteInput::new(
928 &test_env.local_barrier_manager,
929 addr.into(),
930 TEST_PARTIAL_GRAPH_ID,
931 (0.into(), 0.into()),
932 (0.into(), 0.into()),
933 Arc::new(StreamingMetrics::unused()),
934 Arc::new(StreamingConfig::default()),
935 )
936 .await
937 .unwrap()
938 };
939
940 test_env.inject_barrier(&exchange_client_test_barrier(), [remote_input.id()]);
941
942 pin_mut!(remote_input);
943
944 assert_matches!(remote_input.next().await.unwrap().unwrap(), Message::Chunk(chunk) => {
945 let (ops, columns, visibility) = chunk.into_inner();
946 assert!(ops.is_empty());
947 assert!(columns.is_empty());
948 assert!(visibility.is_empty());
949 });
950 assert_matches!(remote_input.next().await.unwrap().unwrap(), Message::Barrier(Barrier { epoch: barrier_epoch, .. }) => {
951 assert_eq!(barrier_epoch.curr, test_epoch(1));
952 });
953 assert!(rpc_called.load(Ordering::SeqCst));
954
955 shutdown_send.send(()).unwrap();
956 join_handle.await.unwrap();
957 }
958}