1use std::fmt::{Display, Formatter};
16use std::sync::Arc;
17
18use risingwave_common::bitmap::Bitmap;
19use risingwave_common::catalog::TableId;
20use risingwave_common::util::epoch::EpochPair;
21use risingwave_pb::id::FragmentId;
22use risingwave_pb::stream_service::barrier_complete_response::PbCreateMviewProgress;
23
24use crate::executor::ActorContext;
25use crate::task::barrier_manager::LocalBarrierEvent::{
26 ReportCreateProgress, ReportTableChangeLogProgress,
27};
28use crate::task::barrier_worker::managed_state::PartialGraphState;
29use crate::task::cdc_progress::CdcTableBackfillState;
30use crate::task::{ActorId, LocalBarrierManager};
31
32type ConsumedEpoch = u64;
33type ConsumedRows = u64;
34type BufferedRows = u64;
35
36#[derive(Debug, Clone, Copy)]
37pub(crate) enum BackfillState {
38 ConsumingUpstreamTableOrSource(ConsumedEpoch, ConsumedRows, BufferedRows),
39 DoneConsumingUpstreamTableOrSource(ConsumedRows, BufferedRows),
40}
41
42#[derive(Debug)]
43pub(crate) struct TableChangeLogProgress {
44 pub(crate) actor_id: ActorId,
45 pub(crate) fragment_id: FragmentId,
46 pub(crate) upstream_table_id: TableId,
47 pub(crate) progress_table_id: TableId,
48 pub(crate) vnode_bitmap: Arc<Bitmap>,
49 pub(crate) truncate_epoch: u64,
50}
51
52impl BackfillState {
53 pub fn to_pb(self, fragment_id: FragmentId, actor_id: ActorId) -> PbCreateMviewProgress {
54 let (done, consumed_epoch, consumed_rows, buffered_rows) = match self {
55 BackfillState::ConsumingUpstreamTableOrSource(
56 consumed_epoch,
57 consumed_rows,
58 buffered_rows,
59 ) => (false, consumed_epoch, consumed_rows, buffered_rows),
60 BackfillState::DoneConsumingUpstreamTableOrSource(consumed_rows, buffered_rows) => {
61 (true, 0, consumed_rows, buffered_rows)
62 }
63 };
64 PbCreateMviewProgress {
65 backfill_actor_id: actor_id,
66 done,
67 consumed_epoch,
68 consumed_rows,
69 buffered_rows,
70 fragment_id,
71 }
72 }
73}
74
75impl Display for BackfillState {
76 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
77 match self {
78 BackfillState::ConsumingUpstreamTableOrSource(epoch, rows, buffered) => {
79 write!(
80 f,
81 "ConsumingUpstreamTable(epoch: {}, rows: {}, buffered: {})",
82 epoch, rows, buffered
83 )
84 }
85 BackfillState::DoneConsumingUpstreamTableOrSource(rows, buffered) => {
86 write!(
87 f,
88 "DoneConsumingUpstreamTable(rows: {}, buffered: {})",
89 rows, buffered
90 )
91 }
92 }
93 }
94}
95
96impl PartialGraphState {
97 pub(crate) fn update_create_mview_progress(
98 &mut self,
99 epoch: EpochPair,
100 fragment_id: FragmentId,
101 actor: ActorId,
102 state: BackfillState,
103 ) {
104 if let Some((prev_fragment_id, _)) = self
105 .graph_state
106 .event_mut(epoch)
107 .create_mview_progress
108 .insert(actor, (fragment_id, state))
109 {
110 assert_eq!(prev_fragment_id, fragment_id)
111 }
112 }
113
114 pub(crate) fn update_cdc_table_backfill_progress(
115 &mut self,
116 epoch: EpochPair,
117 actor: ActorId,
118 state: CdcTableBackfillState,
119 ) {
120 if let Some(actor_state) = self.actor_states.get(&actor)
121 && actor_state.inflight_barriers.contains(&epoch.prev)
122 {
123 self.graph_state
124 .event_mut(epoch)
125 .cdc_table_backfill_progress
126 .insert(actor, state);
127 } else {
128 warn!(?epoch, %actor, ?state, "ignore CDC table backfill progress");
129 }
130 }
131
132 pub(crate) fn update_table_change_log_progress(
133 &mut self,
134 epoch: EpochPair,
135 progress: TableChangeLogProgress,
136 ) {
137 let actor_id = progress.actor_id;
138 if let Some(actor_state) = self.actor_states.get(&actor_id)
139 && actor_state.inflight_barriers.contains(&epoch.prev)
140 {
141 self.graph_state
142 .event_mut(epoch)
143 .table_change_log_progress
144 .push(progress);
145 } else {
146 warn!(?epoch, %actor_id, ?progress, "ignore table change log progress");
147 }
148 }
149}
150
151impl LocalBarrierManager {
152 fn update_create_mview_progress(
153 &self,
154 epoch: EpochPair,
155 fragment_id: FragmentId,
156 actor: ActorId,
157 state: BackfillState,
158 ) {
159 self.send_event(ReportCreateProgress {
160 epoch,
161 fragment_id,
162 actor,
163 state,
164 })
165 }
166
167 fn report_table_change_log_progress(&self, epoch: EpochPair, progress: TableChangeLogProgress) {
168 self.send_event(ReportTableChangeLogProgress { epoch, progress });
169 }
170}
171
172pub struct CreateMviewProgressReporter {
203 barrier_manager: LocalBarrierManager,
204
205 fragment_id: FragmentId,
206
207 backfill_actor_id: ActorId,
209
210 state: Option<BackfillState>,
211}
212
213impl CreateMviewProgressReporter {
214 pub fn new(
215 barrier_manager: LocalBarrierManager,
216 fragment_id: FragmentId,
217 backfill_actor_id: ActorId,
218 ) -> Self {
219 Self {
220 barrier_manager,
221 fragment_id,
222 backfill_actor_id,
223 state: None,
224 }
225 }
226
227 #[cfg(test)]
228 pub fn for_test(barrier_manager: LocalBarrierManager) -> Self {
229 Self::new(barrier_manager, 0.into(), 0.into())
230 }
231
232 pub fn actor_id(&self) -> ActorId {
233 self.backfill_actor_id
234 }
235
236 pub fn report_table_change_log_progress(
239 &self,
240 epoch: EpochPair,
241 upstream_table_id: TableId,
242 progress_table_id: TableId,
243 vnode_bitmap: Arc<Bitmap>,
244 truncate_epoch: u64,
245 ) {
246 self.barrier_manager.report_table_change_log_progress(
247 epoch,
248 TableChangeLogProgress {
249 actor_id: self.backfill_actor_id,
250 fragment_id: self.fragment_id,
251 upstream_table_id,
252 progress_table_id,
253 vnode_bitmap,
254 truncate_epoch,
255 },
256 );
257 }
258
259 fn update_inner(&mut self, epoch: EpochPair, state: BackfillState) {
260 self.state = Some(state);
261 self.barrier_manager.update_create_mview_progress(
262 epoch,
263 self.fragment_id,
264 self.backfill_actor_id,
265 state,
266 );
267 }
268
269 pub fn update(
274 &mut self,
275 epoch: EpochPair,
276 consumed_epoch: ConsumedEpoch,
277 current_consumed_rows: ConsumedRows,
278 ) {
279 self.update_with_buffered_rows(epoch, consumed_epoch, current_consumed_rows, 0);
280 }
281
282 pub fn update_with_buffered_rows(
285 &mut self,
286 epoch: EpochPair,
287 consumed_epoch: ConsumedEpoch,
288 current_consumed_rows: ConsumedRows,
289 buffered_rows: BufferedRows,
290 ) {
291 match self.state {
292 Some(BackfillState::ConsumingUpstreamTableOrSource(last, last_consumed_rows, _)) => {
293 assert!(
294 last <= consumed_epoch,
295 "last_epoch: {:#?} must be greater than consumed epoch: {:#?}",
296 last,
297 consumed_epoch
298 );
299 assert!(last_consumed_rows <= current_consumed_rows);
300 }
301 Some(state) => {
302 panic!(
303 "should not update consuming progress at invalid state: {:?}",
304 state
305 )
306 }
307 None => {}
308 };
309 tracing::debug!(
310 actor_id = %self.backfill_actor_id,
311 ?epoch,
312 consumed_epoch,
313 current_consumed_rows,
314 buffered_rows,
315 "progress update"
316 );
317 self.update_inner(
318 epoch,
319 BackfillState::ConsumingUpstreamTableOrSource(
320 consumed_epoch,
321 current_consumed_rows,
322 buffered_rows,
323 ),
324 );
325 }
326
327 pub fn update_for_source_backfill(
330 &mut self,
331 epoch: EpochPair,
332 current_consumed_rows: ConsumedRows,
333 ) {
334 match self.state {
335 Some(BackfillState::ConsumingUpstreamTableOrSource(
336 dummy_last_epoch,
337 _last_consumed_rows,
338 _,
339 )) => {
340 debug_assert_eq!(dummy_last_epoch, 0);
341 }
342 Some(state) => {
343 panic!(
344 "should not update consuming progress at invalid state: {:?}",
345 state
346 )
347 }
348 None => {}
349 };
350 self.update_inner(
351 epoch,
352 BackfillState::ConsumingUpstreamTableOrSource(0, current_consumed_rows, 0),
354 );
355 }
356
357 pub fn finish(&mut self, epoch: EpochPair, current_consumed_rows: ConsumedRows) {
360 self.finish_with_buffered_rows(epoch, current_consumed_rows, 0);
361 }
362
363 pub fn finish_with_buffered_rows(
366 &mut self,
367 epoch: EpochPair,
368 current_consumed_rows: ConsumedRows,
369 buffered_rows: BufferedRows,
370 ) {
371 if let Some(BackfillState::DoneConsumingUpstreamTableOrSource(_, _)) = self.state {
372 return;
373 }
374 tracing::debug!(
375 actor_id = %self.backfill_actor_id,
376 ?epoch,
377 current_consumed_rows,
378 buffered_rows,
379 "progress finish"
380 );
381 self.update_inner(
383 epoch,
384 BackfillState::DoneConsumingUpstreamTableOrSource(current_consumed_rows, buffered_rows),
385 );
386 }
387}
388
389impl LocalBarrierManager {
390 pub(crate) fn register_create_mview_progress(
398 &self,
399 actor_ctx: &ActorContext,
400 ) -> CreateMviewProgressReporter {
401 let fragment_id = actor_ctx.fragment_id;
402 let backfill_actor_id = actor_ctx.id;
403 trace!(%fragment_id, %backfill_actor_id, "register create mview progress");
404 CreateMviewProgressReporter::new(self.clone(), fragment_id, backfill_actor_id)
405 }
406}