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 d9eb937bfb Core: Add UUID to ViewMetadata (#8591)
d9eb937bfb is described below
commit d9eb937bfb6bfed98b0a7e64ef402792a1a2b777
Author: Eduard Tudenhoefner <[email protected]>
AuthorDate: Wed Sep 20 23:19:32 2023 +0200
Core: Add UUID to ViewMetadata (#8591)
---
.../java/org/apache/iceberg/MetadataUpdate.java | 5 ++
.../java/org/apache/iceberg/view/ViewMetadata.java | 19 ++++++
.../apache/iceberg/view/ViewMetadataParser.java | 4 ++
.../org/apache/iceberg/view/TestViewMetadata.java | 73 +++++++++++++++++++---
.../iceberg/view/TestViewMetadataParser.java | 1 +
.../org/apache/iceberg/view/ValidViewMetadata.json | 1 +
.../view/ViewMetadataInvalidCurrentSchema.json | 1 +
.../view/ViewMetadataInvalidCurrentVersion.json | 1 +
.../view/ViewMetadataMissingCurrentVersion.json | 1 +
.../iceberg/view/ViewMetadataMissingLocation.json | 1 +
format/view-spec.md | 3 +
11 files changed, 102 insertions(+), 8 deletions(-)
diff --git a/core/src/main/java/org/apache/iceberg/MetadataUpdate.java
b/core/src/main/java/org/apache/iceberg/MetadataUpdate.java
index 2cf16bca6c..363aabbff2 100644
--- a/core/src/main/java/org/apache/iceberg/MetadataUpdate.java
+++ b/core/src/main/java/org/apache/iceberg/MetadataUpdate.java
@@ -53,6 +53,11 @@ public interface MetadataUpdate extends Serializable {
public void applyTo(TableMetadata.Builder metadataBuilder) {
metadataBuilder.assignUUID(uuid);
}
+
+ @Override
+ public void applyTo(ViewMetadata.Builder metadataBuilder) {
+ metadataBuilder.assignUUID(uuid);
+ }
}
class UpgradeFormatVersion implements MetadataUpdate {
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 d4df7169fd..fe2f2c8b68 100644
--- a/core/src/main/java/org/apache/iceberg/view/ViewMetadata.java
+++ b/core/src/main/java/org/apache/iceberg/view/ViewMetadata.java
@@ -23,6 +23,7 @@ import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.iceberg.MetadataUpdate;
@@ -46,6 +47,8 @@ public interface ViewMetadata extends Serializable {
int SUPPORTED_VIEW_FORMAT_VERSION = 1;
int DEFAULT_VIEW_FORMAT_VERSION = 1;
+ String uuid();
+
int formatVersion();
String location();
@@ -141,6 +144,7 @@ public interface ViewMetadata extends Serializable {
private int formatVersion = DEFAULT_VIEW_FORMAT_VERSION;
private int currentVersionId;
private String location;
+ private String uuid;
// internal change tracking
private Integer lastAddedVersionId = null;
@@ -157,6 +161,7 @@ public interface ViewMetadata extends Serializable {
this.history = Lists.newArrayList();
this.properties = Maps.newHashMap();
this.changes = Lists.newArrayList();
+ this.uuid = null;
}
private Builder(ViewMetadata base) {
@@ -170,6 +175,7 @@ public interface ViewMetadata extends Serializable {
this.formatVersion = base.formatVersion();
this.currentVersionId = base.currentVersionId();
this.location = base.location();
+ this.uuid = base.uuid();
}
public Builder upgradeFormatVersion(int newFormatVersion) {
@@ -353,6 +359,18 @@ public interface ViewMetadata extends Serializable {
return this;
}
+ public ViewMetadata.Builder assignUUID(String newUUID) {
+ Preconditions.checkArgument(newUUID != null, "Cannot set uuid to null");
+ Preconditions.checkArgument(uuid == null || newUUID.equals(uuid),
"Cannot reassign uuid");
+
+ if (!newUUID.equals(uuid)) {
+ this.uuid = newUUID;
+ changes.add(new MetadataUpdate.AssignUUID(uuid));
+ }
+
+ return this;
+ }
+
public ViewMetadata build() {
Preconditions.checkArgument(null != location, "Invalid location: null");
Preconditions.checkArgument(versions.size() > 0, "Invalid view: no
versions were added");
@@ -386,6 +404,7 @@ public interface ViewMetadata extends Serializable {
}
return ImmutableViewMetadata.of(
+ null == uuid ? UUID.randomUUID().toString() : uuid,
formatVersion,
location,
schemas,
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 c994c82ea8..0852db6a51 100644
--- a/core/src/main/java/org/apache/iceberg/view/ViewMetadataParser.java
+++ b/core/src/main/java/org/apache/iceberg/view/ViewMetadataParser.java
@@ -39,6 +39,7 @@ import org.apache.iceberg.util.JsonUtil;
public class ViewMetadataParser {
+ static final String VIEW_UUID = "view-uuid";
static final String FORMAT_VERSION = "format-version";
static final String LOCATION = "location";
static final String CURRENT_VERSION_ID = "current-version-id";
@@ -62,6 +63,7 @@ public class ViewMetadataParser {
gen.writeStartObject();
+ gen.writeStringField(VIEW_UUID, metadata.uuid());
gen.writeNumberField(FORMAT_VERSION, metadata.formatVersion());
gen.writeStringField(LOCATION, metadata.location());
JsonUtil.writeStringMap(PROPERTIES, metadata.properties(), gen);
@@ -98,6 +100,7 @@ public class ViewMetadataParser {
Preconditions.checkArgument(
json.isObject(), "Cannot parse view metadata from non-object: %s",
json);
+ String uuid = JsonUtil.getString(VIEW_UUID, json);
int formatVersion = JsonUtil.getInt(FORMAT_VERSION, json);
String location = JsonUtil.getString(LOCATION, json);
Map<String, String> properties = JsonUtil.getStringMap(PROPERTIES, json);
@@ -131,6 +134,7 @@ public class ViewMetadataParser {
}
return ImmutableViewMetadata.of(
+ uuid,
formatVersion,
location,
schemas,
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 a852a716d5..acb344ffab 100644
--- a/core/src/test/java/org/apache/iceberg/view/TestViewMetadata.java
+++ b/core/src/test/java/org/apache/iceberg/view/TestViewMetadata.java
@@ -24,6 +24,7 @@ import static
org.assertj.core.api.Assertions.assertThatThrownBy;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.UUID;
import org.apache.iceberg.MetadataUpdate;
import org.apache.iceberg.Schema;
import org.apache.iceberg.catalog.Namespace;
@@ -43,6 +44,8 @@ public class TestViewMetadata {
.defaultCatalog("prod")
.defaultNamespace(Namespace.of("default"))
.summary(ImmutableMap.of("operation", "create"))
+ .addRepresentations(
+
ImmutableSQLViewRepresentation.builder().dialect("spark").sql(sql).build())
.schemaId(1)
.build();
}
@@ -101,6 +104,10 @@ public class TestViewMetadata {
() ->
ViewMetadata.builder().setLocation("location").setCurrentVersionId(1).build())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Cannot set current version to unknown version: 1");
+
+ assertThatThrownBy(() -> ViewMetadata.builder().assignUUID(null).build())
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Cannot set uuid to null");
}
@Test
@@ -380,8 +387,10 @@ public class TestViewMetadata {
.defaultNamespace(Namespace.of("ns"))
.build();
+ String uuid = "fa6506c3-7681-40c8-86dc-e36561f83385";
ViewMetadata viewMetadata =
ViewMetadata.builder()
+ .assignUUID(uuid)
.setLocation("custom-location")
.setProperties(properties)
.addSchema(schemaOne)
@@ -406,23 +415,30 @@ public class TestViewMetadata {
assertThat(viewMetadata.properties()).isEqualTo(properties);
List<MetadataUpdate> changes = viewMetadata.changes();
- assertThat(changes).hasSize(8);
+ assertThat(changes).hasSize(9);
assertThat(changes)
.element(0)
+ .isInstanceOf(MetadataUpdate.AssignUUID.class)
+
.asInstanceOf(InstanceOfAssertFactories.type(MetadataUpdate.AssignUUID.class))
+ .extracting(MetadataUpdate.AssignUUID::uuid)
+ .isEqualTo(uuid);
+
+ assertThat(changes)
+ .element(1)
.isInstanceOf(MetadataUpdate.SetLocation.class)
.asInstanceOf(InstanceOfAssertFactories.type(MetadataUpdate.SetLocation.class))
.extracting(MetadataUpdate.SetLocation::location)
.isEqualTo("custom-location");
assertThat(changes)
- .element(1)
+ .element(2)
.isInstanceOf(MetadataUpdate.SetProperties.class)
.asInstanceOf(InstanceOfAssertFactories.type(MetadataUpdate.SetProperties.class))
.extracting(MetadataUpdate.SetProperties::updated)
.isEqualTo(properties);
assertThat(changes)
- .element(2)
+ .element(3)
.isInstanceOf(MetadataUpdate.AddSchema.class)
.asInstanceOf(InstanceOfAssertFactories.type(MetadataUpdate.AddSchema.class))
.extracting(MetadataUpdate.AddSchema::schema)
@@ -430,7 +446,7 @@ public class TestViewMetadata {
.isEqualTo(1);
assertThat(changes)
- .element(3)
+ .element(4)
.isInstanceOf(MetadataUpdate.AddSchema.class)
.asInstanceOf(InstanceOfAssertFactories.type(MetadataUpdate.AddSchema.class))
.extracting(MetadataUpdate.AddSchema::schema)
@@ -438,31 +454,72 @@ public class TestViewMetadata {
.isEqualTo(2);
assertThat(changes)
- .element(4)
+ .element(5)
.isInstanceOf(MetadataUpdate.AddViewVersion.class)
.asInstanceOf(InstanceOfAssertFactories.type(MetadataUpdate.AddViewVersion.class))
.extracting(MetadataUpdate.AddViewVersion::viewVersion)
.isEqualTo(viewVersionOne);
assertThat(changes)
- .element(5)
+ .element(6)
.isInstanceOf(MetadataUpdate.AddViewVersion.class)
.asInstanceOf(InstanceOfAssertFactories.type(MetadataUpdate.AddViewVersion.class))
.extracting(MetadataUpdate.AddViewVersion::viewVersion)
.isEqualTo(viewVersionTwo);
assertThat(changes)
- .element(6)
+ .element(7)
.isInstanceOf(MetadataUpdate.AddViewVersion.class)
.asInstanceOf(InstanceOfAssertFactories.type(MetadataUpdate.AddViewVersion.class))
.extracting(MetadataUpdate.AddViewVersion::viewVersion)
.isEqualTo(viewVersionThree);
assertThat(changes)
- .element(7)
+ .element(8)
.isInstanceOf(MetadataUpdate.SetCurrentViewVersion.class)
.asInstanceOf(InstanceOfAssertFactories.type(MetadataUpdate.SetCurrentViewVersion.class))
.extracting(MetadataUpdate.SetCurrentViewVersion::versionId)
.isEqualTo(-1);
}
+
+ @Test
+ public void uuidAssignment() {
+ String uuid = "fa6506c3-7681-40c8-86dc-e36561f83385";
+ ViewMetadata viewMetadata =
+ ViewMetadata.builder()
+ .assignUUID(uuid)
+ .setLocation("custom-location")
+ .addSchema(new Schema(1, Types.NestedField.required(1, "x",
Types.LongType.get())))
+ .addVersion(
+ ImmutableViewVersion.builder()
+ .schemaId(1)
+ .versionId(1)
+ .timestampMillis(23L)
+ .putSummary("operation", "create")
+ .defaultNamespace(Namespace.of("ns"))
+ .build())
+ .setCurrentVersionId(1)
+ .build();
+
+ assertThat(viewMetadata.uuid()).isEqualTo(uuid);
+
+ // uuid should be carried over
+ ViewMetadata updated = ViewMetadata.buildFrom(viewMetadata).build();
+ assertThat(updated.uuid()).isEqualTo(uuid);
+ assertThat(updated.changes()).isEmpty();
+
+ // assigning the same uuid shouldn't fail and shouldn't cause any changes
+ updated = ViewMetadata.buildFrom(viewMetadata).assignUUID(uuid).build();
+ assertThat(updated.uuid()).isEqualTo(uuid);
+ assertThat(updated.changes()).isEmpty();
+
+ // can't reassign view uuid
+ assertThatThrownBy(
+ () ->
+ ViewMetadata.buildFrom(viewMetadata)
+ .assignUUID(UUID.randomUUID().toString())
+ .build())
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Cannot reassign uuid");
+ }
}
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 807a1df9b1..5efbcf026f 100644
--- a/core/src/test/java/org/apache/iceberg/view/TestViewMetadataParser.java
+++ b/core/src/test/java/org/apache/iceberg/view/TestViewMetadataParser.java
@@ -89,6 +89,7 @@ public class TestViewMetadataParser {
String json =
readViewMetadataInputFile("org/apache/iceberg/view/ValidViewMetadata.json");
ViewMetadata expectedViewMetadata =
ViewMetadata.builder()
+ .assignUUID("fa6506c3-7681-40c8-86dc-e36561f83385")
.addSchema(TEST_SCHEMA)
.addVersion(version1)
.addVersion(version2)
diff --git
a/core/src/test/resources/org/apache/iceberg/view/ValidViewMetadata.json
b/core/src/test/resources/org/apache/iceberg/view/ValidViewMetadata.json
index 9c0ae0ecbe..4e29ed8702 100644
--- a/core/src/test/resources/org/apache/iceberg/view/ValidViewMetadata.json
+++ b/core/src/test/resources/org/apache/iceberg/view/ValidViewMetadata.json
@@ -1,4 +1,5 @@
{
+ "view-uuid": "fa6506c3-7681-40c8-86dc-e36561f83385",
"format-version": 1,
"location": "s3://bucket/test/location",
"properties": {"some-key": "some-value"},
diff --git
a/core/src/test/resources/org/apache/iceberg/view/ViewMetadataInvalidCurrentSchema.json
b/core/src/test/resources/org/apache/iceberg/view/ViewMetadataInvalidCurrentSchema.json
index b63c6a6285..e6bdff2aad 100644
---
a/core/src/test/resources/org/apache/iceberg/view/ViewMetadataInvalidCurrentSchema.json
+++
b/core/src/test/resources/org/apache/iceberg/view/ViewMetadataInvalidCurrentSchema.json
@@ -1,4 +1,5 @@
{
+ "view-uuid": "fa6506c3-7681-40c8-86dc-e36561f83385",
"format-version": 1,
"location": "s3://bucket/test/location",
"properties": {"some-key": "some-value"},
diff --git
a/core/src/test/resources/org/apache/iceberg/view/ViewMetadataInvalidCurrentVersion.json
b/core/src/test/resources/org/apache/iceberg/view/ViewMetadataInvalidCurrentVersion.json
index fbcb2c9a41..8db0359c0d 100644
---
a/core/src/test/resources/org/apache/iceberg/view/ViewMetadataInvalidCurrentVersion.json
+++
b/core/src/test/resources/org/apache/iceberg/view/ViewMetadataInvalidCurrentVersion.json
@@ -1,4 +1,5 @@
{
+ "view-uuid": "fa6506c3-7681-40c8-86dc-e36561f83385",
"format-version": 1,
"location": "s3://bucket/test/location",
"properties": {"some-key": "some-value"},
diff --git
a/core/src/test/resources/org/apache/iceberg/view/ViewMetadataMissingCurrentVersion.json
b/core/src/test/resources/org/apache/iceberg/view/ViewMetadataMissingCurrentVersion.json
index f09a7a4aa6..07febf71c9 100644
---
a/core/src/test/resources/org/apache/iceberg/view/ViewMetadataMissingCurrentVersion.json
+++
b/core/src/test/resources/org/apache/iceberg/view/ViewMetadataMissingCurrentVersion.json
@@ -1,4 +1,5 @@
{
+ "view-uuid": "fa6506c3-7681-40c8-86dc-e36561f83385",
"format-version": 1,
"location": "s3://bucket/test/location",
"properties": {"some-key": "some-value"},
diff --git
a/core/src/test/resources/org/apache/iceberg/view/ViewMetadataMissingLocation.json
b/core/src/test/resources/org/apache/iceberg/view/ViewMetadataMissingLocation.json
index d0fa7d9392..aa6d56ead3 100644
---
a/core/src/test/resources/org/apache/iceberg/view/ViewMetadataMissingLocation.json
+++
b/core/src/test/resources/org/apache/iceberg/view/ViewMetadataMissingLocation.json
@@ -1,4 +1,5 @@
{
+ "view-uuid": "fa6506c3-7681-40c8-86dc-e36561f83385",
"format-version": 1,
"properties": {"some-key": "some-value"},
"current-schema-id": 1,
diff --git a/format/view-spec.md b/format/view-spec.md
index d7e0b7b7a6..26313193af 100644
--- a/format/view-spec.md
+++ b/format/view-spec.md
@@ -58,6 +58,7 @@ The view version metadata file has the following fields:
| Requirement | Field name | Description |
|-------------|----------------------|-------------|
+| _required_ | `view-uuid` | A UUID that identifies the view,
generated when the view is created. Implementations must throw an exception if
a view's UUID does not match the expected UUID after refreshing metadata |
| _required_ | `format-version` | An integer version number for the view
format; must be 1 |
| _required_ | `location` | The view's base location; used to
create metadata file locations |
| _required_ | `schemas` | A list of known schemas |
@@ -192,6 +193,7 @@
s3://bucket/warehouse/default.db/event_agg/metadata/00001-(uuid).metadata.json
```
```
{
+ "view-uuid": "fa6506c3-7681-40c8-86dc-e36561f83385",
"format-version" : 1,
"location" : "s3://bucket/warehouse/default.db/event_agg",
"current-version-id" : 1,
@@ -259,6 +261,7 @@
s3://bucket/warehouse/default.db/event_agg/metadata/00002-(uuid).metadata.json
```
```
{
+ "view-uuid": "fa6506c3-7681-40c8-86dc-e36561f83385",
"format-version" : 1,
"location" : "s3://bucket/warehouse/default.db/event_agg",
"current-version-id" : 1,