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]

Reply via email to