1mod prelude;
16
17use std::collections::{BTreeMap, HashMap, HashSet, VecDeque};
18use std::fmt::Debug;
19use std::future::pending;
20use std::hash::Hash;
21use std::pin::Pin;
22use std::sync::Arc;
23use std::task::Poll;
24use std::vec;
25
26use await_tree::InstrumentAwait;
27use enum_as_inner::EnumAsInner;
28use futures::future::try_join_all;
29use futures::stream::{BoxStream, FusedStream, FuturesUnordered, StreamFuture};
30use futures::{FutureExt, Stream, StreamExt, TryStreamExt};
31use itertools::Itertools;
32use prometheus::core::{AtomicU64, GenericCounter};
33use risingwave_common::array::StreamChunk;
34use risingwave_common::bitmap::Bitmap;
35use risingwave_common::catalog::{Schema, TableId};
36use risingwave_common::config::StreamingConfig;
37use risingwave_common::metrics::LabelGuardedMetric;
38use risingwave_common::row::OwnedRow;
39use risingwave_common::types::{DataType, Datum, DefaultOrd, ScalarImpl};
40use risingwave_common::util::epoch::{Epoch, EpochPair};
41use risingwave_common::util::tracing::TracingContext;
42use risingwave_common::util::value_encoding::{DatumFromProtoExt, DatumToProtoExt};
43use risingwave_common_estimate_size::EstimateSize;
44use risingwave_connector::source::SplitImpl;
45use risingwave_expr::expr::NonStrictExpression;
46use risingwave_pb::common::ThrottleType;
47use risingwave_pb::data::PbEpoch;
48use risingwave_pb::expr::PbInputRef;
49use risingwave_pb::stream_plan::add_mutation::PbNewUpstreamSink;
50use risingwave_pb::stream_plan::barrier::BarrierKind;
51use risingwave_pb::stream_plan::barrier_mutation::Mutation as PbMutation;
52use risingwave_pb::stream_plan::stream_node::PbStreamKind;
53use risingwave_pb::stream_plan::throttle_mutation::ThrottleConfig;
54use risingwave_pb::stream_plan::update_mutation::{DispatcherUpdate, MergeUpdate};
55use risingwave_pb::stream_plan::{
56 IcebergPkIndexCompactionContext, PbBarrier, PbBarrierMutation, PbDispatcher,
57 PbSinkSchemaChange, PbStreamMessageBatch, PbWatermark, SubscriptionUpstreamInfo,
58};
59use smallvec::SmallVec;
60use tokio::sync::mpsc;
61use tokio::time::{Duration, Instant};
62
63use crate::error::StreamResult;
64use crate::executor::exchange::input::{
65 BoxedActorInput, BoxedInput, assert_equal_dispatcher_barrier, new_input,
66};
67use crate::executor::monitor::ActorInputMetrics;
68use crate::executor::prelude::StreamingMetrics;
69use crate::executor::watermark::BufferedWatermarks;
70use crate::task::{ActorId, FragmentId, LocalBarrierManager};
71
72mod actor;
73mod barrier_align;
74pub mod exchange;
75pub mod monitor;
76
77pub mod aggregate;
78pub mod asof_join;
79mod backfill;
80mod barrier_recv;
81mod batch_query;
82mod chain;
83mod changelog;
84mod dedup;
85mod dispatch;
86pub mod dml;
87mod dynamic_filter;
88pub mod eowc;
89pub mod error;
90mod expand;
91mod filter;
92mod gap_fill;
93pub mod hash_join;
94mod hop_window;
95pub(crate) mod iceberg_with_pk_index;
96mod join;
97pub mod locality_provider;
98mod lookup;
99mod lookup_union;
100pub mod match_recognize;
101mod merge;
102mod mview;
103mod nested_loop_temporal_join;
104mod no_op;
105mod now;
106mod over_window;
107pub mod project;
108mod receiver;
109pub mod row_id_gen;
110mod sink;
111pub mod source;
112mod stream_reader;
113pub mod subtask;
114mod temporal_join;
115mod top_n;
116mod troublemaker;
117mod union;
118mod upstream_sink_union;
119mod values;
120mod watermark;
121mod watermark_filter;
122mod wrapper;
123
124mod approx_percentile;
125
126mod row_merge;
127
128#[cfg(test)]
129mod integration_tests;
130mod sync_kv_log_store;
131#[cfg(any(test, feature = "test"))]
132pub mod test_utils;
133mod utils;
134mod vector;
135
136pub use actor::{Actor, ActorContext, ActorContextRef};
137use anyhow::{Context, anyhow};
138pub use approx_percentile::global::GlobalApproxPercentileExecutor;
139pub use approx_percentile::local::LocalApproxPercentileExecutor;
140pub use backfill::arrangement_backfill::*;
141pub use backfill::cdc::{
142 CdcBackfillExecutor, ExternalStorageTable, ParallelizedCdcBackfillExecutor,
143};
144pub use backfill::no_shuffle_backfill::*;
145pub use backfill::snapshot_backfill::*;
146pub use barrier_recv::BarrierRecvExecutor;
147pub use batch_query::BatchQueryExecutor;
148pub use chain::ChainExecutor;
149pub use changelog::{ChangeLogExecutor, ChangeLogMode};
150pub use dedup::AppendOnlyDedupExecutor;
151pub use dispatch::{DispatchExecutor, SyncLogStoreDispatchExecutor};
152pub use dynamic_filter::DynamicFilterExecutor;
153pub use error::{StreamExecutorError, StreamExecutorResult};
154pub use expand::ExpandExecutor;
155pub use filter::{FilterExecutor, UpsertFilterExecutor};
156pub use gap_fill::{GapFillExecutor, GapFillExecutorArgs};
157pub use hash_join::*;
158pub use hop_window::HopWindowExecutor;
159pub use iceberg_with_pk_index::{
160 CompactionResolverExecutor, IcebergWriterImpl, PositionDeleteHandlerImpl,
161 PositionDeleteMergerExecutor, WriterExecutor,
162};
163pub use join::asof_join::{AsOfCpuEncoding, AsOfMemoryEncoding};
164pub use join::row::{CachedJoinRow, CpuEncoding, JoinEncoding, MemoryEncoding};
165pub use join::{AsOfDesc, AsOfJoinType, JoinType};
166pub use lookup::*;
167pub use lookup_union::LookupUnionExecutor;
168pub use merge::MergeExecutor;
169pub(crate) use merge::{MergeExecutorInput, MergeExecutorUpstream};
170pub use mview::{MaterializeExecutor, RefreshableMaterializeArgs};
171pub use nested_loop_temporal_join::NestedLoopTemporalJoinExecutor;
172pub use no_op::NoOpExecutor;
173pub use now::*;
174pub use over_window::*;
175pub use receiver::ReceiverExecutor;
176use risingwave_common::id::SourceId;
177pub use row_merge::RowMergeExecutor;
178pub use sink::SinkExecutor;
179pub use sync_kv_log_store::SyncedKvLogStoreExecutor;
180pub use sync_kv_log_store::metrics::SyncedKvLogStoreMetrics;
181pub use temporal_join::TemporalJoinExecutor;
182pub use top_n::{
183 AppendOnlyGroupTopNExecutor, AppendOnlyTopNExecutor, GroupTopNExecutor, TopNExecutor,
184};
185pub use troublemaker::TroublemakerExecutor;
186pub use union::UnionExecutor;
187pub use upstream_sink_union::{UpstreamFragmentInfo, UpstreamSinkUnionExecutor};
188pub use utils::DummyExecutor;
189pub use values::ValuesExecutor;
190pub use vector::*;
191pub use watermark_filter::{UpsertWatermarkFilterExecutor, WatermarkFilterExecutor};
192pub use wrapper::WrapperExecutor;
193
194use self::barrier_align::AlignedMessageStream;
195
196pub type MessageStreamItemInner<M> = StreamExecutorResult<MessageInner<M>>;
197pub type MessageStreamItem = MessageStreamItemInner<BarrierMutationType>;
198pub type DispatcherMessageStreamItem = StreamExecutorResult<DispatcherMessage>;
199pub type BoxedMessageStream = BoxStream<'static, MessageStreamItem>;
200
201pub use risingwave_common::util::epoch::task_local::{curr_epoch, epoch, prev_epoch};
202use risingwave_connector::sink::catalog::SinkId;
203use risingwave_connector::source::cdc::{
204 CdcTableSnapshotSplitAssignmentWithGeneration,
205 build_actor_cdc_table_snapshot_splits_with_generation,
206};
207use risingwave_pb::id::{ExecutorId, SubscriberId};
208use risingwave_pb::stream_plan::stream_message_batch::{BarrierBatch, StreamMessageBatch};
209
210pub trait MessageStreamInner<M> = Stream<Item = MessageStreamItemInner<M>> + Send;
211pub trait MessageStream = Stream<Item = MessageStreamItem> + Send;
212pub trait DispatcherMessageStream = Stream<Item = DispatcherMessageStreamItem> + Send;
213
214#[derive(Debug, Default, Clone)]
216pub struct ExecutorInfo {
217 pub schema: Schema,
219
220 pub stream_key: StreamKey,
222
223 pub stream_kind: PbStreamKind,
225
226 pub identity: String,
228
229 pub id: ExecutorId,
231}
232
233impl ExecutorInfo {
234 pub fn for_test(schema: Schema, stream_key: StreamKey, identity: String, id: u64) -> Self {
235 Self {
236 schema,
237 stream_key,
238 stream_kind: PbStreamKind::Retract, identity,
240 id: id.into(),
241 }
242 }
243}
244
245pub trait Execute: Send + 'static {
247 fn execute(self: Box<Self>) -> BoxedMessageStream;
248
249 fn boxed(self) -> Box<dyn Execute>
250 where
251 Self: Sized + Send + 'static,
252 {
253 Box::new(self)
254 }
255}
256
257pub struct Executor {
260 info: ExecutorInfo,
261 execute: Box<dyn Execute>,
262}
263
264impl Executor {
265 pub fn new(info: ExecutorInfo, execute: Box<dyn Execute>) -> Self {
266 Self { info, execute }
267 }
268
269 pub fn info(&self) -> &ExecutorInfo {
270 &self.info
271 }
272
273 pub fn schema(&self) -> &Schema {
274 &self.info.schema
275 }
276
277 pub fn stream_key(&self) -> StreamKeyRef<'_> {
278 &self.info.stream_key
279 }
280
281 pub fn stream_kind(&self) -> PbStreamKind {
282 self.info.stream_kind
283 }
284
285 pub fn identity(&self) -> &str {
286 &self.info.identity
287 }
288
289 pub fn execute(self) -> BoxedMessageStream {
290 self.execute.execute()
291 }
292}
293
294impl std::fmt::Debug for Executor {
295 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
296 f.write_str(self.identity())
297 }
298}
299
300impl From<(ExecutorInfo, Box<dyn Execute>)> for Executor {
301 fn from((info, execute): (ExecutorInfo, Box<dyn Execute>)) -> Self {
302 Self::new(info, execute)
303 }
304}
305
306impl<E> From<(ExecutorInfo, E)> for Executor
307where
308 E: Execute,
309{
310 fn from((info, execute): (ExecutorInfo, E)) -> Self {
311 Self::new(info, execute.boxed())
312 }
313}
314
315pub const INVALID_EPOCH: u64 = 0;
316
317type UpstreamFragmentId = FragmentId;
318type SplitAssignments = HashMap<ActorId, Vec<SplitImpl>>;
319
320#[derive(Debug, Clone, PartialEq)]
321#[cfg_attr(any(test, feature = "test"), derive(Default))]
322pub struct UpdateMutation {
323 pub dispatchers: HashMap<ActorId, Vec<DispatcherUpdate>>,
324 pub merges: HashMap<(ActorId, UpstreamFragmentId), MergeUpdate>,
325 pub vnode_bitmaps: HashMap<ActorId, Arc<Bitmap>>,
326 pub dropped_actors: HashSet<ActorId>,
327 pub actor_splits: SplitAssignments,
328 pub actor_new_dispatchers: HashMap<ActorId, Vec<PbDispatcher>>,
329 pub actor_cdc_table_snapshot_splits: CdcTableSnapshotSplitAssignmentWithGeneration,
330 pub sink_schema_change: HashMap<SinkId, PbSinkSchemaChange>,
331 pub subscriptions_to_drop: Vec<SubscriptionUpstreamInfo>,
332 pub iceberg_pk_index_compaction: Option<IcebergPkIndexCompactionContext>,
333}
334
335#[derive(Debug, Clone, PartialEq)]
336#[cfg_attr(any(test, feature = "test"), derive(Default))]
337pub struct AddMutation {
338 pub adds: HashMap<ActorId, Vec<PbDispatcher>>,
339 pub added_actors: HashSet<ActorId>,
340 pub dropped_actors: HashSet<ActorId>,
341 pub splits: SplitAssignments,
343 pub pause: bool,
344 pub subscriptions_to_add: Vec<(TableId, SubscriberId)>,
346 pub backfill_nodes_to_pause: HashSet<FragmentId>,
348 pub actor_cdc_table_snapshot_splits: CdcTableSnapshotSplitAssignmentWithGeneration,
349 pub new_upstream_sinks: HashMap<FragmentId, PbNewUpstreamSink>,
350 pub sink_log_store_flush: HashSet<SinkId>,
351}
352
353#[derive(Debug, Clone, PartialEq)]
354#[cfg_attr(any(test, feature = "test"), derive(Default))]
355pub struct StopMutation {
356 pub dropped_actors: HashSet<ActorId>,
357 pub dropped_sink_fragments: HashSet<FragmentId>,
358}
359
360#[derive(Debug, Clone, PartialEq)]
362pub enum Mutation {
363 Stop(StopMutation),
364 Update(UpdateMutation),
365 Add(AddMutation),
366 SourceChangeSplit(SplitAssignments),
367 Pause,
368 Resume,
369 Throttle(HashMap<FragmentId, ThrottleConfig>),
370 ConnectorPropsChange(HashMap<u32, HashMap<String, String>>),
371 DropSubscriptions {
372 subscriptions_to_drop: Vec<SubscriptionUpstreamInfo>,
374 },
375 StartFragmentBackfill {
376 fragment_ids: HashSet<FragmentId>,
377 },
378 RefreshStart {
379 table_id: TableId,
380 associated_source_id: SourceId,
381 },
382 ListFinish {
383 associated_source_id: SourceId,
384 },
385 LoadFinish {
386 associated_source_id: SourceId,
387 },
388 ResetSource {
389 source_id: SourceId,
390 },
391 InjectSourceOffsets {
392 source_id: SourceId,
393 split_offsets: HashMap<String, String>,
395 },
396}
397
398#[derive(Debug, Clone)]
403pub struct BarrierInner<M> {
404 pub epoch: EpochPair,
405 pub mutation: M,
406 pub kind: BarrierKind,
407
408 pub tracing_context: TracingContext,
410}
411
412pub type BarrierMutationType = Option<Arc<Mutation>>;
413pub type Barrier = BarrierInner<BarrierMutationType>;
414pub type DispatcherBarrier = BarrierInner<()>;
415
416impl<M: Default> BarrierInner<M> {
417 pub fn new_test_barrier(epoch: u64) -> Self {
419 Self {
420 epoch: EpochPair::new_test_epoch(epoch),
421 kind: BarrierKind::Checkpoint,
422 tracing_context: TracingContext::none(),
423 mutation: Default::default(),
424 }
425 }
426
427 pub fn with_prev_epoch_for_test(epoch: u64, prev_epoch: u64) -> Self {
428 Self {
429 epoch: EpochPair::new(epoch, prev_epoch),
430 kind: BarrierKind::Checkpoint,
431 tracing_context: TracingContext::none(),
432 mutation: Default::default(),
433 }
434 }
435}
436
437impl Barrier {
438 pub fn into_dispatcher(self) -> DispatcherBarrier {
439 DispatcherBarrier {
440 epoch: self.epoch,
441 mutation: (),
442 kind: self.kind,
443 tracing_context: self.tracing_context,
444 }
445 }
446
447 #[must_use]
448 pub fn with_mutation(self, mutation: Mutation) -> Self {
449 Self {
450 mutation: Some(Arc::new(mutation)),
451 ..self
452 }
453 }
454
455 #[cfg(any(test, feature = "test"))]
456 #[must_use]
457 pub fn with_iceberg_pk_index_compaction(self, update: IcebergPkIndexCompactionContext) -> Self {
458 self.with_mutation(Mutation::Update(UpdateMutation {
459 iceberg_pk_index_compaction: Some(update),
460 ..Default::default()
461 }))
462 }
463
464 pub fn iceberg_pk_index_compaction(&self) -> Option<&IcebergPkIndexCompactionContext> {
465 match self.mutation.as_deref() {
466 Some(Mutation::Update(update)) => update.iceberg_pk_index_compaction.as_ref(),
467 _ => None,
468 }
469 }
470
471 #[must_use]
472 pub fn with_stop(self) -> Self {
473 self.with_mutation(Mutation::Stop(StopMutation {
474 dropped_actors: Default::default(),
475 dropped_sink_fragments: Default::default(),
476 }))
477 }
478
479 pub fn is_with_stop_mutation(&self) -> bool {
481 matches!(self.mutation.as_deref(), Some(Mutation::Stop(_)))
482 }
483
484 pub fn is_stop(&self, actor_id: ActorId) -> bool {
486 self.all_stop_actors()
487 .is_some_and(|actors| actors.contains(&actor_id))
488 }
489
490 pub fn is_checkpoint(&self) -> bool {
491 self.kind == BarrierKind::Checkpoint
492 }
493
494 pub fn initial_split_assignment(&self, actor_id: ActorId) -> Option<&[SplitImpl]> {
504 match self.mutation.as_deref()? {
505 Mutation::Update(UpdateMutation { actor_splits, .. })
506 | Mutation::Add(AddMutation {
507 splits: actor_splits,
508 ..
509 }) => actor_splits.get(&actor_id),
510
511 _ => {
512 if cfg!(debug_assertions) {
513 panic!(
514 "the initial mutation of the barrier should not be {:?}",
515 self.mutation
516 );
517 }
518 None
519 }
520 }
521 .map(|s| s.as_slice())
522 }
523
524 pub fn all_stop_actors(&self) -> Option<&HashSet<ActorId>> {
526 self.mutation.as_deref()?.all_stop_actors()
527 }
528
529 pub fn is_newly_added(&self, actor_id: ActorId) -> bool {
535 match self.mutation.as_deref() {
536 Some(Mutation::Add(AddMutation { added_actors, .. })) => {
537 added_actors.contains(&actor_id)
538 }
539 _ => false,
540 }
541 }
542
543 pub fn should_start_fragment_backfill(&self, fragment_id: FragmentId) -> bool {
544 if let Some(Mutation::StartFragmentBackfill { fragment_ids }) = self.mutation.as_deref() {
545 fragment_ids.contains(&fragment_id)
546 } else {
547 false
548 }
549 }
550
551 pub fn has_more_downstream_fragments(&self, upstream_actor_id: ActorId) -> bool {
569 let Some(mutation) = self.mutation.as_deref() else {
570 return false;
571 };
572 match mutation {
573 Mutation::Add(AddMutation { adds, .. }) => adds.get(&upstream_actor_id).is_some(),
575 Mutation::Update(UpdateMutation {
577 actor_new_dispatchers,
578 ..
579 }) => actor_new_dispatchers.contains_key(&upstream_actor_id),
580 Mutation::Stop(_)
581 | Mutation::Pause
582 | Mutation::Resume
583 | Mutation::SourceChangeSplit(_)
584 | Mutation::Throttle { .. }
585 | Mutation::DropSubscriptions { .. }
586 | Mutation::ConnectorPropsChange(_)
587 | Mutation::StartFragmentBackfill { .. }
588 | Mutation::RefreshStart { .. }
589 | Mutation::ListFinish { .. }
590 | Mutation::LoadFinish { .. }
591 | Mutation::ResetSource { .. }
592 | Mutation::InjectSourceOffsets { .. } => false,
593 }
594 }
595
596 pub fn is_pause_on_startup(&self) -> bool {
598 match self.mutation.as_deref() {
599 Some(Mutation::Add(AddMutation { pause, .. })) => *pause,
600 _ => false,
601 }
602 }
603
604 pub fn is_backfill_pause_on_startup(&self, backfill_fragment_id: FragmentId) -> bool {
605 match self.mutation.as_deref() {
606 Some(Mutation::Add(AddMutation {
607 backfill_nodes_to_pause,
608 ..
609 })) => backfill_nodes_to_pause.contains(&backfill_fragment_id),
610 Some(Mutation::Update(_)) => false,
611 _ => {
612 tracing::warn!(
613 "expected an AddMutation or UpdateMutation on Startup, instead got {:?}",
614 self
615 );
616 false
617 }
618 }
619 }
620
621 pub fn is_resume(&self) -> bool {
623 matches!(self.mutation.as_deref(), Some(Mutation::Resume))
624 }
625
626 pub fn as_update_merge(
629 &self,
630 actor_id: ActorId,
631 upstream_fragment_id: UpstreamFragmentId,
632 ) -> Option<&MergeUpdate> {
633 self.mutation
634 .as_deref()
635 .and_then(|mutation| match mutation {
636 Mutation::Update(UpdateMutation { merges, .. }) => {
637 merges.get(&(actor_id, upstream_fragment_id))
638 }
639 _ => None,
640 })
641 }
642
643 pub fn as_new_upstream_sink(&self, fragment_id: FragmentId) -> Option<&PbNewUpstreamSink> {
646 self.mutation
647 .as_deref()
648 .and_then(|mutation| match mutation {
649 Mutation::Add(AddMutation {
650 new_upstream_sinks, ..
651 }) => new_upstream_sinks.get(&fragment_id),
652 _ => None,
653 })
654 }
655
656 pub fn as_dropped_upstream_sinks(&self) -> Option<&HashSet<FragmentId>> {
658 self.mutation
659 .as_deref()
660 .and_then(|mutation| match mutation {
661 Mutation::Stop(StopMutation {
662 dropped_sink_fragments,
663 ..
664 }) => Some(dropped_sink_fragments),
665 _ => None,
666 })
667 }
668
669 pub fn as_update_vnode_bitmap(&self, actor_id: ActorId) -> Option<Arc<Bitmap>> {
675 self.mutation
676 .as_deref()
677 .and_then(|mutation| match mutation {
678 Mutation::Update(UpdateMutation { vnode_bitmaps, .. }) => {
679 vnode_bitmaps.get(&actor_id).cloned()
680 }
681 _ => None,
682 })
683 }
684
685 pub fn assume_no_update_vnode_bitmap(&self, actor_id: ActorId) -> StreamExecutorResult<()> {
686 if self.as_update_vnode_bitmap(actor_id).is_some() {
687 return Err(anyhow!("updating vnode bitmap in place is not supported").into());
688 }
689 Ok(())
690 }
691
692 pub fn as_sink_schema_change(&self, sink_id: SinkId) -> Option<PbSinkSchemaChange> {
693 self.mutation
694 .as_deref()
695 .and_then(|mutation| match mutation {
696 Mutation::Update(UpdateMutation {
697 sink_schema_change, ..
698 }) => sink_schema_change.get(&sink_id).cloned(),
699 _ => None,
700 })
701 }
702
703 pub fn should_flush_sink_log_store(&self, sink_id: SinkId) -> bool {
704 self.mutation
705 .as_deref()
706 .is_some_and(|mutation| match mutation {
707 Mutation::Add(AddMutation {
708 sink_log_store_flush,
709 ..
710 }) => sink_log_store_flush.contains(&sink_id),
711 _ => false,
712 })
713 }
714
715 pub fn as_subscriptions_to_drop(&self) -> Option<&[SubscriptionUpstreamInfo]> {
716 match self.mutation.as_deref() {
717 Some(Mutation::DropSubscriptions {
718 subscriptions_to_drop,
719 })
720 | Some(Mutation::Update(UpdateMutation {
721 subscriptions_to_drop,
722 ..
723 })) => Some(subscriptions_to_drop.as_slice()),
724 _ => None,
725 }
726 }
727
728 pub fn get_curr_epoch(&self) -> Epoch {
729 Epoch(self.epoch.curr)
730 }
731
732 pub fn tracing_context(&self) -> &TracingContext {
734 &self.tracing_context
735 }
736
737 pub fn added_subscriber_on_mv_table(
738 &self,
739 mv_table_id: TableId,
740 ) -> impl Iterator<Item = SubscriberId> + '_ {
741 if let Some(Mutation::Add(add)) = self.mutation.as_deref() {
742 Some(add)
743 } else {
744 None
745 }
746 .into_iter()
747 .flat_map(move |add| {
748 add.subscriptions_to_add.iter().filter_map(
749 move |(upstream_mv_table_id, subscriber_id)| {
750 if *upstream_mv_table_id == mv_table_id {
751 Some(*subscriber_id)
752 } else {
753 None
754 }
755 },
756 )
757 })
758 }
759}
760
761#[cfg(test)]
762mod tests {
763 use risingwave_common::util::epoch::test_epoch;
764
765 use super::*;
766
767 #[test]
768 fn test_has_more_downstream_fragments_for_new_dispatcher() {
769 let actor_id = ActorId::new(1);
770 let other_actor_id = ActorId::new(2);
771
772 let add_barrier =
773 Barrier::new_test_barrier(test_epoch(1)).with_mutation(Mutation::Add(AddMutation {
774 adds: HashMap::from([(actor_id, vec![PbDispatcher::default()])]),
775 ..Default::default()
776 }));
777 assert!(add_barrier.has_more_downstream_fragments(actor_id));
778 assert!(!add_barrier.has_more_downstream_fragments(other_actor_id));
779
780 let update_barrier = Barrier::new_test_barrier(test_epoch(2)).with_mutation(
781 Mutation::Update(UpdateMutation {
782 actor_new_dispatchers: HashMap::from([(actor_id, vec![PbDispatcher::default()])]),
783 ..Default::default()
784 }),
785 );
786 assert!(update_barrier.has_more_downstream_fragments(actor_id));
787 assert!(!update_barrier.has_more_downstream_fragments(other_actor_id));
788
789 let dispatcher_update_barrier = Barrier::new_test_barrier(test_epoch(3)).with_mutation(
790 Mutation::Update(UpdateMutation {
791 dispatchers: HashMap::from([(actor_id, vec![DispatcherUpdate::default()])]),
792 ..Default::default()
793 }),
794 );
795 assert!(!dispatcher_update_barrier.has_more_downstream_fragments(actor_id));
796 }
797}
798
799impl<M: PartialEq> PartialEq for BarrierInner<M> {
800 fn eq(&self, other: &Self) -> bool {
801 self.epoch == other.epoch && self.mutation == other.mutation
802 }
803}
804
805impl Mutation {
806 pub fn backfill_throttle_config(&self, fragment_id: FragmentId) -> Option<&ThrottleConfig> {
808 let Mutation::Throttle(fragment_throttles) = self else {
809 return None;
810 };
811
812 fragment_throttles
813 .get(&fragment_id)
814 .filter(|config| config.throttle_type() == ThrottleType::Backfill)
815 }
816
817 pub fn all_stop_actors(&self) -> Option<&HashSet<ActorId>> {
819 match self {
820 Mutation::Stop(StopMutation { dropped_actors, .. })
821 | Mutation::Update(UpdateMutation { dropped_actors, .. })
822 | Mutation::Add(AddMutation { dropped_actors, .. }) => Some(dropped_actors),
823 _ => None,
824 }
825 }
826
827 pub fn is_stop(&self, actor_id: ActorId) -> bool {
829 self.all_stop_actors()
830 .is_some_and(|actors| actors.contains(&actor_id))
831 }
832
833 #[cfg(test)]
837 pub fn is_stop_mutation(&self) -> bool {
838 matches!(self, Mutation::Stop(_))
839 }
840
841 #[cfg(test)]
842 fn to_protobuf(&self) -> PbMutation {
843 use risingwave_pb::source::{
844 ConnectorSplit, ConnectorSplits, PbCdcTableSnapshotSplitsWithGeneration,
845 };
846 use risingwave_pb::stream_plan::connector_props_change_mutation::ConnectorPropsInfo;
847 use risingwave_pb::stream_plan::{
848 PbAddMutation, PbConnectorPropsChangeMutation, PbDispatchers,
849 PbDropSubscriptionsMutation, PbPauseMutation, PbResumeMutation,
850 PbSourceChangeSplitMutation, PbStartFragmentBackfillMutation, PbStopMutation,
851 PbThrottleMutation, PbUpdateMutation,
852 };
853 let actor_splits_to_protobuf = |actor_splits: &SplitAssignments| {
854 actor_splits
855 .iter()
856 .map(|(&actor_id, splits)| {
857 (
858 actor_id,
859 ConnectorSplits {
860 splits: splits.clone().iter().map(ConnectorSplit::from).collect(),
861 },
862 )
863 })
864 .collect::<HashMap<_, _>>()
865 };
866
867 match self {
868 Mutation::Stop(StopMutation {
869 dropped_actors,
870 dropped_sink_fragments,
871 }) => PbMutation::Stop(PbStopMutation {
872 actors: dropped_actors.iter().copied().collect(),
873 dropped_sink_fragments: dropped_sink_fragments.iter().copied().collect(),
874 }),
875 Mutation::Update(UpdateMutation {
876 dispatchers,
877 merges,
878 vnode_bitmaps,
879 dropped_actors,
880 actor_splits,
881 actor_new_dispatchers,
882 actor_cdc_table_snapshot_splits,
883 sink_schema_change,
884 subscriptions_to_drop,
885 iceberg_pk_index_compaction,
886 }) => PbMutation::Update(PbUpdateMutation {
887 dispatcher_update: dispatchers.values().flatten().cloned().collect(),
888 merge_update: merges.values().cloned().collect(),
889 actor_vnode_bitmap_update: vnode_bitmaps
890 .iter()
891 .map(|(&actor_id, bitmap)| (actor_id, bitmap.to_protobuf()))
892 .collect(),
893 dropped_actors: dropped_actors.iter().copied().collect(),
894 actor_splits: actor_splits_to_protobuf(actor_splits),
895 actor_new_dispatchers: actor_new_dispatchers
896 .iter()
897 .map(|(&actor_id, dispatchers)| {
898 (
899 actor_id,
900 PbDispatchers {
901 dispatchers: dispatchers.clone(),
902 },
903 )
904 })
905 .collect(),
906 actor_cdc_table_snapshot_splits: Some(PbCdcTableSnapshotSplitsWithGeneration {
907 splits:actor_cdc_table_snapshot_splits.splits.iter().map(|(actor_id,(splits, generation))| {
908 (*actor_id, risingwave_pb::source::PbCdcTableSnapshotSplits {
909 splits: splits.iter().map(risingwave_connector::source::cdc::build_cdc_table_snapshot_split).collect(),
910 generation: *generation,
911 })
912 }).collect()
913 }),
914 sink_schema_change: sink_schema_change
915 .iter()
916 .map(|(sink_id, change)| ((*sink_id).as_raw_id(), change.clone()))
917 .collect(),
918 subscriptions_to_drop: subscriptions_to_drop.clone(),
919 iceberg_pk_index_compaction: iceberg_pk_index_compaction.clone(),
920 }),
921 Mutation::Add(AddMutation {
922 adds,
923 added_actors,
924 dropped_actors,
925 splits,
926 pause,
927 subscriptions_to_add,
928 backfill_nodes_to_pause,
929 actor_cdc_table_snapshot_splits,
930 new_upstream_sinks,
931 sink_log_store_flush,
932 }) => PbMutation::Add(PbAddMutation {
933 actor_dispatchers: adds
934 .iter()
935 .map(|(&actor_id, dispatchers)| {
936 (
937 actor_id,
938 PbDispatchers {
939 dispatchers: dispatchers.clone(),
940 },
941 )
942 })
943 .collect(),
944 added_actors: added_actors.iter().copied().collect(),
945 actor_splits: actor_splits_to_protobuf(splits),
946 pause: *pause,
947 subscriptions_to_add: subscriptions_to_add
948 .iter()
949 .map(|(table_id, subscriber_id)| SubscriptionUpstreamInfo {
950 subscriber_id: *subscriber_id,
951 upstream_mv_table_id: *table_id,
952 })
953 .collect(),
954 backfill_nodes_to_pause: backfill_nodes_to_pause.iter().copied().collect(),
955 actor_cdc_table_snapshot_splits:
956 Some(PbCdcTableSnapshotSplitsWithGeneration {
957 splits:actor_cdc_table_snapshot_splits.splits.iter().map(|(actor_id,(splits, generation))| {
958 (*actor_id, risingwave_pb::source::PbCdcTableSnapshotSplits {
959 splits: splits.iter().map(risingwave_connector::source::cdc::build_cdc_table_snapshot_split).collect(),
960 generation: *generation,
961 })
962 }).collect()
963 }),
964 new_upstream_sinks: new_upstream_sinks
965 .iter()
966 .map(|(k, v)| (*k, v.clone()))
967 .collect(),
968 dropped_actors: dropped_actors.iter().copied().collect(),
969 sink_log_store_flush: sink_log_store_flush.iter().copied().collect(),
970 }),
971 Mutation::SourceChangeSplit(changes) => {
972 PbMutation::Splits(PbSourceChangeSplitMutation {
973 actor_splits: changes
974 .iter()
975 .map(|(&actor_id, splits)| {
976 (
977 actor_id,
978 ConnectorSplits {
979 splits: splits
980 .clone()
981 .iter()
982 .map(ConnectorSplit::from)
983 .collect(),
984 },
985 )
986 })
987 .collect(),
988 })
989 }
990 Mutation::Pause => PbMutation::Pause(PbPauseMutation {}),
991 Mutation::Resume => PbMutation::Resume(PbResumeMutation {}),
992 Mutation::Throttle (changes) => PbMutation::Throttle(PbThrottleMutation {
993 fragment_throttle: changes.clone(),
994 }),
995 Mutation::DropSubscriptions {
996 subscriptions_to_drop,
997 } => PbMutation::DropSubscriptions(PbDropSubscriptionsMutation {
998 info: subscriptions_to_drop.clone(),
999 }),
1000 Mutation::ConnectorPropsChange(map) => {
1001 PbMutation::ConnectorPropsChange(PbConnectorPropsChangeMutation {
1002 connector_props_infos: map
1003 .iter()
1004 .map(|(actor_id, options)| {
1005 (
1006 *actor_id,
1007 ConnectorPropsInfo {
1008 connector_props_info: options
1009 .iter()
1010 .map(|(k, v)| (k.clone(), v.clone()))
1011 .collect(),
1012 },
1013 )
1014 })
1015 .collect(),
1016 })
1017 }
1018 Mutation::StartFragmentBackfill { fragment_ids } => {
1019 PbMutation::StartFragmentBackfill(PbStartFragmentBackfillMutation {
1020 fragment_ids: fragment_ids.iter().copied().collect(),
1021 })
1022 }
1023 Mutation::RefreshStart {
1024 table_id,
1025 associated_source_id,
1026 } => PbMutation::RefreshStart(risingwave_pb::stream_plan::RefreshStartMutation {
1027 table_id: *table_id,
1028 associated_source_id: *associated_source_id,
1029 }),
1030 Mutation::ListFinish {
1031 associated_source_id,
1032 } => PbMutation::ListFinish(risingwave_pb::stream_plan::ListFinishMutation {
1033 associated_source_id: *associated_source_id,
1034 }),
1035 Mutation::LoadFinish {
1036 associated_source_id,
1037 } => PbMutation::LoadFinish(risingwave_pb::stream_plan::LoadFinishMutation {
1038 associated_source_id: *associated_source_id,
1039 }),
1040 Mutation::ResetSource { source_id } => {
1041 PbMutation::ResetSource(risingwave_pb::stream_plan::ResetSourceMutation {
1042 source_id: source_id.as_raw_id(),
1043 })
1044 }
1045 Mutation::InjectSourceOffsets {
1046 source_id,
1047 split_offsets,
1048 } => PbMutation::InjectSourceOffsets(
1049 risingwave_pb::stream_plan::InjectSourceOffsetsMutation {
1050 source_id: source_id.as_raw_id(),
1051 split_offsets: split_offsets.clone(),
1052 },
1053 ),
1054 }
1055 }
1056
1057 fn from_protobuf(prost: &PbMutation) -> StreamExecutorResult<Self> {
1058 let mutation = match prost {
1059 PbMutation::Stop(stop) => Mutation::Stop(StopMutation {
1060 dropped_actors: stop.actors.iter().copied().collect(),
1061 dropped_sink_fragments: stop.dropped_sink_fragments.iter().copied().collect(),
1062 }),
1063
1064 PbMutation::Update(update) => Mutation::Update(UpdateMutation {
1065 dispatchers: update
1066 .dispatcher_update
1067 .iter()
1068 .map(|u| (u.actor_id, u.clone()))
1069 .into_group_map(),
1070 merges: update
1071 .merge_update
1072 .iter()
1073 .map(|u| ((u.actor_id, u.upstream_fragment_id), u.clone()))
1074 .collect(),
1075 vnode_bitmaps: update
1076 .actor_vnode_bitmap_update
1077 .iter()
1078 .map(|(&actor_id, bitmap)| (actor_id, Arc::new(bitmap.into())))
1079 .collect(),
1080 dropped_actors: update.dropped_actors.iter().copied().collect(),
1081 actor_splits: update
1082 .actor_splits
1083 .iter()
1084 .map(|(&actor_id, splits)| {
1085 (
1086 actor_id,
1087 splits
1088 .splits
1089 .iter()
1090 .map(|split| split.try_into().unwrap())
1091 .collect(),
1092 )
1093 })
1094 .collect(),
1095 actor_new_dispatchers: update
1096 .actor_new_dispatchers
1097 .iter()
1098 .map(|(&actor_id, dispatchers)| (actor_id, dispatchers.dispatchers.clone()))
1099 .collect(),
1100 actor_cdc_table_snapshot_splits:
1101 build_actor_cdc_table_snapshot_splits_with_generation(
1102 update
1103 .actor_cdc_table_snapshot_splits
1104 .clone()
1105 .unwrap_or_default(),
1106 ),
1107 sink_schema_change: update
1108 .sink_schema_change
1109 .iter()
1110 .map(|(sink_id, change)| (SinkId::from(*sink_id), change.clone()))
1111 .collect(),
1112 subscriptions_to_drop: update.subscriptions_to_drop.clone(),
1113 iceberg_pk_index_compaction: update.iceberg_pk_index_compaction.clone(),
1114 }),
1115
1116 PbMutation::Add(add) => Mutation::Add(AddMutation {
1117 adds: add
1118 .actor_dispatchers
1119 .iter()
1120 .map(|(&actor_id, dispatchers)| (actor_id, dispatchers.dispatchers.clone()))
1121 .collect(),
1122 added_actors: add.added_actors.iter().copied().collect(),
1123 dropped_actors: add.dropped_actors.iter().copied().collect(),
1124 splits: add
1127 .actor_splits
1128 .iter()
1129 .map(|(&actor_id, splits)| {
1130 (
1131 actor_id,
1132 splits
1133 .splits
1134 .iter()
1135 .map(|split| split.try_into().unwrap())
1136 .collect(),
1137 )
1138 })
1139 .collect(),
1140 pause: add.pause,
1141 subscriptions_to_add: add
1142 .subscriptions_to_add
1143 .iter()
1144 .map(
1145 |SubscriptionUpstreamInfo {
1146 subscriber_id,
1147 upstream_mv_table_id,
1148 }| { (*upstream_mv_table_id, *subscriber_id) },
1149 )
1150 .collect(),
1151 backfill_nodes_to_pause: add.backfill_nodes_to_pause.iter().copied().collect(),
1152 actor_cdc_table_snapshot_splits:
1153 build_actor_cdc_table_snapshot_splits_with_generation(
1154 add.actor_cdc_table_snapshot_splits
1155 .clone()
1156 .unwrap_or_default(),
1157 ),
1158 new_upstream_sinks: add
1159 .new_upstream_sinks
1160 .iter()
1161 .map(|(k, v)| (*k, v.clone()))
1162 .collect(),
1163 sink_log_store_flush: add.sink_log_store_flush.iter().copied().collect(),
1164 }),
1165
1166 PbMutation::Splits(s) => {
1167 let mut change_splits: Vec<(ActorId, Vec<SplitImpl>)> =
1168 Vec::with_capacity(s.actor_splits.len());
1169 for (&actor_id, splits) in &s.actor_splits {
1170 if !splits.splits.is_empty() {
1171 change_splits.push((
1172 actor_id,
1173 splits
1174 .splits
1175 .iter()
1176 .map(SplitImpl::try_from)
1177 .try_collect()?,
1178 ));
1179 }
1180 }
1181 Mutation::SourceChangeSplit(change_splits.into_iter().collect())
1182 }
1183 PbMutation::Pause(_) => Mutation::Pause,
1184 PbMutation::Resume(_) => Mutation::Resume,
1185 PbMutation::Throttle(changes) => Mutation::Throttle(changes.fragment_throttle.clone()),
1186 PbMutation::DropSubscriptions(drop) => Mutation::DropSubscriptions {
1187 subscriptions_to_drop: drop.info.clone(),
1188 },
1189 PbMutation::ConnectorPropsChange(alter_connector_props) => {
1190 Mutation::ConnectorPropsChange(
1191 alter_connector_props
1192 .connector_props_infos
1193 .iter()
1194 .map(|(connector_id, options)| {
1195 (
1196 *connector_id,
1197 options
1198 .connector_props_info
1199 .iter()
1200 .map(|(k, v)| (k.clone(), v.clone()))
1201 .collect(),
1202 )
1203 })
1204 .collect(),
1205 )
1206 }
1207 PbMutation::StartFragmentBackfill(start_fragment_backfill) => {
1208 Mutation::StartFragmentBackfill {
1209 fragment_ids: start_fragment_backfill
1210 .fragment_ids
1211 .iter()
1212 .copied()
1213 .collect(),
1214 }
1215 }
1216 PbMutation::RefreshStart(refresh_start) => Mutation::RefreshStart {
1217 table_id: refresh_start.table_id,
1218 associated_source_id: refresh_start.associated_source_id,
1219 },
1220 PbMutation::ListFinish(list_finish) => Mutation::ListFinish {
1221 associated_source_id: list_finish.associated_source_id,
1222 },
1223 PbMutation::LoadFinish(load_finish) => Mutation::LoadFinish {
1224 associated_source_id: load_finish.associated_source_id,
1225 },
1226 PbMutation::ResetSource(reset_source) => Mutation::ResetSource {
1227 source_id: SourceId::from(reset_source.source_id),
1228 },
1229 PbMutation::InjectSourceOffsets(inject) => Mutation::InjectSourceOffsets {
1230 source_id: SourceId::from(inject.source_id),
1231 split_offsets: inject.split_offsets.clone(),
1232 },
1233 };
1234 Ok(mutation)
1235 }
1236}
1237
1238impl<M> BarrierInner<M> {
1239 fn to_protobuf_inner(&self, barrier_fn: impl FnOnce(&M) -> Option<PbMutation>) -> PbBarrier {
1240 let Self {
1241 epoch,
1242 mutation,
1243 kind,
1244 tracing_context,
1245 } = self;
1246
1247 PbBarrier {
1248 epoch: Some(PbEpoch {
1249 curr: epoch.curr,
1250 prev: epoch.prev,
1251 }),
1252 mutation: barrier_fn(mutation).map(|mutation| PbBarrierMutation {
1253 mutation: Some(mutation),
1254 }),
1255 tracing_context: tracing_context.to_protobuf(),
1256 kind: *kind as _,
1257 }
1258 }
1259
1260 fn from_protobuf_inner(
1261 prost: &PbBarrier,
1262 mutation_from_pb: impl FnOnce(Option<&PbMutation>) -> StreamExecutorResult<M>,
1263 ) -> StreamExecutorResult<Self> {
1264 let epoch = prost.get_epoch()?;
1265
1266 Ok(Self {
1267 kind: prost.kind(),
1268 epoch: EpochPair::new(epoch.curr, epoch.prev),
1269 mutation: mutation_from_pb(
1270 (prost.mutation.as_ref()).and_then(|mutation| mutation.mutation.as_ref()),
1271 )?,
1272 tracing_context: TracingContext::from_protobuf(&prost.tracing_context),
1273 })
1274 }
1275
1276 pub fn map_mutation<M2>(self, f: impl FnOnce(M) -> M2) -> BarrierInner<M2> {
1277 BarrierInner {
1278 epoch: self.epoch,
1279 mutation: f(self.mutation),
1280 kind: self.kind,
1281 tracing_context: self.tracing_context,
1282 }
1283 }
1284}
1285
1286impl DispatcherBarrier {
1287 pub fn to_protobuf(&self) -> PbBarrier {
1288 self.to_protobuf_inner(|_| None)
1289 }
1290}
1291
1292impl Barrier {
1293 #[cfg(test)]
1294 pub fn to_protobuf(&self) -> PbBarrier {
1295 self.to_protobuf_inner(|mutation| mutation.as_ref().map(|mutation| mutation.to_protobuf()))
1296 }
1297
1298 pub fn from_protobuf(prost: &PbBarrier) -> StreamExecutorResult<Self> {
1299 Self::from_protobuf_inner(prost, |mutation| {
1300 mutation
1301 .map(|m| Mutation::from_protobuf(m).map(Arc::new))
1302 .transpose()
1303 })
1304 }
1305}
1306
1307#[derive(Debug, PartialEq, Eq, Clone, EstimateSize)]
1308pub struct Watermark {
1309 pub col_idx: usize,
1310 #[estimate_size(ignore)]
1311 pub data_type: DataType,
1312 pub val: ScalarImpl,
1313}
1314
1315impl PartialOrd for Watermark {
1316 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
1317 Some(self.cmp(other))
1318 }
1319}
1320
1321impl Ord for Watermark {
1322 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
1323 self.val.default_cmp(&other.val)
1324 }
1325}
1326
1327impl Watermark {
1328 pub fn new(col_idx: usize, data_type: DataType, val: ScalarImpl) -> Self {
1329 Self {
1330 col_idx,
1331 data_type,
1332 val,
1333 }
1334 }
1335
1336 pub async fn transform_with_expr(
1337 self,
1338 expr: &NonStrictExpression,
1339 new_col_idx: usize,
1340 ) -> Option<Self> {
1341 let Self { col_idx, val, .. } = self;
1342 let row = {
1343 let mut row = vec![None; col_idx + 1];
1344 row[col_idx] = Some(val);
1345 OwnedRow::new(row)
1346 };
1347 let val = expr.eval_row_infallible(&row).await?;
1348 Some(Self::new(new_col_idx, expr.inner().return_type(), val))
1349 }
1350
1351 pub fn transform_with_indices(self, output_indices: &[usize]) -> Option<Self> {
1354 output_indices
1355 .iter()
1356 .position(|p| *p == self.col_idx)
1357 .map(|new_col_idx| self.with_idx(new_col_idx))
1358 }
1359
1360 pub fn to_protobuf(&self) -> PbWatermark {
1361 PbWatermark {
1362 column: Some(PbInputRef {
1363 index: self.col_idx as _,
1364 r#type: Some(self.data_type.to_protobuf()),
1365 }),
1366 val: Some(&self.val).to_protobuf().into(),
1367 }
1368 }
1369
1370 pub fn from_protobuf(prost: &PbWatermark) -> StreamExecutorResult<Self> {
1371 let col_ref = prost.get_column()?;
1372 let data_type = DataType::from(col_ref.get_type()?);
1373 let val = Datum::from_protobuf(prost.get_val()?, &data_type)?
1374 .expect("watermark value cannot be null");
1375 Ok(Self::new(col_ref.get_index() as _, data_type, val))
1376 }
1377
1378 pub fn with_idx(self, idx: usize) -> Self {
1379 Self::new(idx, self.data_type, self.val)
1380 }
1381}
1382
1383#[cfg_attr(any(test, feature = "test"), derive(PartialEq))]
1384#[derive(Debug, EnumAsInner, Clone)]
1385pub enum MessageInner<M> {
1386 Chunk(StreamChunk),
1387 Barrier(BarrierInner<M>),
1388 Watermark(Watermark),
1389}
1390
1391impl<M> MessageInner<M> {
1392 pub fn map_mutation<M2>(self, f: impl FnOnce(M) -> M2) -> MessageInner<M2> {
1393 match self {
1394 MessageInner::Chunk(chunk) => MessageInner::Chunk(chunk),
1395 MessageInner::Barrier(barrier) => MessageInner::Barrier(barrier.map_mutation(f)),
1396 MessageInner::Watermark(watermark) => MessageInner::Watermark(watermark),
1397 }
1398 }
1399}
1400
1401pub type Message = MessageInner<BarrierMutationType>;
1402pub type DispatcherMessage = MessageInner<()>;
1403
1404#[derive(Debug, EnumAsInner, Clone)]
1407pub enum MessageBatchInner<M> {
1408 Chunk(StreamChunk),
1409 BarrierBatch(Vec<BarrierInner<M>>),
1410 Watermark(Watermark),
1411}
1412pub type MessageBatch = MessageBatchInner<BarrierMutationType>;
1413pub type DispatcherBarriers = Vec<DispatcherBarrier>;
1414pub type DispatcherMessageBatch = MessageBatchInner<()>;
1415
1416impl<M> From<MessageInner<M>> for MessageBatchInner<M> {
1417 fn from(m: MessageInner<M>) -> Self {
1418 match m {
1419 MessageInner::Chunk(c) => Self::Chunk(c),
1420 MessageInner::Barrier(b) => Self::BarrierBatch(vec![b]),
1421 MessageInner::Watermark(w) => Self::Watermark(w),
1422 }
1423 }
1424}
1425
1426impl From<StreamChunk> for Message {
1427 fn from(chunk: StreamChunk) -> Self {
1428 Message::Chunk(chunk)
1429 }
1430}
1431
1432impl<'a> TryFrom<&'a Message> for &'a Barrier {
1433 type Error = ();
1434
1435 fn try_from(m: &'a Message) -> std::result::Result<Self, Self::Error> {
1436 match m {
1437 Message::Chunk(_) => Err(()),
1438 Message::Barrier(b) => Ok(b),
1439 Message::Watermark(_) => Err(()),
1440 }
1441 }
1442}
1443
1444impl Message {
1445 #[cfg(test)]
1450 pub fn is_stop(&self) -> bool {
1451 matches!(
1452 self,
1453 Message::Barrier(Barrier {
1454 mutation,
1455 ..
1456 }) if mutation.as_ref().unwrap().is_stop_mutation()
1457 )
1458 }
1459}
1460
1461impl DispatcherMessageBatch {
1462 pub fn to_protobuf(&self) -> PbStreamMessageBatch {
1463 let prost = match self {
1464 Self::Chunk(stream_chunk) => {
1465 let prost_stream_chunk = stream_chunk.to_protobuf();
1466 StreamMessageBatch::StreamChunk(prost_stream_chunk)
1467 }
1468 Self::BarrierBatch(barrier_batch) => StreamMessageBatch::BarrierBatch(BarrierBatch {
1469 barriers: barrier_batch.iter().map(|b| b.to_protobuf()).collect(),
1470 }),
1471 Self::Watermark(watermark) => StreamMessageBatch::Watermark(watermark.to_protobuf()),
1472 };
1473 PbStreamMessageBatch {
1474 stream_message_batch: Some(prost),
1475 }
1476 }
1477
1478 pub fn from_protobuf(prost: &PbStreamMessageBatch) -> StreamExecutorResult<Self> {
1479 let res = match prost.get_stream_message_batch()? {
1480 StreamMessageBatch::StreamChunk(chunk) => {
1481 Self::Chunk(StreamChunk::from_protobuf(chunk)?)
1482 }
1483 StreamMessageBatch::BarrierBatch(barrier_batch) => {
1484 let barriers = barrier_batch
1485 .barriers
1486 .iter()
1487 .map(|barrier| {
1488 DispatcherBarrier::from_protobuf_inner(barrier, |mutation| {
1489 if mutation.is_some() {
1490 if cfg!(debug_assertions) {
1491 panic!("should not receive message of barrier with mutation");
1492 } else {
1493 warn!(?barrier, "receive message of barrier with mutation");
1494 }
1495 }
1496 Ok(())
1497 })
1498 })
1499 .try_collect()?;
1500 Self::BarrierBatch(barriers)
1501 }
1502 StreamMessageBatch::Watermark(watermark) => {
1503 Self::Watermark(Watermark::from_protobuf(watermark)?)
1504 }
1505 };
1506 Ok(res)
1507 }
1508
1509 pub fn get_encoded_len(msg: &impl ::prost::Message) -> usize {
1510 ::prost::Message::encoded_len(msg)
1511 }
1512}
1513
1514pub type StreamKey = Vec<usize>;
1515pub type StreamKeyRef<'a> = &'a [usize];
1516pub type StreamKeyDataTypes = SmallVec<[DataType; 1]>;
1517
1518pub async fn expect_first_barrier<M: Debug>(
1520 stream: &mut (impl MessageStreamInner<M> + Unpin),
1521) -> StreamExecutorResult<BarrierInner<M>> {
1522 let message = stream
1523 .next()
1524 .instrument_await("expect_first_barrier")
1525 .await
1526 .context("failed to extract the first message: stream closed unexpectedly")??;
1527 let barrier = message
1528 .into_barrier()
1529 .expect("the first message must be a barrier");
1530 assert!(matches!(
1532 barrier.kind,
1533 BarrierKind::Checkpoint | BarrierKind::Initial
1534 ));
1535 Ok(barrier)
1536}
1537
1538pub async fn expect_first_barrier_from_aligned_stream(
1540 stream: &mut (impl AlignedMessageStream + Unpin),
1541) -> StreamExecutorResult<Barrier> {
1542 let message = stream
1543 .next()
1544 .instrument_await("expect_first_barrier")
1545 .await
1546 .context("failed to extract the first message: stream closed unexpectedly")??;
1547 let barrier = message
1548 .into_barrier()
1549 .expect("the first message must be a barrier");
1550 Ok(barrier)
1551}
1552
1553pub trait StreamConsumer: Send + 'static {
1555 type BarrierStream: Stream<Item = StreamResult<Barrier>> + Send;
1556
1557 fn execute(self: Box<Self>) -> Self::BarrierStream;
1558}
1559
1560type BoxedMessageInput<InputId, M> = BoxedInput<InputId, MessageStreamItemInner<M>>;
1561
1562pub struct DynamicReceivers<InputId, M> {
1566 barrier: Option<BarrierInner<M>>,
1568 start_ts: Option<Instant>,
1570 blocked: Vec<BoxedMessageInput<InputId, M>>,
1572 active: FuturesUnordered<StreamFuture<BoxedMessageInput<InputId, M>>>,
1574 buffered_watermarks: BTreeMap<usize, BufferedWatermarks<InputId>>,
1576 barrier_align_duration: Option<LabelGuardedMetric<GenericCounter<AtomicU64>>>,
1578 merge_barrier_align_duration: Option<LabelGuardedMetric<GenericCounter<AtomicU64>>>,
1580}
1581
1582impl<InputId: Clone + Ord + Hash + std::fmt::Debug + Unpin, M: Clone + Unpin> Stream
1583 for DynamicReceivers<InputId, M>
1584{
1585 type Item = MessageStreamItemInner<M>;
1586
1587 fn poll_next(
1588 mut self: Pin<&mut Self>,
1589 cx: &mut std::task::Context<'_>,
1590 ) -> Poll<Option<Self::Item>> {
1591 if self.is_empty() {
1592 return Poll::Ready(None);
1593 }
1594
1595 loop {
1596 match futures::ready!(self.active.poll_next_unpin(cx)) {
1597 Some((Some(Err(e)), _)) => {
1599 return Poll::Ready(Some(Err(e)));
1600 }
1601 Some((Some(Ok(message)), remaining)) => {
1603 let input_id = remaining.id();
1604 match message {
1605 MessageInner::Chunk(chunk) => {
1606 self.active.push(remaining.into_future());
1608 return Poll::Ready(Some(Ok(MessageInner::Chunk(chunk))));
1609 }
1610 MessageInner::Watermark(watermark) => {
1611 self.active.push(remaining.into_future());
1613 if let Some(watermark) = self.handle_watermark(input_id, watermark) {
1614 return Poll::Ready(Some(Ok(MessageInner::Watermark(watermark))));
1615 }
1616 }
1617 MessageInner::Barrier(barrier) => {
1618 if self.blocked.is_empty() {
1620 self.start_ts = Some(Instant::now());
1621 }
1622 self.blocked.push(remaining);
1623 if let Some(current_barrier) = self.barrier.as_ref() {
1624 if current_barrier.epoch != barrier.epoch {
1625 return Poll::Ready(Some(Err(
1626 StreamExecutorError::align_barrier(
1627 current_barrier.clone().map_mutation(|_| None),
1628 barrier.map_mutation(|_| None),
1629 ),
1630 )));
1631 }
1632 } else {
1633 self.barrier = Some(barrier);
1634 }
1635 }
1636 }
1637 }
1638 Some((None, remaining)) => {
1646 return Poll::Ready(Some(Err(StreamExecutorError::channel_closed(format!(
1647 "upstream input {:?} unexpectedly closed",
1648 remaining.id()
1649 )))));
1650 }
1651 None => {
1653 assert!(!self.blocked.is_empty());
1654
1655 let start_ts = self
1656 .start_ts
1657 .take()
1658 .expect("should have received at least one barrier");
1659 if let Some(barrier_align_duration) = &self.barrier_align_duration {
1660 barrier_align_duration.inc_by(start_ts.elapsed().as_nanos() as u64);
1661 }
1662 if let Some(merge_barrier_align_duration) = &self.merge_barrier_align_duration {
1663 merge_barrier_align_duration.inc_by(start_ts.elapsed().as_nanos() as u64);
1664 }
1665
1666 break;
1667 }
1668 }
1669 }
1670
1671 assert!(self.active.is_terminated());
1672
1673 let barrier = self.barrier.take().unwrap();
1674
1675 let upstreams = std::mem::take(&mut self.blocked);
1676 self.extend_active(upstreams);
1677 assert!(!self.active.is_terminated());
1678
1679 Poll::Ready(Some(Ok(MessageInner::Barrier(barrier))))
1680 }
1681}
1682
1683impl<InputId: Clone + Ord + Hash + std::fmt::Debug, M> DynamicReceivers<InputId, M> {
1684 pub fn new(
1685 upstreams: Vec<BoxedMessageInput<InputId, M>>,
1686 barrier_align_duration: Option<LabelGuardedMetric<GenericCounter<AtomicU64>>>,
1687 merge_barrier_align_duration: Option<LabelGuardedMetric<GenericCounter<AtomicU64>>>,
1688 ) -> Self {
1689 let mut this = Self {
1690 barrier: None,
1691 start_ts: None,
1692 blocked: Vec::with_capacity(upstreams.len()),
1693 active: Default::default(),
1694 buffered_watermarks: Default::default(),
1695 merge_barrier_align_duration,
1696 barrier_align_duration,
1697 };
1698 this.extend_active(upstreams);
1699 this
1700 }
1701
1702 pub fn extend_active(
1705 &mut self,
1706 upstreams: impl IntoIterator<Item = BoxedMessageInput<InputId, M>>,
1707 ) {
1708 assert!(self.blocked.is_empty() && self.barrier.is_none());
1709
1710 self.active
1711 .extend(upstreams.into_iter().map(|s| s.into_future()));
1712 }
1713
1714 pub fn handle_watermark(
1716 &mut self,
1717 input_id: InputId,
1718 watermark: Watermark,
1719 ) -> Option<Watermark> {
1720 let col_idx = watermark.col_idx;
1721 let upstream_ids: Vec<_> = self.upstream_input_ids().collect();
1723 let watermarks = self
1724 .buffered_watermarks
1725 .entry(col_idx)
1726 .or_insert_with(|| BufferedWatermarks::with_ids(upstream_ids));
1727 watermarks.handle_watermark(input_id, watermark)
1728 }
1729
1730 pub fn add_upstreams_from(
1733 &mut self,
1734 new_inputs: impl IntoIterator<Item = BoxedMessageInput<InputId, M>>,
1735 ) {
1736 assert!(self.blocked.is_empty() && self.barrier.is_none());
1737
1738 let new_inputs: Vec<_> = new_inputs.into_iter().collect();
1739 let input_ids = new_inputs.iter().map(|input| input.id());
1740 self.buffered_watermarks.values_mut().for_each(|buffers| {
1741 buffers.add_buffers(input_ids.clone());
1743 });
1744 self.active
1745 .extend(new_inputs.into_iter().map(|s| s.into_future()));
1746 }
1747
1748 pub fn remove_upstreams(&mut self, upstream_input_ids: &HashSet<InputId>) {
1752 assert!(self.blocked.is_empty() && self.barrier.is_none());
1753
1754 let new_upstreams = std::mem::take(&mut self.active)
1755 .into_iter()
1756 .map(|s| s.into_inner().unwrap())
1757 .filter(|u| !upstream_input_ids.contains(&u.id()));
1758 self.extend_active(new_upstreams);
1759 self.buffered_watermarks.values_mut().for_each(|buffers| {
1760 buffers.remove_buffer(upstream_input_ids.clone());
1763 });
1764 }
1765
1766 pub fn merge_barrier_align_duration(
1767 &self,
1768 ) -> Option<LabelGuardedMetric<GenericCounter<AtomicU64>>> {
1769 self.merge_barrier_align_duration.clone()
1770 }
1771
1772 pub fn flush_buffered_watermarks(&mut self) {
1773 self.buffered_watermarks
1774 .values_mut()
1775 .for_each(|buffers| buffers.clear());
1776 }
1777
1778 pub fn upstream_input_ids(&self) -> impl Iterator<Item = InputId> + '_ {
1779 self.blocked
1780 .iter()
1781 .map(|s| s.id())
1782 .chain(self.active.iter().map(|s| s.get_ref().unwrap().id()))
1783 }
1784
1785 pub fn is_empty(&self) -> bool {
1786 self.blocked.is_empty() && self.active.is_empty()
1787 }
1788}
1789
1790pub(crate) struct DispatchBarrierBuffer {
1811 buffer: VecDeque<(Barrier, Option<Vec<BoxedActorInput>>)>,
1812 barrier_rx: mpsc::UnboundedReceiver<Barrier>,
1813 recv_state: BarrierReceiverState,
1814 curr_upstream_fragment_id: FragmentId,
1815 actor_id: ActorId,
1816 build_input_ctx: Arc<BuildInputContext>,
1818}
1819
1820struct BuildInputContext {
1821 actor_id: ActorId,
1822 local_barrier_manager: LocalBarrierManager,
1823 metrics: Arc<StreamingMetrics>,
1824 fragment_id: FragmentId,
1825 actor_config: Arc<StreamingConfig>,
1826}
1827
1828impl BuildInputContext {
1829 fn new(
1830 actor_id: ActorId,
1831 local_barrier_manager: LocalBarrierManager,
1832 metrics: Arc<StreamingMetrics>,
1833 fragment_id: FragmentId,
1834 actor_config: Arc<StreamingConfig>,
1835 ) -> Self {
1836 Self {
1837 actor_id,
1838 local_barrier_manager,
1839 metrics,
1840 fragment_id,
1841 actor_config,
1842 }
1843 }
1844
1845 async fn build_new_inputs(
1846 self: Arc<Self>,
1847 barrier: Barrier,
1848 upstream_fragment_id: FragmentId,
1849 added_upstream_actors: Vec<risingwave_pb::common::ActorInfo>,
1850 ) -> StreamExecutorResult<Vec<BoxedActorInput>> {
1851 try_join_all(added_upstream_actors.iter().map(|upstream_actor| async {
1852 let mut new_input = new_input(
1853 &self.local_barrier_manager,
1854 self.metrics.clone(),
1855 self.actor_id,
1856 self.fragment_id,
1857 upstream_actor,
1858 upstream_fragment_id,
1859 self.actor_config.clone(),
1860 )
1861 .await?;
1862
1863 let first_barrier = expect_first_barrier(&mut new_input).await?;
1865 assert_equal_dispatcher_barrier(&barrier, &first_barrier);
1866
1867 StreamExecutorResult::Ok(new_input)
1868 }))
1869 .await
1870 }
1871}
1872
1873type BoxedNewInputsFuture =
1874 Pin<Box<dyn Future<Output = StreamExecutorResult<Vec<BoxedActorInput>>> + Send>>;
1875
1876enum BarrierReceiverState {
1877 ReceivingBarrier,
1878 CreatingNewInput(Barrier, BoxedNewInputsFuture),
1879}
1880
1881impl DispatchBarrierBuffer {
1882 pub fn new(
1883 barrier_rx: mpsc::UnboundedReceiver<Barrier>,
1884 actor_id: ActorId,
1885 curr_upstream_fragment_id: FragmentId,
1886 local_barrier_manager: LocalBarrierManager,
1887 metrics: Arc<StreamingMetrics>,
1888 fragment_id: FragmentId,
1889 actor_config: Arc<StreamingConfig>,
1890 ) -> Self {
1891 Self {
1892 buffer: VecDeque::new(),
1893 barrier_rx,
1894 recv_state: BarrierReceiverState::ReceivingBarrier,
1895 curr_upstream_fragment_id,
1896 actor_id,
1897 build_input_ctx: Arc::new(BuildInputContext::new(
1898 actor_id,
1899 local_barrier_manager,
1900 metrics,
1901 fragment_id,
1902 actor_config,
1903 )),
1904 }
1905 }
1906
1907 pub async fn await_next_message(
1908 &mut self,
1909 stream: &mut (impl Stream<Item = StreamExecutorResult<DispatcherMessage>> + Unpin),
1910 metrics: &ActorInputMetrics,
1911 upstream_is_empty: bool,
1912 ) -> StreamExecutorResult<DispatcherMessage> {
1913 if upstream_is_empty {
1914 while self.buffer.is_empty() {
1915 self.try_fetch_barrier_rx(false).await?;
1916 }
1917 let (barrier, _) = self.buffer.front().unwrap();
1918 return Ok(DispatcherMessage::Barrier(
1919 barrier.clone().into_dispatcher(),
1920 ));
1921 }
1922
1923 let mut start_time = Instant::now();
1924 let interval_duration = Duration::from_secs(15);
1925 let mut interval =
1926 tokio::time::interval_at(start_time + interval_duration, interval_duration);
1927
1928 loop {
1929 tokio::select! {
1930 biased;
1931 msg = stream.try_next() => {
1932 metrics
1933 .actor_input_buffer_blocking_duration_ns
1934 .inc_by(start_time.elapsed().as_nanos() as u64);
1935 return msg?.ok_or_else(
1936 || StreamExecutorError::channel_closed("upstream executor closed unexpectedly")
1937 );
1938 }
1939
1940 e = self.continuously_fetch_barrier_rx() => {
1941 return Err(e);
1942 }
1943
1944 _ = interval.tick() => {
1945 start_time = Instant::now();
1946 metrics.actor_input_buffer_blocking_duration_ns.inc_by(interval_duration.as_nanos() as u64);
1947 continue;
1948 }
1949 }
1950 }
1951 }
1952
1953 pub async fn pop_barrier_with_inputs(
1954 &mut self,
1955 barrier: DispatcherBarrier,
1956 ) -> StreamExecutorResult<(Barrier, Option<Vec<BoxedActorInput>>)> {
1957 while self.buffer.is_empty() {
1958 self.try_fetch_barrier_rx(false).await?;
1959 }
1960 let (recv_barrier, inputs) = self.buffer.pop_front().unwrap();
1961 assert_equal_dispatcher_barrier(&recv_barrier, &barrier);
1962
1963 Ok((recv_barrier, inputs))
1964 }
1965
1966 async fn continuously_fetch_barrier_rx(&mut self) -> StreamExecutorError {
1967 loop {
1968 if let Err(e) = self.try_fetch_barrier_rx(true).await {
1969 return e;
1970 }
1971 }
1972 }
1973
1974 async fn try_fetch_barrier_rx(&mut self, pending_on_end: bool) -> StreamExecutorResult<()> {
1975 match &mut self.recv_state {
1976 BarrierReceiverState::ReceivingBarrier => {
1977 let Some(barrier) = self.barrier_rx.recv().await else {
1978 if pending_on_end {
1979 return pending().await;
1980 } else {
1981 return Err(StreamExecutorError::channel_closed(
1982 "barrier channel closed unexpectedly",
1983 ));
1984 }
1985 };
1986 if let Some(fut) = self.pre_apply_barrier(&barrier) {
1987 self.recv_state = BarrierReceiverState::CreatingNewInput(barrier, fut);
1988 } else {
1989 self.buffer.push_back((barrier, None));
1990 }
1991 }
1992 BarrierReceiverState::CreatingNewInput(barrier, fut) => {
1993 let new_inputs = fut.await?;
1994 self.buffer.push_back((barrier.clone(), Some(new_inputs)));
1995 self.recv_state = BarrierReceiverState::ReceivingBarrier;
1996 }
1997 }
1998 Ok(())
1999 }
2000
2001 fn pre_apply_barrier(&mut self, barrier: &Barrier) -> Option<BoxedNewInputsFuture> {
2002 let update = barrier.as_update_merge(self.actor_id, self.curr_upstream_fragment_id)?;
2003 let upstream_fragment_id = update
2004 .new_upstream_fragment_id
2005 .unwrap_or(self.curr_upstream_fragment_id);
2006 self.curr_upstream_fragment_id = upstream_fragment_id;
2010
2011 if !update.added_upstream_actors.is_empty() {
2012 let ctx = self.build_input_ctx.clone();
2013 let added_upstream_actors = update.added_upstream_actors.clone();
2014 let barrier = barrier.clone();
2015 let fut = ctx
2016 .build_new_inputs(barrier, upstream_fragment_id, added_upstream_actors)
2017 .boxed();
2018
2019 Some(fut)
2020 } else {
2021 None
2022 }
2023 }
2024}