MCPcopy Create free account
hub / github.com/apache/paimon-rust / validate_row_id_alignment

Method validate_row_id_alignment

crates/paimon/src/table/table_commit.rs:714–791  ·  view source on GitHub ↗

Validate that files with pre-assigned `first_row_id` (e.g. partial-column files from MERGE INTO) still match existing files in the current snapshot. When MERGE INTO and COMPACT run concurrently, compaction may rewrite the original files that partial-column files reference. If the original file's row ID range no longer exists, the partial-column files become invalid and the commit must be rejected

(
        &self,
        commit_entries: &[ManifestEntry],
        latest_snapshot: &Option<Snapshot>,
    )

Source from the content-addressed store, hash-verified

712 /// row ID range no longer exists, the partial-column files become invalid and
713 /// the commit must be rejected.
714 async fn validate_row_id_alignment(
715 &self,
716 commit_entries: &[ManifestEntry],
717 latest_snapshot: &Option<Snapshot>,
718 ) -> Result<()> {
719 // Collect files that already have first_row_id assigned (pre-set by writer).
720 let files_to_check: Vec<_> = commit_entries
721 .iter()
722 .filter(|e| *e.kind() == FileKind::Add && e.file().first_row_id.is_some())
723 .collect();
724
725 if files_to_check.is_empty() {
726 return Ok(());
727 }
728
729 let snap = match latest_snapshot {
730 Some(s) => s,
731 None => {
732 // No existing snapshot means no existing files — any pre-assigned
733 // first_row_id cannot match anything.
734 let entry = &files_to_check[0];
735 return Err(crate::Error::DataInvalid {
736 message: format!(
737 "Row ID conflict: file '{}' has pre-assigned first_row_id={} \
738 but no snapshot exists. The referenced files may have been removed \
739 by a concurrent compaction.",
740 entry.file().file_name,
741 entry.file().first_row_id.unwrap(),
742 ),
743 source: None,
744 });
745 }
746 };
747
748 // Read current files from the latest snapshot, filtered by partitions.
749 let partition_filter = self.build_entries_partition_filter(&files_to_check)?;
750 let scan = TableScan::new(&self.table, partition_filter, vec![], None, None, None)
751 .with_scan_all_files();
752 let existing_entries = scan.plan_manifest_entries(snap).await?;
753
754 // Build index: (partition, bucket, first_row_id, row_count)
755 let existing_index: HashSet<(&[u8], i32, i64, i64)> = existing_entries
756 .iter()
757 .filter_map(|e| {
758 e.file()
759 .first_row_id
760 .map(|fid| (e.partition(), e.bucket(), fid, e.file().row_count))
761 })
762 .collect();
763
764 for entry in &files_to_check {
765 let fid = entry.file().first_row_id.unwrap();
766 let key = (
767 entry.partition(),
768 entry.bucket(),
769 fid,
770 entry.file().row_count,
771 );

Callers 1

resolve_commitMethod · 0.80

Calls 10

kindMethod · 0.80
fileMethod · 0.80
with_scan_all_filesMethod · 0.80
plan_manifest_entriesMethod · 0.80
containsMethod · 0.80
iterMethod · 0.45
is_emptyMethod · 0.45
partitionMethod · 0.45
bucketMethod · 0.45

Tested by

no test coverage detected