1use std::collections::{BTreeMap, HashMap};
16use std::marker::PhantomData;
17use std::ops::Bound;
18use std::ops::Bound::*;
19use std::sync::Arc;
20use std::time::Instant;
21
22use anyhow::anyhow;
23use await_tree::InstrumentAwait;
24use bytes::Bytes;
25use educe::Educe;
26use either::Either;
27use foyer::Hint;
28use futures::future::{ready, try_join_all};
29use futures::stream::BoxStream;
30use futures::{Stream, StreamExt, TryStreamExt, pin_mut};
31use itertools::Itertools;
32use risingwave_common::array::stream_record::Record;
33use risingwave_common::array::{ArrayImplBuilder, ArrayRef, DataChunk, Op, StreamChunk};
34use risingwave_common::bitmap::Bitmap;
35use risingwave_common::catalog::{
36 ColumnDesc, ColumnId, TableId, TableOption, get_dist_key_in_pk_indices,
37};
38use risingwave_common::config::StreamingConfig;
39use risingwave_common::hash::{VirtualNode, VnodeBitmapExt, VnodeCountCompat};
40use risingwave_common::id::FragmentId;
41use risingwave_common::row::{self, OwnedRow, Row, RowExt};
42use risingwave_common::types::{DataType, ScalarImpl};
43use risingwave_common::util::column_index_mapping::ColIndexMapping;
44use risingwave_common::util::epoch::EpochPair;
45use risingwave_common::util::row_serde::OrderedRowSerde;
46use risingwave_common::util::sort_util::{OrderType, cmp_datum};
47use risingwave_common::util::value_encoding::BasicSerde;
48use risingwave_hummock_sdk::HummockReadEpoch;
49use risingwave_hummock_sdk::key::{
50 CopyFromSlice, TableKey, end_bound_of_prefix, next_key, prefix_slice_with_vnode,
51 prefixed_range_with_vnode, start_bound_of_excluded_prefix,
52};
53use risingwave_hummock_sdk::table_watermark::{
54 VnodeWatermark, WatermarkDirection, WatermarkSerdeType,
55};
56use risingwave_pb::catalog::Table;
57use risingwave_pb::plan_common::StorageTableDesc;
58use risingwave_storage::StateStore;
59use risingwave_storage::error::{ErrorKind, StorageError, StorageResult};
60use risingwave_storage::hummock::CachePolicy;
61use risingwave_storage::mem_table::MemTableError;
62use risingwave_storage::row_serde::find_columns_by_ids;
63use risingwave_storage::row_serde::row_serde_util::{
64 deserialize_pk_with_vnode, serialize_pk, serialize_pk_with_vnode, serialize_row,
65};
66use risingwave_storage::row_serde::value_serde::ValueRowSerde;
67use risingwave_storage::store::*;
68use risingwave_storage::table::{KeyedRow, TableDistribution, should_calculate_prefix_hint};
69use thiserror_ext::AsReport;
70use tracing::{Instrument, trace};
71
72use crate::cache::keyed_cache_may_stale;
73use crate::executor::monitor::streaming_stats::StateTableMetrics;
74use crate::executor::{StreamExecutorError, StreamExecutorResult};
75
76macro_rules! insane_mode_discard_point {
79 () => {{
80 use rand::Rng;
81 if crate::consistency::insane() && rand::rng().random_bool(0.3) {
82 return;
83 }
84 }};
85}
86
87struct VnodeStatistics {
91 min_key: Option<Bytes>,
92 max_key: Option<Bytes>,
93}
94
95impl VnodeStatistics {
96 fn new() -> Self {
97 Self {
98 min_key: None,
99 max_key: None,
100 }
101 }
102
103 fn update_with_key(&mut self, key: &Bytes) {
104 if let Some(min) = &self.min_key {
105 if key < min {
106 self.min_key = Some(key.clone());
107 }
108 } else {
109 self.min_key = Some(key.clone());
110 }
111
112 if let Some(max) = &self.max_key {
113 if key > max {
114 self.max_key = Some(key.clone());
115 }
116 } else {
117 self.max_key = Some(key.clone());
118 }
119 }
120
121 fn can_prune(&self, key: &Bytes) -> bool {
122 if let Some(min) = &self.min_key
123 && key < min
124 {
125 return true;
126 }
127 if let Some(max) = &self.max_key
128 && key > max
129 {
130 return true;
131 }
132 false
133 }
134
135 fn can_prune_range(&self, start: &Bound<Bytes>, end: &Bound<Bytes>) -> bool {
136 if let Some(max) = &self.max_key {
138 match start {
139 Included(s) if s > max => return true,
140 Excluded(s) if s >= max => return true,
141 _ => {}
142 }
143 }
144 if let Some(min) = &self.min_key {
145 match end {
146 Included(e) if e < min => return true,
147 Excluded(e) if e <= min => return true,
148 _ => {}
149 }
150 }
151 false
152 }
153
154 fn pruned_key_range(
155 &self,
156 start: &Bound<Bytes>,
157 end: &Bound<Bytes>,
158 ) -> Option<(Bound<Bytes>, Bound<Bytes>)> {
159 if self.can_prune_range(start, end) {
160 return None;
161 }
162 let new_start = if let Some(min) = &self.min_key {
163 match start {
164 Included(s) if s <= min => Included(min.clone()),
165 Excluded(s) if s < min => Included(min.clone()),
166 _ => start.clone(),
167 }
168 } else {
169 start.clone()
170 };
171
172 let new_end = if let Some(max) = &self.max_key {
173 match end {
174 Included(e) if e >= max => Included(max.clone()),
175 Excluded(e) if e > max => Included(max.clone()),
176 _ => end.clone(),
177 }
178 } else {
179 end.clone()
180 };
181
182 Some((new_start, new_end))
183 }
184}
185
186pub struct StateTableInner<S, SD = BasicSerde, const IS_REPLICATED: bool = false>
189where
190 S: StateStore,
191 SD: ValueRowSerde,
192{
193 table_id: TableId,
195
196 row_store: StateTableRowStore<S::Local, SD>,
198
199 store: S,
201
202 epoch: Option<EpochPair>,
204
205 pk_serde: OrderedRowSerde,
207
208 pk_indices: Vec<usize>,
212
213 distribution: TableDistribution,
219
220 prefix_hint_len: usize,
221
222 value_indices: Option<Vec<usize>>,
223
224 pub clean_watermark_index: Option<usize>,
226 pending_watermark: Option<ScalarImpl>,
228 committed_watermark: Option<ScalarImpl>,
230 watermark_serde: Option<(OrderedRowSerde, WatermarkSerdeType)>,
232
233 data_types: Vec<DataType>,
236
237 i2o_mapping: ColIndexMapping,
243
244 pub output_indices: Vec<usize>,
249
250 op_consistency_level: StateTableOpConsistencyLevel,
251
252 on_post_commit: bool,
255}
256
257pub type StateTable<S> = StateTableInner<S, BasicSerde>;
259pub type ReplicatedStateTable<S, SD> = StateTableInner<S, SD, true>;
262
263pub type FlushedStateTableReader<S, SD = BasicSerde> = StateTableFlushedSnapshotReader<
264 <<S as StateStore>::Local as LocalStateStore>::FlushedSnapshotReader,
265 SD,
266>;
267
268#[derive(Educe)]
269#[educe(Clone)]
270pub struct StateTableFlushedSnapshotReader<R, SD = BasicSerde>
271where
272 R: StateStoreRead,
273 SD: ValueRowSerde,
274{
275 reader: Arc<R>,
276 pk_serde: OrderedRowSerde,
277 vnodes: Arc<Bitmap>,
278 row_serde: Arc<SD>,
279 metrics: Option<StateTableMetrics>,
280}
281
282impl<S, SD, const IS_REPLICATED: bool> StateTableInner<S, SD, IS_REPLICATED>
284where
285 S: StateStore,
286 SD: ValueRowSerde,
287{
288 pub async fn init_epoch(&mut self, epoch: EpochPair) -> StreamExecutorResult<()> {
291 self.row_store
292 .init(epoch, self.distribution.vnodes())
293 .await?;
294 assert_eq!(None, self.epoch.replace(epoch), "should not init for twice");
295 Ok(())
296 }
297
298 pub async fn try_wait_committed_epoch(&self, prev_epoch: u64) -> StorageResult<()> {
299 self.store
300 .try_wait_epoch(
301 HummockReadEpoch::Committed(prev_epoch),
302 TryWaitEpochOptions {
303 table_id: self.table_id,
304 },
305 )
306 .await
307 }
308
309 pub fn state_store(&self) -> &S {
310 &self.store
311 }
312}
313
314fn consistent_old_value_op(
315 row_serde: Arc<impl ValueRowSerde>,
316 is_log_store: bool,
317) -> OpConsistencyLevel {
318 OpConsistencyLevel::ConsistentOldValue {
319 check_old_value: Arc::new(move |first: &Bytes, second: &Bytes| {
320 if first == second {
321 return true;
322 }
323 let first = match row_serde.deserialize(first) {
324 Ok(rows) => rows,
325 Err(e) => {
326 error!(error = %e.as_report(), value = ?first, "fail to deserialize serialized value");
327 return false;
328 }
329 };
330 let second = match row_serde.deserialize(second) {
331 Ok(rows) => rows,
332 Err(e) => {
333 error!(error = %e.as_report(), value = ?second, "fail to deserialize serialized value");
334 return false;
335 }
336 };
337 if first != second {
338 error!(first = ?first, second = ?second, "sanity check fail");
339 false
340 } else {
341 true
342 }
343 }),
344 is_log_store,
345 }
346}
347
348macro_rules! dispatch_value_indices {
349 ($value_indices:expr, [$($row_var_name:ident),+], $body:expr) => {
350 if let Some(value_indices) = $value_indices {
351 $(
352 let $row_var_name = $row_var_name.project(value_indices);
353 )+
354 $body
355 } else {
356 $body
357 }
358 };
359}
360
361struct StateTableRowStore<LS: LocalStateStore, SD: ValueRowSerde> {
366 state_store: LS,
367 all_rows: Option<HashMap<VirtualNode, BTreeMap<Bytes, OwnedRow>>>,
368
369 table_id: TableId,
370 row_serde: Arc<SD>,
371 pk_serde: OrderedRowSerde,
373
374 vnode_stats: Option<HashMap<VirtualNode, VnodeStatistics>>,
376 enable_state_table_vnode_stats_pruning: bool,
380 pub metrics: Option<StateTableMetrics>,
382}
383
384impl<LS: LocalStateStore, SD: ValueRowSerde> StateTableRowStore<LS, SD> {
385 async fn may_load_vnode_stats(&mut self, vnode_bitmap: &Bitmap) -> StreamExecutorResult<()> {
386 if self.vnode_stats.is_none() {
387 return Ok(());
388 }
389
390 assert!(self.all_rows.is_none());
392
393 let start_time = Instant::now();
394 let mut stats_map = HashMap::new();
395
396 for vnode in vnode_bitmap.iter_vnodes() {
398 let mut stats = VnodeStatistics::new();
399
400 let memcomparable_range_with_vnode = prefixed_range_with_vnode::<Bytes>(.., vnode);
402 let read_options = ReadOptions {
403 cache_policy: CachePolicy::Fill(Hint::Low),
404 ..Default::default()
405 };
406
407 let mut iter = self
408 .state_store
409 .iter(memcomparable_range_with_vnode.clone(), read_options.clone())
410 .await?;
411 if let Some(item) = iter.try_next().await? {
412 let (key_vnode, key_without_vnode) = item.0.user_key.table_key.split_vnode();
413 assert_eq!(vnode, key_vnode);
414 stats.min_key = Some(Bytes::copy_from_slice(key_without_vnode));
415 }
416
417 let mut rev_iter = self
419 .state_store
420 .rev_iter(memcomparable_range_with_vnode, read_options)
421 .await?;
422 if let Some(item) = rev_iter.try_next().await? {
423 let (key_vnode, key_without_vnode) = item.0.user_key.table_key.split_vnode();
424 assert_eq!(vnode, key_vnode);
425 stats.max_key = Some(Bytes::copy_from_slice(key_without_vnode));
426 }
427
428 stats_map.insert(vnode, stats);
429 }
430
431 self.vnode_stats = Some(stats_map);
432
433 if !cfg!(debug_assertions) {
435 info!(
436 table_id = %self.table_id,
437 vnode_count = vnode_bitmap.count_ones(),
438 duration = ?start_time.elapsed(),
439 "finished initializing vnode statistics"
440 );
441 }
442
443 Ok(())
444 }
445
446 async fn may_reload_all_rows(&mut self, vnode_bitmap: &Bitmap) -> StreamExecutorResult<()> {
447 if let Some(rows) = &mut self.all_rows {
448 rows.clear();
449 let start_time = Instant::now();
450 *rows = try_join_all(vnode_bitmap.iter_vnodes().map(|vnode| {
451 let state_store = &self.state_store;
452 let row_serde = &self.row_serde;
453 async move {
454 let mut rows = BTreeMap::new();
455 let memcomparable_range_with_vnode =
456 prefixed_range_with_vnode::<Bytes>(.., vnode);
457 let stream = deserialize_keyed_row_stream::<Bytes>(
459 state_store
460 .iter(
461 memcomparable_range_with_vnode,
462 ReadOptions {
463 prefix_hint: None,
464 prefetch_options: Default::default(),
465 cache_policy: Default::default(),
466 },
467 )
468 .await?,
469 &**row_serde,
470 );
471 pin_mut!(stream);
472 while let Some((encoded_key, row)) = stream.try_next().await? {
473 let key = TableKey(encoded_key);
474 let (iter_vnode, key) = key.split_vnode_bytes();
475 assert_eq!(vnode, iter_vnode);
476 rows.try_insert(key, row).expect("non-duplicated");
477 }
478 Ok((vnode, rows)) as StreamExecutorResult<_>
479 }
480 }))
481 .await?
482 .into_iter()
483 .collect();
484 if !cfg!(debug_assertions) {
486 info!(table_id = %self.table_id, vnode_count = vnode_bitmap.count_ones(), duration = ?start_time.elapsed(),"finished reloading all rows");
487 }
488 }
489 Ok(())
490 }
491
492 async fn init(&mut self, epoch: EpochPair, vnode_bitmap: &Bitmap) -> StreamExecutorResult<()> {
493 self.state_store.init(InitOptions::new(epoch)).await?;
494 self.may_reload_all_rows(vnode_bitmap).await?;
495 self.may_load_vnode_stats(vnode_bitmap).await
496 }
497
498 async fn update_vnode_bitmap(
499 &mut self,
500 vnodes: Arc<Bitmap>,
501 ) -> StreamExecutorResult<Arc<Bitmap>> {
502 let prev_vnodes = self.state_store.update_vnode_bitmap(vnodes.clone()).await?;
503 self.may_reload_all_rows(&vnodes).await?;
504 self.may_load_vnode_stats(&vnodes).await?;
505
506 Ok(prev_vnodes)
507 }
508
509 async fn try_flush(&mut self) -> StreamExecutorResult<()> {
510 self.state_store.try_flush().await?;
511 Ok(())
512 }
513
514 async fn seal_current_epoch(
515 &mut self,
516 next_epoch: u64,
517 table_watermarks: Option<(WatermarkDirection, Vec<VnodeWatermark>, WatermarkSerdeType)>,
518 switch_consistent_op: Option<StateTableOpConsistencyLevel>,
519 ) -> StreamExecutorResult<()> {
520 if let Some((direction, watermarks, serde_type)) = &table_watermarks
521 && let Some(rows) = &mut self.all_rows
522 {
523 match serde_type {
524 WatermarkSerdeType::PkPrefix => {
525 for vnode_watermark in watermarks {
526 match direction {
527 WatermarkDirection::Ascending => {
528 for vnode in vnode_watermark.vnode_bitmap().iter_vnodes() {
529 let rows = rows.get_mut(&vnode).expect("covered vnode");
530 *rows = rows.split_off(vnode_watermark.watermark());
532 }
533 }
534 WatermarkDirection::Descending => {
535 let split_off_key = next_key(vnode_watermark.watermark());
537 for vnode in vnode_watermark.vnode_bitmap().iter_vnodes() {
538 let rows = rows.get_mut(&vnode).expect("covered vnode");
539 rows.split_off(split_off_key.as_slice());
542 }
543 }
544 }
545 }
546 }
547 WatermarkSerdeType::NonPkPrefix => {
548 warn!(table_id = %self.table_id, "table enabled preloading rows got disabled by written non pk prefix watermark");
549 self.all_rows = None;
550 }
551 WatermarkSerdeType::Value => {
552 warn!(table_id = %self.table_id, "table enabled preloading rows got disabled by written value watermark");
553 self.all_rows = None;
554 }
555 }
556 }
557 self.state_store
558 .flush()
559 .instrument(tracing::info_span!("state_table_flush"))
560 .await?;
561 let switch_op_consistency_level =
562 switch_consistent_op.map(|new_consistency_level| match new_consistency_level {
563 StateTableOpConsistencyLevel::Inconsistent => OpConsistencyLevel::Inconsistent,
564 StateTableOpConsistencyLevel::ConsistentOldValue => {
565 consistent_old_value_op(self.row_serde.clone(), false)
566 }
567 StateTableOpConsistencyLevel::LogStoreEnabled => {
568 consistent_old_value_op(self.row_serde.clone(), true)
569 }
570 });
571 self.state_store.seal_current_epoch(
572 next_epoch,
573 SealCurrentEpochOptions {
574 table_watermarks,
575 switch_op_consistency_level,
576 },
577 );
578 Ok(())
579 }
580}
581
582#[derive(Eq, PartialEq, Copy, Clone, Debug)]
583pub enum StateTableOpConsistencyLevel {
584 Inconsistent,
586 ConsistentOldValue,
590 LogStoreEnabled,
593}
594
595pub struct StateTableBuilder<S, SD, const IS_REPLICATED: bool, PreloadAllRow> {
596 table_id: TableId,
598 table_name_for_debug: String,
599 table_columns: Vec<ColumnDesc>,
600 order_types: Vec<OrderType>,
601 pk_indices: Vec<usize>,
602 dist_key_in_pk_indices: Vec<usize>,
603 vnode_col_idx_in_pk: Option<usize>,
604 expected_vnode_count: usize,
605 value_indices: Vec<usize>,
606 prefix_hint_len: usize,
607 retention_seconds: Option<u32>,
608 versioned: bool,
609 fragment_id: FragmentId,
610 clean_watermark_index: Option<usize>,
611
612 store: S,
614 vnodes: Option<Arc<Bitmap>>,
615 op_consistency_level: Option<StateTableOpConsistencyLevel>,
616 output_column_ids: Option<Vec<ColumnId>>,
617 preload_all_rows: PreloadAllRow,
618 enable_vnode_key_stats: Option<bool>,
619 enable_state_table_vnode_stats_pruning: bool,
622 metrics: Option<StateTableMetrics>,
623
624 _serde: PhantomData<SD>,
625}
626
627impl<S: StateStore, SD: ValueRowSerde, const IS_REPLICATED: bool>
628 StateTableBuilder<S, SD, IS_REPLICATED, ()>
629{
630 fn with_preload_all_rows(
631 self,
632 preload_all_rows: bool,
633 ) -> StateTableBuilder<S, SD, IS_REPLICATED, bool> {
634 StateTableBuilder {
635 table_id: self.table_id,
636 table_name_for_debug: self.table_name_for_debug,
637 table_columns: self.table_columns,
638 order_types: self.order_types,
639 pk_indices: self.pk_indices,
640 dist_key_in_pk_indices: self.dist_key_in_pk_indices,
641 vnode_col_idx_in_pk: self.vnode_col_idx_in_pk,
642 expected_vnode_count: self.expected_vnode_count,
643 value_indices: self.value_indices,
644 prefix_hint_len: self.prefix_hint_len,
645 retention_seconds: self.retention_seconds,
646 versioned: self.versioned,
647 fragment_id: self.fragment_id,
648 clean_watermark_index: self.clean_watermark_index,
649 store: self.store,
650 vnodes: self.vnodes,
651 op_consistency_level: self.op_consistency_level,
652 output_column_ids: self.output_column_ids,
653 preload_all_rows,
654 enable_vnode_key_stats: self.enable_vnode_key_stats,
655 enable_state_table_vnode_stats_pruning: self.enable_state_table_vnode_stats_pruning,
656 metrics: self.metrics,
657 _serde: Default::default(),
658 }
659 }
660
661 pub fn enable_preload_all_rows_by_config(
662 self,
663 config: &StreamingConfig,
664 ) -> StateTableBuilder<S, SD, IS_REPLICATED, bool> {
665 let developer = &config.developer;
666 let preload_all_rows = if developer.default_enable_mem_preload_state_table {
667 !developer
668 .mem_preload_state_table_ids_blacklist
669 .contains(&self.table_id.as_raw_id())
670 } else {
671 developer
672 .mem_preload_state_table_ids_whitelist
673 .contains(&self.table_id.as_raw_id())
674 };
675 self.with_preload_all_rows(preload_all_rows)
676 }
677
678 pub fn forbid_preload_all_rows(self) -> StateTableBuilder<S, SD, IS_REPLICATED, bool> {
679 self.with_preload_all_rows(false)
680 }
681}
682
683impl<S: StateStore, SD: ValueRowSerde, const IS_REPLICATED: bool, PreloadAllRow>
684 StateTableBuilder<S, SD, IS_REPLICATED, PreloadAllRow>
685{
686 pub fn with_op_consistency_level(
687 mut self,
688 op_consistency_level: StateTableOpConsistencyLevel,
689 ) -> Self {
690 self.op_consistency_level = Some(op_consistency_level);
691 self
692 }
693
694 pub fn enable_vnode_key_stats(mut self, enable: bool, config: &StreamingConfig) -> Self {
695 self.enable_vnode_key_stats = Some(enable);
696 self.enable_state_table_vnode_stats_pruning =
697 enable && config.developer.enable_state_table_vnode_stats_pruning;
698 self
699 }
700
701 pub fn with_metrics(mut self, metrics: StateTableMetrics) -> Self {
702 self.metrics = Some(metrics);
703 self
704 }
705}
706
707impl<S: StateStore, SD: ValueRowSerde, PreloadAllRow>
708 StateTableBuilder<S, SD, true, PreloadAllRow>
709{
710 pub fn with_output_column_ids(mut self, output_column_ids: Vec<ColumnId>) -> Self {
711 self.output_column_ids = Some(output_column_ids);
712 self
713 }
714}
715
716impl<S: StateStore, SD: ValueRowSerde, const IS_REPLICATED: bool>
717 StateTableBuilder<S, SD, IS_REPLICATED, bool>
718{
719 pub async fn build(self) -> StateTableInner<S, SD, IS_REPLICATED> {
720 let mut preload_all_rows = self.preload_all_rows;
721 if preload_all_rows
722 && let Err(e) =
723 risingwave_common::license::Feature::StateTableMemoryPreload.check_available()
724 {
725 warn!(table_id=%self.table_id, e=%e.as_report(), "table configured to preload rows to memory but disabled by license");
726 preload_all_rows = false;
727 }
728
729 let should_enable_vnode_key_stats = if preload_all_rows
730 && let Some(enable_vnode_key_stats) = self.enable_vnode_key_stats
731 && enable_vnode_key_stats
732 {
733 false
734 } else {
735 self.enable_vnode_key_stats.unwrap_or(false)
736 };
737 self.build_inner(preload_all_rows, should_enable_vnode_key_stats)
738 .await
739 }
740}
741
742impl<S, SD, const IS_REPLICATED: bool> StateTableInner<S, SD, IS_REPLICATED>
747where
748 S: StateStore,
749 SD: ValueRowSerde,
750{
751 #[cfg(any(test, feature = "test"))]
755 pub async fn from_table_catalog(
756 table_catalog: &Table,
757 store: S,
758 vnodes: Option<Arc<Bitmap>>,
759 ) -> Self {
760 StateTableBuilder::new(table_catalog, store, vnodes)
761 .forbid_preload_all_rows()
762 .build()
763 .await
764 }
765
766 pub async fn from_table_catalog_inconsistent_op(
768 table_catalog: &Table,
769 store: S,
770 vnodes: Option<Arc<Bitmap>>,
771 ) -> Self {
772 StateTableBuilder::new(table_catalog, store, vnodes)
773 .with_op_consistency_level(StateTableOpConsistencyLevel::Inconsistent)
774 .forbid_preload_all_rows()
775 .build()
776 .await
777 }
778}
779
780impl<S: StateStore, SD: ValueRowSerde, const IS_REPLICATED: bool>
781 StateTableBuilder<S, SD, IS_REPLICATED, ()>
782{
783 pub fn new(table_catalog: &Table, store: S, vnodes: Option<Arc<Bitmap>>) -> Self {
784 let table_id = table_catalog.id;
785 let table_columns: Vec<ColumnDesc> = table_catalog
786 .columns
787 .iter()
788 .map(|col| col.column_desc.as_ref().unwrap().into())
789 .collect();
790 let order_types: Vec<OrderType> = table_catalog
791 .pk
792 .iter()
793 .map(|col_order| OrderType::from_protobuf(col_order.get_order_type().unwrap()))
794 .collect();
795 let dist_key_indices: Vec<usize> = table_catalog
796 .distribution_key
797 .iter()
798 .map(|dist_index| *dist_index as usize)
799 .collect();
800
801 let pk_indices = table_catalog
802 .pk
803 .iter()
804 .map(|col_order| col_order.column_index as usize)
805 .collect_vec();
806
807 let dist_key_in_pk_indices = if table_catalog.get_dist_key_in_pk().is_empty() {
809 get_dist_key_in_pk_indices(&dist_key_indices, &pk_indices).unwrap()
810 } else {
811 table_catalog
812 .get_dist_key_in_pk()
813 .iter()
814 .map(|idx| *idx as usize)
815 .collect()
816 };
817
818 let vnode_col_idx_in_pk = table_catalog.vnode_col_index.as_ref().and_then(|idx| {
819 let vnode_col_idx = *idx as usize;
820 pk_indices.iter().position(|&i| vnode_col_idx == i)
821 });
822 let value_indices = table_catalog
823 .value_indices
824 .iter()
825 .map(|val| *val as usize)
826 .collect_vec();
827 let clean_watermark_indices = table_catalog.get_clean_watermark_column_indices();
828 if clean_watermark_indices.len() > 1 {
829 unimplemented!("multiple clean watermark columns are not supported yet")
830 }
831 let clean_watermark_index = clean_watermark_indices.first().map(|&i| i as usize);
832
833 Self {
834 table_id,
835 table_name_for_debug: table_catalog.name.clone(),
836 table_columns,
837 order_types,
838 pk_indices,
839 dist_key_in_pk_indices,
840 vnode_col_idx_in_pk,
841 expected_vnode_count: table_catalog.vnode_count(),
842 value_indices,
843 prefix_hint_len: table_catalog.read_prefix_len_hint as usize,
844 retention_seconds: table_catalog.retention_seconds,
845 versioned: table_catalog.version.is_some(),
846 fragment_id: table_catalog.fragment_id,
847 clean_watermark_index,
848 store,
849 vnodes,
850 op_consistency_level: None,
851 output_column_ids: None,
852 preload_all_rows: (),
853 enable_vnode_key_stats: None,
854 enable_state_table_vnode_stats_pruning: false,
855 metrics: None,
856 _serde: Default::default(),
857 }
858 }
859}
860
861impl<S: StateStore, SD: ValueRowSerde, const IS_REPLICATED: bool>
862 StateTableBuilder<S, SD, IS_REPLICATED, bool>
863{
864 async fn build_inner(
865 self,
866 preload_all_rows: bool,
867 should_enable_vnode_key_stats: bool,
868 ) -> StateTableInner<S, SD, IS_REPLICATED> {
869 let table_id = self.table_id;
870 let table_columns = self.table_columns;
871 let order_types = self.order_types;
872 let pk_indices = self.pk_indices;
873 let dist_key_in_pk_indices = self.dist_key_in_pk_indices;
874 let vnode_col_idx_in_pk = self.vnode_col_idx_in_pk;
875 let prefix_hint_len = self.prefix_hint_len;
876 let metrics = self.metrics;
877
878 let op_consistency_level = self
879 .op_consistency_level
880 .unwrap_or(StateTableOpConsistencyLevel::ConsistentOldValue);
881
882 let output_column_ids = self.output_column_ids.unwrap_or_default();
883
884 let data_types: Vec<DataType> = table_columns
885 .iter()
886 .map(|col| col.data_type.clone())
887 .collect();
888
889 if IS_REPLICATED && prefix_hint_len > 0 {
893 assert!(
894 dist_key_in_pk_indices.iter().all(|&d| d < prefix_hint_len),
895 "replicated state table: distribution key indices {:?} must all be covered by \
896 prefix_hint_len {}",
897 dist_key_in_pk_indices,
898 prefix_hint_len,
899 );
900 }
901
902 let distribution =
903 TableDistribution::new(self.vnodes, dist_key_in_pk_indices, vnode_col_idx_in_pk);
904 assert_eq!(
905 distribution.vnode_count(),
906 self.expected_vnode_count,
907 "vnode count mismatch, scanning table {} under wrong distribution?",
908 self.table_name_for_debug,
909 );
910
911 let pk_data_types = pk_indices
912 .iter()
913 .map(|i| table_columns[*i].data_type.clone())
914 .collect();
915 let pk_serde = OrderedRowSerde::new(pk_data_types, order_types);
916
917 let input_value_indices = self.value_indices;
918
919 let no_shuffle_value_indices = (0..table_columns.len()).collect_vec();
920
921 let value_indices = match input_value_indices.len() == table_columns.len()
923 && input_value_indices == no_shuffle_value_indices
924 {
925 true => None,
926 false => Some(input_value_indices.clone()),
927 };
928
929 let row_serde = Arc::new(SD::new(
930 Arc::from_iter(input_value_indices.iter().copied()),
931 Arc::from(table_columns.clone().into_boxed_slice()),
932 ));
933
934 let state_table_op_consistency_level = op_consistency_level;
935 let op_consistency_level = match state_table_op_consistency_level {
936 StateTableOpConsistencyLevel::Inconsistent => OpConsistencyLevel::Inconsistent,
937 StateTableOpConsistencyLevel::ConsistentOldValue => {
938 consistent_old_value_op(row_serde.clone(), false)
939 }
940 StateTableOpConsistencyLevel::LogStoreEnabled => {
941 consistent_old_value_op(row_serde.clone(), true)
942 }
943 };
944
945 let table_option = TableOption::new(self.retention_seconds);
946 let new_local_options = if IS_REPLICATED {
947 NewLocalOptions::new_replicated(
948 table_id,
949 self.fragment_id,
950 op_consistency_level,
951 table_option,
952 distribution.vnodes().clone(),
953 )
954 } else {
955 NewLocalOptions::new(
956 table_id,
957 self.fragment_id,
958 op_consistency_level,
959 table_option,
960 distribution.vnodes().clone(),
961 true,
962 )
963 };
964 let local_state_store = self.store.new_local(new_local_options).await;
965
966 assert_eq!(self.versioned, row_serde.kind().is_column_aware());
972
973 let output_column_ids_to_input_idx = output_column_ids
975 .iter()
976 .enumerate()
977 .map(|(pos, id)| (*id, pos))
978 .collect::<HashMap<_, _>>();
979
980 let columns = table_columns;
981
982 let mut i2o_mapping = vec![None; columns.len()];
986 for (i, column) in columns.iter().enumerate() {
987 if let Some(pos) = output_column_ids_to_input_idx.get(&column.column_id) {
988 i2o_mapping[i] = Some(*pos);
989 }
990 }
991 let i2o_mapping = ColIndexMapping::new(i2o_mapping, output_column_ids.len());
993
994 let (_, output_indices) = find_columns_by_ids(&columns[..], &output_column_ids);
996
997 if IS_REPLICATED {
1000 assert!(
1001 pk_indices
1002 .iter()
1003 .all(|&pk_idx| output_indices.contains(&pk_idx)),
1004 "all pk columns must be included in output_column_ids for replicated state table"
1005 );
1006 }
1007
1008 let clean_watermark_index = self.clean_watermark_index;
1009 let watermark_serde = clean_watermark_index.map(|idx| {
1010 let pk_idx = pk_indices.iter().position(|&i| i == idx);
1011 let (watermark_serde, watermark_serde_type) = match pk_idx {
1012 Some(0) => (pk_serde.index(0).into_owned(), WatermarkSerdeType::PkPrefix),
1013 Some(pk_idx) => (
1014 pk_serde.index(pk_idx).into_owned(),
1015 WatermarkSerdeType::NonPkPrefix,
1016 ),
1017 None => (
1018 OrderedRowSerde::new(
1019 vec![data_types[idx].clone()],
1020 vec![OrderType::ascending()],
1021 ),
1022 WatermarkSerdeType::Value,
1023 ),
1024 };
1025 (watermark_serde, watermark_serde_type)
1026 });
1027
1028 let committed_watermark = if let Some((deser, _)) = watermark_serde.as_ref() {
1030 distribution
1031 .vnodes()
1032 .iter_vnodes()
1033 .filter_map(|vnode| {
1034 let bytes = local_state_store.get_table_watermark(vnode)?;
1035 let datum = deser.deserialize(&bytes).ok().and_then(|row| {
1036 assert!(row.len() == 1);
1037 row[0].clone()
1038 });
1039 if datum.is_none() {
1040 tracing::error!(
1041 ?vnode,
1042 watermark = ?bytes,
1043 "Failed to deserialize persisted watermark from state store.",
1044 );
1045 }
1046 datum
1047 })
1048 .max_by(|a, b| cmp_datum(Some(a), Some(b), OrderType::ascending()))
1049 } else {
1050 None
1051 };
1052
1053 StateTableInner {
1054 table_id,
1055 row_store: StateTableRowStore {
1056 all_rows: preload_all_rows.then(HashMap::new),
1057 state_store: local_state_store,
1058 row_serde,
1059 pk_serde: pk_serde.clone(),
1060 table_id,
1061 vnode_stats: should_enable_vnode_key_stats.then(HashMap::new),
1063 enable_state_table_vnode_stats_pruning: self.enable_state_table_vnode_stats_pruning,
1064 metrics,
1065 },
1066 store: self.store,
1067 epoch: None,
1068 pk_serde,
1069 pk_indices,
1070 distribution,
1071 prefix_hint_len,
1072 value_indices,
1073 pending_watermark: None,
1074 committed_watermark,
1075 watermark_serde,
1076 data_types,
1077 output_indices,
1078 i2o_mapping,
1079 op_consistency_level: state_table_op_consistency_level,
1080 clean_watermark_index,
1081 on_post_commit: false,
1082 }
1083 }
1084}
1085
1086impl<S: StateStore, SD: ValueRowSerde, const IS_REPLICATED: bool>
1087 StateTableBuilder<S, SD, IS_REPLICATED, ()>
1088{
1089 pub fn new_from_storage_table_desc(
1090 table_desc: &StorageTableDesc,
1091 store: S,
1092 vnodes: Option<Arc<Bitmap>>,
1093 fragment_id: FragmentId,
1094 ) -> Self {
1095 let table_id = table_desc.table_id;
1096 let table_columns: Vec<ColumnDesc> =
1097 table_desc.columns.iter().map(ColumnDesc::from).collect();
1098 let order_types: Vec<OrderType> = table_desc
1099 .pk
1100 .iter()
1101 .map(|col_order| OrderType::from_protobuf(col_order.get_order_type().unwrap()))
1102 .collect();
1103 let pk_indices = table_desc
1104 .pk
1105 .iter()
1106 .map(|col_order| col_order.column_index as usize)
1107 .collect_vec();
1108 let dist_key_in_pk_indices = table_desc
1109 .dist_key_in_pk_indices
1110 .iter()
1111 .map(|&idx| idx as usize)
1112 .collect();
1113 let vnode_col_idx_in_pk = table_desc.vnode_col_idx_in_pk.map(|k| k as usize);
1116 let raw_value_indices = table_desc
1117 .value_indices
1118 .iter()
1119 .map(|val| *val as usize)
1120 .collect_vec();
1121
1122 Self {
1123 table_id,
1124 table_name_for_debug: table_id.to_string(),
1125 table_columns,
1126 order_types,
1127 pk_indices,
1128 dist_key_in_pk_indices,
1129 vnode_col_idx_in_pk,
1130 expected_vnode_count: table_desc.vnode_count(),
1131 value_indices: raw_value_indices,
1132 prefix_hint_len: table_desc.read_prefix_len_hint as usize,
1133 retention_seconds: table_desc.retention_seconds,
1134 versioned: table_desc.versioned,
1135 fragment_id,
1136 clean_watermark_index: None,
1137 store,
1138 vnodes,
1139 op_consistency_level: None,
1140 output_column_ids: None,
1141 preload_all_rows: (),
1142 enable_vnode_key_stats: None,
1143 enable_state_table_vnode_stats_pruning: false,
1144 metrics: None,
1145 _serde: Default::default(),
1146 }
1147 }
1148}
1149
1150impl<S, SD, const IS_REPLICATED: bool> StateTableInner<S, SD, IS_REPLICATED>
1151where
1152 S: StateStore,
1153 SD: ValueRowSerde,
1154{
1155 pub fn get_data_types(&self) -> &[DataType] {
1156 &self.data_types
1157 }
1158
1159 pub fn table_id(&self) -> TableId {
1160 self.table_id
1161 }
1162
1163 fn compute_prefix_vnode(&self, pk_prefix: &impl Row) -> VirtualNode {
1165 self.distribution
1166 .try_compute_vnode_by_pk_prefix(pk_prefix)
1167 .expect("For streaming, the given prefix must be enough to calculate the vnode")
1168 }
1169
1170 pub fn compute_vnode_by_pk(&self, pk: impl Row) -> VirtualNode {
1172 self.distribution.compute_vnode_by_pk(pk)
1173 }
1174
1175 pub fn pk_indices(&self) -> &[usize] {
1178 &self.pk_indices
1179 }
1180
1181 pub fn pk_in_output_indices(&self) -> Option<Vec<usize>> {
1185 assert!(IS_REPLICATED);
1186 self.pk_indices
1187 .iter()
1188 .map(|&i| self.output_indices.iter().position(|&j| i == j))
1189 .collect()
1190 }
1191
1192 pub fn pk_serde(&self) -> &OrderedRowSerde {
1193 &self.pk_serde
1194 }
1195
1196 pub fn vnodes(&self) -> &Arc<Bitmap> {
1197 self.distribution.vnodes()
1198 }
1199
1200 pub fn flushed_snapshot_reader(&self) -> FlushedStateTableReader<S, SD> {
1201 StateTableFlushedSnapshotReader {
1202 reader: Arc::new(self.row_store.state_store.new_flushed_snapshot_reader()),
1203 pk_serde: self.pk_serde.clone(),
1204 vnodes: self.distribution.vnodes().clone(),
1205 row_serde: self.row_store.row_serde.clone(),
1206 metrics: self.row_store.metrics.clone(),
1207 }
1208 }
1209
1210 pub fn value_indices(&self) -> &Option<Vec<usize>> {
1211 &self.value_indices
1212 }
1213
1214 pub fn is_consistent_op(&self) -> bool {
1215 matches!(
1216 self.op_consistency_level,
1217 StateTableOpConsistencyLevel::ConsistentOldValue
1218 | StateTableOpConsistencyLevel::LogStoreEnabled
1219 )
1220 }
1221
1222 pub fn metrics(&self) -> Option<&StateTableMetrics> {
1223 self.row_store.metrics.as_ref()
1224 }
1225}
1226
1227impl<S, SD> StateTableInner<S, SD, true>
1228where
1229 S: StateStore,
1230 SD: ValueRowSerde,
1231{
1232 pub async fn new_replicated(
1234 table_catalog: &Table,
1235 store: S,
1236 vnodes: Option<Arc<Bitmap>>,
1237 output_column_ids: Vec<ColumnId>,
1238 ) -> Self {
1239 StateTableBuilder::new(table_catalog, store, vnodes)
1242 .with_op_consistency_level(StateTableOpConsistencyLevel::Inconsistent)
1243 .with_output_column_ids(output_column_ids)
1244 .forbid_preload_all_rows()
1245 .build()
1246 .await
1247 }
1248}
1249
1250impl<S, SD, const IS_REPLICATED: bool> StateTableInner<S, SD, IS_REPLICATED>
1252where
1253 S: StateStore,
1254 SD: ValueRowSerde,
1255{
1256 pub async fn get_row(&self, pk: impl Row) -> StreamExecutorResult<Option<OwnedRow>> {
1258 let (serialized_pk, prefix_hint) = self.serialize_pk_and_get_prefix_hint(&pk);
1259 let row = self.row_store.get(serialized_pk, prefix_hint).await?;
1260 match row {
1261 Some(row) => {
1262 if IS_REPLICATED {
1263 let row = row.project(&self.output_indices);
1266 Ok(Some(row.into_owned_row()))
1267 } else {
1268 Ok(Some(row))
1269 }
1270 }
1271 None => Ok(None),
1272 }
1273 }
1274
1275 pub async fn exists(&self, pk: impl Row) -> StreamExecutorResult<bool> {
1277 let (serialized_pk, prefix_hint) = self.serialize_pk_and_get_prefix_hint(&pk);
1278 self.row_store.exists(serialized_pk, prefix_hint).await
1279 }
1280
1281 fn serialize_pk(&self, pk: &impl Row) -> TableKey<Bytes> {
1282 assert!(pk.len() <= self.pk_indices.len());
1283 serialize_pk_with_vnode(pk, &self.pk_serde, self.compute_vnode_by_pk(pk))
1284 }
1285
1286 fn serialize_pk_and_get_prefix_hint(&self, pk: &impl Row) -> (TableKey<Bytes>, Option<Bytes>) {
1287 let serialized_pk = self.serialize_pk(&pk);
1288 let prefix_hint = if should_calculate_prefix_hint(self.prefix_hint_len, pk.len(), false) {
1289 Some(serialized_pk.slice(VirtualNode::SIZE..))
1290 } else {
1291 #[cfg(debug_assertions)]
1292 if self.prefix_hint_len != 0 {
1293 warn!(
1294 "prefix_hint_len is not equal to pk.len(), may not be able to utilize bloom filter"
1295 );
1296 }
1297 None
1298 };
1299 (serialized_pk, prefix_hint)
1300 }
1301}
1302
1303impl<LS: LocalStateStore, SD: ValueRowSerde> StateTableRowStore<LS, SD> {
1304 async fn get(
1305 &self,
1306 key_bytes: TableKey<Bytes>,
1307 prefix_hint: Option<Bytes>,
1308 ) -> StreamExecutorResult<Option<OwnedRow>> {
1309 if let Some(m) = &self.metrics {
1310 m.get_count.inc();
1311 }
1312 if let Some(rows) = &self.all_rows {
1313 let (vnode, key) = key_bytes.split_vnode_bytes();
1314 return Ok(rows.get(&vnode).expect("covered vnode").get(&key).cloned());
1315 }
1316
1317 let should_prune = if let Some(stats) = &self.vnode_stats
1319 && let (vnode, key) = key_bytes.split_vnode_bytes()
1320 && let Some(vnode_stat) = stats.get(&vnode)
1321 && vnode_stat.can_prune(&key)
1322 {
1323 if let Some(m) = &self.metrics {
1324 m.get_vnode_pruned_count.inc();
1325 }
1326 true
1327 } else {
1328 false
1329 };
1330
1331 if should_prune && self.enable_state_table_vnode_stats_pruning {
1332 return Ok(None);
1333 }
1334
1335 let read_options = ReadOptions {
1336 prefix_hint,
1337 cache_policy: CachePolicy::Fill(Hint::Normal),
1338 ..Default::default()
1339 };
1340
1341 let result = self
1342 .state_store
1343 .on_key_value(key_bytes, read_options, move |_, value| {
1344 let row = self.row_serde.deserialize(value)?;
1345 Ok(OwnedRow::new(row))
1346 })
1347 .await
1348 .map_err(Into::<StreamExecutorError>::into)?;
1349
1350 if should_prune && result.is_some() {
1352 tracing::warn!(
1353 table_id = %self.table_id,
1354 "vnode stats pruning dry run fails for get. This will not affect correctness."
1355 );
1356 }
1357
1358 Ok(result)
1359 }
1360
1361 async fn exists(
1362 &self,
1363 key_bytes: TableKey<Bytes>,
1364 prefix_hint: Option<Bytes>,
1365 ) -> StreamExecutorResult<bool> {
1366 if let Some(m) = &self.metrics {
1367 m.get_count.inc();
1368 }
1369 if let Some(rows) = &self.all_rows {
1370 let (vnode, key) = key_bytes.split_vnode_bytes();
1371 return Ok(rows.get(&vnode).expect("covered vnode").contains_key(&key));
1372 }
1373
1374 let should_prune = if let Some(stats) = &self.vnode_stats
1376 && let (vnode, key) = key_bytes.split_vnode_bytes()
1377 && let Some(vnode_stat) = stats.get(&vnode)
1378 && vnode_stat.can_prune(&key)
1379 {
1380 if let Some(m) = &self.metrics {
1381 m.get_vnode_pruned_count.inc();
1382 }
1383 true
1384 } else {
1385 false
1386 };
1387
1388 if should_prune && self.enable_state_table_vnode_stats_pruning {
1389 return Ok(false);
1390 }
1391
1392 let read_options = ReadOptions {
1393 prefix_hint,
1394 cache_policy: CachePolicy::Fill(Hint::Normal),
1395 ..Default::default()
1396 };
1397 let result = self
1398 .state_store
1399 .on_key_value(key_bytes, read_options, move |_, _| Ok(()))
1400 .await?;
1401 let exists = result.is_some();
1402
1403 if should_prune && exists {
1405 tracing::warn!(
1406 table_id = %self.table_id,
1407 "vnode stats pruning dry run fails for exists. This will not affect correctness."
1408 );
1409 }
1410
1411 Ok(exists)
1412 }
1413}
1414
1415#[must_use]
1430pub struct StateTablePostCommit<'a, S, SD = BasicSerde, const IS_REPLICATED: bool = false>
1431where
1432 S: StateStore,
1433 SD: ValueRowSerde,
1434{
1435 inner: &'a mut StateTableInner<S, SD, IS_REPLICATED>,
1436}
1437
1438impl<'a, S, SD, const IS_REPLICATED: bool> StateTablePostCommit<'a, S, SD, IS_REPLICATED>
1439where
1440 S: StateStore,
1441 SD: ValueRowSerde,
1442{
1443 pub async fn post_yield_barrier(
1448 mut self,
1449 new_vnodes: Option<Arc<Bitmap>>,
1450 ) -> StreamExecutorResult<
1451 Option<(
1452 (
1453 Arc<Bitmap>,
1454 Arc<Bitmap>,
1455 &'a mut StateTableInner<S, SD, IS_REPLICATED>,
1456 ),
1457 bool,
1458 )>,
1459 > {
1460 self.inner.on_post_commit = false;
1461 Ok(if let Some(new_vnodes) = new_vnodes {
1462 let (old_vnodes, keyed_cache_may_stale) =
1463 self.update_vnode_bitmap(new_vnodes.clone()).await?;
1464 Some(((new_vnodes, old_vnodes, self.inner), keyed_cache_may_stale))
1465 } else {
1466 None
1467 })
1468 }
1469
1470 pub fn inner(&self) -> &StateTableInner<S, SD, IS_REPLICATED> {
1471 &*self.inner
1472 }
1473
1474 async fn update_vnode_bitmap(
1476 &mut self,
1477 new_vnodes: Arc<Bitmap>,
1478 ) -> StreamExecutorResult<(Arc<Bitmap>, bool)> {
1479 let prev_vnodes = self
1480 .inner
1481 .row_store
1482 .update_vnode_bitmap(new_vnodes.clone())
1483 .await?;
1484 assert_eq!(
1485 &prev_vnodes,
1486 self.inner.vnodes(),
1487 "state table and state store vnode bitmap mismatches"
1488 );
1489
1490 if self.inner.distribution.is_singleton() {
1491 assert_eq!(
1492 &new_vnodes,
1493 self.inner.vnodes(),
1494 "should not update vnode bitmap for singleton table"
1495 );
1496 }
1497 assert_eq!(self.inner.vnodes().len(), new_vnodes.len());
1498
1499 let keyed_cache_may_stale = keyed_cache_may_stale(self.inner.vnodes(), &new_vnodes);
1500
1501 if keyed_cache_may_stale {
1502 self.inner.pending_watermark = None;
1503 }
1504
1505 Ok((
1506 self.inner.distribution.update_vnode_bitmap(new_vnodes),
1507 keyed_cache_may_stale,
1508 ))
1509 }
1510}
1511
1512impl<LS: LocalStateStore, SD: ValueRowSerde> StateTableRowStore<LS, SD> {
1514 fn handle_mem_table_error(&self, e: StorageError) {
1515 let e = match e.into_inner() {
1516 ErrorKind::MemTable(e) => e,
1517 _ => unreachable!("should only get memtable error"),
1518 };
1519 match *e {
1520 MemTableError::InconsistentOperation { key, prev, new, .. } => {
1521 let (vnode, key) = deserialize_pk_with_vnode(&key, &self.pk_serde).unwrap();
1522 panic!(
1523 "mem-table operation inconsistent! table_id: {}, vnode: {}, key: {:?}, prev: {}, new: {}",
1524 self.table_id,
1525 vnode,
1526 key,
1527 prev.debug_fmt(&*self.row_serde),
1528 new.debug_fmt(&*self.row_serde),
1529 )
1530 }
1531 }
1532 }
1533
1534 fn insert(&mut self, key: TableKey<Bytes>, value: impl Row) {
1535 insane_mode_discard_point!();
1536 let value_bytes = self.row_serde.serialize(&value).into();
1537
1538 let (vnode, key_without_vnode) = key.split_vnode_bytes();
1539
1540 if self.all_rows.is_none()
1542 && let Some(stats) = &mut self.vnode_stats
1543 && let Some(vnode_stat) = stats.get_mut(&vnode)
1544 {
1545 vnode_stat.update_with_key(&key_without_vnode);
1546 }
1547
1548 if let Some(rows) = &mut self.all_rows {
1549 rows.get_mut(&vnode)
1550 .expect("covered vnode")
1551 .insert(key_without_vnode, value.into_owned_row());
1552 }
1553 self.state_store
1554 .insert(key, value_bytes, None)
1555 .unwrap_or_else(|e| self.handle_mem_table_error(e));
1556 }
1557
1558 fn delete(&mut self, key: TableKey<Bytes>, value: impl Row) {
1559 insane_mode_discard_point!();
1560 let value_bytes = self.row_serde.serialize(value).into();
1561
1562 let (vnode, key_without_vnode) = key.split_vnode_bytes();
1563
1564 if self.all_rows.is_none()
1565 && let Some(stats) = &mut self.vnode_stats
1566 && let Some(vnode_stat) = stats.get_mut(&vnode)
1567 {
1568 vnode_stat.update_with_key(&key_without_vnode);
1569 }
1570
1571 if let Some(rows) = &mut self.all_rows {
1572 rows.get_mut(&vnode)
1573 .expect("covered vnode")
1574 .remove(&key_without_vnode);
1575 }
1576 self.state_store
1577 .delete(key, value_bytes)
1578 .unwrap_or_else(|e| self.handle_mem_table_error(e));
1579 }
1580
1581 fn update(&mut self, key_bytes: TableKey<Bytes>, old_value: impl Row, new_value: impl Row) {
1582 insane_mode_discard_point!();
1583 let new_value_bytes = self.row_serde.serialize(&new_value).into();
1584 let old_value_bytes = self.row_serde.serialize(old_value).into();
1585
1586 let (vnode, key_without_vnode) = key_bytes.split_vnode_bytes();
1587
1588 if self.all_rows.is_none()
1591 && let Some(stats) = &mut self.vnode_stats
1592 && let Some(vnode_stat) = stats.get_mut(&vnode)
1593 {
1594 vnode_stat.update_with_key(&key_without_vnode);
1595 }
1596
1597 if let Some(rows) = &mut self.all_rows {
1598 rows.get_mut(&vnode)
1599 .expect("covered vnode")
1600 .insert(key_without_vnode, new_value.into_owned_row());
1601 }
1602 self.state_store
1603 .insert(key_bytes, new_value_bytes, Some(old_value_bytes))
1604 .unwrap_or_else(|e| self.handle_mem_table_error(e));
1605 }
1606}
1607
1608impl<S, SD, const IS_REPLICATED: bool> StateTableInner<S, SD, IS_REPLICATED>
1609where
1610 S: StateStore,
1611 SD: ValueRowSerde,
1612{
1613 pub fn insert(&mut self, value: impl Row) {
1616 let pk_indices = &self.pk_indices;
1617 let pk = (&value).project(pk_indices);
1618
1619 let key_bytes = self.serialize_pk(&pk);
1620 dispatch_value_indices!(&self.value_indices, [value], {
1621 self.row_store.insert(key_bytes, value)
1622 })
1623 }
1624
1625 pub fn delete(&mut self, old_value: impl Row) {
1628 let pk_indices = &self.pk_indices;
1629 let pk = (&old_value).project(pk_indices);
1630
1631 let key_bytes = self.serialize_pk(&pk);
1632 dispatch_value_indices!(&self.value_indices, [old_value], {
1633 self.row_store.delete(key_bytes, old_value)
1634 })
1635 }
1636
1637 pub fn update(&mut self, old_value: impl Row, new_value: impl Row) {
1639 let old_pk = (&old_value).project(self.pk_indices());
1640 let new_pk = (&new_value).project(self.pk_indices());
1641 debug_assert!(
1642 Row::eq(&old_pk, new_pk),
1643 "pk should not change: {old_pk:?} vs {new_pk:?}. {}",
1644 self.table_id
1645 );
1646
1647 let key_bytes = self.serialize_pk(&new_pk);
1648 dispatch_value_indices!(&self.value_indices, [old_value, new_value], {
1649 self.row_store.update(key_bytes, old_value, new_value)
1650 })
1651 }
1652
1653 pub fn write_record(&mut self, record: Record<impl Row>) {
1655 match record {
1656 Record::Insert { new_row } => self.insert(new_row),
1657 Record::Delete { old_row } => self.delete(old_row),
1658 Record::Update { old_row, new_row } => self.update(old_row, new_row),
1659 }
1660 }
1661
1662 fn fill_non_output_indices(&self, chunk: StreamChunk) -> StreamChunk {
1663 fill_non_output_indices(&self.i2o_mapping, &self.data_types, chunk)
1664 }
1665
1666 #[allow(clippy::disallowed_methods)]
1669 pub fn write_chunk(&mut self, chunk: StreamChunk) {
1670 let chunk = if IS_REPLICATED {
1671 self.fill_non_output_indices(chunk)
1672 } else {
1673 chunk
1674 };
1675
1676 let vnodes = self
1677 .distribution
1678 .compute_chunk_vnode(&chunk, &self.pk_indices);
1679
1680 for (idx, optional_row) in chunk.rows_with_holes().enumerate() {
1681 let Some((op, row)) = optional_row else {
1682 continue;
1683 };
1684 let pk = row.project(&self.pk_indices);
1685 let vnode = vnodes[idx];
1686 let key_bytes = serialize_pk_with_vnode(pk, &self.pk_serde, vnode);
1687 match op {
1688 Op::Insert | Op::UpdateInsert => {
1689 dispatch_value_indices!(&self.value_indices, [row], {
1690 self.row_store.insert(key_bytes, row);
1691 });
1692 }
1693 Op::Delete | Op::UpdateDelete => {
1694 dispatch_value_indices!(&self.value_indices, [row], {
1695 self.row_store.delete(key_bytes, row);
1696 });
1697 }
1698 }
1699 }
1700 }
1701
1702 pub fn update_watermark(&mut self, watermark: ScalarImpl) {
1708 trace!(table_id = %self.table_id, watermark = ?watermark, "update watermark");
1709 self.pending_watermark = Some(watermark);
1710 }
1711
1712 pub fn get_committed_watermark(&self) -> Option<&ScalarImpl> {
1715 self.committed_watermark.as_ref()
1716 }
1717
1718 pub async fn commit(
1719 &mut self,
1720 new_epoch: EpochPair,
1721 ) -> StreamExecutorResult<StateTablePostCommit<'_, S, SD, IS_REPLICATED>> {
1722 self.commit_inner(new_epoch, None).await
1723 }
1724
1725 #[cfg(test)]
1726 pub async fn commit_for_test(&mut self, new_epoch: EpochPair) -> StreamExecutorResult<()> {
1727 self.commit_assert_no_update_vnode_bitmap(new_epoch).await
1728 }
1729
1730 pub async fn commit_assert_no_update_vnode_bitmap(
1731 &mut self,
1732 new_epoch: EpochPair,
1733 ) -> StreamExecutorResult<()> {
1734 let post_commit = self.commit_inner(new_epoch, None).await?;
1735 post_commit.post_yield_barrier(None).await?;
1736 Ok(())
1737 }
1738
1739 pub async fn commit_may_switch_consistent_op(
1740 &mut self,
1741 new_epoch: EpochPair,
1742 op_consistency_level: StateTableOpConsistencyLevel,
1743 ) -> StreamExecutorResult<StateTablePostCommit<'_, S, SD, IS_REPLICATED>> {
1744 if self.op_consistency_level != op_consistency_level {
1745 if !cfg!(debug_assertions) {
1747 info!(
1748 ?new_epoch,
1749 prev_op_consistency_level = ?self.op_consistency_level,
1750 ?op_consistency_level,
1751 table_id = %self.table_id,
1752 "switch to new op consistency level"
1753 );
1754 }
1755 self.commit_inner(new_epoch, Some(op_consistency_level))
1756 .await
1757 } else {
1758 self.commit_inner(new_epoch, None).await
1759 }
1760 }
1761
1762 async fn commit_inner(
1763 &mut self,
1764 new_epoch: EpochPair,
1765 switch_consistent_op: Option<StateTableOpConsistencyLevel>,
1766 ) -> StreamExecutorResult<StateTablePostCommit<'_, S, SD, IS_REPLICATED>> {
1767 assert!(!self.on_post_commit);
1768 assert_eq!(
1769 self.epoch.expect("should only be called after init").curr,
1770 new_epoch.prev
1771 );
1772 if let Some(new_consistency_level) = switch_consistent_op {
1773 assert_ne!(self.op_consistency_level, new_consistency_level);
1774 self.op_consistency_level = new_consistency_level;
1775 }
1776 trace!(
1777 table_id = %self.table_id,
1778 epoch = ?self.epoch,
1779 "commit state table"
1780 );
1781
1782 let table_watermarks = self.commit_pending_watermark();
1783 self.row_store
1784 .seal_current_epoch(new_epoch.curr, table_watermarks, switch_consistent_op)
1785 .instrument_await(await_tree::span!(
1786 "state_table_commit table_id={} epoch={}",
1787 self.table_id,
1788 new_epoch.curr
1789 ))
1790 .await?;
1791 self.epoch = Some(new_epoch);
1792
1793 self.on_post_commit = true;
1794 Ok(StateTablePostCommit { inner: self })
1795 }
1796
1797 fn commit_pending_watermark(
1799 &mut self,
1800 ) -> Option<(WatermarkDirection, Vec<VnodeWatermark>, WatermarkSerdeType)> {
1801 let watermark = self.pending_watermark.take()?;
1802 trace!(table_id = %self.table_id, watermark = ?watermark, "state cleaning");
1803
1804 assert!(
1805 !self.pk_indices().is_empty(),
1806 "see pending watermark on empty pk"
1807 );
1808 let (watermark_serializer, watermark_type) = self
1809 .watermark_serde
1810 .as_ref()
1811 .expect("watermark serde should be initialized to commit watermark");
1812 let watermark_suffix =
1813 serialize_row(row::once(Some(watermark.clone())), watermark_serializer);
1814 let vnode_watermark = VnodeWatermark::new(
1815 self.vnodes().clone(),
1816 Bytes::copy_from_slice(watermark_suffix.as_ref()),
1817 );
1818 trace!(table_id = %self.table_id, ?vnode_watermark, "table watermark");
1819
1820 let order_type = watermark_serializer.get_order_types().get(0).unwrap();
1821 let direction = if order_type.is_ascending() {
1822 WatermarkDirection::Ascending
1823 } else {
1824 WatermarkDirection::Descending
1825 };
1826
1827 self.committed_watermark = Some(watermark);
1828 Some((direction, vec![vnode_watermark], *watermark_type))
1829 }
1830
1831 pub async fn try_flush(&mut self) -> StreamExecutorResult<()> {
1832 self.row_store.try_flush().await?;
1833 Ok(())
1834 }
1835}
1836
1837pub trait RowStream<'a>: Stream<Item = StreamExecutorResult<OwnedRow>> + 'a {}
1839impl<'a, S: Stream<Item = StreamExecutorResult<OwnedRow>> + 'a> RowStream<'a> for S {}
1840
1841pub trait KeyedRowStream<'a>: Stream<Item = StreamExecutorResult<KeyedRow<Bytes>>> + 'a {}
1842impl<'a, S: Stream<Item = StreamExecutorResult<KeyedRow<Bytes>>> + 'a> KeyedRowStream<'a> for S {}
1843
1844pub trait PkRowStream<'a, K>: Stream<Item = StreamExecutorResult<(K, OwnedRow)>> + 'a {}
1845impl<'a, K, S: Stream<Item = StreamExecutorResult<(K, OwnedRow)>> + 'a> PkRowStream<'a, K> for S {}
1846
1847pub type BoxedRowStream<'a> = BoxStream<'a, StreamExecutorResult<OwnedRow>>;
1848
1849pub trait FromVnodeBytes {
1850 fn from_vnode_bytes(vnode: VirtualNode, bytes: &Bytes) -> Self;
1851}
1852
1853impl FromVnodeBytes for Bytes {
1854 fn from_vnode_bytes(vnode: VirtualNode, bytes: &Bytes) -> Self {
1855 prefix_slice_with_vnode(vnode, bytes)
1856 }
1857}
1858
1859impl FromVnodeBytes for () {
1860 fn from_vnode_bytes(_vnode: VirtualNode, _bytes: &Bytes) -> Self {}
1861}
1862
1863impl<R, SD> StateTableFlushedSnapshotReader<R, SD>
1864where
1865 R: StateStoreRead,
1866 SD: ValueRowSerde,
1867{
1868 pub fn vnodes(&self) -> &Arc<Bitmap> {
1869 &self.vnodes
1870 }
1871
1872 pub async fn iter_with_vnode(
1874 &self,
1875 vnode: VirtualNode,
1876 pk_range: &(Bound<impl Row>, Bound<impl Row>),
1877 prefetch_options: PrefetchOptions,
1878 ) -> StreamExecutorResult<impl RowStream<'static>> {
1879 if let Some(m) = &self.metrics {
1880 m.iter_count.inc();
1881 }
1882
1883 let memcomparable_range = prefix_range_to_memcomparable(&self.pk_serde, pk_range);
1884 let iter = self
1885 .reader
1886 .iter(
1887 prefixed_range_with_vnode(memcomparable_range, vnode),
1888 ReadOptions {
1889 prefix_hint: None,
1890 prefetch_options,
1891 cache_policy: CachePolicy::Fill(Hint::Normal),
1892 },
1893 )
1894 .await?;
1895 let row_serde = self.row_serde.clone();
1896 Ok(iter
1897 .into_stream(move |(_key, value)| Ok(OwnedRow::new(row_serde.deserialize(value)?)))
1898 .map_err(Into::into))
1899 }
1900}
1901
1902impl<S, SD, const IS_REPLICATED: bool> StateTableInner<S, SD, IS_REPLICATED>
1904where
1905 S: StateStore,
1906 SD: ValueRowSerde,
1907{
1908 pub async fn iter_with_vnode(
1911 &self,
1912
1913 vnode: VirtualNode,
1917 pk_range: &(Bound<impl Row>, Bound<impl Row>),
1918 prefetch_options: PrefetchOptions,
1919 ) -> StreamExecutorResult<impl RowStream<'_>> {
1920 Ok(self
1921 .iter_kv_with_pk_range::<()>(pk_range, vnode, prefetch_options)
1922 .await?
1923 .map_ok(|(_, row)| {
1924 if IS_REPLICATED {
1925 row.project(&self.output_indices).into_owned_row()
1926 } else {
1927 row
1928 }
1929 }))
1930 }
1931
1932 pub async fn iter_keyed_row_with_vnode(
1933 &self,
1934 vnode: VirtualNode,
1935 pk_range: &(Bound<impl Row>, Bound<impl Row>),
1936 prefetch_options: PrefetchOptions,
1937 ) -> StreamExecutorResult<impl KeyedRowStream<'_>> {
1938 Ok(self
1939 .iter_kv_with_pk_range(pk_range, vnode, prefetch_options)
1940 .await?
1941 .map_ok(|(key, row)| KeyedRow::new(TableKey(key), row)))
1942 }
1943}
1944
1945impl<LS: LocalStateStore, SD: ValueRowSerde> StateTableRowStore<LS, SD> {
1946 async fn iter_kv<K: CopyFromSlice + FromVnodeBytes>(
1951 &self,
1952 vnode: VirtualNode,
1953 (start, end): (Bound<Bytes>, Bound<Bytes>),
1954 prefix_hint: Option<Bytes>,
1955 prefetch_options: PrefetchOptions,
1956 ) -> StreamExecutorResult<impl PkRowStream<'_, K>> {
1957 if let Some(m) = &self.metrics {
1958 m.iter_count.inc();
1959 }
1960 let (pruned_start, pruned_end, should_prune_entirely) = if let Some(stats) =
1962 &self.vnode_stats
1963 && let Some(vnode_stat) = stats.get(&vnode)
1964 {
1965 match vnode_stat.pruned_key_range(&start, &end) {
1966 Some((new_start, new_end)) => {
1967 if self.enable_state_table_vnode_stats_pruning {
1968 (new_start, new_end, false)
1969 } else {
1970 (start, end, false)
1972 }
1973 }
1974 None => {
1975 if let Some(m) = &self.metrics {
1976 m.iter_vnode_pruned_count.inc();
1977 }
1978 (start.clone(), end.clone(), true)
1980 }
1981 }
1982 } else {
1983 (start, end, false)
1984 };
1985
1986 if should_prune_entirely && self.enable_state_table_vnode_stats_pruning {
1987 return Ok(futures::future::Either::Left(futures::stream::empty()));
1988 }
1989
1990 let table_id = self.table_id;
1991 let inspect_fn = move |result: &StreamExecutorResult<(K, OwnedRow)>| {
1992 if should_prune_entirely && result.is_ok() {
1994 tracing::warn!(
1995 table_id = %table_id,
1996 "vnode stats pruning dry run fails for iter. This will not affect correctness."
1997 );
1998 }
1999 };
2000
2001 if let Some(rows) = &self.all_rows {
2002 return Ok(futures::future::Either::Right(
2003 futures::future::Either::Left(
2004 futures::stream::iter(
2005 rows.get(&vnode)
2006 .expect("covered vnode")
2007 .range((pruned_start, pruned_end))
2008 .map(move |(key, value)| {
2009 Ok((K::from_vnode_bytes(vnode, key), value.clone()))
2010 }),
2011 )
2012 .inspect(inspect_fn),
2013 ),
2014 ));
2015 }
2016 let read_options = ReadOptions {
2017 prefix_hint,
2018 prefetch_options,
2019 cache_policy: CachePolicy::Fill(Hint::Normal),
2020 };
2021
2022 Ok(futures::future::Either::Right(
2023 futures::future::Either::Right(
2024 deserialize_keyed_row_stream(
2025 self.state_store
2026 .iter(
2027 prefixed_range_with_vnode((pruned_start, pruned_end), vnode),
2028 read_options,
2029 )
2030 .await?,
2031 &*self.row_serde,
2032 )
2033 .inspect(inspect_fn),
2034 ),
2035 ))
2036 }
2037
2038 async fn rev_iter_kv<K: CopyFromSlice + FromVnodeBytes>(
2039 &self,
2040 vnode: VirtualNode,
2041 (start, end): (Bound<Bytes>, Bound<Bytes>),
2042 prefix_hint: Option<Bytes>,
2043 prefetch_options: PrefetchOptions,
2044 ) -> StreamExecutorResult<impl PkRowStream<'_, K>> {
2045 if let Some(m) = &self.metrics {
2046 m.iter_count.inc();
2047 }
2048 let (pruned_start, pruned_end, should_prune_entirely) = if let Some(stats) =
2050 &self.vnode_stats
2051 && let Some(vnode_stat) = stats.get(&vnode)
2052 {
2053 match vnode_stat.pruned_key_range(&start, &end) {
2054 Some((new_start, new_end)) => {
2055 if self.enable_state_table_vnode_stats_pruning {
2056 (new_start, new_end, false)
2057 } else {
2058 (start, end, false)
2060 }
2061 }
2062 None => {
2063 if let Some(m) = &self.metrics {
2064 m.iter_vnode_pruned_count.inc();
2065 }
2066 (start, end, true)
2068 }
2069 }
2070 } else {
2071 (start, end, false)
2072 };
2073
2074 if should_prune_entirely && self.enable_state_table_vnode_stats_pruning {
2075 return Ok(futures::future::Either::Left(futures::stream::empty()));
2076 }
2077
2078 let table_id = self.table_id;
2079 let inspect_fn = move |result: &StreamExecutorResult<(K, OwnedRow)>| {
2080 if should_prune_entirely && result.is_ok() {
2082 tracing::warn!(
2083 table_id = %table_id,
2084 "vnode stats pruning dry run fails for rev_iter. This will not affect correctness."
2085 );
2086 }
2087 };
2088
2089 if let Some(rows) = &self.all_rows {
2090 return Ok(futures::future::Either::Right(
2091 futures::future::Either::Left(
2092 futures::stream::iter(
2093 rows.get(&vnode)
2094 .expect("covered vnode")
2095 .range((pruned_start, pruned_end))
2096 .rev()
2097 .map(move |(key, value)| {
2098 Ok((K::from_vnode_bytes(vnode, key), value.clone()))
2099 }),
2100 )
2101 .inspect(inspect_fn),
2102 ),
2103 ));
2104 }
2105 let read_options = ReadOptions {
2106 prefix_hint,
2107 prefetch_options,
2108 cache_policy: CachePolicy::Fill(Hint::Normal),
2109 };
2110
2111 Ok(futures::future::Either::Right(
2112 futures::future::Either::Right(
2113 deserialize_keyed_row_stream(
2114 self.state_store
2115 .rev_iter(
2116 prefixed_range_with_vnode((pruned_start, pruned_end), vnode),
2117 read_options,
2118 )
2119 .await?,
2120 &*self.row_serde,
2121 )
2122 .inspect(inspect_fn),
2123 ),
2124 ))
2125 }
2126}
2127
2128impl<S, SD, const IS_REPLICATED: bool> StateTableInner<S, SD, IS_REPLICATED>
2129where
2130 S: StateStore,
2131 SD: ValueRowSerde,
2132{
2133 pub async fn iter_with_prefix(
2137 &self,
2138 pk_prefix: impl Row,
2139 sub_range: &(Bound<impl Row>, Bound<impl Row>),
2140 prefetch_options: PrefetchOptions,
2141 ) -> StreamExecutorResult<impl RowStream<'_>> {
2142 let stream = self.iter_with_prefix_inner::<false, ()>(pk_prefix, sub_range, prefetch_options)
2143 .await?;
2144 Ok(stream.map_ok(|(_, row)| {
2145 if IS_REPLICATED {
2146 row.project(&self.output_indices).into_owned_row()
2147 } else {
2148 row
2149 }
2150 }))
2151 }
2152
2153 pub async fn iter_with_prefix_respecting_watermark(
2159 &self,
2160 pk_prefix: impl Row,
2161 sub_range: &(Bound<impl Row>, Bound<impl Row>),
2162 prefetch_options: PrefetchOptions,
2163 ) -> StreamExecutorResult<BoxedRowStream<'_>> {
2164 let vnode = self.compute_prefix_vnode(&pk_prefix);
2165 let Some(clean_watermark_index) = self.clean_watermark_index else {
2166 return self
2167 .iter_with_prefix(pk_prefix, sub_range, prefetch_options)
2168 .await
2169 .map(|s| s.boxed());
2170 };
2171 let Some((watermark_serde, watermark_type)) = &self.watermark_serde else {
2172 return Err(StreamExecutorError::from(anyhow!(
2173 "Missing watermark serde"
2174 )));
2175 };
2176 if matches!(watermark_type, WatermarkSerdeType::PkPrefix) {
2178 return self
2179 .iter_with_prefix(pk_prefix, sub_range, prefetch_options)
2180 .await
2181 .map(|s| s.boxed());
2182 }
2183
2184 let watermark_bytes = self.row_store.state_store.get_table_watermark(vnode);
2185 let Some(watermark_bytes) = watermark_bytes else {
2186 return self
2187 .iter_with_prefix(pk_prefix, sub_range, prefetch_options)
2188 .await
2189 .map(|s| s.boxed());
2190 };
2191 let watermark_row = watermark_serde.deserialize(&watermark_bytes)?;
2192 if watermark_row.len() != 1 {
2193 return Err(StreamExecutorError::from(format!(
2194 "Watermark row should have exactly 1 column, got {}",
2195 watermark_row.len()
2196 )));
2197 }
2198 let watermark_value = watermark_row[0].clone();
2199 if watermark_value.is_none() {
2201 return Err(StreamExecutorError::from(anyhow!(
2202 "Watermark cannot be NULL"
2203 )));
2204 }
2205 let order_type = watermark_serde.get_order_types().get(0).ok_or_else(|| {
2206 StreamExecutorError::from(anyhow!(
2207 "Watermark serde should have at least one order type"
2208 ))
2209 })?;
2210
2211 let direction = if order_type.is_ascending() {
2212 WatermarkDirection::Ascending
2213 } else {
2214 WatermarkDirection::Descending
2215 };
2216 let clean_watermark_index_in_pk = self
2217 .pk_indices
2218 .iter()
2219 .position(|&i| i == clean_watermark_index);
2220 let clean_watermark_index_in_value = match &self.value_indices {
2221 Some(value_indices) => value_indices
2222 .iter()
2223 .position(|idx| *idx == clean_watermark_index)
2224 .ok_or_else(|| {
2225 StreamExecutorError::from(anyhow!(
2226 "clean watermark column index {} is not included in table value indices {:?}",
2227 clean_watermark_index,
2228 value_indices
2229 ))
2230 })?,
2231 None => clean_watermark_index,
2232 };
2233
2234 let stream = self
2235 .iter_with_prefix_inner::<false, Bytes>(pk_prefix, sub_range, prefetch_options)
2236 .await?
2237 .try_filter_map(move |(pk, row)| {
2238 let should_filter = match watermark_type {
2239 WatermarkSerdeType::PkPrefix => unreachable!(),
2240 WatermarkSerdeType::NonPkPrefix => {
2241 let table_key = TableKey(pk);
2242 let (vnode, key) = table_key.split_vnode();
2243 let pk_cols = self.pk_serde
2244 .deserialize(key)
2245 .unwrap_or_else(|e| {
2246 panic!("Failed to deserialize table {} vnode {:?} key {:?} error: {:?}", self.table_id(), vnode, key, e.as_report());
2247 });
2248 direction.datum_filter_by_watermark(
2249 pk_cols.datum_at(clean_watermark_index_in_pk.unwrap()),
2250 &watermark_value,
2251 *order_type,
2252 )
2253 },
2254 WatermarkSerdeType::Value => {
2255 direction.datum_filter_by_watermark(
2256 row.datum_at(clean_watermark_index_in_value),
2257 &watermark_value,
2258 *order_type,
2259 )
2260 }
2261 };
2262 if should_filter {
2263 ready(Ok(None))
2264 } else {
2265 ready(Ok(Some(row)))
2266 }
2267 });
2268 Ok(stream.boxed())
2269 }
2270
2271 pub async fn get_from_one_row_table(&self) -> StreamExecutorResult<Option<OwnedRow>> {
2273 let sub_range: &(Bound<OwnedRow>, Bound<OwnedRow>) = &(Unbounded, Unbounded);
2274 let stream = self
2275 .iter_with_prefix(row::empty(), sub_range, Default::default())
2276 .await?;
2277 pin_mut!(stream);
2278
2279 if let Some(res) = stream.next().await {
2280 let value = res?.into_owned_row();
2281 assert!(stream.next().await.is_none());
2282 Ok(Some(value))
2283 } else {
2284 Ok(None)
2285 }
2286 }
2287
2288 pub async fn get_from_one_value_table(&self) -> StreamExecutorResult<Option<ScalarImpl>> {
2293 Ok(self
2294 .get_from_one_row_table()
2295 .await?
2296 .and_then(|row| row[0].clone()))
2297 }
2298
2299 pub async fn iter_keyed_row_with_prefix(
2300 &self,
2301 pk_prefix: impl Row,
2302 sub_range: &(Bound<impl Row>, Bound<impl Row>),
2303 prefetch_options: PrefetchOptions,
2304 ) -> StreamExecutorResult<impl KeyedRowStream<'_>> {
2305 Ok(
2306 self.iter_with_prefix_inner::<false, Bytes>(pk_prefix, sub_range, prefetch_options)
2307 .await?.map_ok(|(key, row)| KeyedRow::new(TableKey(key), row)),
2308 )
2309 }
2310
2311 pub async fn rev_iter_keyed_row_with_prefix(
2312 &self,
2313 pk_prefix: impl Row,
2314 sub_range: &(Bound<impl Row>, Bound<impl Row>),
2315 prefetch_options: PrefetchOptions,
2316 ) -> StreamExecutorResult<impl KeyedRowStream<'_>> {
2317 Ok(
2318 self.iter_with_prefix_inner::<true, Bytes>(pk_prefix, sub_range, prefetch_options)
2319 .await?.map_ok(|(key, row)| KeyedRow::new(TableKey(key), row)),
2320 )
2321 }
2322
2323 pub async fn rev_iter_with_prefix(
2325 &self,
2326 pk_prefix: impl Row,
2327 sub_range: &(Bound<impl Row>, Bound<impl Row>),
2328 prefetch_options: PrefetchOptions,
2329 ) -> StreamExecutorResult<impl RowStream<'_>> {
2330 Ok(
2331 self.iter_with_prefix_inner::<true, ()>(pk_prefix, sub_range, prefetch_options)
2332 .await?.map_ok(|(_, row)| row),
2333 )
2334 }
2335
2336 async fn iter_with_prefix_inner<const REVERSE: bool, K: CopyFromSlice + FromVnodeBytes>(
2337 &self,
2338 pk_prefix: impl Row,
2339 sub_range: &(Bound<impl Row>, Bound<impl Row>),
2340 prefetch_options: PrefetchOptions,
2341 ) -> StreamExecutorResult<impl PkRowStream<'_, K>> {
2342 let prefix_serializer = self.pk_serde.prefix(pk_prefix.len());
2343 let encoded_prefix = serialize_pk(&pk_prefix, &prefix_serializer);
2344
2345 let vnode = self.compute_prefix_vnode(&pk_prefix);
2349
2350 let pk_prefix_indices = &self.pk_indices[..pk_prefix.len()];
2352 if self.prefix_hint_len != 0 && !IS_REPLICATED {
2353 debug_assert_eq!(self.prefix_hint_len, pk_prefix.len());
2354 }
2355 let prefix_hint = {
2356 if should_calculate_prefix_hint(self.prefix_hint_len, pk_prefix.len(), true) {
2357 let encoded_prefix_len = self
2358 .pk_serde
2359 .deserialize_prefix_len(&encoded_prefix, self.prefix_hint_len)?;
2360
2361 Some(Bytes::copy_from_slice(
2362 &encoded_prefix[..encoded_prefix_len],
2363 ))
2364 } else {
2365 None
2366 }
2367 };
2368
2369 trace!(
2370 table_id = %self.table_id(),
2371 ?prefix_hint, ?pk_prefix,
2372 ?pk_prefix_indices,
2373 iter_direction = if REVERSE { "reverse" } else { "forward" },
2374 "storage_iter_with_prefix"
2375 );
2376
2377 let memcomparable_range =
2378 prefix_and_sub_range_to_memcomparable(&self.pk_serde, sub_range, pk_prefix);
2379
2380 Ok(if REVERSE {
2381 futures::future::Either::Left(
2382 self.row_store
2383 .rev_iter_kv(vnode, memcomparable_range, prefix_hint, prefetch_options)
2384 .await?,
2385 )
2386 } else {
2387 futures::future::Either::Right(
2388 self.row_store
2389 .iter_kv(vnode, memcomparable_range, prefix_hint, prefetch_options)
2390 .await?,
2391 )
2392 })
2393 }
2394
2395 async fn iter_kv_with_pk_range<'a, K: CopyFromSlice + FromVnodeBytes>(
2398 &'a self,
2399 pk_range: &(Bound<impl Row>, Bound<impl Row>),
2400 vnode: VirtualNode,
2404 prefetch_options: PrefetchOptions,
2405 ) -> StreamExecutorResult<impl PkRowStream<'a, K>> {
2406 let memcomparable_range = prefix_range_to_memcomparable(&self.pk_serde, pk_range);
2407
2408 self.row_store
2410 .iter_kv(vnode, memcomparable_range, None, prefetch_options)
2411 .await
2412 }
2413}
2414
2415fn deserialize_keyed_row_stream<'a, K: CopyFromSlice>(
2416 iter: impl StateStoreIter + 'a,
2417 deserializer: &'a impl ValueRowSerde,
2418) -> impl PkRowStream<'a, K> {
2419 iter.into_stream(move |(key, value)| {
2420 Ok((
2421 K::copy_from_slice(key.user_key.table_key.as_ref()),
2422 deserializer.deserialize(value).map(OwnedRow::new)?,
2423 ))
2424 })
2425 .map_err(Into::into)
2426}
2427
2428pub fn prefix_range_to_memcomparable(
2429 pk_serde: &OrderedRowSerde,
2430 range: &(Bound<impl Row>, Bound<impl Row>),
2431) -> (Bound<Bytes>, Bound<Bytes>) {
2432 (
2433 start_range_to_memcomparable(pk_serde, &range.0),
2434 end_range_to_memcomparable(pk_serde, &range.1, None),
2435 )
2436}
2437
2438fn prefix_and_sub_range_to_memcomparable(
2439 pk_serde: &OrderedRowSerde,
2440 sub_range: &(Bound<impl Row>, Bound<impl Row>),
2441 pk_prefix: impl Row,
2442) -> (Bound<Bytes>, Bound<Bytes>) {
2443 let (range_start, range_end) = sub_range;
2444 let prefix_serializer = pk_serde.prefix(pk_prefix.len());
2445 let serialized_pk_prefix = serialize_pk(&pk_prefix, &prefix_serializer);
2446 let start_range = match range_start {
2447 Included(start_range) => Bound::Included(Either::Left((&pk_prefix).chain(start_range))),
2448 Excluded(start_range) => Bound::Excluded(Either::Left((&pk_prefix).chain(start_range))),
2449 Unbounded => Bound::Included(Either::Right(&pk_prefix)),
2450 };
2451 let end_range = match range_end {
2452 Included(end_range) => Bound::Included((&pk_prefix).chain(end_range)),
2453 Excluded(end_range) => Bound::Excluded((&pk_prefix).chain(end_range)),
2454 Unbounded => Unbounded,
2455 };
2456 (
2457 start_range_to_memcomparable(pk_serde, &start_range),
2458 end_range_to_memcomparable(pk_serde, &end_range, Some(serialized_pk_prefix)),
2459 )
2460}
2461
2462fn start_range_to_memcomparable<R: Row>(
2463 pk_serde: &OrderedRowSerde,
2464 bound: &Bound<R>,
2465) -> Bound<Bytes> {
2466 let serialize_pk_prefix = |pk_prefix: &R| {
2467 let prefix_serializer = pk_serde.prefix(pk_prefix.len());
2468 serialize_pk(pk_prefix, &prefix_serializer)
2469 };
2470 match bound {
2471 Unbounded => Unbounded,
2472 Included(r) => {
2473 let serialized = serialize_pk_prefix(r);
2474
2475 Included(serialized)
2476 }
2477 Excluded(r) => {
2478 let serialized = serialize_pk_prefix(r);
2479
2480 start_bound_of_excluded_prefix(&serialized)
2481 }
2482 }
2483}
2484
2485fn end_range_to_memcomparable<R: Row>(
2486 pk_serde: &OrderedRowSerde,
2487 bound: &Bound<R>,
2488 serialized_pk_prefix: Option<Bytes>,
2489) -> Bound<Bytes> {
2490 let serialize_pk_prefix = |pk_prefix: &R| {
2491 let prefix_serializer = pk_serde.prefix(pk_prefix.len());
2492 serialize_pk(pk_prefix, &prefix_serializer)
2493 };
2494 match bound {
2495 Unbounded => match serialized_pk_prefix {
2496 Some(serialized_pk_prefix) => end_bound_of_prefix(&serialized_pk_prefix),
2497 None => Unbounded,
2498 },
2499 Included(r) => {
2500 let serialized = serialize_pk_prefix(r);
2501 end_bound_of_prefix(&serialized)
2503 }
2504 Excluded(r) => {
2505 let serialized = serialize_pk_prefix(r);
2506 Excluded(serialized)
2507 }
2508 }
2509}
2510
2511fn fill_non_output_indices(
2512 i2o_mapping: &ColIndexMapping,
2513 data_types: &[DataType],
2514 chunk: StreamChunk,
2515) -> StreamChunk {
2516 let (ops, columns, vis) = chunk.into_inner();
2517 let capacity = vis.len();
2518 let mut full_columns = Vec::with_capacity(data_types.len());
2519 for (i, data_type) in data_types.iter().enumerate() {
2520 if let Some(j) = i2o_mapping.try_map(i) {
2521 full_columns.push(columns[j].clone());
2522 } else {
2523 let mut column_builder = ArrayImplBuilder::with_type(capacity, data_type.clone());
2524 column_builder.append_n_null(capacity);
2525 let column: ArrayRef = column_builder.finish().into();
2526 full_columns.push(column)
2527 }
2528 }
2529 let data_chunk = DataChunk::new(full_columns, vis);
2530 StreamChunk::from_parts(ops, data_chunk)
2531}
2532
2533#[cfg(test)]
2534mod tests {
2535 use std::fmt::Debug;
2536
2537 use expect_test::{Expect, expect};
2538
2539 use super::*;
2540
2541 fn check(actual: impl Debug, expect: Expect) {
2542 let actual = format!("{:#?}", actual);
2543 expect.assert_eq(&actual);
2544 }
2545
2546 #[test]
2547 fn test_fill_non_output_indices() {
2548 let data_types = vec![DataType::Int32, DataType::Int32, DataType::Int32];
2549 let replicated_chunk = [OwnedRow::new(vec![
2550 Some(222_i32.into()),
2551 Some(2_i32.into()),
2552 ])];
2553 let replicated_chunk = StreamChunk::from_parts(
2554 vec![Op::Insert],
2555 DataChunk::from_rows(&replicated_chunk, &[DataType::Int32, DataType::Int32]),
2556 );
2557 let i2o_mapping = ColIndexMapping::new(vec![Some(1), None, Some(0)], 2);
2558 let filled_chunk = fill_non_output_indices(&i2o_mapping, &data_types, replicated_chunk);
2559 check(
2560 filled_chunk,
2561 expect![[r#"
2562 StreamChunk { cardinality: 1, capacity: 1, data:
2563 +---+---+---+-----+
2564 | + | 2 | | 222 |
2565 +---+---+---+-----+
2566 }"#]],
2567 );
2568 }
2569
2570 #[test]
2571 fn test_fill_non_output_indices_with_invisible_rows() {
2572 let data_types = vec![DataType::Int32, DataType::Int32, DataType::Int32];
2573 let replicated_chunk = [
2574 OwnedRow::new(vec![Some(222_i32.into()), Some(2_i32.into())]),
2575 OwnedRow::new(vec![Some(333_i32.into()), Some(3_i32.into())]),
2576 ];
2577 let (columns, _) =
2578 DataChunk::from_rows(&replicated_chunk, &[DataType::Int32, DataType::Int32])
2579 .into_parts();
2580 let replicated_chunk = StreamChunk::with_visibility(
2581 vec![Op::Insert, Op::Insert],
2582 columns,
2583 Bitmap::from_iter([false, false]),
2584 );
2585 let i2o_mapping = ColIndexMapping::new(vec![Some(1), None, Some(0)], 2);
2586 let filled_chunk = fill_non_output_indices(&i2o_mapping, &data_types, replicated_chunk);
2587 check(
2588 filled_chunk,
2589 expect![[r#"
2590 StreamChunk { cardinality: 0, capacity: 2, data:
2591 (empty)
2592 }"#]],
2593 );
2594 }
2595}