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

yuqi1129 pushed a commit to branch branch-1.3
in repository https://gitbox.apache.org/repos/asf/gravitino.git


The following commit(s) were added to refs/heads/branch-1.3 by this push:
     new b53834f95e [Cherry-pick to branch-1.3] [#13290] fix(iceberg): Set 
metadata_location when load table with snapshots=refs (#13291) (#13336)
b53834f95e is described below

commit b53834f95ee1446809acde8da733c496432b4309
Author: github-actions[bot] 
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Sun Sep 20 09:48:27 2026 +0800

    [Cherry-pick to branch-1.3] [#13290] fix(iceberg): Set metadata_location 
when load table with snapshots=refs (#13291) (#13336)
    
    **Cherry-pick Information:**
    - Original commit: fa66e0b5e9b7865d3f241a349b17488f6a76d1b0
    - Target branch: `branch-1.3`
    - Status: ✅ Clean cherry-pick (no conflicts)
    
    Co-authored-by: Xinyi Lu <[email protected]>
---
 .../service/rest/IcebergTableOperations.java       |  5 +-
 .../service/rest/TestIcebergTableOperations.java   | 85 +++++++++++++++++++++-
 2 files changed, 85 insertions(+), 5 deletions(-)

diff --git 
a/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/rest/IcebergTableOperations.java
 
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/rest/IcebergTableOperations.java
index 1782fe8ec9..5355bd0439 100644
--- 
a/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/rest/IcebergTableOperations.java
+++ 
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/rest/IcebergTableOperations.java
@@ -566,7 +566,10 @@ public class IcebergTableOperations {
       return loadTableResponse;
     }
     TableMetadata filteredMetadata =
-        
TableMetadata.buildFrom(metadata).suppressHistoricalSnapshots().build();
+        TableMetadata.buildFrom(metadata)
+            .withMetadataLocation(metadata.metadataFileLocation())
+            .suppressHistoricalSnapshots()
+            .build();
     LoadTableResponse.Builder builder =
         LoadTableResponse.builder()
             .withTableMetadata(filteredMetadata)
diff --git 
a/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/rest/TestIcebergTableOperations.java
 
b/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/rest/TestIcebergTableOperations.java
index 8cb0557837..5a0c395206 100644
--- 
a/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/rest/TestIcebergTableOperations.java
+++ 
b/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/rest/TestIcebergTableOperations.java
@@ -67,10 +67,13 @@ import 
org.apache.gravitino.listener.api.event.IcebergUpdateTablePreEvent;
 import org.apache.gravitino.server.ServerConfig;
 import org.apache.gravitino.server.authorization.GravitinoAuthorizerProvider;
 import org.apache.iceberg.MetadataUpdate;
+import org.apache.iceberg.PartitionSpec;
 import org.apache.iceberg.Schema;
 import org.apache.iceberg.Snapshot;
+import org.apache.iceberg.SnapshotParser;
 import org.apache.iceberg.SnapshotRef;
 import org.apache.iceberg.TableMetadata;
+import org.apache.iceberg.TableMetadataParser;
 import org.apache.iceberg.UpdateRequirement;
 import org.apache.iceberg.UpdateRequirements;
 import org.apache.iceberg.catalog.Namespace;
@@ -1091,6 +1094,25 @@ public class TestIcebergTableOperations extends 
IcebergNamespaceTestBase {
         refs.keySet(),
         refsTableResponse.tableMetadata().refs().keySet(),
         "Refs should be preserved in filtered response");
+
+    // Filtering must not alter anything other than the snapshot list
+    Assertions.assertNotNull(allTableResponse.metadataLocation());
+    Assertions.assertEquals(
+        allTableResponse.metadataLocation(),
+        refsTableResponse.metadataLocation(),
+        "snapshots=refs must keep metadata-location in the response");
+    Assertions.assertEquals(
+        allTableResponse.tableMetadata().lastUpdatedMillis(),
+        refsTableResponse.tableMetadata().lastUpdatedMillis(),
+        "snapshots=refs must not change last-updated-ms");
+    Assertions.assertEquals(
+        allTableResponse.tableMetadata().previousFiles(),
+        refsTableResponse.tableMetadata().previousFiles(),
+        "snapshots=refs must not add a metadata-log entry");
+    Assertions.assertEquals(
+        allTableResponse.tableMetadata().snapshotLog(),
+        refsTableResponse.tableMetadata().snapshotLog(),
+        "snapshots=refs must keep the full snapshot-log for lazy loading");
   }
 
   @ParameterizedTest
@@ -1133,10 +1155,7 @@ public class TestIcebergTableOperations extends 
IcebergNamespaceTestBase {
   void testFilterSnapshotsByRefsKeepsCredentials() {
     TableMetadata metadata =
         TableMetadata.newTableMetadata(
-            tableSchema,
-            org.apache.iceberg.PartitionSpec.unpartitioned(),
-            "s3://bucket/db/tbl",
-            ImmutableMap.of());
+            tableSchema, PartitionSpec.unpartitioned(), "s3://bucket/db/tbl", 
ImmutableMap.of());
     org.apache.iceberg.rest.credentials.Credential credential =
         IcebergRESTUtils.toRESTCredential(
             "s3://bucket/db/tbl/",
@@ -1160,6 +1179,64 @@ public class TestIcebergTableOperations extends 
IcebergNamespaceTestBase {
     Assertions.assertEquals("org.apache.iceberg.aws.s3.S3FileIO", 
filtered.config().get("io-impl"));
   }
 
+  @Test
+  void testFilterSnapshotsByRefsPreservesMetadataLocationAndHistory() {
+    TableMetadata base =
+        TableMetadata.newTableMetadata(
+            tableSchema, PartitionSpec.unpartitioned(), "s3://bucket/db/tbl", 
ImmutableMap.of());
+    Snapshot first = snapshot(1L, null, 1000L);
+    Snapshot second = snapshot(2L, 1L, 2000L);
+    TableMetadata withHistory =
+        TableMetadata.buildFrom(
+                TableMetadata.buildFrom(base).setBranchSnapshot(first, 
"main").build())
+            .setBranchSnapshot(second, "main")
+            .build();
+    String metadataLocation = 
"s3://bucket/db/tbl/metadata/00002-abc.metadata.json";
+    // Round-trip through the parser so the metadata looks like one loaded 
from a metadata file:
+    // no pending changes and a known metadata location, exactly what 
loadTable hands over.
+    TableMetadata metadata =
+        TableMetadataParser.fromJson(metadataLocation, 
TableMetadataParser.toJson(withHistory));
+    Assertions.assertEquals(2, metadata.snapshots().size());
+    LoadTableResponse original = 
LoadTableResponse.builder().withTableMetadata(metadata).build();
+
+    LoadTableResponse filtered = 
IcebergTableOperations.filterSnapshotsByRefs(original);
+
+    Assertions.assertEquals(
+        ImmutableSet.of(2L),
+        filtered.tableMetadata().snapshots().stream()
+            .map(Snapshot::snapshotId)
+            .collect(Collectors.toSet()),
+        "only the ref-referenced snapshot should remain");
+    Assertions.assertEquals(
+        metadataLocation, filtered.metadataLocation(), "metadata-location must 
be preserved");
+    Assertions.assertEquals(
+        metadata.lastUpdatedMillis(),
+        filtered.tableMetadata().lastUpdatedMillis(),
+        "last-updated-ms must not be bumped by filtering");
+    Assertions.assertEquals(
+        metadata.previousFiles(),
+        filtered.tableMetadata().previousFiles(),
+        "filtering must not append a metadata-log entry");
+    Assertions.assertEquals(
+        metadata.snapshotLog(),
+        filtered.tableMetadata().snapshotLog(),
+        "snapshot-log must be kept intact for lazy snapshot loading");
+  }
+
+  private static Snapshot snapshot(long snapshotId, Long parentId, long 
timestampMs) {
+    String json =
+        String.format(
+            "{\"snapshot-id\":%d,%s\"timestamp-ms\":%d,\"sequence-number\":%d,"
+                + "\"summary\":{\"operation\":\"append\"},"
+                + 
"\"manifest-list\":\"s3://bucket/db/tbl/metadata/snap-%d.avro\",\"schema-id\":0}",
+            snapshotId,
+            parentId == null ? "" : 
String.format("\"parent-snapshot-id\":%d,", parentId),
+            timestampMs,
+            snapshotId,
+            snapshotId);
+    return SnapshotParser.fromJson(json);
+  }
+
   @ParameterizedTest
   
@MethodSource("org.apache.gravitino.iceberg.service.rest.IcebergRestTestUtil#testNamespaces")
   void testLoadTableSnapshotsAllReturnsAllSnapshots(Namespace namespace) {

Reply via email to