Skip to content

Table: assert every written ref in a multi-branch transaction - #4223

Open
pujitha24 wants to merge 1 commit into
apache:mainfrom
pujitha24:auto/issue-4183
Open

pujitha24 wants to merge 1 commit into
apache:mainfrom
pujitha24:auto/issue-4183

Conversation

@pujitha24

Copy link
Copy Markdown

Rationale for this change

Transaction._stage deduplicated requirements by type only, so in a transaction writing two branches only the first AssertRefSnapshotId was sent. A concurrent change to the second branch was not detected and got overwritten. Requirements are now deduplicated by (type, ref) for AssertRefSnapshotId; all other types are unchanged. Duplicates within a single _stage call are also dropped now.

Are these changes tested?

Yes. Added test_stage_keeps_ref_requirement_per_ref (fails before the fix, passes after). The issue's repro script prints [1, 2, 3] before and [1, 3] after. make lint passes. In tests/table/test_init.py, 4 tests fail identically on main (missing optional modules in my env); test_partitioning.py also has failures on main.

Are there any user-facing changes?

Multi-branch transactions now assert every written branch, so a concurrent change to any of them raises a conflict and retries instead of being silently overwritten.

Fixes #4183

Motivation: Transaction._stage deduplicated requirements by type only, so
a transaction writing two branches sent AssertRefSnapshotId for the first
branch only. A concurrent change to the second branch was not detected and
was overwritten.

Approach: deduplicate AssertRefSnapshotId by (type, ref); other
requirement types keep per-type deduplication. Duplicates within a single
_stage call are also dropped.

Validation: added test_stage_keeps_ref_requirement_per_ref, which fails
without the change and passes with it (uv run pytest
tests/table/test_init.py -k stage_keeps). The reproduction script from the
issue prints [1, 2, 3] before and [1, 3] after. make lint passes. Four
other tests in tests/table/test_init.py fail identically on the base
commit in this environment (missing optional modules). The retry path
with two branches is not covered by a dedicated test.

Report: apache#4183
Signed-off-by: Pujitha Paladugu <10557236+pujitha24@users.noreply.github.com>
Assisted-by: claude-sonnet-5-5 (via Claude Code)
Copilot AI balanced review requested due to automatic review settings November 1, 2026 18:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No active review issues remain for the per-ref transaction requirement deduplication change.

No open issues 🎉

What changed in this PR

Fixes requirement deduplication in PyIceberg transactions so each written branch retains its own snapshot assertion, preventing concurrent changes to a second branch from being silently overwritten.

Changes:

  • Deduplicates ref requirements by (type, ref), while keeping type-only deduplication for other requirements.
  • Drops duplicates within a single _stage call and adds a regression test for distinct refs and repeated requirements.
File Description
tests/​table/​test_init.py Adds regression coverage for per-ref requirement deduplication.
pyiceberg/​table/​__init__.py Preserves snapshot assertions for every distinct ref during transaction staging.

Review effort: Balanced

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A transaction writing two branches overwrites concurrent changes to the second

2 participants