Skip to content

Commit

Permalink
Core: Retain current view version during expiration (#12067)
Browse files Browse the repository at this point in the history
Co-authored-by: Christian Thiel <[email protected]>
  • Loading branch information
nastra and c-thiel authored Jan 24, 2025
1 parent 026a9b0 commit 681ff57
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 7 deletions.
17 changes: 14 additions & 3 deletions core/src/main/java/org/apache/iceberg/view/ViewMetadata.java
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,8 @@ public ViewMetadata build() {
List<ViewVersion> retainedVersions;
List<ViewHistoryEntry> retainedHistory;
if (versions.size() > numVersionsToKeep) {
retainedVersions = expireVersions(versionsById, numVersionsToKeep);
retainedVersions =
expireVersions(versionsById, numVersionsToKeep, versionsById.get(currentVersionId));
Set<Integer> retainedVersionIds =
retainedVersions.stream().map(ViewVersion::versionId).collect(Collectors.toSet());
retainedHistory = updateHistory(history, retainedVersionIds);
Expand All @@ -493,14 +494,24 @@ public ViewMetadata build() {

@VisibleForTesting
static List<ViewVersion> expireVersions(
Map<Integer, ViewVersion> versionsById, int numVersionsToKeep) {
Map<Integer, ViewVersion> versionsById, int numVersionsToKeep, ViewVersion currentVersion) {
// version ids are assigned sequentially. keep the latest versions by ID.
List<Integer> ids = Lists.newArrayList(versionsById.keySet());
ids.sort(Comparator.reverseOrder());

List<ViewVersion> retainedVersions = Lists.newArrayList();
// always retain the current version
retainedVersions.add(currentVersion);

for (int idToKeep : ids.subList(0, numVersionsToKeep)) {
retainedVersions.add(versionsById.get(idToKeep));
if (retainedVersions.size() == numVersionsToKeep) {
break;
}

ViewVersion version = versionsById.get(idToKeep);
if (currentVersion.versionId() != version.versionId()) {
retainedVersions.add(version);
}
}

return retainedVersions;
Expand Down
48 changes: 44 additions & 4 deletions core/src/test/java/org/apache/iceberg/view/TestViewMetadata.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,11 @@ public void testExpiration() {
ViewVersion v2 = newViewVersion(2, "select count(1) as count from t2");
Map<Integer, ViewVersion> versionsById = ImmutableMap.of(1, v1, 2, v2, 3, v3);

assertThat(ViewMetadata.Builder.expireVersions(versionsById, 3))
assertThat(ViewMetadata.Builder.expireVersions(versionsById, 3, v1))
.containsExactlyInAnyOrder(v1, v2, v3);
assertThat(ViewMetadata.Builder.expireVersions(versionsById, 2))
.containsExactlyInAnyOrder(v2, v3);
assertThat(ViewMetadata.Builder.expireVersions(versionsById, 1)).containsExactly(v3);
assertThat(ViewMetadata.Builder.expireVersions(versionsById, 2, v1))
.containsExactlyInAnyOrder(v1, v3);
assertThat(ViewMetadata.Builder.expireVersions(versionsById, 1, v1)).containsExactly(v1);
}

@Test
Expand Down Expand Up @@ -1181,4 +1181,44 @@ public void droppingDialectAllowedAndThenDisallowed() {
+ "Previous dialects: [trino]\n"
+ "New dialects: [spark]");
}

@Test
public void currentViewVersionIsNeverExpired() {
Map<String, String> properties = ImmutableMap.of(ViewProperties.VERSION_HISTORY_SIZE, "1");
ViewVersion viewVersionOne = newViewVersion(1, "select * from ns.tbl");
ViewVersion viewVersionTwo = newViewVersion(2, "select count(*) from ns.tbl");
ViewVersion viewVersionThree = newViewVersion(3, "select count(*) as count from ns.tbl");

ViewMetadata originalViewMetadata =
ViewMetadata.builder()
.setProperties(properties)
.setLocation("location")
.addSchema(new Schema(Types.NestedField.required(1, "x", Types.LongType.get())))
.addVersion(viewVersionOne)
.addVersion(viewVersionTwo)
.addVersion(viewVersionThree)
.setCurrentVersionId(1)
.build();

// the first build will not expire versions that were added in the builder
assertThat(originalViewMetadata.versions()).hasSize(3);
assertThat(originalViewMetadata.history())
.hasSize(1)
.element(0)
.extracting(ViewHistoryEntry::versionId)
.isEqualTo(1);

// rebuild the metadata to expire older versions
ViewMetadata viewMetadata = ViewMetadata.buildFrom(originalViewMetadata).build();
assertThat(viewMetadata.versions()).hasSize(1);

// make sure history and current version are retained
assertThat(viewMetadata.currentVersionId()).isEqualTo(1);
assertThat(viewMetadata.currentVersion()).isEqualTo(viewVersionOne);
assertThat(viewMetadata.history())
.hasSize(1)
.element(0)
.extracting(ViewHistoryEntry::versionId)
.isEqualTo(1);
}
}

0 comments on commit 681ff57

Please sign in to comment.