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