Skip to main content

risingwave_stream/executor/
mod.rs

1// Copyright 2022 RisingWave Labs
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15mod 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/// Static information of an executor.
213#[derive(Debug, Default, Clone)]
214pub struct ExecutorInfo {
215    /// The schema of the OUTPUT of the executor.
216    pub schema: Schema,
217
218    /// The stream key indices of the OUTPUT of the executor.
219    pub stream_key: StreamKey,
220
221    /// The stream kind of the OUTPUT of the executor.
222    pub stream_kind: PbStreamKind,
223
224    /// Identity of the executor.
225    pub identity: String,
226
227    /// The executor id of the executor.
228    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, // dummy value for test
237            identity,
238            id: id.into(),
239        }
240    }
241}
242
243/// [`Execute`] describes the methods an executor should implement to handle control messages.
244pub 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
255/// [`Executor`] combines the static information ([`ExecutorInfo`]) and the executable object to
256/// handle messages ([`Execute`]).
257pub 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    // TODO: remove this and use `SourceChangesSplit` after we support multiple mutations.
339    pub splits: SplitAssignments,
340    pub pause: bool,
341    /// (`upstream_mv_table_id`,  `subscriber_id`)
342    pub subscriptions_to_add: Vec<(TableId, SubscriberId)>,
343    /// nodes which should start backfill
344    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/// See [`PbMutation`] for the semantics of each mutation.
358#[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        /// `subscriber` -> `upstream_mv_table_id`
371        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 ID -> offset (JSON-encoded based on connector type)
392        split_offsets: HashMap<String, String>,
393    },
394}
395
396/// The generic type `M` is the mutation type of the barrier.
397///
398/// For barrier of in the dispatcher, `M` is `()`, which means the mutation is erased.
399/// For barrier flowing within the streaming actor, `M` is the normal `BarrierMutationType`.
400#[derive(Debug, Clone)]
401pub struct BarrierInner<M> {
402    pub epoch: EpochPair,
403    pub mutation: M,
404    pub kind: BarrierKind,
405
406    /// Tracing context for the **current** epoch of this barrier.
407    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    /// Create a plain barrier.
417    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    /// Whether this barrier carries stop mutation.
476    pub fn is_with_stop_mutation(&self) -> bool {
477        matches!(self.mutation.as_deref(), Some(Mutation::Stop(_)))
478    }
479
480    /// Whether this barrier is to stop the actor with `actor_id`.
481    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    /// Get the initial split assignments for the actor with `actor_id`.
491    ///
492    /// This should only be called on the initial barrier received by the executor. It must be
493    ///
494    /// - `Add` mutation when it's a new streaming job, or recovery.
495    /// - `Update` mutation when it's created for scaling.
496    ///
497    /// Note that `SourceChangeSplit` is **not** included, because it's only used for changing splits
498    /// of existing executors.
499    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    /// Get all actors that to be stopped (dropped) by this barrier.
521    pub fn all_stop_actors(&self) -> Option<&HashSet<ActorId>> {
522        self.mutation.as_deref()?.all_stop_actors()
523    }
524
525    /// Whether this barrier is to newly add the actor with `actor_id`. This is used for `Chain` and
526    /// `Values` to decide whether to output the existing (historical) data.
527    ///
528    /// By "newly", we mean the actor belongs to a subgraph of a new streaming job. That is, actors
529    /// added for scaling are not included.
530    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    /// Whether this barrier adds new downstream fragment for the actor with `upstream_actor_id`.
548    ///
549    /// # Use case
550    /// Some optimizations are applied when an actor doesn't have any downstreams ("standalone" actors).
551    /// * Pause a standalone shared `SourceExecutor`.
552    /// * Disable a standalone `MaterializeExecutor`'s conflict check.
553    ///
554    /// This is implemented by checking `actor_context.initial_dispatch_num` on startup, and
555    /// check `has_more_downstream_fragments` on barrier to see whether the optimization
556    /// needs to be turned off.
557    ///
558    /// ## Some special cases not included
559    ///
560    /// Note that this is not `has_new_downstream_actor/fragment`. For our use case, we only
561    /// care about **number of downstream fragments** (more precisely, existence).
562    /// - When scaling, the number of downstream actors is changed, and they are "new", but downstream fragments is not changed.
563    /// - When `ALTER TABLE sink_into_table`, the fragment is replaced with a "new" one, but the number is not changed.
564    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            // Add is for mv, index and sink creation.
570            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    /// Whether this barrier requires the executor to pause its data stream on startup.
589    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    /// Whether this barrier is for resume.
614    pub fn is_resume(&self) -> bool {
615        matches!(self.mutation.as_deref(), Some(Mutation::Resume))
616    }
617
618    /// Returns the [`MergeUpdate`] if this barrier is to update the merge executors for the actor
619    /// with `actor_id`.
620    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    /// Returns the new upstream sink information if this barrier is to add a new upstream sink for
636    /// the specified downstream fragment.
637    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    /// Returns the dropped upstream sink-fragment if this barrier is to drop any sink.
649    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    /// Returns the new vnode bitmap if this barrier is to update the vnode bitmap for the actor
662    /// with `actor_id`.
663    ///
664    /// Actually, this vnode bitmap update is only useful for the record accessing validation for
665    /// distributed executors, since the read/write pattern will never be across multiple vnodes.
666    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    /// Retrieve the tracing context for the **current** epoch of this barrier.
725    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    /// Get all actors to be stopped (dropped) by this mutation.
761    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    /// Return true if the mutation stops the given actor.
771    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    /// Return true if the mutation is stop.
777    ///
778    /// Note that this does not mean we will stop the current actor.
779    #[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                // TODO: remove this and use `SourceChangesSplit` after we support multiple
1065                // mutations.
1066                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    /// Transform the watermark with the given output indices. If this watermark is not in the
1300    /// output, return `None`.
1301    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/// `MessageBatchInner` is used exclusively by `Dispatcher` and the `Merger`/`Receiver` for exchanging messages between them.
1353/// It shares the same message type as the fundamental `MessageInner`, but batches multiple barriers into a single message.
1354#[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    /// Return true if the message is a stop barrier, meaning the stream
1394    /// will not continue, false otherwise.
1395    ///
1396    /// Note that this does not mean we will stop the current actor.
1397    #[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
1466/// Expect the first message of the given `stream` as a barrier.
1467pub 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    // TODO: Is this check correct?
1479    assert!(matches!(
1480        barrier.kind,
1481        BarrierKind::Checkpoint | BarrierKind::Initial
1482    ));
1483    Ok(barrier)
1484}
1485
1486/// Expect the first message of the given `stream` as a barrier.
1487pub 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
1501/// `StreamConsumer` is the last step in an actor.
1502pub 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
1510/// A stream for merging messages from multiple upstreams.
1511/// Can dynamically add and delete upstream streams.
1512/// For the meaning of the generic parameter `M` used, refer to `BarrierInner<M>`.
1513pub struct DynamicReceivers<InputId, M> {
1514    /// The barrier we're aligning to. If this is `None`, then `blocked_upstreams` is empty.
1515    barrier: Option<BarrierInner<M>>,
1516    /// The start timestamp of the current barrier. Used for measuring the alignment duration.
1517    start_ts: Option<Instant>,
1518    /// The upstreams that're blocked by the `barrier`.
1519    blocked: Vec<BoxedMessageInput<InputId, M>>,
1520    /// The upstreams that're not blocked and can be polled.
1521    active: FuturesUnordered<StreamFuture<BoxedMessageInput<InputId, M>>>,
1522    /// watermark column index -> `BufferedWatermarks`
1523    buffered_watermarks: BTreeMap<usize, BufferedWatermarks<InputId>>,
1524    /// Currently only used for union.
1525    barrier_align_duration: Option<LabelGuardedMetric<GenericCounter<AtomicU64>>>,
1526    /// Only for merge. If None, then we don't take `Instant::now()` and `observe` during `poll_next`
1527    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                // Directly forward the error.
1546                Some((Some(Err(e)), _)) => {
1547                    return Poll::Ready(Some(Err(e)));
1548                }
1549                // Handle the message from some upstream.
1550                Some((Some(Ok(message)), remaining)) => {
1551                    let input_id = remaining.id();
1552                    match message {
1553                        MessageInner::Chunk(chunk) => {
1554                            // Continue polling this upstream by pushing it back to `active`.
1555                            self.active.push(remaining.into_future());
1556                            return Poll::Ready(Some(Ok(MessageInner::Chunk(chunk))));
1557                        }
1558                        MessageInner::Watermark(watermark) => {
1559                            // Continue polling this upstream by pushing it back to `active`.
1560                            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                            // Block this upstream by pushing it to `blocked`.
1567                            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                // We use barrier as the control message of the stream. That is, we always stop the
1587                // actors actively when we receive a `Stop` mutation, instead of relying on the stream
1588                // termination.
1589                //
1590                // Besides, in abnormal cases when the other side of the `Input` closes unexpectedly,
1591                // we also yield an `Err(ExchangeChannelClosed)`, which will hit the `Err` arm above.
1592                // So this branch will never be reached in all cases.
1593                Some((None, remaining)) => {
1594                    return Poll::Ready(Some(Err(StreamExecutorError::channel_closed(format!(
1595                        "upstream input {:?} unexpectedly closed",
1596                        remaining.id()
1597                    )))));
1598                }
1599                // There's no active upstreams. Process the barrier and resume the blocked ones.
1600                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    /// Extend the active upstreams with the given upstreams. The current stream must be at the
1651    /// clean state right after a barrier.
1652    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    /// Handle a new watermark message. Optionally returns the watermark message to emit.
1663    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        // Insert a buffer watermarks when first received from a column.
1670        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    /// Consume `other` and add its upstreams to `self`. The two streams must be at the clean state
1679    /// right after a barrier.
1680    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            // Add buffers to the buffered watermarks for all cols
1690            buffers.add_buffers(input_ids.clone());
1691        });
1692        self.active
1693            .extend(new_inputs.into_iter().map(|s| s.into_future()));
1694    }
1695
1696    /// Remove upstreams from `self` in `upstream_input_ids`. The current stream must be at the
1697    /// clean state right after a barrier.
1698    /// The current container does not necessarily contain all the input ids passed in.
1699    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            // Call `check_heap` in case the only upstream(s) that does not have
1709            // watermark in heap is removed
1710            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
1738// Explanation of why we need `DispatchBarrierBuffer`:
1739//
1740// When we need to create or replace an upstream fragment for the current fragment, the `Merge` operator must
1741// add some new upstream actor inputs. However, the `Merge` operator may still have old upstreams. We must wait
1742// for these old upstreams to completely process their barriers and align before we can safely update the
1743// `upstream-input-set`.
1744//
1745// Meanwhile, the creation of a new upstream actor can only succeed after the channel to the downstream `Merge`
1746// operator has been established. This creates a potential dependency chain: [new_actor_creation ->
1747// downstream_merge_update -> old_actor_processing]
1748//
1749// To address this, we split the application of a barrier's `Mutation` into two steps:
1750// 1. Parse the `Mutation`. If there is an addition on the upstream-set, establish a channel with the upstream
1751//    and cache it.
1752// 2. When the upstream barrier actually arrives, apply the cached upstream changes to the upstream-set
1753//
1754// Additionally, since receiving a barrier from current upstream input and from the `barrier_rx` are
1755// asynchronous, we cannot determine which will arrive first. Therefore, when a barrier is received from an
1756// upstream: if a cached mutation is present, we apply it. Otherwise, we must fetch a new barrier from
1757// `barrier_rx`.
1758pub(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    // read-only context for building new inputs
1765    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            // When update upstream fragment, added_actors will not be empty.
1898            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                    // Poll the first barrier from the new upstreams. It must be the same as the one we polled from
1922                    // original upstreams.
1923                    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}