avison9 opened a new pull request, #4315:
URL: https://github.com/apache/iceberg-python/pull/4315

   Closes #4183
   
   # Rationale for this change
   
   A transaction that writes two refs only guarded the first one against 
concurrent changes.
   `Transaction._stage` de-duplicated requirements by type alone, so after the 
first write staged
   `AssertRefSnapshotId(ref="b")`, the second write's 
`AssertRefSnapshotId(ref="main")` was dropped and
   the commit reached the catalog without an assertion on `main`.
   
   The type-only de-duplication was correct when it was added (#569), because a 
transaction could only
   ever assert `main`. Writing to branches (#941) made `AssertRefSnapshotId` 
per-ref, but the
   de-duplication was never updated.
   
   This changes the key to `(type, ref)` for `AssertRefSnapshotId`. Each ref 
keeps its first (base)
   assertion, matching Java's `UpdateRequirements`. Other requirement types are 
unchanged. Retries go
   through `_stage` too, so they now keep every ref's assertion as well.
   
   ```python
   cat.load_table("ns.t").manage_snapshots().rollback_to_snapshot(s1).commit()  
 # another writer
   with t.transaction() as tx:
       tx.append(row(3), branch="b")
       tx.append(row(3))
   
   cat.load_table("ns.t").scan()   # before: [1, 2, 3]  rollback silently undone
                                   # after:  [1, 3]     conflict detected, 
commit retried
   ```
   
   Measured on a transaction that writes branch `b` and then `main`:
   
   | Concurrent change to `main` | Format | Before | After |
   |---|---|---|---|
   | rollback | v1 / v2 | rollback undone | retried, `[1, 3]` |
   | append | v1 | appended row lost | retried, `[1, 2, 3, 4]` |
   | append | v2 | non-retryable `ValueError` (sequence number) | retried, `[1, 
2, 3, 4]` |
   
   ## Are these changes tested?
   
   Yes. Two tests were added to `tests/table/test_commit_retry.py`, and each 
runs against every catalog
   fixture:
   
   - 
`test_transaction_writing_two_branches_detects_concurrent_change_to_either` 
covers the issue's
     scenario on format v1 and v2, with both a concurrent rollback and a 
concurrent append.
   - `test_transaction_stages_one_ref_assertion_per_ref` checks that writing 
`b` and then `main` twice
     stages exactly one assertion per ref, each holding the base snapshot id.
   
   Both fail when the `_stage` change is reverted. Unit suite: 4524 → 4530 
passed, no new failures.
   `make lint` is clean. `make test-integration` passes (1362 passed, 0 failed).
   
   ## Are there any user-facing changes?
   
   Yes, as a bug fix. Multi-ref transactions now detect concurrent changes to 
every ref they write, and
   retry or fail with `CommitFailedException` instead of overwriting them. 
There is no API change.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to