This is an automated email from the ASF dual-hosted git repository.

JingsongLi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/paimon.git


The following commit(s) were added to refs/heads/master by this push:
     new 5daa02a6a9 [core] Simplify catalog rollback requests (#10577)
5daa02a6a9 is described below

commit 5daa02a6a9eb027fee13304e37b22fe629c7a3ed
Author: Jingsong Lee <[email protected]>
AuthorDate: Thu Oct 15 12:46:50 2026 +0800

    [core] Simplify catalog rollback requests (#10577)
---
 docs/docs/concepts/concurrency-control.md          | 21 ++++++------
 docs/static/rest-catalog-open-api.yaml             | 28 +++++-----------
 .../main/java/org/apache/paimon/rest/RESTApi.java  | 10 ++----
 .../paimon/rest/requests/RollbackTableRequest.java | 30 ++---------------
 .../java/org/apache/paimon/AbstractFileStore.java  |  3 +-
 .../org/apache/paimon/catalog/AbstractCatalog.java |  4 +--
 .../java/org/apache/paimon/catalog/Catalog.java    |  8 ++---
 .../org/apache/paimon/catalog/DelegateCatalog.java |  7 ++--
 .../org/apache/paimon/catalog/TableRollback.java   |  3 +-
 .../paimon/operation/commit/CommitRollback.java    |  6 ++--
 .../java/org/apache/paimon/rest/RESTCatalog.java   |  7 ++--
 .../apache/paimon/table/CatalogEnvironment.java    | 15 +++------
 .../org/apache/paimon/tag/SnapshotLoaderImpl.java  |  2 +-
 .../operation/commit/CommitRollbackTest.java       | 34 ++++++++++++++++---
 .../apache/paimon/rest/CommitLockProtocolTest.java | 19 ++++++-----
 .../org/apache/paimon/rest/MockRESTMessage.java    |  9 ++---
 .../org/apache/paimon/rest/RESTCatalogTest.java    | 18 ++--------
 .../paimon/rest/RESTCommitLockIntegrationTest.java |  5 +--
 .../apache/paimon/rest/RollbackProtocolTest.java   | 25 ++++----------
 .../paimon/table/CatalogEnvironmentTest.java       | 38 +++++++---------------
 .../table/FallbackReadFileStoreTableTest.java      |  4 ---
 .../apache/paimon/tag/SnapshotLoaderImplTest.java  | 13 ++------
 22 files changed, 106 insertions(+), 203 deletions(-)

diff --git a/docs/docs/concepts/concurrency-control.md 
b/docs/docs/concepts/concurrency-control.md
index b3d641a4c4..c6fb698436 100644
--- a/docs/docs/concepts/concurrency-control.md
+++ b/docs/docs/concepts/concurrency-control.md
@@ -136,17 +136,16 @@ respect another writer's active lease. The server uses 
its own persisted table p
 decision, rather than client options. Capability changes must be serialized 
with publication and
 lease acquisition; disabling enforcement must not bypass an active lease.
 
-Automatic conflict rollback always supplies the runtime branch and writer's 
`commitUser`, together
-with the expected head's `fromSnapshot` and `fromSnapshotUuid`. Snapshot IDs 
can be reused after a
-rollback, so the server must check both fields against the current head inside 
the mutation
-transaction, before changing partitions or deleting files. Automatic rollback 
skips legacy snapshots
-without a UUID. A known table or branch UUID is supplied independently of 
writer identity.
-
-`commitUser` identifies the writer; it does not require a lease to exist. If a 
live lease exists, the
-writer and authenticated caller must match its owner. Without a live lease, 
conditional optimistic
-rollback is allowed. The server must validate admission and the expected head, 
roll back and clear
-the lease atomically. Manual rollback can omit writer identity, but cannot 
change a leased head.
-The table UUID is omitted only when the target table or branch identity is 
unknown.
+Automatic conflict rollback supplies the runtime branch and the expected 
head's `fromSnapshot`.
+A known table or branch UUID is supplied as `tableId`; it is omitted only when 
the target identity
+is unknown. Rollback does not carry writer identity or a snapshot UUID and can 
execute independently
+of commit leases, including for legacy snapshots without a UUID.
+
+The server must validate the table incarnation and expected snapshot ID 
atomically with rollback,
+before changing partitions or deleting files. For automatic conflict rollback, 
it should also check
+that the current head is still a `COMPACT` snapshot and the target is its 
predecessor, since snapshot
+IDs can be reused after rollback. A concurrent writer's publication remains 
protected by its expected
+base snapshot UUID. Manual rollback can omit `fromSnapshot`.
 
 This is a commit admission lease, not a generation or fencing token. Requests 
with the same
 commit user and authenticated caller share ownership. Use a unique commit user 
per logical writer
diff --git a/docs/static/rest-catalog-open-api.yaml 
b/docs/static/rest-catalog-open-api.yaml
index 276da1ce82..7892db6a23 100644
--- a/docs/static/rest-catalog-open-api.yaml
+++ b/docs/static/rest-catalog-open-api.yaml
@@ -3660,33 +3660,23 @@ components:
     RollbackTableRequest:
       type: object
       description: >-
-        tableId identifies the expected table incarnation independently of 
lock ownership.
-        Writer rollback supplies commitUser, fromSnapshot and fromSnapshotUuid 
regardless of
-        whether the writer acquired a lease. commitUser identifies the writer, 
not a requirement
-        for a lease to exist. A live lease requires the exact owner and 
authenticated caller;
-        without a live lease, conditional optimistic rollback is allowed. 
Snapshot IDs can be
-        reused after rollback, so both expected head fields must be checked 
against the current
-        head inside the mutation transaction before partition changes or file 
cleanup. The server
-        must validate table incarnation, admission and expected head, then 
roll back and clear
-        the lease atomically. Manual rollback may omit writer identity, but 
cannot change a
-        leased head. Omit tableId only when its UUID is unavailable.
+        tableId identifies the expected table incarnation; omit it only when 
its UUID is unavailable.
+        Automatic conflict rollback supplies fromSnapshot and targets its 
predecessor. Rollback
+        executes independently of commit leases and does not carry writer 
identity or a snapshot
+        UUID. The server must validate the table incarnation and expected 
snapshot ID atomically
+        with rollback, before partition changes or file cleanup. For automatic 
conflict rollback,
+        it should also check that the current head is still a COMPACT 
snapshot, since snapshot IDs
+        can be reused after rollback. Manual rollback may omit fromSnapshot.
       properties:
         instant:
           $ref: '#/components/schemas/Instant'
         fromSnapshot:
           type: [ integer, "null" ]
           format: int64
-          description: Expected latest snapshot ID, required for writer 
rollback.
-        fromSnapshotUuid:
-          type: [ string, "null" ]
-          minLength: 1
-          description: Expected latest snapshot UUID; requires fromSnapshot 
and is required for writer rollback.
+          description: Expected latest snapshot ID, required for automatic 
conflict rollback.
         tableId:
           type: [ string, "null" ]
-          description: Expected table or branch UUID, independently of 
commitUser.
-        commitUser:
-          type: [ string, "null" ]
-          description: Writer identity for admission against any active lease; 
requires both expected head fields.
+          description: Expected table or branch UUID.
     RollbackSchemaRequest:
       type: object
       required:
diff --git a/paimon-api/src/main/java/org/apache/paimon/rest/RESTApi.java 
b/paimon-api/src/main/java/org/apache/paimon/rest/RESTApi.java
index b50957d3d9..de8c30ab5d 100644
--- a/paimon-api/src/main/java/org/apache/paimon/rest/RESTApi.java
+++ b/paimon-api/src/main/java/org/apache/paimon/rest/RESTApi.java
@@ -767,8 +767,6 @@ public class RESTApi {
      * @param instant instant to rollback
      * @param fromSnapshot snapshot from, success only occurs when the latest 
snapshot is this
      *     snapshot.
-     * @param fromSnapshotUuid expected snapshot UUID, checked together with 
fromSnapshot
-     * @param commitUser writer identity for active-lock admission, or null 
without a writer
      * @throws NoSuchResourceException Exception thrown on HTTP 404 means the 
table or the snapshot
      *     or the tag not exists
      * @throws ForbiddenException Exception thrown on HTTP 403 means don't 
have the permission for
@@ -778,12 +776,8 @@ public class RESTApi {
             Identifier identifier,
             @Nullable String tableUuid,
             Instant instant,
-            @Nullable Long fromSnapshot,
-            @Nullable String fromSnapshotUuid,
-            @Nullable String commitUser) {
-        RollbackTableRequest request =
-                new RollbackTableRequest(
-                        instant, fromSnapshot, fromSnapshotUuid, tableUuid, 
commitUser);
+            @Nullable Long fromSnapshot) {
+        RollbackTableRequest request = new RollbackTableRequest(instant, 
fromSnapshot, tableUuid);
         client.post(
                 resourcePaths.rollbackTable(
                         identifier.getDatabaseName(), 
identifier.getObjectName()),
diff --git 
a/paimon-api/src/main/java/org/apache/paimon/rest/requests/RollbackTableRequest.java
 
b/paimon-api/src/main/java/org/apache/paimon/rest/requests/RollbackTableRequest.java
index b76747ef2a..81bfdfa81d 100644
--- 
a/paimon-api/src/main/java/org/apache/paimon/rest/requests/RollbackTableRequest.java
+++ 
b/paimon-api/src/main/java/org/apache/paimon/rest/requests/RollbackTableRequest.java
@@ -46,34 +46,20 @@ public class RollbackTableRequest implements RESTRequest {
     @Nullable
     private final Long fromSnapshot;
 
-    @JsonProperty("fromSnapshotUuid")
-    @JsonInclude(JsonInclude.Include.NON_NULL)
-    @Nullable
-    private final String fromSnapshotUuid;
-
     @JsonProperty("tableId")
     @JsonInclude(JsonInclude.Include.NON_NULL)
     @Nullable
     private final String tableId;
 
-    @JsonProperty("commitUser")
-    @JsonInclude(JsonInclude.Include.NON_NULL)
-    @Nullable
-    private final String commitUser;
-
     @JsonCreator
-    @ConstructorProperties({"instant", "fromSnapshot", "fromSnapshotUuid", 
"tableId", "commitUser"})
+    @ConstructorProperties({"instant", "fromSnapshot", "tableId"})
     public RollbackTableRequest(
             @JsonProperty(FIELD_INSTANT) Instant instant,
             @JsonProperty(FIELD_FROM_SNAPSHOT) @Nullable Long fromSnapshot,
-            @JsonProperty("fromSnapshotUuid") @Nullable String 
fromSnapshotUuid,
-            @JsonProperty("tableId") @Nullable String tableId,
-            @JsonProperty("commitUser") @Nullable String commitUser) {
+            @JsonProperty("tableId") @Nullable String tableId) {
         this.instant = instant;
         this.fromSnapshot = fromSnapshot;
-        this.fromSnapshotUuid = fromSnapshotUuid;
         this.tableId = tableId;
-        this.commitUser = commitUser;
     }
 
     @JsonGetter("tableId")
@@ -82,12 +68,6 @@ public class RollbackTableRequest implements RESTRequest {
         return tableId;
     }
 
-    @JsonGetter("commitUser")
-    @Nullable
-    public String getCommitUser() {
-        return commitUser;
-    }
-
     @JsonGetter(FIELD_INSTANT)
     public Instant getInstant() {
         return instant;
@@ -98,10 +78,4 @@ public class RollbackTableRequest implements RESTRequest {
     public Long getFromSnapshot() {
         return fromSnapshot;
     }
-
-    @JsonGetter("fromSnapshotUuid")
-    @Nullable
-    public String getFromSnapshotUuid() {
-        return fromSnapshotUuid;
-    }
 }
diff --git a/paimon-core/src/main/java/org/apache/paimon/AbstractFileStore.java 
b/paimon-core/src/main/java/org/apache/paimon/AbstractFileStore.java
index 15ae1627ad..9e554ce8e2 100644
--- a/paimon-core/src/main/java/org/apache/paimon/AbstractFileStore.java
+++ b/paimon-core/src/main/java/org/apache/paimon/AbstractFileStore.java
@@ -307,8 +307,7 @@ abstract class AbstractFileStore<T> implements FileStore<T> 
{
                                 snapshotManager,
                                 scanner);
         CommitRollback rollback = null;
-        TableRollback tableRollback =
-                catalogEnvironment.catalogTableRollback(options.branch(), 
commitUser);
+        TableRollback tableRollback = 
catalogEnvironment.catalogTableRollback(options.branch());
         if (tableRollback != null) {
             rollback = new CommitRollback(tableRollback);
         }
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/catalog/AbstractCatalog.java 
b/paimon-core/src/main/java/org/apache/paimon/catalog/AbstractCatalog.java
index 49eabacbf0..48587b1770 100644
--- a/paimon-core/src/main/java/org/apache/paimon/catalog/AbstractCatalog.java
+++ b/paimon-core/src/main/java/org/apache/paimon/catalog/AbstractCatalog.java
@@ -716,9 +716,7 @@ public abstract class AbstractCatalog implements Catalog {
             Identifier identifier,
             @Nullable String tableUuid,
             Instant instant,
-            @Nullable Long fromSnapshot,
-            @Nullable String fromSnapshotUuid,
-            @Nullable String commitUser)
+            @Nullable Long fromSnapshot)
             throws Catalog.TableNotExistException {
         throw new UnsupportedOperationException();
     }
diff --git a/paimon-core/src/main/java/org/apache/paimon/catalog/Catalog.java 
b/paimon-core/src/main/java/org/apache/paimon/catalog/Catalog.java
index beb43b59d5..f3882b5b66 100644
--- a/paimon-core/src/main/java/org/apache/paimon/catalog/Catalog.java
+++ b/paimon-core/src/main/java/org/apache/paimon/catalog/Catalog.java
@@ -715,7 +715,7 @@ public interface Catalog extends AutoCloseable {
      * <ul>
      *   <li>{@link #commitSnapshot(Identifier, String, String, Snapshot, 
List)}.
      *   <li>{@link #loadSnapshot(Identifier)}.
-     *   <li>{@link #rollbackTo(Identifier, String, Instant, Long, String, 
String)}.
+     *   <li>{@link #rollbackTo(Identifier, String, Instant, Long)}.
      *   <li>{@link #createBranch(Identifier, String, String)}.
      *   <li>{@link #dropBranch(Identifier, String)}.
      *   <li>{@link #renameBranch(Identifier, String, String)}.
@@ -847,8 +847,6 @@ public interface Catalog extends AutoCloseable {
      * @param instant like snapshotId or tagName
      * @param fromSnapshot snapshot from, success only occurs when the latest 
snapshot is this
      *     snapshot
-     * @param fromSnapshotUuid expected head UUID; distinguishes snapshots 
that reuse the same ID
-     * @param commitUser writer identity for active-lock admission, or null 
when unavailable
      * @throws Catalog.TableNotExistException if the table does not exist
      * @throws UnsupportedOperationException if the catalog does not {@link
      *     #supportsVersionManagement()}
@@ -857,9 +855,7 @@ public interface Catalog extends AutoCloseable {
             Identifier identifier,
             @Nullable String tableUuid,
             Instant instant,
-            @Nullable Long fromSnapshot,
-            @Nullable String fromSnapshotUuid,
-            @Nullable String commitUser)
+            @Nullable Long fromSnapshot)
             throws Catalog.TableNotExistException;
 
     /**
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/catalog/DelegateCatalog.java 
b/paimon-core/src/main/java/org/apache/paimon/catalog/DelegateCatalog.java
index 1aeeff926d..8b0aa817d4 100644
--- a/paimon-core/src/main/java/org/apache/paimon/catalog/DelegateCatalog.java
+++ b/paimon-core/src/main/java/org/apache/paimon/catalog/DelegateCatalog.java
@@ -253,12 +253,9 @@ public abstract class DelegateCatalog implements Catalog {
             Identifier identifier,
             @Nullable String tableUuid,
             Instant instant,
-            @Nullable Long fromSnapshot,
-            @Nullable String fromSnapshotUuid,
-            @Nullable String commitUser)
+            @Nullable Long fromSnapshot)
             throws Catalog.TableNotExistException {
-        wrapped.rollbackTo(
-                identifier, tableUuid, instant, fromSnapshot, 
fromSnapshotUuid, commitUser);
+        wrapped.rollbackTo(identifier, tableUuid, instant, fromSnapshot);
     }
 
     @Override
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/catalog/TableRollback.java 
b/paimon-core/src/main/java/org/apache/paimon/catalog/TableRollback.java
index bbe16ec3bb..5cb2a52192 100644
--- a/paimon-core/src/main/java/org/apache/paimon/catalog/TableRollback.java
+++ b/paimon-core/src/main/java/org/apache/paimon/catalog/TableRollback.java
@@ -25,6 +25,5 @@ import javax.annotation.Nullable;
 /** Rollback table to instant from snapshot. */
 public interface TableRollback {
 
-    void rollbackTo(
-            Instant instant, @Nullable Long fromSnapshot, @Nullable String 
fromSnapshotUuid);
+    void rollbackTo(Instant instant, @Nullable Long fromSnapshot);
 }
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/operation/commit/CommitRollback.java
 
b/paimon-core/src/main/java/org/apache/paimon/operation/commit/CommitRollback.java
index ead30bc8f8..683b6555a6 100644
--- 
a/paimon-core/src/main/java/org/apache/paimon/operation/commit/CommitRollback.java
+++ 
b/paimon-core/src/main/java/org/apache/paimon/operation/commit/CommitRollback.java
@@ -32,12 +32,10 @@ public class CommitRollback {
     }
 
     public boolean tryToRollback(Snapshot latestSnapshot) {
-        if (latestSnapshot.commitKind() == Snapshot.CommitKind.COMPACT
-                && latestSnapshot.uuid() != null) {
+        if (latestSnapshot.commitKind() == Snapshot.CommitKind.COMPACT) {
             long latest = latestSnapshot.id();
             try {
-                tableRollback.rollbackTo(
-                        Instant.snapshot(latest - 1), latest, 
latestSnapshot.uuid());
+                tableRollback.rollbackTo(Instant.snapshot(latest - 1), latest);
                 return true;
             } catch (Exception ignored) {
             }
diff --git a/paimon-core/src/main/java/org/apache/paimon/rest/RESTCatalog.java 
b/paimon-core/src/main/java/org/apache/paimon/rest/RESTCatalog.java
index 07e4a4ae18..57bca8a794 100644
--- a/paimon-core/src/main/java/org/apache/paimon/rest/RESTCatalog.java
+++ b/paimon-core/src/main/java/org/apache/paimon/rest/RESTCatalog.java
@@ -561,13 +561,10 @@ public class RESTCatalog implements Catalog {
             Identifier identifier,
             @Nullable String tableUuid,
             Instant instant,
-            @Nullable Long fromSnapshot,
-            @Nullable String fromSnapshotUuid,
-            @Nullable String commitUser)
+            @Nullable Long fromSnapshot)
             throws Catalog.TableNotExistException {
         try {
-            api.rollbackTo(
-                    identifier, tableUuid, instant, fromSnapshot, 
fromSnapshotUuid, commitUser);
+            api.rollbackTo(identifier, tableUuid, instant, fromSnapshot);
         } catch (NoSuchResourceException e) {
             if (StringUtils.equals(e.resourceType(), 
ErrorResponse.RESOURCE_TYPE_SNAPSHOT)) {
                 throw new IllegalArgumentException(
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/table/CatalogEnvironment.java 
b/paimon-core/src/main/java/org/apache/paimon/table/CatalogEnvironment.java
index 7cea98df00..9b575bc203 100644
--- a/paimon-core/src/main/java/org/apache/paimon/table/CatalogEnvironment.java
+++ b/paimon-core/src/main/java/org/apache/paimon/table/CatalogEnvironment.java
@@ -180,10 +180,9 @@ public class CatalogEnvironment implements Serializable {
                         lockContext, lockIdentifier, uuid, commitUser, 
tableOptions);
     }
 
-    /** Create rollback with the table incarnation and optional writer 
identity. */
+    /** Create rollback with the table incarnation and runtime branch. */
     @Nullable
-    public TableRollback catalogTableRollback(
-            @Nullable String branch, @Nullable String commitUser) {
+    public TableRollback catalogTableRollback(@Nullable String branch) {
         if (catalogLoader != null && supportsVersionManagement) {
             Catalog catalog = catalogLoader.load();
             Identifier rollbackIdentifier =
@@ -193,15 +192,9 @@ public class CatalogEnvironment implements Serializable {
                                     identifier.getDatabaseName(),
                                     identifier.getTableName(),
                                     branch);
-            return (instant, fromSnapshot, fromSnapshotUuid) -> {
+            return (instant, fromSnapshot) -> {
                 try {
-                    catalog.rollbackTo(
-                            rollbackIdentifier,
-                            uuid,
-                            instant,
-                            fromSnapshot,
-                            fromSnapshotUuid,
-                            commitUser);
+                    catalog.rollbackTo(rollbackIdentifier, uuid, instant, 
fromSnapshot);
                 } catch (Catalog.TableNotExistException e) {
                     throw new RuntimeException(e);
                 }
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/tag/SnapshotLoaderImpl.java 
b/paimon-core/src/main/java/org/apache/paimon/tag/SnapshotLoaderImpl.java
index 3aab3235ae..fae4763232 100644
--- a/paimon-core/src/main/java/org/apache/paimon/tag/SnapshotLoaderImpl.java
+++ b/paimon-core/src/main/java/org/apache/paimon/tag/SnapshotLoaderImpl.java
@@ -59,7 +59,7 @@ public class SnapshotLoaderImpl implements SnapshotLoader {
     @Override
     public void rollback(Instant instant) throws IOException {
         try (Catalog catalog = catalogLoader.load()) {
-            catalog.rollbackTo(identifier, uuid, instant, null, null, null);
+            catalog.rollbackTo(identifier, uuid, instant, null);
         } catch (RuntimeException e) {
             throw e;
         } catch (Exception e) {
diff --git 
a/paimon-core/src/test/java/org/apache/paimon/operation/commit/CommitRollbackTest.java
 
b/paimon-core/src/test/java/org/apache/paimon/operation/commit/CommitRollbackTest.java
index 6e0c4e50dc..95c56063dc 100644
--- 
a/paimon-core/src/test/java/org/apache/paimon/operation/commit/CommitRollbackTest.java
+++ 
b/paimon-core/src/test/java/org/apache/paimon/operation/commit/CommitRollbackTest.java
@@ -23,21 +23,48 @@ import org.apache.paimon.catalog.TableRollback;
 import org.apache.paimon.table.Instant;
 
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.EnumSource;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoInteractions;
 import static org.mockito.Mockito.when;
 
 class CommitRollbackTest {
 
     @Test
-    void legacyCompactionWithoutUuidCannotBeRolledBackAutomatically() {
+    void legacyCompactionWithoutUuidCanBeRolledBackAutomatically() {
         Snapshot head = mock(Snapshot.class);
         when(head.commitKind()).thenReturn(Snapshot.CommitKind.COMPACT);
+        when(head.id()).thenReturn(6L);
+        TableRollback rollback = mock(TableRollback.class);
+
+        assertThat(new CommitRollback(rollback).tryToRollback(head)).isTrue();
+        verify(rollback)
+                .rollbackTo(
+                        argThat(
+                                instant ->
+                                        instant instanceof 
Instant.SnapshotInstant
+                                                && ((Instant.SnapshotInstant) 
instant)
+                                                                
.getSnapshotId()
+                                                        == 5L),
+                        eq(6L));
+    }
+
+    @ParameterizedTest
+    @EnumSource(
+            value = Snapshot.CommitKind.class,
+            names = "COMPACT",
+            mode = EnumSource.Mode.EXCLUDE)
+    void nonCompactionCannotBeRolledBackAutomatically(Snapshot.CommitKind 
kind) {
+        Snapshot head = mock(Snapshot.class);
+        when(head.commitKind()).thenReturn(kind);
         TableRollback rollback = mock(TableRollback.class);
 
         assertThat(new CommitRollback(rollback).tryToRollback(head)).isFalse();
@@ -49,11 +76,10 @@ class CommitRollbackTest {
         Snapshot head = mock(Snapshot.class);
         when(head.commitKind()).thenReturn(Snapshot.CommitKind.COMPACT);
         when(head.id()).thenReturn(6L);
-        when(head.uuid()).thenReturn("head-uuid");
         TableRollback rollback = mock(TableRollback.class);
-        doThrow(new IllegalStateException("Head UUID changed"))
+        doThrow(new IllegalStateException("Latest snapshot changed"))
                 .when(rollback)
-                .rollbackTo(any(Instant.class), eq(6L), eq("head-uuid"));
+                .rollbackTo(any(Instant.class), eq(6L));
 
         assertThat(new CommitRollback(rollback).tryToRollback(head)).isFalse();
     }
diff --git 
a/paimon-core/src/test/java/org/apache/paimon/rest/CommitLockProtocolTest.java 
b/paimon-core/src/test/java/org/apache/paimon/rest/CommitLockProtocolTest.java
index 5c046d80f8..6e0ce6c987 100644
--- 
a/paimon-core/src/test/java/org/apache/paimon/rest/CommitLockProtocolTest.java
+++ 
b/paimon-core/src/test/java/org/apache/paimon/rest/CommitLockProtocolTest.java
@@ -114,7 +114,7 @@ class CommitLockProtocolTest {
     }
 
     @Test
-    void rollbackWithinLeaseCarriesOwnerAndLegacyPayloadStaysUnchanged() 
throws Exception {
+    void rollbackCarriesTableUuidWithoutWriterContext() throws Exception {
         try (MockWebServer server = new MockWebServer()) {
             server.start();
             Options options = new Options();
@@ -131,17 +131,18 @@ class CommitLockProtocolTest {
                     };
             Identifier identifier = new Identifier("db", "table", "dev");
             server.enqueue(json("{}"));
-            catalog.rollbackTo(
-                    identifier, "table-id", Instant.snapshot(1L), 2L, 
"head-uuid", "morax-job");
-            RecordedRequest owned = server.takeRequest(10, TimeUnit.SECONDS);
-            assertThat(owned.getPath()).endsWith("/rollback");
-            RollbackTableRequest request =
-                    RESTApi.fromJson(owned.getBody().readUtf8(), 
RollbackTableRequest.class);
+            catalog.rollbackTo(identifier, "table-id", Instant.snapshot(1L), 
2L);
+            RecordedRequest recorded = server.takeRequest(10, 
TimeUnit.SECONDS);
+            assertThat(recorded.getPath()).endsWith("/rollback");
+            String body = recorded.getBody().readUtf8();
+            RollbackTableRequest request = RESTApi.fromJson(body, 
RollbackTableRequest.class);
             assertThat(request.getTableId()).isEqualTo("table-id");
-            assertThat(request.getCommitUser()).isEqualTo("morax-job");
             assertThat(request.getFromSnapshot()).isEqualTo(2L);
+            ObjectNode payload = RESTApi.fromJson(body, ObjectNode.class);
+            assertThat(payload.has("commitUser")).isFalse();
+            assertThat(payload.has("fromSnapshotUuid")).isFalse();
             server.enqueue(json("{}"));
-            catalog.rollbackTo(identifier, null, Instant.snapshot(1L), 2L, 
null, null);
+            catalog.rollbackTo(identifier, null, Instant.snapshot(1L), 2L);
             ObjectNode legacy =
                     RESTApi.fromJson(
                             server.takeRequest(10, 
TimeUnit.SECONDS).getBody().readUtf8(),
diff --git 
a/paimon-core/src/test/java/org/apache/paimon/rest/MockRESTMessage.java 
b/paimon-core/src/test/java/org/apache/paimon/rest/MockRESTMessage.java
index caa1e5c08d..cc4994b773 100644
--- a/paimon-core/src/test/java/org/apache/paimon/rest/MockRESTMessage.java
+++ b/paimon-core/src/test/java/org/apache/paimon/rest/MockRESTMessage.java
@@ -92,11 +92,6 @@ public class MockRESTMessage {
                             current == null ? null : current.snapshot().id(),
                             request.getFromSnapshot()));
         }
-        if (request.getFromSnapshotUuid() != null
-                && (current == null
-                        || 
!request.getFromSnapshotUuid().equals(current.snapshot().uuid()))) {
-            throw new IllegalStateException("Latest snapshot UUID changed");
-        }
     }
 
     public static String databaseName() {
@@ -294,11 +289,11 @@ public class MockRESTMessage {
     }
 
     public static RollbackTableRequest rollbackTableRequestBySnapshot(long 
snapshotId) {
-        return new RollbackTableRequest(Instant.snapshot(snapshotId), null, 
null, null, null);
+        return new RollbackTableRequest(Instant.snapshot(snapshotId), null, 
null);
     }
 
     public static RollbackTableRequest rollbackTableRequestByTag(String 
tagName) {
-        return new RollbackTableRequest(Instant.tag(tagName), null, null, 
null, null);
+        return new RollbackTableRequest(Instant.tag(tagName), null, null);
     }
 
     public static AlterViewRequest alterViewRequest() {
diff --git 
a/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogTest.java 
b/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogTest.java
index 9a5e1af6ed..ad6f315261 100644
--- a/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogTest.java
+++ b/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogTest.java
@@ -2377,23 +2377,9 @@ public abstract class RESTCatalogTest extends 
CatalogTestBase {
         
assertThat(tagSnapshot).isEqualTo(restCatalog.loadSnapshot(identifier).get().snapshot());
 
         // rollback to snapshot 2 from snapshot
-        assertThatThrownBy(
-                        () ->
-                                catalog.rollbackTo(
-                                        identifier,
-                                        null,
-                                        Instant.snapshot(2L),
-                                        3L,
-                                        "stale-head-uuid",
-                                        "writer"))
-                .hasMessageContaining("Latest snapshot UUID changed");
-        assertThat(table.latestSnapshot().get().id()).isEqualTo(3);
-        assertThatThrownBy(
-                        () ->
-                                catalog.rollbackTo(
-                                        identifier, null, 
Instant.snapshot(2L), 4L, null, null))
+        assertThatThrownBy(() -> catalog.rollbackTo(identifier, null, 
Instant.snapshot(2L), 4L))
                 .hasMessageContaining("Latest snapshot 3 is not 4");
-        catalog.rollbackTo(identifier, null, Instant.snapshot(2L), 3L, null, 
null);
+        catalog.rollbackTo(identifier, null, Instant.snapshot(2L), 3L);
         assertThat(table.latestSnapshot().get().id()).isEqualTo(2);
     }
 
diff --git 
a/paimon-core/src/test/java/org/apache/paimon/rest/RESTCommitLockIntegrationTest.java
 
b/paimon-core/src/test/java/org/apache/paimon/rest/RESTCommitLockIntegrationTest.java
index e6a236283f..21a37fbf2e 100644
--- 
a/paimon-core/src/test/java/org/apache/paimon/rest/RESTCommitLockIntegrationTest.java
+++ 
b/paimon-core/src/test/java/org/apache/paimon/rest/RESTCommitLockIntegrationTest.java
@@ -262,7 +262,7 @@ class RESTCommitLockIntegrationTest {
 
     @ParameterizedTest
     @ValueSource(booleans = {false, true})
-    void compactionConflictRollsBackWithWriterContextAndReacquires(
+    void compactionConflictRollsBackWithoutWriterContextAndReacquires(
             boolean locking, @TempDir Path directory) throws Exception {
         Schema schema =
                 Schema.newBuilder()
@@ -327,7 +327,6 @@ class RESTCommitLockIntegrationTest {
                                         .isEqualTo(head.get().id());
                                 if (locking) {
                                     assertThat(owner.get()).isNotNull();
-                                    
assertThat(requestBody.getCommitUser()).isEqualTo(owner.get());
                                 }
                                 head.set(
                                         snapshots.get(
@@ -424,10 +423,8 @@ class RESTCommitLockIntegrationTest {
                 
assertThat(replacement.uuid()).isNotEqualTo(compactHead.uuid());
                 
assertThat(replacement.commitKind()).isEqualTo(Snapshot.CommitKind.OVERWRITE);
                 assertThat(rollback.get().getFromSnapshot()).isEqualTo(6L);
-                
assertThat(rollback.get().getFromSnapshotUuid()).isEqualTo(compactHead.uuid());
                 assertThat(((Instant.SnapshotInstant) 
rollback.get().getInstant()).getSnapshotId())
                         .isEqualTo(5L);
-                
assertThat(rollback.get().getCommitUser()).isEqualTo(replacement.commitUser());
                 if (locking) {
                     assertThat(events)
                             .containsSubsequence(
diff --git 
a/paimon-core/src/test/java/org/apache/paimon/rest/RollbackProtocolTest.java 
b/paimon-core/src/test/java/org/apache/paimon/rest/RollbackProtocolTest.java
index 4e710c0f1c..fd53f67bf4 100644
--- a/paimon-core/src/test/java/org/apache/paimon/rest/RollbackProtocolTest.java
+++ b/paimon-core/src/test/java/org/apache/paimon/rest/RollbackProtocolTest.java
@@ -39,15 +39,11 @@ import java.util.concurrent.TimeUnit;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
-/** Tests rollback routing and optional writer context through a delegated 
REST catalog. */
+/** Tests rollback routing and optional table UUID through a delegated REST 
catalog. */
 class RollbackProtocolTest {
     @ParameterizedTest
-    @CsvSource({
-        "owned,snapshot", "unowned,snapshot", "without-uuid,snapshot",
-        "owned,tag", "unowned,tag", "without-uuid,tag"
-    })
-    void testRollbackCarriesTableUuidIndependentlyOfWriterContext(String 
context, String kind)
-            throws Exception {
+    @CsvSource({"table-id,snapshot", ",snapshot", "table-id,tag", ",tag"})
+    void testRollbackCarriesOptionalTableUuid(String tableUuid, String kind) 
throws Exception {
         try (MockWebServer server = new MockWebServer()) {
             server.start();
             Options options = new Options();
@@ -70,9 +66,7 @@ class RollbackProtocolTest {
                                 .setResponseCode(200)
                                 .setHeader("Content-Type", "application/json")
                                 .setBody("{}"));
-                String tableUuid = "without-uuid".equals(context) ? null : 
"table-id";
-                String commitUser = "owned".equals(context) ? "Writer-1" : 
null;
-                catalog.rollbackTo(identifier, tableUuid, instant, 2L, 
"head-uuid", commitUser);
+                catalog.rollbackTo(identifier, tableUuid, instant, 2L);
                 RecordedRequest recorded = server.takeRequest(10, 
TimeUnit.SECONDS);
                 assertThat(recorded.getMethod()).isEqualTo("POST");
                 assertThat(recorded.getPath())
@@ -82,7 +76,6 @@ class RollbackProtocolTest {
                 
assertThat(payload.get("instant").get("type").asText()).isEqualTo(kind);
                 RollbackTableRequest request = RESTApi.fromJson(body, 
RollbackTableRequest.class);
                 assertThat(request.getFromSnapshot()).isEqualTo(2L);
-                
assertThat(request.getFromSnapshotUuid()).isEqualTo("head-uuid");
                 if ("snapshot".equals(kind)) {
                     assertThat(((Instant.SnapshotInstant) 
request.getInstant()).getSnapshotId())
                             .isEqualTo(1L);
@@ -95,13 +88,9 @@ class RollbackProtocolTest {
                 } else {
                     assertThat(payload.has("tableId")).isFalse();
                 }
-                if (commitUser != null) {
-                    assertThat(request.getCommitUser()).isEqualTo(commitUser);
-                } else {
-                    assertThat(payload.has("commitUser")).isFalse();
-                }
-                assertThat(payload.size())
-                        .isEqualTo(3 + (tableUuid == null ? 0 : 1) + 
(commitUser == null ? 0 : 1));
+                assertThat(payload.has("commitUser")).isFalse();
+                assertThat(payload.has("fromSnapshotUuid")).isFalse();
+                assertThat(payload.size()).isEqualTo(2 + (tableUuid == null ? 
0 : 1));
             }
         }
     }
diff --git 
a/paimon-core/src/test/java/org/apache/paimon/table/CatalogEnvironmentTest.java 
b/paimon-core/src/test/java/org/apache/paimon/table/CatalogEnvironmentTest.java
index 3489b8e506..931a842c5e 100644
--- 
a/paimon-core/src/test/java/org/apache/paimon/table/CatalogEnvironmentTest.java
+++ 
b/paimon-core/src/test/java/org/apache/paimon/table/CatalogEnvironmentTest.java
@@ -67,7 +67,7 @@ class CatalogEnvironmentTest {
 
     @ParameterizedTest
     @ValueSource(strings = {"main", "dev"})
-    void testCatalogTableRollbackUsesRuntimeBranchAndOwner(String branch) 
throws Exception {
+    void testCatalogTableRollbackUsesRuntimeBranch(String branch) throws 
Exception {
         Catalog catalog = mock(Catalog.class);
         CatalogEnvironment environment =
                 new CatalogEnvironment(
@@ -80,20 +80,13 @@ class CatalogEnvironmentTest {
                         true,
                         false);
         Instant instant = Instant.snapshot(1L);
-        environment.catalogTableRollback(branch, "writer").rollbackTo(instant, 
2L, "head-uuid");
-        verify(catalog)
-                .rollbackTo(
-                        new Identifier("db", "table", branch),
-                        "table-id",
-                        instant,
-                        2L,
-                        "head-uuid",
-                        "writer");
+        environment.catalogTableRollback(branch).rollbackTo(instant, 2L);
+        verify(catalog).rollbackTo(new Identifier("db", "table", branch), 
"table-id", instant, 2L);
     }
 
     @ParameterizedTest
     @CsvSource({"main,table-id", "dev,table-id", "main,", "dev,"})
-    void testCatalogTableRollbackWithoutOwnerPreservesTableUuid(String branch, 
String tableUuid)
+    void testCatalogTableRollbackPreservesTableUuid(String branch, String 
tableUuid)
             throws Exception {
         Catalog catalog = mock(Catalog.class);
         CatalogEnvironment environment =
@@ -107,15 +100,8 @@ class CatalogEnvironmentTest {
                         true,
                         false);
         Instant instant = Instant.tag("tag-1");
-        environment.catalogTableRollback(null, null).rollbackTo(instant, null, 
null);
-        verify(catalog)
-                .rollbackTo(
-                        new Identifier("db", "table", branch),
-                        tableUuid,
-                        instant,
-                        null,
-                        null,
-                        null);
+        environment.catalogTableRollback(null).rollbackTo(instant, null);
+        verify(catalog).rollbackTo(new Identifier("db", "table", branch), 
tableUuid, instant, null);
     }
 
     @ParameterizedTest
@@ -142,18 +128,18 @@ class CatalogEnvironmentTest {
         CatalogEnvironment copied = environment.copy(targetIdentifier);
 
         Instant snapshot = Instant.snapshot(1L);
-        copied.catalogTableRollback(null, null).rollbackTo(snapshot, 2L, 
"head-uuid");
-        verify(catalog).rollbackTo(targetIdentifier, expectedUuid, snapshot, 
2L, "head-uuid", null);
+        copied.catalogTableRollback(null).rollbackTo(snapshot, 2L);
+        verify(catalog).rollbackTo(targetIdentifier, expectedUuid, snapshot, 
2L);
 
         Instant tag = Instant.tag("checkpoint");
         copied.snapshotLoader().rollback(tag);
-        verify(catalog).rollbackTo(targetIdentifier, expectedUuid, tag, null, 
null, null);
+        verify(catalog).rollbackTo(targetIdentifier, expectedUuid, tag, null);
         assertThat(environment.uuid()).isEqualTo(sourceUuid);
     }
 
     @Test
     void testCatalogTableRollbackWithoutCatalogReturnsNull() {
-        assertThat(CatalogEnvironment.empty().catalogTableRollback(null, 
null)).isNull();
+        
assertThat(CatalogEnvironment.empty().catalogTableRollback(null)).isNull();
     }
 
     @Test
@@ -161,8 +147,8 @@ class CatalogEnvironmentTest {
         Catalog catalog = mock(Catalog.class);
         CatalogEnvironment environment =
                 new CatalogEnvironment(null, null, () -> catalog, null, null, 
null, false, false);
-        assertThat(environment.catalogTableRollback(null, null)).isNull();
-        assertThat(environment.catalogTableRollback("dev", "writer")).isNull();
+        assertThat(environment.catalogTableRollback(null)).isNull();
+        assertThat(environment.catalogTableRollback("dev")).isNull();
         verifyNoInteractions(catalog);
     }
 
diff --git 
a/paimon-core/src/test/java/org/apache/paimon/table/FallbackReadFileStoreTableTest.java
 
b/paimon-core/src/test/java/org/apache/paimon/table/FallbackReadFileStoreTableTest.java
index 213de33561..8c93914299 100644
--- 
a/paimon-core/src/test/java/org/apache/paimon/table/FallbackReadFileStoreTableTest.java
+++ 
b/paimon-core/src/test/java/org/apache/paimon/table/FallbackReadFileStoreTableTest.java
@@ -578,8 +578,6 @@ public class FallbackReadFileStoreTableTest {
                                                 && ((Instant.SnapshotInstant) 
instant)
                                                                 
.getSnapshotId()
                                                         == 1L),
-                        Mockito.isNull(),
-                        Mockito.isNull(),
                         Mockito.isNull());
 
         table.switchToBranch("bc").rollbackTo("checkpoint");
@@ -594,8 +592,6 @@ public class FallbackReadFileStoreTableTest {
                                                         .equals(
                                                                 
((Instant.TagInstant) instant)
                                                                         
.getTagName())),
-                        Mockito.isNull(),
-                        Mockito.isNull(),
                         Mockito.isNull());
         assertThat(table.catalogEnvironment().uuid()).isEqualTo("main-uuid");
     }
diff --git 
a/paimon-core/src/test/java/org/apache/paimon/tag/SnapshotLoaderImplTest.java 
b/paimon-core/src/test/java/org/apache/paimon/tag/SnapshotLoaderImplTest.java
index 0346690bad..ed9789813d 100644
--- 
a/paimon-core/src/test/java/org/apache/paimon/tag/SnapshotLoaderImplTest.java
+++ 
b/paimon-core/src/test/java/org/apache/paimon/tag/SnapshotLoaderImplTest.java
@@ -43,7 +43,7 @@ class SnapshotLoaderImplTest {
 
         environment.snapshotLoader().rollback(instant);
 
-        verify(catalog).rollbackTo(identifier, uuid, instant, null, null, 
null);
+        verify(catalog).rollbackTo(identifier, uuid, instant, null);
     }
 
     @ParameterizedTest
@@ -61,13 +61,7 @@ class SnapshotLoaderImplTest {
         loader.copyWithBranch(branch).rollback(instant);
 
         verify(catalog)
-                .rollbackTo(
-                        new Identifier("db", "table", branch),
-                        "table-uuid",
-                        instant,
-                        null,
-                        null,
-                        null);
+                .rollbackTo(new Identifier("db", "table", branch), 
"table-uuid", instant, null);
     }
 
     @ParameterizedTest
@@ -82,8 +76,7 @@ class SnapshotLoaderImplTest {
 
         loader.copyWithBranch(target).rollback(instant);
 
-        verify(catalog)
-                .rollbackTo(new Identifier("db", "table", target), null, 
instant, null, null, null);
+        verify(catalog).rollbackTo(new Identifier("db", "table", target), 
null, instant, null);
     }
 
     private CatalogEnvironment environment(Catalog catalog, Identifier 
identifier, String uuid) {

Reply via email to