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) {