This is an automated email from the ASF dual-hosted git repository.
danny0405 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hudi.git
The following commit(s) were added to refs/heads/master by this push:
new edca3907eae [HUDI-9505] Adding table version 9 and fixing
upgrade/downgrade paths (#13520)
edca3907eae is described below
commit edca3907eae79dfcc51a6465dc0c62efe999b6fc
Author: Davis-Zhang-Onehouse
<[email protected]>
AuthorDate: Mon Jul 7 20:13:16 2025 -0700
[HUDI-9505] Adding table version 9 and fixing upgrade/downgrade paths
(#13520)
---
.../apache/hudi/client/BaseHoodieWriteClient.java | 3 +-
.../org/apache/hudi/config/HoodieWriteConfig.java | 3 +-
.../table/upgrade/EightToNineUpgradeHandler.java | 36 ++++++++++++++++
.../table/upgrade/NineToEightDowngradeHandler.java | 37 ++++++++++++++++
.../hudi/table/upgrade/UpgradeDowngrade.java | 4 ++
.../hudi/table/upgrade/UpgradeDowngradeUtils.java | 4 +-
.../org/apache/hudi/util/CommonClientUtils.java | 21 ++++++---
.../apache/hudi/config/TestHoodieWriteConfig.java | 2 +-
.../apache/hudi/utils/TestCommonClientUtils.java | 50 ++++++++++++++++++++++
.../hudi/common/table/HoodieTableVersion.java | 6 ++-
10 files changed, 151 insertions(+), 15 deletions(-)
diff --git
a/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/client/BaseHoodieWriteClient.java
b/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/client/BaseHoodieWriteClient.java
index 6496c89cdf9..4e9ee7c82d4 100644
---
a/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/client/BaseHoodieWriteClient.java
+++
b/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/client/BaseHoodieWriteClient.java
@@ -46,7 +46,6 @@ import org.apache.hudi.common.model.TableServiceType;
import org.apache.hudi.common.model.WriteOperationType;
import org.apache.hudi.common.table.HoodieTableConfig;
import org.apache.hudi.common.table.HoodieTableMetaClient;
-import org.apache.hudi.common.table.HoodieTableVersion;
import org.apache.hudi.common.table.TableSchemaResolver;
import org.apache.hudi.common.table.timeline.HoodieActiveTimeline;
import org.apache.hudi.common.table.timeline.HoodieInstant;
@@ -1518,7 +1517,7 @@ public abstract class BaseHoodieWriteClient<T, I, K, O>
extends BaseHoodieClient
}
new UpgradeDowngrade(metaClient, config, context, upgradeDowngradeHelper)
- .run(HoodieTableVersion.current(), instantTime.orElse(null));
+ .run(config.getWriteVersion(), instantTime.orElse(null));
metaClient.reloadTableConfig();
metaClient.reloadActiveTimeline();
diff --git
a/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/config/HoodieWriteConfig.java
b/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/config/HoodieWriteConfig.java
index 289863cc3a4..fd590d1a9d0 100644
---
a/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/config/HoodieWriteConfig.java
+++
b/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/config/HoodieWriteConfig.java
@@ -146,7 +146,8 @@ public class HoodieWriteConfig extends HoodieConfig {
.defaultValue(HoodieTableVersion.current().versionCode())
.withValidValues(
String.valueOf(HoodieTableVersion.SIX.versionCode()),
- String.valueOf(HoodieTableVersion.current().versionCode())
+ String.valueOf(HoodieTableVersion.EIGHT.versionCode()),
+ String.valueOf(HoodieTableVersion.NINE.versionCode())
)
.sinceVersion("1.0.0")
.withDocumentation("The table version this writer is storing the table
in. This should match the current table version.");
diff --git
a/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/table/upgrade/EightToNineUpgradeHandler.java
b/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/table/upgrade/EightToNineUpgradeHandler.java
new file mode 100644
index 00000000000..dfb429af9d1
--- /dev/null
+++
b/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/table/upgrade/EightToNineUpgradeHandler.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hudi.table.upgrade;
+
+import org.apache.hudi.common.config.ConfigProperty;
+import org.apache.hudi.common.engine.HoodieEngineContext;
+import org.apache.hudi.config.HoodieWriteConfig;
+
+import java.util.Collections;
+import java.util.Map;
+
+public class EightToNineUpgradeHandler implements UpgradeHandler {
+
+ @Override
+ public Map<ConfigProperty, String> upgrade(HoodieWriteConfig config,
HoodieEngineContext context,
+ String instantTime,
SupportsUpgradeDowngrade upgradeDowngradeHelper) {
+
+ return Collections.emptyMap();
+ }
+}
diff --git
a/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/table/upgrade/NineToEightDowngradeHandler.java
b/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/table/upgrade/NineToEightDowngradeHandler.java
new file mode 100644
index 00000000000..9d576125a1b
--- /dev/null
+++
b/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/table/upgrade/NineToEightDowngradeHandler.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.hudi.table.upgrade;
+
+import org.apache.hudi.common.config.ConfigProperty;
+import org.apache.hudi.common.engine.HoodieEngineContext;
+import org.apache.hudi.common.util.collection.Pair;
+import org.apache.hudi.config.HoodieWriteConfig;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+public class NineToEightDowngradeHandler implements DowngradeHandler {
+
+ @Override
+ public Pair<Map<ConfigProperty, String>, List<ConfigProperty>>
downgrade(HoodieWriteConfig config, HoodieEngineContext context, String
instantTime, SupportsUpgradeDowngrade upgradeDowngradeHelper) {
+ return Pair.of(Collections.emptyMap(), Collections.emptyList());
+ }
+}
diff --git
a/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/table/upgrade/UpgradeDowngrade.java
b/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/table/upgrade/UpgradeDowngrade.java
index da391abe78f..b67065f127a 100644
---
a/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/table/upgrade/UpgradeDowngrade.java
+++
b/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/table/upgrade/UpgradeDowngrade.java
@@ -245,6 +245,8 @@ public class UpgradeDowngrade {
return new SixToSevenUpgradeHandler().upgrade(config, context,
instantTime, upgradeDowngradeHelper);
} else if (fromVersion == HoodieTableVersion.SEVEN && toVersion ==
HoodieTableVersion.EIGHT) {
return new SevenToEightUpgradeHandler().upgrade(config, context,
instantTime, upgradeDowngradeHelper);
+ } else if (fromVersion == HoodieTableVersion.EIGHT && toVersion ==
HoodieTableVersion.NINE) {
+ return new EightToNineUpgradeHandler().upgrade(config, context,
instantTime, upgradeDowngradeHelper);
} else {
throw new HoodieUpgradeDowngradeException(fromVersion.versionCode(),
toVersion.versionCode(), true);
}
@@ -267,6 +269,8 @@ public class UpgradeDowngrade {
return new SevenToSixDowngradeHandler().downgrade(config, context,
instantTime, upgradeDowngradeHelper);
} else if (fromVersion == HoodieTableVersion.EIGHT && toVersion ==
HoodieTableVersion.SEVEN) {
return new EightToSevenDowngradeHandler().downgrade(config, context,
instantTime, upgradeDowngradeHelper);
+ } else if (fromVersion == HoodieTableVersion.NINE && toVersion ==
HoodieTableVersion.EIGHT) {
+ return new NineToEightDowngradeHandler().downgrade(config, context,
instantTime, upgradeDowngradeHelper);
} else {
throw new HoodieUpgradeDowngradeException(fromVersion.versionCode(),
toVersion.versionCode(), false);
}
diff --git
a/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/table/upgrade/UpgradeDowngradeUtils.java
b/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/table/upgrade/UpgradeDowngradeUtils.java
index 3d39a47809b..d1a475883b3 100644
---
a/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/table/upgrade/UpgradeDowngradeUtils.java
+++
b/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/table/upgrade/UpgradeDowngradeUtils.java
@@ -174,13 +174,13 @@ public class UpgradeDowngradeUtils {
properties.putAll(config.getProps());
// TimeGenerators are cached and re-used based on table base path. Since
here we are changing the lock configurations, avoiding the cache use
// for upgrade code block.
-
properties.put(HoodieTimeGeneratorConfig.TIME_GENERATOR_REUSE_ENABLE.key(),"false");
+
properties.put(HoodieTimeGeneratorConfig.TIME_GENERATOR_REUSE_ENABLE.key(),
"false");
// override w/ NoopLock Provider to avoid re-entrant locking. already
upgrade is happening within the table level lock.
// Below we do trigger rollback and compaction which might again try to
acquire the lock. So, here we are explicitly overriding to
// NoopLockProvider for just the upgrade code block.
properties.put(HoodieLockConfig.LOCK_PROVIDER_CLASS_NAME.key(),
NoopLockProvider.class.getName());
// if auto adjust it not disabled, chances that InProcessLockProvider
will get overridden for single writer use-cases.
- properties.put(HoodieWriteConfig.AUTO_ADJUST_LOCK_CONFIGS.key(),"false");
+ properties.put(HoodieWriteConfig.AUTO_ADJUST_LOCK_CONFIGS.key(),
"false");
HoodieWriteConfig rollbackWriteConfig = HoodieWriteConfig.newBuilder()
.withProps(properties)
.withWriteTableVersion(tableVersion.versionCode())
diff --git
a/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/util/CommonClientUtils.java
b/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/util/CommonClientUtils.java
index c201f30aa93..7d0ab05c45c 100644
---
a/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/util/CommonClientUtils.java
+++
b/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/util/CommonClientUtils.java
@@ -52,14 +52,10 @@ public class CommonClientUtils {
public static void validateTableVersion(HoodieTableConfig tableConfig,
HoodieWriteConfig writeConfig) {
// mismatch of table versions.
- if (!tableConfig.getTableVersion().equals(writeConfig.getWriteVersion())) {
+ if (!isValidTableVersionWriteVersionPair(tableConfig.getTableVersion(),
writeConfig.getWriteVersion())) {
// if table version is greater than 6, while writer version is 6, we can
still allow it for upgrade
- if (tableConfig.getTableVersion().greaterThan(HoodieTableVersion.SIX) &&
writeConfig.getWriteVersion().equals(HoodieTableVersion.SIX)) {
- LOG.warn("Table version is greater than 6, while writer version is 6.
Allowing it for upgrade.");
- } else {
- throw new HoodieNotSupportedException(String.format("Table version
(%s) and Writer version (%s) do not match for table at: %s.",
- tableConfig.getTableVersion(), writeConfig.getWriteVersion(),
writeConfig.getBasePath()));
- }
+ throw new HoodieNotSupportedException(String.format("Table version (%s)
and Writer version (%s) do not match for table at: %s.",
+ tableConfig.getTableVersion(), writeConfig.getWriteVersion(),
writeConfig.getBasePath()));
}
// incompatible configurations.
if (tableConfig.getTableVersion().lesserThan(HoodieTableVersion.EIGHT) &&
writeConfig.shouldWritePartialUpdates()) {
@@ -72,6 +68,17 @@ public class CommonClientUtils {
}
}
+ public static boolean isValidTableVersionWriteVersionPair(HoodieTableVersion
tableVersion, HoodieTableVersion writeVersion) {
+ if (tableVersion.equals(writeVersion) ||
tableVersion.lesserThan(writeVersion)) {
+ return true;
+ }
+ if (tableVersion.greaterThan(HoodieTableVersion.SIX) &&
tableVersion.lesserThan(HoodieTableVersion.NINE) &&
writeVersion.equals(HoodieTableVersion.SIX)) {
+ LOG.warn("Table version is greater than 6 and lower than 9, while writer
version is 6. Allowing it for upgrade.");
+ return true;
+ }
+ return false;
+ }
+
/**
* Returns the base file format.
*/
diff --git
a/hudi-client/hudi-client-common/src/test/java/org/apache/hudi/config/TestHoodieWriteConfig.java
b/hudi-client/hudi-client-common/src/test/java/org/apache/hudi/config/TestHoodieWriteConfig.java
index c9cc16f1c04..690e8408a2c 100644
---
a/hudi-client/hudi-client-common/src/test/java/org/apache/hudi/config/TestHoodieWriteConfig.java
+++
b/hudi-client/hudi-client-common/src/test/java/org/apache/hudi/config/TestHoodieWriteConfig.java
@@ -96,7 +96,7 @@ public class TestHoodieWriteConfig {
@Test
public void testSupportedTableWriteVersions() {
Set<HoodieTableVersion> supportedVersions = CollectionUtils.createSet(
- HoodieTableVersion.SIX, HoodieTableVersion.EIGHT
+ HoodieTableVersion.SIX, HoodieTableVersion.EIGHT,
HoodieTableVersion.NINE
);
Arrays.stream(HoodieTableVersion.values())
.filter(version -> !supportedVersions.contains(version))
diff --git
a/hudi-client/hudi-client-common/src/test/java/org/apache/hudi/utils/TestCommonClientUtils.java
b/hudi-client/hudi-client-common/src/test/java/org/apache/hudi/utils/TestCommonClientUtils.java
index 9b3c56d5e79..21ee5300946 100644
---
a/hudi-client/hudi-client-common/src/test/java/org/apache/hudi/utils/TestCommonClientUtils.java
+++
b/hudi-client/hudi-client-common/src/test/java/org/apache/hudi/utils/TestCommonClientUtils.java
@@ -28,7 +28,13 @@ import org.apache.hudi.exception.HoodieNotSupportedException;
import org.apache.hudi.util.CommonClientUtils;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import java.util.stream.Stream;
+
+import static
org.apache.hudi.util.CommonClientUtils.isValidTableVersionWriteVersionPair;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.mock;
@@ -71,4 +77,48 @@ public class TestCommonClientUtils {
// when:
assertEquals("0-0-0",
CommonClientUtils.generateWriteToken(taskContextSupplier));
}
+
+ @ParameterizedTest(name = "Table version {0} with write version {1} should
be valid: {2}")
+ @MethodSource("provideValidTableVersionWriteVersionPairs")
+ public void testValidTableVersionWriteVersionPairs(
+ HoodieTableVersion tableVersion, HoodieTableVersion writeVersion,
boolean expectedResult) throws Exception {
+ boolean result = isValidTableVersionWriteVersionPair(tableVersion,
writeVersion);
+ assertEquals(expectedResult, result);
+ }
+
+ private static Stream<Arguments> provideValidTableVersionWriteVersionPairs()
{
+ return Stream.concat(
+ Stream.concat(
+ // Rule 1: writer > table version - always allowed
+ generateWriterGreaterThanTableCases(),
+ // Rule 2: same versions - always allowed
+ generateSameVersionCases()
+ ),
+ Stream.of(
+ // Rule 3: special case - upgrade scenario (table > 6, table < 9,
writer = 6)
+ Arguments.of(HoodieTableVersion.SEVEN, HoodieTableVersion.SIX,
true),
+ Arguments.of(HoodieTableVersion.EIGHT, HoodieTableVersion.SIX,
true),
+
+ // Rule 4: otherwise disallowed - table > writer (except special
case above)
+ Arguments.of(HoodieTableVersion.NINE, HoodieTableVersion.SIX,
false),
+ Arguments.of(HoodieTableVersion.NINE, HoodieTableVersion.EIGHT,
false),
+ Arguments.of(HoodieTableVersion.EIGHT, HoodieTableVersion.SEVEN,
false)
+ )
+ );
+ }
+
+ private static Stream<Arguments> generateWriterGreaterThanTableCases() {
+ HoodieTableVersion[] allVersions = HoodieTableVersion.values();
+ return Stream.of(allVersions)
+ .flatMap(tableVersion ->
+ Stream.of(allVersions)
+ .filter(writeVersion -> writeVersion.greaterThan(tableVersion))
+ .map(writeVersion -> Arguments.of(tableVersion, writeVersion,
true))
+ );
+ }
+
+ private static Stream<Arguments> generateSameVersionCases() {
+ return Stream.of(HoodieTableVersion.values())
+ .map(version -> Arguments.of(version, version, true));
+ }
}
diff --git
a/hudi-common/src/main/java/org/apache/hudi/common/table/HoodieTableVersion.java
b/hudi-common/src/main/java/org/apache/hudi/common/table/HoodieTableVersion.java
index 2599a461f01..49a4b7215b1 100644
---
a/hudi-common/src/main/java/org/apache/hudi/common/table/HoodieTableVersion.java
+++
b/hudi-common/src/main/java/org/apache/hudi/common/table/HoodieTableVersion.java
@@ -47,8 +47,10 @@ public enum HoodieTableVersion {
// 0.16.0
SEVEN(7, CollectionUtils.createImmutableList("0.16.0"),
TimelineLayoutVersion.LAYOUT_VERSION_1),
// 1.0
- EIGHT(8, CollectionUtils.createImmutableList("1.0.0"),
TimelineLayoutVersion.LAYOUT_VERSION_2);
-
+ EIGHT(8, CollectionUtils.createImmutableList("1.0.0"),
TimelineLayoutVersion.LAYOUT_VERSION_2),
+ // 1.1
+ NINE(9, CollectionUtils.createImmutableList("1.1.0"),
TimelineLayoutVersion.LAYOUT_VERSION_2);
+
private final int versionCode;
private final List<String> releaseVersions;