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