Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Core: Retain current view version during expiration #12067

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
}
}