wombatu-kun opened a new issue, #20347:
URL: https://github.com/apache/hudi/issues/20347
### Bug Description
**What happened:**
Since 1.1.0 a table can order records on several fields
(`hoodie.table.ordering.fields=ts,seq`, #13526). Below version 9 a table
records its ordering field under `hoodie.table.precombine.field`, which Hudi
1.0.x (table version 8) and 0.x (version 6) read as a single field name. The 9
to 8 downgrade (`NineToEightDowngradeHandler`) copies the ordering fields into
that key as they are and removes `hoodie.table.ordering.fields`, so after a
downgrade those releases look for one field literally named `ts,seq`:
- Hudi 1.0.2 Spark writes take the precombine field from the table config
and read it with `HoodieAvroUtils.getNestedFieldVal(record, "ts,seq", false,
...)` in `HoodieCreateRecordUtils`, which throws for a missing field. Passing
any other precombine field fails `HoodieWriterUtils.validateTableConfig`
instead.
- The Hudi 1.0.2 file group reader adds `ts,seq` as a mandatory merge field
in `FileGroupReaderSchemaHandler` and fails MOR merges with `Field: ts,seq does
not exist in the table schema` once there are log files.
The downgrade reports success but leaves a table that the release it targets
cannot upsert into.
**What you expected:**
Hudi 1.0.x and 0.x cannot read several ordering fields, so the downgrade
refuses such a table with a clear message, before it rolls back, compacts or
downgrades the metadata table. `MySqlDebeziumAvroPayload` tables, which order
on `_event_bin_file,_event_pos` since version 9 and go back to their single
`_event_seq` on a downgrade, keep downgrading.
**Steps to reproduce:**
1. Take a table at version 9 or above whose `hoodie.table.ordering.fields`
lists several fields, for example `ts,name`.
2. Downgrade it below version 9, for example with `call
downgrade_table(table => 't', to_version => 'EIGHT')`.
3. `.hoodie/hoodie.properties` now holds `hoodie.table.version=8` and
`hoodie.table.precombine.field=ts,name`, and no `hoodie.table.ordering.fields`.
Loading it into the `HoodieTableConfig` of Hudi 1.0.2 gives
`getPreCombineField() = ts,name`. A downgrade to version 6 gives the same in
Hudi 0.15.0.
Reproducing tests, which fail on master:
```java
// TestNineToEightDowngradeHandler (hudi-client-common)
@Test
void testDowngradeRefusesSeveralOrderingFields() {
try (MockedStatic<UpgradeDowngradeUtils> utilities =
Mockito.mockStatic(UpgradeDowngradeUtils.class)) {
when(tableConfig.getOrderingFieldsStr()).thenReturn(Option.of("ts,seq"));
HoodieUpgradeDowngradeException exception =
assertThrows(HoodieUpgradeDowngradeException.class,
() -> handler.downgrade(config, context, "anyInstant",
upgradeDowngradeHelper));
assertEquals("Cannot downgrade to table version 8:
hoodie.table.ordering.fields=ts,seq orders records on several fields, "
+ "which Hudi 1.0.x and 0.x cannot read. Below version 9 the
ordering field is recorded under "
+ "hoodie.table.precombine.field, which they take as a single field
name. "
+ "Keep the table at version 9 or above, or recreate it with a
single ordering field.", exception.getMessage());
// refused before any index partition is dropped
utilities.verifyNoInteractions();
}
}
// TestUpgradeDowngrade (hudi-spark), on the checked-in version 9 MOR fixture
@ParameterizedTest
@EnumSource(value = HoodieTableVersion.class, names = {"EIGHT", "SIX"})
public void
testDowngradeBelowNineRefusesSeveralOrderingFields(HoodieTableVersion
toVersion) throws Exception {
HoodieTableMetaClient fixtureMetaClient =
loadFixtureTable(HoodieTableVersion.NINE, "-mor");
Properties severalOrderingFields = new Properties();
severalOrderingFields.setProperty(HoodieTableConfig.ORDERING_FIELDS.key(),
"ts,name");
HoodieTableConfig.update(fixtureMetaClient.getStorage(),
fixtureMetaClient.getMetaPath(), severalOrderingFields);
HoodieTableMetaClient originalMetaClient =
HoodieTableMetaClient.reload(fixtureMetaClient);
List<HoodieInstant> originalInstants =
originalMetaClient.getActiveTimeline().getInstants();
validateLogFilesCount(originalMetaClient, "downgrade", true);
HoodieWriteConfig config = createWriteConfig(originalMetaClient, true);
HoodieUpgradeDowngradeException exception =
assertThrows(HoodieUpgradeDowngradeException.class,
() -> new UpgradeDowngrade(originalMetaClient, config, context(),
SparkUpgradeDowngradeHelper.getInstance()).run(toVersion, null));
// ... asserts the message, then that the data and metadata tables are
still at version 9 with the same
// ordering fields, no precombine key, the same active timeline and their
log files
}
```
### Environment
**Hudi version:** master (1.3.0-SNAPSHOT), and every release since 1.1.0
**Query engine:** any path that downgrades a table (Spark `downgrade_table`
procedure, Hudi CLI `downgrade table`)
**Relevant configs:** `hoodie.table.ordering.fields` with several fields
### Logs and Stack Trace
The reproducing tests on master (the hudi-spark test fails for both target
versions):
```
[ERROR] Run 1:
TestNineToEightDowngradeHandler.testDowngradeRefusesSeveralOrderingFields:260
Expected org.apache.hudi.exception.HoodieUpgradeDowngradeException to be
thrown, but nothing was thrown.
[ERROR] Run 1:
TestUpgradeDowngrade.testDowngradeBelowNineRefusesSeveralOrderingFields:409
Expected org.apache.hudi.exception.HoodieUpgradeDowngradeException to be
thrown, but nothing was thrown.
```
`hoodie.properties` written by the downgrade on master (the version 9 MOR
fixture with `hoodie.table.ordering.fields=ts,name`), loaded into the
`HoodieTableConfig` of the released readers:
```
== downgrade to version 8
hoodie.compaction.payload.class=org.apache.hudi.common.model.DefaultHoodieRecordPayload
hoodie.record.merge.mode=EVENT_TIME_ORDERING
hoodie.table.precombine.field=ts,name
hoodie.table.version=8
== downgrade to version 6
hoodie.compaction.payload.class=org.apache.hudi.common.model.DefaultHoodieRecordPayload
hoodie.table.precombine.field=ts,name
hoodie.table.version=6
== Hudi 1.0.2 (table version 8 reader)
master-downgraded/v8/hoodie.properties -> hoodie.table.version=8,
getPreCombineField()=ts,name
== Hudi 0.15.0 (table version 6 reader)
master-downgraded/v6/hoodie.properties -> hoodie.table.version=6,
getPreCombineField()=ts,name
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]