Skip to content

fix: reject DataReplacement racing concurrent Update/Delete/Merge#7373

Open
wkalt wants to merge 1 commit into
lance-format:mainfrom
wkalt:ticket/gen-633/datareplacement-stale-version-conflict
Open

fix: reject DataReplacement racing concurrent Update/Delete/Merge#7373
wkalt wants to merge 1 commit into
lance-format:mainfrom
wkalt:ticket/gen-633/datareplacement-stale-version-conflict

Conversation

@wkalt

@wkalt wkalt commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

A DataReplacement rewrites a column's data file positionally against the fragments it targets. The conflict resolver returned Ok unconditionally for a concurrent Update, Delete, or Merge, so a DataReplacement committed at a read version those operations had superseded was applied silently -- dropping or misaligning the rows the concurrent op moved or deleted, with no error raised. Merge was additionally asymmetric: check_merge_txn already treats a concurrent DataReplacement as a conflict, but not the reverse.

For Update/Delete, conflict when the other transaction's updated/removed fragment ids overlap our replacement fragment ids (mirrors the existing Rewrite handling). For Merge, which rewrites the entire fragment list, conflict unconditionally (mirrors check_merge_txn). All are retryable, so the committer rebuilds against the new layout.

Adds DataReplacement vs Update, Delete, and Merge cases (same and different fragment) to test_conflicts_data_replacement.

@github-actions github-actions Bot added the bug Something isn't working label Jun 19, 2026
A DataReplacement rewrites a column's data file positionally against the
fragments it targets. The conflict resolver returned Ok unconditionally for a
concurrent Update, Delete, or Merge, so a DataReplacement committed at a read
version those operations had superseded was applied silently -- dropping or
misaligning the rows the concurrent op moved or deleted, with no error raised.
Merge was additionally asymmetric: check_merge_txn already treats a concurrent
DataReplacement as a conflict, but not the reverse.

For Update/Delete, conflict when the other transaction's updated/removed fragment
ids overlap our replacement fragment ids (mirrors the existing Rewrite handling).
For Merge, which rewrites the entire fragment list, conflict unconditionally
(mirrors check_merge_txn). All are retryable, so the committer rebuilds against
the new layout.

Adds DataReplacement vs Update, Delete, and Merge cases (same and different
fragment) to test_conflicts_data_replacement, and updates
test_datafile_replacement_error to read at the current version (its pre-Merge
read version now correctly conflicts with the Merge).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@wkalt wkalt force-pushed the ticket/gen-633/datareplacement-stale-version-conflict branch from 0d4a340 to b33113c Compare June 19, 2026 14:56
@codecov

codecov Bot commented Jun 19, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant