This is an automated email from the ASF dual-hosted git repository.

JingsongLi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/paimon.git


The following commit(s) were added to refs/heads/master by this push:
     new 00dca14161 [python] Invalidate commit retry cache after overwrite 
(#9688)
00dca14161 is described below

commit 00dca141616470c67f08a4a52bf20bd9f589717a
Author: XiaoHongbo <[email protected]>
AuthorDate: Tue Sep 8 16:56:57 2026 +0800

    [python] Invalidate commit retry cache after overwrite (#9688)
---
 .../tests/overwrite_commit_conflict_test.py        | 32 ++++++++++++++++++----
 .../pypaimon/write/commit/commit_scanner.py        |  6 ++--
 2 files changed, 31 insertions(+), 7 deletions(-)

diff --git a/paimon-python/pypaimon/tests/overwrite_commit_conflict_test.py 
b/paimon-python/pypaimon/tests/overwrite_commit_conflict_test.py
index da20c300bc..919d4830a3 100644
--- a/paimon-python/pypaimon/tests/overwrite_commit_conflict_test.py
+++ b/paimon-python/pypaimon/tests/overwrite_commit_conflict_test.py
@@ -276,15 +276,17 @@ class OverwriteCommitConflictTest(unittest.TestCase):
         self.assertEqual([], incr_results)
         self.assertEqual(full_scans['n'], 1)
 
-    def test_incremental_merge_across_non_append_snapshot(self):
-        self._assert_merge_equals_full_scan(self._overwrite_target)
+    def test_full_scan_across_empty_delta_overwrite_snapshot(self):
+        self._assert_merge_equals_full_scan(
+            self._overwrite_target, hide_overwrite_delta=True)
 
     def test_incremental_merge_across_compact_snapshot(self):
         self._assert_merge_equals_full_scan(self._compact_target)
 
-    def _assert_merge_equals_full_scan(self, concurrent_fn):
-        # A non-APPEND snapshot (OVERWRITE/COMPACT, delta = ADD+DELETE) lands
-        # between retries; the merged base must still equal a fresh full scan.
+    def _assert_merge_equals_full_scan(self, concurrent_fn,
+                                       hide_overwrite_delta=False):
+        # A non-APPEND snapshot lands between retries; the conflict base must
+        # still equal a fresh full scan.
         K = 2
 
         wb = self.table.new_batch_write_builder().overwrite({'f0': 1})
@@ -298,6 +300,18 @@ class OverwriteCommitConflictTest(unittest.TestCase):
         orig_check = fsc.conflict_detection.check_conflicts
         orig_full = fsc.commit_scanner.read_all_entries_from_changed_partitions
 
+        if hide_overwrite_delta:
+            orig_read_delta = 
fsc.commit_scanner.manifest_list_manager.read_delta
+
+            def read_delta(snapshot):
+                # Row-id reassignment replaces the base manifests in an
+                # OVERWRITE snapshot while deliberately writing an empty delta.
+                if snapshot.commit_kind == "OVERWRITE":
+                    return []
+                return orig_read_delta(snapshot)
+
+            fsc.commit_scanner.manifest_list_manager.read_delta = read_delta
+
         def spy_check(latest_snapshot, base_entries, delta_entries, *a, **k):
             captured.append((latest_snapshot, list(base_entries), 
list(delta_entries)))
             return orig_check(latest_snapshot, base_entries, delta_entries, 
*a, **k)
@@ -316,6 +330,14 @@ class OverwriteCommitConflictTest(unittest.TestCase):
 
         fsc.snapshot_commit.commit = patched_cas
 
+        if hide_overwrite_delta:
+            with self.assertRaisesRegex(
+                    RuntimeError, "File deletion conflicts detected"):
+                c.commit(messages)
+            c.close()
+            self.assertEqual(cas['fails'], 1)
+            return
+
         c.commit(messages)
         c.close()
 
diff --git a/paimon-python/pypaimon/write/commit/commit_scanner.py 
b/paimon-python/pypaimon/write/commit/commit_scanner.py
index 4612054e6c..835df4bf61 100644
--- a/paimon-python/pypaimon/write/commit/commit_scanner.py
+++ b/paimon-python/pypaimon/write/commit/commit_scanner.py
@@ -134,8 +134,8 @@ class CommitScanner:
                                  index_entries=None) -> 
Optional[List[ManifestEntry]]:
         """Delta entries (incl. DELETEs) in ``(from_snapshot, to_snapshot]``,
         changed-partition filtered, so a retry can reuse the prior base and 
read
-        only the changes since. Returns None on a missing snapshot (caller then
-        full-scans). Mirrors Java ``CommitScanner#readIncrementalChanges``.
+        only the changes since. Returns None on a missing or OVERWRITE snapshot
+        (caller then full-scans). Mirrors Java conflict detection behavior.
         """
         snapshot_manager = self.table.snapshot_manager()
         partition_filter = self._build_partition_filter_from_changes(
@@ -145,6 +145,8 @@ class CommitScanner:
             snapshot = snapshot_manager.get_snapshot_by_id(snapshot_id)
             if snapshot is None:
                 return None
+            if snapshot.commit_kind == "OVERWRITE":
+                return None
             entries.extend(
                 self.read_incremental_raw_entries_from_changed_partitions(
                     snapshot, commit_entries, partition_filter))

Reply via email to