Skip to content

Commit e81907d

Browse files
committed
Fixed bug: concurrent same name branch and tag writes
1 parent ee591b4 commit e81907d

File tree

4 files changed

+28
-8
lines changed

4 files changed

+28
-8
lines changed

pyiceberg/table/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ def set_ref_snapshot(
349349
),
350350
)
351351

352-
requirements = (AssertRefSnapshotId(snapshot_id=parent_snapshot_id, ref=ref_name),)
352+
requirements = (AssertRefSnapshotId(snapshot_id=parent_snapshot_id, ref=ref_name, ref_type=type),)
353353
return self._apply(updates, requirements)
354354

355355
def _set_ref_snapshot(
@@ -380,6 +380,7 @@ def _set_ref_snapshot(
380380
AssertRefSnapshotId(
381381
snapshot_id=self.table_metadata.refs[ref_name].snapshot_id if ref_name in self.table_metadata.refs else None,
382382
ref=ref_name,
383+
ref_type=type,
383384
),
384385
)
385386

pyiceberg/table/update/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,7 @@ class AssertRefSnapshotId(ValidatableTableRequirement):
592592

593593
type: Literal["assert-ref-snapshot-id"] = Field(default="assert-ref-snapshot-id")
594594
ref: str = Field(...)
595+
ref_type: SnapshotRefType = Field(...)
595596
snapshot_id: Optional[int] = Field(default=None, alias="snapshot-id")
596597

597598
def validate(self, base_metadata: Optional[TableMetadata]) -> None:
@@ -607,6 +608,8 @@ def validate(self, base_metadata: Optional[TableMetadata]) -> None:
607608
raise CommitFailedException(
608609
f"Requirement failed: {ref_type} {self.ref} has changed: expected id {self.snapshot_id}, found {snapshot_ref.snapshot_id}"
609610
)
611+
elif ref_type != self.ref_type:
612+
raise CommitFailedException(f"Requirement failed: {ref_type} {self.ref} can't be changed to type {self.ref_type}")
610613
elif self.snapshot_id is not None:
611614
raise CommitFailedException(f"Requirement failed: branch or tag {self.ref} is missing, expected {self.snapshot_id}")
612615

pyiceberg/table/update/snapshot.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@ def _commit(self) -> UpdatesAndRequirements:
287287
if self._branch in self._transaction.table_metadata.refs
288288
else self._transaction.table_metadata.current_snapshot_id,
289289
ref=self._branch,
290+
ref_type=SnapshotRefType.BRANCH,
290291
),
291292
),
292293
)

tests/table/test_init.py

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
_match_deletes_to_data_file,
5050
)
5151
from pyiceberg.table.metadata import INITIAL_SEQUENCE_NUMBER, TableMetadataUtil, TableMetadataV2, _generate_snapshot_id
52-
from pyiceberg.table.refs import SnapshotRef
52+
from pyiceberg.table.refs import SnapshotRef, SnapshotRefType
5353
from pyiceberg.table.snapshots import (
5454
MetadataLogEntry,
5555
Operation,
@@ -982,28 +982,43 @@ def test_assert_table_uuid(table_v2: Table) -> None:
982982

983983
def test_assert_ref_snapshot_id(table_v2: Table) -> None:
984984
base_metadata = table_v2.metadata
985-
AssertRefSnapshotId(ref="main", snapshot_id=base_metadata.current_snapshot_id).validate(base_metadata)
985+
AssertRefSnapshotId(ref="main", snapshot_id=base_metadata.current_snapshot_id, ref_type=SnapshotRefType.BRANCH).validate(
986+
base_metadata
987+
)
986988

987989
with pytest.raises(CommitFailedException, match="Requirement failed: current table metadata is missing"):
988-
AssertRefSnapshotId(ref="main", snapshot_id=1).validate(None)
990+
AssertRefSnapshotId(ref="main", snapshot_id=1, ref_type=SnapshotRefType.BRANCH).validate(None)
989991

990992
with pytest.raises(
991993
CommitFailedException,
992994
match="Requirement failed: branch main was created concurrently",
993995
):
994-
AssertRefSnapshotId(ref="main", snapshot_id=None).validate(base_metadata)
996+
AssertRefSnapshotId(ref="main", snapshot_id=None, ref_type=SnapshotRefType.BRANCH).validate(base_metadata)
995997

996998
with pytest.raises(
997999
CommitFailedException,
9981000
match="Requirement failed: branch main has changed: expected id 1, found 3055729675574597004",
9991001
):
1000-
AssertRefSnapshotId(ref="main", snapshot_id=1).validate(base_metadata)
1002+
AssertRefSnapshotId(ref="main", snapshot_id=1, ref_type=SnapshotRefType.BRANCH).validate(base_metadata)
1003+
1004+
with pytest.raises(
1005+
CommitFailedException,
1006+
match="Requirement failed: branch or tag not_exist_branch is missing, expected 1",
1007+
):
1008+
AssertRefSnapshotId(ref="not_exist_branch", snapshot_id=1, ref_type=SnapshotRefType.BRANCH).validate(base_metadata)
1009+
1010+
with pytest.raises(
1011+
CommitFailedException,
1012+
match="Requirement failed: branch or tag not_exist_tag is missing, expected 1",
1013+
):
1014+
AssertRefSnapshotId(ref="not_exist_tag", snapshot_id=1, ref_type=SnapshotRefType.TAG).validate(base_metadata)
10011015

1016+
# existing Tag in metadata: test
10021017
with pytest.raises(
10031018
CommitFailedException,
1004-
match="Requirement failed: branch or tag not_exist is missing, expected 1",
1019+
match="Requirement failed: tag test can't be changed to type branch",
10051020
):
1006-
AssertRefSnapshotId(ref="not_exist", snapshot_id=1).validate(base_metadata)
1021+
AssertRefSnapshotId(ref="test", snapshot_id=3051729675574597004, ref_type=SnapshotRefType.BRANCH).validate(base_metadata)
10071022

10081023

10091024
def test_assert_last_assigned_field_id(table_v2: Table) -> None:

0 commit comments

Comments
 (0)