dancsi opened a new issue, #4022:
URL: https://github.com/apache/iceberg-python/issues/4022
**Apache Iceberg version:** 0.12.0 (also reproduced on `main` at ebbc0ba3e4)
### Please describe the bug 🐞
After a failed attempt, `Transaction.commit_transaction` checks whether the
attempt actually landed:
```python
if all(
self._table.metadata.snapshot_by_id(producer._snapshot_id) is not None
for producer in self._snapshot_producers
):
```
A transaction can contain a producer that never creates a snapshot.
`Table.overwrite` on an empty table (or any `delete` that matches nothing,
followed by an append) registers a delete producer, but only the append
produces an `AddSnapshotUpdate`. The delete producer's `_snapshot_id` never
appears in the table, so the check is always false, even when the append landed.
pyiceberg then rebuilds and retries. On the rebuilt attempt, the delete
producer's concurrency validation sees the transaction's *own* landed append as
a concurrent conflicting write, and raises `ValidationException`. That goes to
`_clean_all_uncommitted()`, which deletes the manifest list and manifests of
the snapshot that landed.
### Reproduction
```python
import tempfile
import pyarrow as pa
from pyiceberg.catalog.sql import SqlCatalog
from pyiceberg.exceptions import CommitFailedException
from pyiceberg.schema import Schema
from pyiceberg.types import LongType, NestedField
warehouse = tempfile.mkdtemp()
catalog = SqlCatalog("default", uri=f"sqlite:///{warehouse}/catalog.db",
warehouse=f"file://{warehouse}")
catalog.create_namespace("default")
table = catalog.create_table(
"default.t",
Schema(NestedField(1, "a", LongType(), required=False)),
properties={"commit.retry.min-wait-ms": "0"},
)
# The catalog applies the first commit, but the client sees a failure.
commit_table = catalog.commit_table
calls = 0
def commit_table_lose_first_response(*args):
global calls
calls += 1
response = commit_table(*args)
if calls == 1:
raise CommitFailedException("simulated lost response")
return response
catalog.commit_table = commit_table_lose_first_response
try:
table.overwrite(pa.table({"a": pa.array([1, 2, 3], pa.int64())}))
except Exception as e:
print(f"overwrite raised: {type(e).__name__}: {e}")
table = catalog.load_table("default.t")
snapshot = table.current_snapshot()
print("manifest list exists:",
table.io.new_input(snapshot.manifest_list).exists())
table.scan().to_arrow()
```
Output:
```
Commit failed due to a concurrent update, retrying (1/4) in 0 ms
overwrite raised: ValidationException: Added data files were found matching
the filter for snapshots set()!
manifest list exists: False
FileNotFoundError: [Errno 2] Failed to open local file
'.../metadata/snap-...avro'
```
The same overwrite with a response that isn't lost succeeds, and a plain
`append` with a lost first response is correctly detected as landed.
### Suggested fix
Base the check on the snapshots the attempt actually tried to add, i.e. the
`AddSnapshotUpdate`s in `self._updates`, rather than on every producer.
Equivalently, skip producers that didn't produce a snapshot. Ideally, a
`ValidationException` raised during a rebuild should also never clean up a
snapshot that is present in the refreshed metadata.
Related: #4021, which covers the missing check on the last attempt.
### Willingness to contribute
- [x] I would be willing to contribute a fix for this bug with guidance from
the Iceberg community
I have a fix with regression tests for both this and #4021: it keys the
landed check on the `AddSnapshotUpdate` snapshot ids that were sent, and runs
it after every `CommitFailedException`, including on the last attempt. I'm
happy to open a PR.
--
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]