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

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


The following commit(s) were added to refs/heads/master by this push:
     new f574743abc Core: Track metadata file location in ViewMetadata (#8608)
f574743abc is described below

commit f574743abc8ca62e25c7c02f2c4d54f435b3238c
Author: Eduard Tudenhoefner <[email protected]>
AuthorDate: Thu Sep 21 21:44:10 2023 +0200

    Core: Track metadata file location in ViewMetadata (#8608)
---
 .../java/org/apache/iceberg/view/ViewMetadata.java | 21 ++++++-
 .../apache/iceberg/view/ViewMetadataParser.java    | 13 ++++-
 .../org/apache/iceberg/view/TestViewMetadata.java  | 38 +++++++++++++
 .../iceberg/view/TestViewMetadataParser.java       | 65 ++++++++++++++++++++++
 4 files changed, 134 insertions(+), 3 deletions(-)

diff --git a/core/src/main/java/org/apache/iceberg/view/ViewMetadata.java 
b/core/src/main/java/org/apache/iceberg/view/ViewMetadata.java
index fe2f2c8b68..cb905bce09 100644
--- a/core/src/main/java/org/apache/iceberg/view/ViewMetadata.java
+++ b/core/src/main/java/org/apache/iceberg/view/ViewMetadata.java
@@ -26,6 +26,7 @@ import java.util.Set;
 import java.util.UUID;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
+import javax.annotation.Nullable;
 import org.apache.iceberg.MetadataUpdate;
 import org.apache.iceberg.Schema;
 import org.apache.iceberg.exceptions.ValidationException;
@@ -78,6 +79,9 @@ public interface ViewMetadata extends Serializable {
 
   List<MetadataUpdate> changes();
 
+  @Nullable
+  String metadataFileLocation();
+
   default ViewVersion version(int versionId) {
     return versionsById().get(versionId);
   }
@@ -145,6 +149,7 @@ public interface ViewMetadata extends Serializable {
     private int currentVersionId;
     private String location;
     private String uuid;
+    private String metadataLocation;
 
     // internal change tracking
     private Integer lastAddedVersionId = null;
@@ -176,6 +181,7 @@ public interface ViewMetadata extends Serializable {
       this.currentVersionId = base.currentVersionId();
       this.location = base.location();
       this.uuid = base.uuid();
+      this.metadataLocation = null;
     }
 
     public Builder upgradeFormatVersion(int newFormatVersion) {
@@ -205,6 +211,11 @@ public interface ViewMetadata extends Serializable {
       return this;
     }
 
+    public Builder setMetadataLocation(String newMetadataLocation) {
+      this.metadataLocation = newMetadataLocation;
+      return this;
+    }
+
     public Builder setCurrentVersionId(int newVersionId) {
       if (newVersionId == LAST_ADDED) {
         ValidationException.check(
@@ -375,6 +386,13 @@ public interface ViewMetadata extends Serializable {
       Preconditions.checkArgument(null != location, "Invalid location: null");
       Preconditions.checkArgument(versions.size() > 0, "Invalid view: no 
versions were added");
 
+      // when associated with a metadata file, metadata must have no changes 
so that the metadata
+      // matches exactly what is in the metadata file, which does not store 
changes. metadata
+      // location with changes is inconsistent.
+      Preconditions.checkArgument(
+          metadataLocation == null || changes.isEmpty(),
+          "Cannot create view metadata with a metadata location and changes");
+
       int historySize =
           PropertyUtil.propertyAsInt(
               properties,
@@ -412,7 +430,8 @@ public interface ViewMetadata extends Serializable {
           retainedVersions,
           retainedHistory,
           properties,
-          changes);
+          changes,
+          metadataLocation);
     }
 
     static List<ViewVersion> expireVersions(
diff --git a/core/src/main/java/org/apache/iceberg/view/ViewMetadataParser.java 
b/core/src/main/java/org/apache/iceberg/view/ViewMetadataParser.java
index 0852db6a51..7a29c87bad 100644
--- a/core/src/main/java/org/apache/iceberg/view/ViewMetadataParser.java
+++ b/core/src/main/java/org/apache/iceberg/view/ViewMetadataParser.java
@@ -90,12 +90,20 @@ public class ViewMetadataParser {
     gen.writeEndObject();
   }
 
+  public static ViewMetadata fromJson(String metadataLocation, String json) {
+    return JsonUtil.parse(json, node -> 
ViewMetadataParser.fromJson(metadataLocation, node));
+  }
+
   public static ViewMetadata fromJson(String json) {
     Preconditions.checkArgument(json != null, "Cannot parse view metadata from 
null string");
     return JsonUtil.parse(json, ViewMetadataParser::fromJson);
   }
 
   public static ViewMetadata fromJson(JsonNode json) {
+    return fromJson(null, json);
+  }
+
+  public static ViewMetadata fromJson(String metadataLocation, JsonNode json) {
     Preconditions.checkArgument(json != null, "Cannot parse view metadata from 
null object");
     Preconditions.checkArgument(
         json.isObject(), "Cannot parse view metadata from non-object: %s", 
json);
@@ -142,7 +150,8 @@ public class ViewMetadataParser {
         versions,
         historyEntries,
         properties,
-        ImmutableList.of());
+        ImmutableList.of(),
+        metadataLocation);
   }
 
   public static void overwrite(ViewMetadata metadata, OutputFile outputFile) {
@@ -155,7 +164,7 @@ public class ViewMetadataParser {
 
   public static ViewMetadata read(InputFile file) {
     try (InputStream is = file.newStream()) {
-      return fromJson(JsonUtil.mapper().readValue(is, JsonNode.class));
+      return fromJson(file.location(), JsonUtil.mapper().readValue(is, 
JsonNode.class));
     } catch (IOException e) {
       throw new UncheckedIOException(String.format("Failed to read json file: 
%s", file), e);
     }
diff --git a/core/src/test/java/org/apache/iceberg/view/TestViewMetadata.java 
b/core/src/test/java/org/apache/iceberg/view/TestViewMetadata.java
index acb344ffab..b525068cdf 100644
--- a/core/src/test/java/org/apache/iceberg/view/TestViewMetadata.java
+++ b/core/src/test/java/org/apache/iceberg/view/TestViewMetadata.java
@@ -522,4 +522,42 @@ public class TestViewMetadata {
         .isInstanceOf(IllegalArgumentException.class)
         .hasMessage("Cannot reassign uuid");
   }
+
+  @Test
+  public void viewMetadataWithMetadataLocation() {
+    Schema schema = new Schema(1, Types.NestedField.required(1, "x", 
Types.LongType.get()));
+    ViewVersion viewVersion =
+        ImmutableViewVersion.builder()
+            .schemaId(schema.schemaId())
+            .versionId(1)
+            .timestampMillis(23L)
+            .putSummary("operation", "a")
+            .defaultNamespace(Namespace.of("ns"))
+            .build();
+
+    assertThatThrownBy(
+            () ->
+                ViewMetadata.builder()
+                    .setLocation("custom-location")
+                    .setMetadataLocation("metadata-location")
+                    .addSchema(schema)
+                    .addVersion(viewVersion)
+                    .setCurrentVersionId(1)
+                    .build())
+        .isInstanceOf(IllegalArgumentException.class)
+        .hasMessage("Cannot create view metadata with a metadata location and 
changes");
+
+    // setting metadata location without changes is ok
+    ViewMetadata viewMetadata =
+        ViewMetadata.buildFrom(
+                ViewMetadata.builder()
+                    .setLocation("custom-location")
+                    .addSchema(schema)
+                    .addVersion(viewVersion)
+                    .setCurrentVersionId(1)
+                    .build())
+            .setMetadataLocation("metadata-location")
+            .build();
+    
assertThat(viewMetadata.metadataFileLocation()).isEqualTo("metadata-location");
+  }
 }
diff --git 
a/core/src/test/java/org/apache/iceberg/view/TestViewMetadataParser.java 
b/core/src/test/java/org/apache/iceberg/view/TestViewMetadataParser.java
index 5efbcf026f..076626d9fa 100644
--- a/core/src/test/java/org/apache/iceberg/view/TestViewMetadataParser.java
+++ b/core/src/test/java/org/apache/iceberg/view/TestViewMetadataParser.java
@@ -162,4 +162,69 @@ public class TestViewMetadataParser {
     Path path = 
Paths.get(getClass().getClassLoader().getResource(fileName).toURI());
     return String.join("", java.nio.file.Files.readAllLines(path));
   }
+
+  @Test
+  public void viewMetadataWithMetadataLocation() throws Exception {
+    ViewVersion version1 =
+        ImmutableViewVersion.builder()
+            .versionId(1)
+            .timestampMillis(4353L)
+            .summary(ImmutableMap.of("operation", "create"))
+            .schemaId(1)
+            .defaultCatalog("some-catalog")
+            .defaultNamespace(Namespace.empty())
+            .addRepresentations(
+                ImmutableSQLViewRepresentation.builder()
+                    .sql("select 'foo' foo")
+                    .dialect("spark-sql")
+                    .build())
+            .build();
+
+    ViewVersion version2 =
+        ImmutableViewVersion.builder()
+            .versionId(2)
+            .schemaId(1)
+            .timestampMillis(5555L)
+            .summary(ImmutableMap.of("operation", "replace"))
+            .defaultCatalog("some-catalog")
+            .defaultNamespace(Namespace.empty())
+            .addRepresentations(
+                ImmutableSQLViewRepresentation.builder()
+                    .sql("select 1 id, 'abc' data")
+                    .dialect("spark-sql")
+                    .build())
+            .build();
+
+    String json = 
readViewMetadataInputFile("org/apache/iceberg/view/ValidViewMetadata.json");
+    String metadataLocation = 
"s3://bucket/test/location/metadata/v1.metadata.json";
+    ViewMetadata expectedViewMetadata =
+        ViewMetadata.buildFrom(
+                ViewMetadata.builder()
+                    .assignUUID("fa6506c3-7681-40c8-86dc-e36561f83385")
+                    .addSchema(TEST_SCHEMA)
+                    .addVersion(version1)
+                    .addVersion(version2)
+                    .setLocation("s3://bucket/test/location")
+                    .setProperties(ImmutableMap.of("some-key", "some-value"))
+                    .setCurrentVersionId(2)
+                    .upgradeFormatVersion(1)
+                    .build())
+            .setMetadataLocation(metadataLocation)
+            .build();
+
+    ViewMetadata actual = ViewMetadataParser.fromJson(metadataLocation, json);
+    assertThat(actual)
+        .usingRecursiveComparison()
+        .ignoringFieldsOfTypes(Schema.class)
+        .isEqualTo(expectedViewMetadata);
+
+    actual =
+        ViewMetadataParser.fromJson(
+            metadataLocation, ViewMetadataParser.toJson(expectedViewMetadata));
+    assertThat(actual)
+        .usingRecursiveComparison()
+        .ignoringFieldsOfTypes(Schema.class)
+        .isEqualTo(expectedViewMetadata);
+    assertThat(actual.metadataFileLocation()).isEqualTo(metadataLocation);
+  }
 }

Reply via email to