1use std::borrow::Cow;
16use std::cmp::{Ordering, max, min};
17use std::collections::HashMap;
18use std::ops::Bound;
19
20use await_tree::InstrumentAwait;
21use futures::Stream;
22use futures::future::try_join_all;
23use futures_async_stream::try_stream;
24use risingwave_common::array::stream_record::Record;
25use risingwave_common::array::{DataChunk, Op, StreamChunk};
26use risingwave_common::bail;
27use risingwave_common::bitmap::BitmapBuilder;
28use risingwave_common::hash::{VirtualNode, VnodeBitmapExt};
29use risingwave_common::row::{OwnedRow, Row, RowExt};
30use risingwave_common::types::{DataType, Datum, DatumRef, ScalarRefImpl};
31use risingwave_common::util::chunk_coalesce::DataChunkBuilder;
32use risingwave_common::util::epoch::EpochPair;
33use risingwave_common::util::iter_util::ZipEqDebug;
34use risingwave_common::util::sort_util::{OrderType, cmp_datum, cmp_datum_iter};
35use risingwave_common::util::value_encoding::BasicSerde;
36use risingwave_common_rate_limit::RateLimit;
37use risingwave_connector::error::ConnectorError;
38use risingwave_connector::source::cdc::external::{CdcOffset, CdcOffsetParseFunc};
39use risingwave_storage::StateStore;
40use risingwave_storage::row_serde::value_serde::ValueRowSerde;
41use risingwave_storage::table::collect_data_chunk_with_builder;
42
43use crate::common::table::state_table::{ReplicatedStateTable, StateTableInner};
44use crate::executor::{Message, StreamExecutorError, StreamExecutorResult, Watermark};
45
46pub const METADATA_STATE_LEN: usize = 3;
48
49#[derive(Clone, Debug)]
50pub struct BackfillState {
51 inner: HashMap<VirtualNode, BackfillStatePerVnode>,
54}
55
56impl BackfillState {
57 pub(crate) fn has_progress(&self) -> bool {
61 self.inner
62 .values()
63 .any(|p| !matches!(p.current_state(), &BackfillProgressPerVnode::NotStarted))
64 }
65
66 pub(crate) fn get_current_state(
67 &mut self,
68 vnode: &VirtualNode,
69 ) -> &mut BackfillProgressPerVnode {
70 &mut self.inner.get_mut(vnode).unwrap().current_state
71 }
72
73 pub(crate) fn get_progress(
75 &self,
76 vnode: &VirtualNode,
77 ) -> StreamExecutorResult<&BackfillProgressPerVnode> {
78 match self.inner.get(vnode) {
79 Some(p) => Ok(p.current_state()),
80 None => bail!(
81 "Backfill progress for vnode {:#?} not found, backfill_state not initialized properly",
82 vnode,
83 ),
84 }
85 }
86
87 pub(crate) fn update_progress(
88 &mut self,
89 vnode: VirtualNode,
90 new_pos: OwnedRow,
91 snapshot_row_count_delta: u64,
92 ) -> StreamExecutorResult<()> {
93 let state = self.get_current_state(&vnode);
94 match state {
95 BackfillProgressPerVnode::NotStarted => {
96 *state = BackfillProgressPerVnode::InProgress {
97 current_pos: new_pos,
98 snapshot_row_count: snapshot_row_count_delta,
99 };
100 }
101 BackfillProgressPerVnode::InProgress {
102 snapshot_row_count, ..
103 } => {
104 *state = BackfillProgressPerVnode::InProgress {
105 current_pos: new_pos,
106 snapshot_row_count: *snapshot_row_count + snapshot_row_count_delta,
107 };
108 }
109 BackfillProgressPerVnode::Completed { .. } => unreachable!(),
110 }
111 Ok(())
112 }
113
114 pub(crate) fn finish_progress(&mut self, vnode: VirtualNode, pos_len: usize) {
115 let finished_placeholder_position = construct_initial_finished_state(pos_len);
116 let current_state = self.get_current_state(&vnode);
117 let (new_pos, snapshot_row_count) = match current_state {
118 BackfillProgressPerVnode::NotStarted => (finished_placeholder_position, 0),
119 BackfillProgressPerVnode::InProgress {
120 current_pos,
121 snapshot_row_count,
122 } => (current_pos.clone(), *snapshot_row_count),
123 BackfillProgressPerVnode::Completed { .. } => {
124 return;
125 }
126 };
127 *current_state = BackfillProgressPerVnode::Completed {
128 current_pos: new_pos,
129 snapshot_row_count,
130 };
131 }
132
133 fn get_commit_state(&self, vnode: &VirtualNode) -> Option<(Option<Vec<Datum>>, Vec<Datum>)> {
135 let new_state = self.inner.get(vnode).unwrap().current_state().clone();
136 let new_encoded_state = match new_state {
137 BackfillProgressPerVnode::NotStarted => unreachable!(),
138 BackfillProgressPerVnode::InProgress {
139 current_pos,
140 snapshot_row_count,
141 } => {
142 let mut encoded_state = vec![None; current_pos.len() + METADATA_STATE_LEN];
143 encoded_state[0] = Some(vnode.to_scalar().into());
144 encoded_state[1..current_pos.len() + 1].clone_from_slice(current_pos.as_inner());
145 encoded_state[current_pos.len() + 1] = Some(false.into());
146 encoded_state[current_pos.len() + 2] = Some((snapshot_row_count as i64).into());
147 encoded_state
148 }
149 BackfillProgressPerVnode::Completed {
150 current_pos,
151 snapshot_row_count,
152 } => {
153 let mut encoded_state = vec![None; current_pos.len() + METADATA_STATE_LEN];
154 encoded_state[0] = Some(vnode.to_scalar().into());
155 encoded_state[1..current_pos.len() + 1].clone_from_slice(current_pos.as_inner());
156 encoded_state[current_pos.len() + 1] = Some(true.into());
157 encoded_state[current_pos.len() + 2] = Some((snapshot_row_count as i64).into());
158 encoded_state
159 }
160 };
161 let old_state = self.inner.get(vnode).unwrap().committed_state().clone();
162 let old_encoded_state = match old_state {
163 BackfillProgressPerVnode::NotStarted => None,
164 BackfillProgressPerVnode::InProgress {
165 current_pos,
166 snapshot_row_count,
167 } => {
168 let committed_pos = current_pos;
169 let mut encoded_state = vec![None; committed_pos.len() + METADATA_STATE_LEN];
170 encoded_state[0] = Some(vnode.to_scalar().into());
171 encoded_state[1..committed_pos.len() + 1]
172 .clone_from_slice(committed_pos.as_inner());
173 encoded_state[committed_pos.len() + 1] = Some(false.into());
174 encoded_state[committed_pos.len() + 2] = Some((snapshot_row_count as i64).into());
175 Some(encoded_state)
176 }
177 BackfillProgressPerVnode::Completed {
178 current_pos,
179 snapshot_row_count,
180 } => {
181 let committed_pos = current_pos;
182 let mut encoded_state = vec![None; committed_pos.len() + METADATA_STATE_LEN];
183 encoded_state[0] = Some(vnode.to_scalar().into());
184 encoded_state[1..committed_pos.len() + 1]
185 .clone_from_slice(committed_pos.as_inner());
186 encoded_state[committed_pos.len() + 1] = Some(true.into());
187 encoded_state[committed_pos.len() + 2] = Some((snapshot_row_count as i64).into());
188 Some(encoded_state)
189 }
190 };
191 Some((old_encoded_state, new_encoded_state))
192 }
193
194 fn need_commit(&self, vnode: &VirtualNode) -> bool {
197 let state = self.inner.get(vnode).unwrap();
198 match state.current_state() {
199 s @ BackfillProgressPerVnode::InProgress { .. }
201 | s @ BackfillProgressPerVnode::Completed { .. } => s != state.committed_state(),
202 BackfillProgressPerVnode::NotStarted => false,
203 }
204 }
205
206 fn mark_committed(&mut self, vnode: VirtualNode) {
207 let BackfillStatePerVnode {
208 committed_state,
209 current_state,
210 } = self.inner.get_mut(&vnode).unwrap();
211
212 assert!(matches!(
213 current_state,
214 BackfillProgressPerVnode::InProgress { .. }
215 | BackfillProgressPerVnode::Completed { .. }
216 ));
217 *committed_state = current_state.clone();
218 }
219
220 pub(crate) fn get_snapshot_row_count(&self) -> u64 {
221 self.inner
222 .values()
223 .map(|p| p.get_snapshot_row_count())
224 .sum()
225 }
226}
227
228#[derive(Clone, Debug, PartialEq, Eq)]
229pub struct BackfillStatePerVnode {
230 committed_state: BackfillProgressPerVnode,
231 current_state: BackfillProgressPerVnode,
232}
233
234impl BackfillStatePerVnode {
235 pub(crate) fn new(
236 committed_state: BackfillProgressPerVnode,
237 current_state: BackfillProgressPerVnode,
238 ) -> Self {
239 Self {
240 committed_state,
241 current_state,
242 }
243 }
244
245 pub(crate) fn committed_state(&self) -> &BackfillProgressPerVnode {
246 &self.committed_state
247 }
248
249 pub(crate) fn current_state(&self) -> &BackfillProgressPerVnode {
250 &self.current_state
251 }
252
253 pub(crate) fn get_snapshot_row_count(&self) -> u64 {
254 self.current_state().get_snapshot_row_count()
255 }
256}
257
258impl From<Vec<(VirtualNode, BackfillStatePerVnode)>> for BackfillState {
259 fn from(v: Vec<(VirtualNode, BackfillStatePerVnode)>) -> Self {
260 Self {
261 inner: v.into_iter().collect(),
262 }
263 }
264}
265
266#[derive(Clone, Eq, PartialEq, Debug)]
269pub enum BackfillProgressPerVnode {
270 NotStarted,
272 InProgress {
273 current_pos: OwnedRow,
275 snapshot_row_count: u64,
277 },
278 Completed {
279 current_pos: OwnedRow,
281 snapshot_row_count: u64,
283 },
284}
285
286impl BackfillProgressPerVnode {
287 fn get_snapshot_row_count(&self) -> u64 {
288 match self {
289 BackfillProgressPerVnode::NotStarted => 0,
290 BackfillProgressPerVnode::InProgress {
291 snapshot_row_count, ..
292 }
293 | BackfillProgressPerVnode::Completed {
294 snapshot_row_count, ..
295 } => *snapshot_row_count,
296 }
297 }
298}
299
300pub(crate) fn mark_cdc_chunk(
304 offset_parse_func: &CdcOffsetParseFunc,
305 chunk: StreamChunk,
306 current_pos: &OwnedRow,
307 pk_in_output_indices: &[usize],
308 pk_order: &[OrderType],
309 pk_needs_unsigned_i64_compare: &[bool],
310 last_cdc_offset: Option<CdcOffset>,
311) -> StreamExecutorResult<StreamChunk> {
312 let chunk = chunk.compact_vis();
313 mark_cdc_chunk_inner(
314 offset_parse_func,
315 chunk,
316 current_pos,
317 last_cdc_offset,
318 pk_in_output_indices,
319 pk_order,
320 pk_needs_unsigned_i64_compare,
321 )
322}
323
324pub(crate) fn cmp_pk_unsigned_aware<'a>(
333 lhs: impl Iterator<Item = DatumRef<'a>>,
334 rhs: impl Iterator<Item = DatumRef<'a>>,
335 pk_order: &[OrderType],
336 pk_needs_unsigned_i64_compare: &[bool],
337) -> Ordering {
338 for (((l, r), order), &needs_unsigned_i64_compare) in lhs
339 .zip_eq_debug(rhs)
340 .zip_eq_debug(pk_order.iter())
341 .zip_eq_debug(pk_needs_unsigned_i64_compare.iter())
342 {
343 let ord = match (needs_unsigned_i64_compare, l, r) {
344 (true, Some(ScalarRefImpl::Int64(a)), Some(ScalarRefImpl::Int64(b))) => {
345 let ord = (a as u64).cmp(&(b as u64));
346 if order.is_descending() {
349 ord.reverse()
350 } else {
351 ord
352 }
353 }
354 _ => cmp_datum(l, r, *order),
357 };
358 if ord != Ordering::Equal {
359 return ord;
360 }
361 }
362 Ordering::Equal
363}
364
365pub(crate) fn mark_chunk_ref_by_vnode<S: StateStore, SD: ValueRowSerde>(
370 chunk: &StreamChunk,
371 backfill_state: &BackfillState,
372 pk_in_output_indices: &[usize],
373 upstream_table: &ReplicatedStateTable<S, SD>,
374 pk_order: &[OrderType],
375) -> StreamExecutorResult<StreamChunk> {
376 let chunk = chunk.clone();
377 let (data, ops) = chunk.into_parts();
378 let mut new_visibility = BitmapBuilder::with_capacity(ops.len());
379
380 let mut new_ops: Cow<'_, [Op]> = Cow::Borrowed(ops.as_ref());
381 let mut unmatched_update_delete = false;
382 let mut visible_update_delete = false;
383 for (i, (op, row)) in ops.iter().zip_eq_debug(data.rows()).enumerate() {
384 let pk = row.project(pk_in_output_indices);
385 let vnode = upstream_table.compute_vnode_by_pk(pk);
386 let visible = match backfill_state.get_progress(&vnode)? {
387 BackfillProgressPerVnode::Completed { .. } => true,
389 BackfillProgressPerVnode::NotStarted => false,
391 BackfillProgressPerVnode::InProgress { current_pos, .. } => {
393 cmp_datum_iter(pk.iter(), current_pos.iter(), pk_order.iter().copied()).is_le()
394 }
395 };
396 if !visible {
397 tracing::trace!(
398 source = "upstream",
399 state = "process_barrier",
400 action = "mark_chunk",
401 ?vnode,
402 ?op,
403 ?pk,
404 ?row,
405 "update_filtered",
406 );
407 }
408 new_visibility.append(visible);
409
410 normalize_unmatched_updates(
411 &mut new_ops,
412 &mut unmatched_update_delete,
413 &mut visible_update_delete,
414 visible,
415 i,
416 op,
417 );
418 }
419 let (columns, _) = data.into_parts();
420 let chunk = StreamChunk::with_visibility(new_ops, columns, new_visibility.finish());
421 Ok(chunk)
422}
423
424fn normalize_unmatched_updates(
432 normalized_ops: &mut Cow<'_, [Op]>,
433 unmatched_update_delete: &mut bool,
434 visible_update_delete: &mut bool,
435 current_visibility: bool,
436 current_op_index: usize,
437 current_op: &Op,
438) {
439 if *unmatched_update_delete {
440 assert_eq!(*current_op, Op::UpdateInsert);
441 let visible_update_insert = current_visibility;
442 match (visible_update_delete, visible_update_insert) {
443 (true, false) => {
444 let ops = normalized_ops.to_mut();
446 ops[current_op_index - 1] = Op::Delete;
447 }
448 (false, true) => {
449 let ops = normalized_ops.to_mut();
451 ops[current_op_index] = Op::Insert;
452 }
453 (true, true) | (false, false) => {}
454 }
455 *unmatched_update_delete = false;
456 } else {
457 match current_op {
458 Op::UpdateDelete => {
459 *unmatched_update_delete = true;
460 *visible_update_delete = current_visibility;
461 }
462 Op::UpdateInsert => {
463 unreachable!("UpdateInsert should not be present without UpdateDelete")
464 }
465 _ => {}
466 }
467 }
468}
469
470fn mark_cdc_chunk_inner(
471 offset_parse_func: &CdcOffsetParseFunc,
472 chunk: StreamChunk,
473 current_pos: &OwnedRow,
474 last_cdc_offset: Option<CdcOffset>,
475 pk_in_output_indices: &[usize],
476 pk_order: &[OrderType],
477 pk_needs_unsigned_i64_compare: &[bool],
478) -> StreamExecutorResult<StreamChunk> {
479 let (data, ops) = chunk.into_parts();
480 let mut new_visibility = BitmapBuilder::with_capacity(ops.len());
481
482 let offset_col_idx = data.dimension() - 1;
484 for v in data.rows().map(|row| {
485 let offset_datum = row.datum_at(offset_col_idx).unwrap();
486 let event_offset = (*offset_parse_func)(offset_datum.into_utf8())?;
487 let visible = {
488 let in_binlog_range = if let Some(binlog_low) = &last_cdc_offset {
490 binlog_low <= &event_offset
491 } else {
492 true
493 };
494
495 if in_binlog_range {
496 let lhs = row.project(pk_in_output_indices);
497 let rhs = current_pos;
498 cmp_pk_unsigned_aware(
499 lhs.iter(),
500 rhs.iter(),
501 pk_order,
502 pk_needs_unsigned_i64_compare,
503 )
504 .is_le()
505 } else {
506 false
507 }
508 };
509 Ok::<_, ConnectorError>(visible)
510 }) {
511 new_visibility.append(v?);
512 }
513
514 let (columns, _) = data.into_parts();
515 Ok(StreamChunk::with_visibility(
516 ops,
517 columns,
518 new_visibility.finish(),
519 ))
520}
521
522pub(crate) fn mapping_chunk(chunk: StreamChunk, output_indices: &[usize]) -> StreamChunk {
524 let (ops, columns, visibility) = chunk.into_inner();
525 let mapped_columns = output_indices.iter().map(|&i| columns[i].clone()).collect();
526 StreamChunk::with_visibility(ops, mapped_columns, visibility)
527}
528
529fn mapping_watermark(watermark: Watermark, upstream_indices: &[usize]) -> Option<Watermark> {
530 watermark.transform_with_indices(upstream_indices)
531}
532
533pub(crate) fn mapping_message(msg: Message, upstream_indices: &[usize]) -> Option<Message> {
534 match msg {
535 Message::Barrier(_) => Some(msg),
536 Message::Watermark(watermark) => {
537 mapping_watermark(watermark, upstream_indices).map(Message::Watermark)
538 }
539 Message::Chunk(chunk) => Some(Message::Chunk(mapping_chunk(chunk, upstream_indices))),
540 }
541}
542
543fn same_key_columns(lhs: &[usize], rhs: &[usize]) -> bool {
544 lhs.len() == rhs.len() && lhs.iter().all(|idx| rhs.contains(idx))
545}
546
547pub(super) struct UpstreamStreamKeyUpdateNormalizer {
554 current_stream_key_indices: Option<Vec<usize>>,
555}
556
557impl UpstreamStreamKeyUpdateNormalizer {
558 pub(super) fn new(
573 input_stream_key_indices: &[usize],
574 current_stream_key_indices: Vec<usize>,
575 ) -> Self {
576 let current_stream_key_indices =
577 (!same_key_columns(input_stream_key_indices, ¤t_stream_key_indices))
578 .then_some(current_stream_key_indices);
579 Self {
580 current_stream_key_indices,
581 }
582 }
583
584 pub(super) fn normalize_chunk(&self, chunk: StreamChunk) -> Option<StreamChunk> {
585 if let Some(current_stream_key_indices) = &self.current_stream_key_indices {
586 normalize_update_chunk_by_key(chunk, current_stream_key_indices)
587 } else {
588 Some(chunk)
589 }
590 }
591
592 pub(super) fn normalize_message(&self, msg: Message) -> Option<Message> {
593 match msg {
594 Message::Chunk(chunk) => self.normalize_chunk(chunk).map(Message::Chunk),
595 msg => Some(msg),
596 }
597 }
598}
599
600fn normalize_update_chunk_by_key(chunk: StreamChunk, key_indices: &[usize]) -> Option<StreamChunk> {
601 let (data_chunk, ops) = chunk.into_parts();
602 let mut update_indices = vec![];
603 let mut row_idx = data_chunk.next_visible_row_idx(0);
604 while let Some(idx) = row_idx {
605 let row = data_chunk.row_at_unchecked_vis(idx);
606 match ops[idx] {
607 Op::UpdateDelete => {
608 let next_idx = data_chunk
609 .next_visible_row_idx(idx + 1)
610 .unwrap_or_else(|| panic!("expect a U+ after U-\nU- row: {}", row.display()));
611 let next_row = data_chunk.row_at_unchecked_vis(next_idx);
612 debug_assert_eq!(
613 ops[next_idx],
614 Op::UpdateInsert,
615 "expect a U+ after U-\nU- row: {}\nrow after U-: {}",
616 row.display(),
617 next_row.display()
618 );
619 if row.project(key_indices) != next_row.project(key_indices) {
620 update_indices.push((idx, next_idx));
621 }
622 row_idx = data_chunk.next_visible_row_idx(next_idx + 1);
623 }
624 Op::UpdateInsert => panic!("expect a U- before U+\nU+ row: {}", row.display()),
625 Op::Insert | Op::Delete => {
626 row_idx = data_chunk.next_visible_row_idx(idx + 1);
627 }
628 }
629 }
630
631 if update_indices.is_empty() {
632 return Some(StreamChunk::from_parts(ops, data_chunk));
633 }
634
635 let (columns, visibility) = data_chunk.into_parts();
636 let mut ops = ops.to_vec();
637 for (delete_idx, insert_idx) in update_indices {
638 ops[delete_idx] = Op::Delete;
639 ops[insert_idx] = Op::Insert;
640 }
641 Some(StreamChunk::from_parts(
642 ops,
643 DataChunk::new(columns, visibility),
644 ))
645}
646
647pub(crate) async fn get_progress_per_vnode<S: StateStore, const IS_REPLICATED: bool>(
650 state_table: &StateTableInner<S, BasicSerde, IS_REPLICATED>,
651) -> StreamExecutorResult<Vec<(VirtualNode, BackfillStatePerVnode)>> {
652 debug_assert!(!state_table.vnodes().is_empty());
653 let vnodes = state_table.vnodes().iter_vnodes();
654 let mut result = Vec::with_capacity(state_table.vnodes().len());
655 let vnode_keys = vnodes.map(|vnode| {
657 let datum: [Datum; 1] = [Some(vnode.to_scalar().into())];
658 datum
659 });
660 let tasks = vnode_keys.map(|vnode_key| state_table.get_row(vnode_key));
661 let state_for_vnodes = try_join_all(tasks).await?;
665 for (vnode, state_for_vnode) in state_table
666 .vnodes()
667 .iter_vnodes()
668 .zip_eq_debug(state_for_vnodes)
669 {
670 let backfill_progress = match state_for_vnode {
671 Some(row) => {
673 let snapshot_row_count = row.as_inner().get(row.len() - 1).unwrap();
676 let snapshot_row_count = (*snapshot_row_count.as_ref().unwrap().as_int64()) as u64;
677
678 let vnode_is_finished = row.as_inner().get(row.len() - 2).unwrap();
681 let vnode_is_finished = vnode_is_finished.as_ref().unwrap();
682
683 let current_pos = row.as_inner().get(..row.len() - 2).unwrap();
685 let current_pos = current_pos.into_owned_row();
686
687 if *vnode_is_finished.as_bool() {
689 BackfillStatePerVnode::new(
690 BackfillProgressPerVnode::Completed {
691 current_pos: current_pos.clone(),
692 snapshot_row_count,
693 },
694 BackfillProgressPerVnode::Completed {
695 current_pos,
696 snapshot_row_count,
697 },
698 )
699 } else {
700 BackfillStatePerVnode::new(
701 BackfillProgressPerVnode::InProgress {
702 current_pos: current_pos.clone(),
703 snapshot_row_count,
704 },
705 BackfillProgressPerVnode::InProgress {
706 current_pos,
707 snapshot_row_count,
708 },
709 )
710 }
711 }
712 None => BackfillStatePerVnode::new(
714 BackfillProgressPerVnode::NotStarted,
715 BackfillProgressPerVnode::NotStarted,
716 ),
717 };
718 result.push((vnode, backfill_progress));
719 }
720 assert_eq!(result.len(), state_table.vnodes().count_ones());
721 Ok(result)
722}
723
724pub(crate) fn update_pos_by_vnode(
726 vnode: VirtualNode,
727 chunk: &StreamChunk,
728 pk_in_output_indices: &[usize],
729 backfill_state: &mut BackfillState,
730 snapshot_row_count_delta: u64,
731) -> StreamExecutorResult<()> {
732 let new_pos = get_new_pos(chunk, pk_in_output_indices);
733 assert_eq!(new_pos.len(), pk_in_output_indices.len());
734 backfill_state.update_progress(vnode, new_pos, snapshot_row_count_delta)?;
735 Ok(())
736}
737
738pub(crate) fn get_new_pos(chunk: &StreamChunk, pk_in_output_indices: &[usize]) -> OwnedRow {
741 chunk
742 .rows()
743 .last()
744 .unwrap()
745 .1
746 .project(pk_in_output_indices)
747 .into_owned_row()
748}
749
750pub(crate) fn get_cdc_chunk_last_offset(
751 offset_parse_func: &CdcOffsetParseFunc,
752 chunk: &StreamChunk,
753) -> StreamExecutorResult<Option<CdcOffset>> {
754 let row = chunk.rows().last().unwrap().1;
755 let offset_col = row.iter().last().unwrap();
756 let output =
757 offset_col.map(|scalar| Ok::<_, ConnectorError>((*offset_parse_func)(scalar.into_utf8()))?);
758 output.transpose().map_err(|e| e.into())
759}
760
761pub(crate) fn construct_initial_finished_state(pos_len: usize) -> OwnedRow {
767 OwnedRow::new(vec![None; pos_len])
768}
769
770pub(crate) fn compute_bounds(
771 pk_indices: &[usize],
772 current_pos: Option<OwnedRow>,
773) -> Option<(Bound<OwnedRow>, Bound<OwnedRow>)> {
774 if let Some(current_pos) = current_pos {
777 if current_pos.is_empty() {
781 assert!(pk_indices.is_empty());
782 return None;
783 }
784
785 Some((Bound::Excluded(current_pos), Bound::Unbounded))
786 } else {
787 Some((Bound::Unbounded, Bound::Unbounded))
788 }
789}
790
791#[try_stream(ok = StreamChunk, error = StreamExecutorError)]
792pub(crate) async fn iter_chunks<'a, S, E, R>(mut iter: S, builder: &'a mut DataChunkBuilder)
793where
794 StreamExecutorError: From<E>,
795 R: Row,
796 S: Stream<Item = Result<R, E>> + Unpin + 'a,
797{
798 while let Some(data_chunk) = collect_data_chunk_with_builder(&mut iter, builder)
799 .instrument_await("backfill_snapshot_read")
800 .await?
801 {
802 debug_assert!(data_chunk.cardinality() > 0);
803 let ops = vec![Op::Insert; data_chunk.capacity()];
804 let stream_chunk = StreamChunk::from_parts(ops, data_chunk);
805 yield stream_chunk;
806 }
807}
808
809pub(crate) async fn persist_state_per_vnode<S: StateStore, const IS_REPLICATED: bool>(
833 epoch: EpochPair,
834 table: &mut StateTableInner<S, BasicSerde, IS_REPLICATED>,
835 backfill_state: &mut BackfillState,
836 #[cfg(debug_assertions)] state_len: usize,
837 vnodes: impl Iterator<Item = VirtualNode>,
838) -> StreamExecutorResult<()> {
839 for vnode in vnodes {
840 if !backfill_state.need_commit(&vnode) {
841 continue;
842 }
843 let (encoded_prev_state, encoded_current_state) =
844 match backfill_state.get_commit_state(&vnode) {
845 Some((old_state, new_state)) => (old_state, new_state),
846 None => continue,
847 };
848 if let Some(encoded_prev_state) = encoded_prev_state {
849 #[cfg(debug_assertions)]
851 {
852 let pk: &[Datum; 1] = &[Some(vnode.to_scalar().into())];
853 let old_row = table.get_row(pk).await?;
855 match old_row {
856 Some(old_row) => {
857 let inner = old_row.as_inner();
858 assert_eq!(inner, &encoded_prev_state[1..]);
860 assert_ne!(inner, &encoded_current_state[1..]);
861 assert_eq!(old_row.len(), state_len - 1);
862 assert_eq!(encoded_current_state.len(), state_len);
863 }
864 None => {
865 bail!("row {:#?} not found", pk);
866 }
867 }
868 }
869 table.write_record(Record::Update {
870 old_row: &encoded_prev_state[..],
871 new_row: &encoded_current_state[..],
872 });
873 } else {
874 #[cfg(debug_assertions)]
876 {
877 let pk: &[Datum; 1] = &[Some(vnode.to_scalar().into())];
878 let row = table.get_row(pk).await?;
879 assert!(row.is_none(), "row {:#?}", row);
880 assert_eq!(encoded_current_state.len(), state_len);
881 }
882 table.write_record(Record::Insert {
883 new_row: &encoded_current_state[..],
884 });
885 }
886 backfill_state.mark_committed(vnode);
887 }
888
889 table.commit_assert_no_update_vnode_bitmap(epoch).await?;
890 Ok(())
891}
892
893pub fn create_builder(
897 rate_limit: RateLimit,
898 chunk_size: usize,
899 data_types: Vec<DataType>,
900) -> DataChunkBuilder {
901 let batch_size = match rate_limit {
902 RateLimit::Disabled | RateLimit::Pause => chunk_size,
903 RateLimit::Fixed(limit) => min(limit.get() as usize, chunk_size),
904 };
905 let batch_size = max(2, batch_size);
907 DataChunkBuilder::new(data_types, batch_size)
908}
909
910#[cfg(test)]
911mod tests {
912 use std::sync::Arc;
913
914 use super::*;
915
916 #[test]
917 fn test_normalizing_unmatched_updates() {
918 let ops = vec![
919 Op::UpdateDelete,
920 Op::UpdateInsert,
921 Op::UpdateDelete,
922 Op::UpdateInsert,
923 ];
924 let ops: Arc<[Op]> = ops.into();
925
926 {
927 let mut new_ops: Cow<'_, [Op]> = Cow::Borrowed(ops.as_ref());
928 let mut unmatched_update_delete = true;
929 let mut visible_update_delete = true;
930 let current_visibility = true;
931 normalize_unmatched_updates(
932 &mut new_ops,
933 &mut unmatched_update_delete,
934 &mut visible_update_delete,
935 current_visibility,
936 1,
937 &Op::UpdateInsert,
938 );
939 assert_eq!(
940 &new_ops[..],
941 vec![
942 Op::UpdateDelete,
943 Op::UpdateInsert,
944 Op::UpdateDelete,
945 Op::UpdateInsert
946 ]
947 );
948 }
949 {
950 let mut new_ops: Cow<'_, [Op]> = Cow::Borrowed(ops.as_ref());
951 let mut unmatched_update_delete = true;
952 let mut visible_update_delete = false;
953 let current_visibility = false;
954 normalize_unmatched_updates(
955 &mut new_ops,
956 &mut unmatched_update_delete,
957 &mut visible_update_delete,
958 current_visibility,
959 1,
960 &Op::UpdateInsert,
961 );
962 assert_eq!(
963 &new_ops[..],
964 vec![
965 Op::UpdateDelete,
966 Op::UpdateInsert,
967 Op::UpdateDelete,
968 Op::UpdateInsert
969 ]
970 );
971 }
972 {
973 let mut new_ops: Cow<'_, [Op]> = Cow::Borrowed(ops.as_ref());
974 let mut unmatched_update_delete = true;
975 let mut visible_update_delete = true;
976 let current_visibility = false;
977 normalize_unmatched_updates(
978 &mut new_ops,
979 &mut unmatched_update_delete,
980 &mut visible_update_delete,
981 current_visibility,
982 1,
983 &Op::UpdateInsert,
984 );
985 assert_eq!(
986 &new_ops[..],
987 vec![
988 Op::Delete,
989 Op::UpdateInsert,
990 Op::UpdateDelete,
991 Op::UpdateInsert
992 ]
993 );
994 }
995 {
996 let mut new_ops: Cow<'_, [Op]> = Cow::Borrowed(ops.as_ref());
997 let mut unmatched_update_delete = true;
998 let mut visible_update_delete = false;
999 let current_visibility = true;
1000 normalize_unmatched_updates(
1001 &mut new_ops,
1002 &mut unmatched_update_delete,
1003 &mut visible_update_delete,
1004 current_visibility,
1005 1,
1006 &Op::UpdateInsert,
1007 );
1008 assert_eq!(
1009 &new_ops[..],
1010 vec![
1011 Op::UpdateDelete,
1012 Op::Insert,
1013 Op::UpdateDelete,
1014 Op::UpdateInsert
1015 ]
1016 );
1017 }
1018 }
1019}