Fokko commented on code in PR #3649:
URL: https://github.com/apache/iceberg-python/pull/3649#discussion_r3959382278
##########
mkdocs/docs/api.md:
##########
@@ -1483,6 +1483,110 @@ Remove an existing branch:
table.manage_snapshots().remove_branch("dev").commit()
```
+#### Fast-forwarding a branch
+
+Fast-forward the `main` branch to the `audit-branch` branch:
+
+```python
+with table.manage_snapshots() as ms:
+ ms.fast_forward_branch(from_branch="main", to_ref="audit-branch")
+```
+
+Fast-forward `from_branch` to point at the snapshot referenced by `to_ref`.
+`to_ref` may be a branch or tag. `from_branch` must be a branch.
+
+<!-- markdownlint-disable MD046 -- Allowing indented multi-line formatting in
admonition-->
+
+!!! info "Fast Forward Behavior"
+
+ * Case 1: If `from_branch` does not yet exist it is created and pointing
at `to_ref`'s
+ snapshot. The default retention properties are applied on the
auto-created snapshot.
+ * Case 2:** If both already point at the same snapshot the call is a no-op.
+ * Case 3: Otherwise `from_branch`'s current snapshot must be an ancestor
of `to_ref`'s snapshot;
+ if not, `NotAncestorError` is raised.
+
+<!-- markdownlint-enable MD046 -->
+
+#### Example Use-Case: write-audit-publish (WAP)
+
+The use of branching & fast-forwarding enable the usage of the
write-audit-publish (WAP) process:
+
+1. Writes proceed on a side branch
+2. Audit Validation runs against that branch
+3. Publish the new data by fast-forwarding the main branch
+
+```mermaid
+---
+title: Conceptually Illustration of the WAP Process
Review Comment:
Nice!
<img width="2056" height="1283" alt="Image"
src="https://github.com/user-attachments/assets/7ccb870d-d97d-4c31-bad4-04cfb6312923"
/>
##########
pyiceberg/table/update/snapshot.py:
##########
@@ -1232,6 +1267,61 @@ def _current_ancestors(self) -> set[int]:
)
}
+ def fast_forward_branch(self, from_branch: str, to_ref: str) ->
ManageSnapshots:
+ """Fast-forward ``from_branch`` to the snapshot referenced by
``to_ref``.
+
+ * If ``from_branch`` does not exist, it is created pointing at
``to_ref``'s snapshot (Java/Spark parity).
+ * If both refs already point to the same snapshot the call is a no-op.
+ * Otherwise ``from_branch`` must be a branch (not a tag) and its
current snapshot
+ must be an ancestor of ``to_ref``'s snapshot.
+
+ Within a single ``manage_snapshots()`` chain, ref lookups observe
earlier staged
+ operations via :meth:`_effective_refs`. This means that
`create_branch(...)` followed
+ by `fast_forward_branch(...)` on the same ref works as expected.
+
+ Args:
+ from_branch: name of the branch to advance.
+ to_ref: name of the branch or tag whose snapshot ``from_branch``
will point to.
+
+ Returns:
+ This for method chaining.
+
+ Raises:
+ NoSuchSnapshotRefError: ``to_ref`` does not exist.
+ SnapshotRefTypeError: ``from_branch`` exists but is a tag.
+ NotAncestorError: ``from_branch``'s snapshot is not an ancestor of
``to_ref``'s snapshot.
+ """
+ refs = self._effective_refs()
+
+ if to_ref not in refs:
+ raise NoSuchSnapshotRefError(f"Ref does not exist: {to_ref}")
+ to_snapshot_id = refs[to_ref].snapshot_id
Review Comment:
nit, if you want to do a single lookup:
```suggestion
if (to_snapshot_id := refs.get(to_ref)) is None:
raise NoSuchSnapshotRefError(f"Ref does not exist: {to_ref}")
```
Another example below
##########
pyiceberg/exceptions.py:
##########
@@ -146,3 +146,15 @@ class WaitingForLockException(Exception):
class ValidationException(Exception):
"""Raised when validation fails."""
+
+
+class NoSuchSnapshotRefError(ValueError):
+ """Raised when a named snapshot ref (branch or tag) does not exist."""
+
+
+class SnapshotRefTypeError(ValueError):
+ """Raised when an operation expects a branch and gets a tag (or vice
versa)."""
+
+
+class NotAncestorError(ValueError):
+ """Raised when an operation requires ancestry between two snapshots and it
does not hold."""
Review Comment:
At most places in the code, we default to `ValueError`, but I can see the
value of this.
--
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]