linliu-code opened a new pull request, #672:
URL: https://github.com/apache/hudi-rs/pull/672
**Stacked on #639–#671** — review only the last commit. **Merge-on-read
reader only; the existing reader is untouched.**
## The bug
A table from version 9 on records how it merges in
`hoodie.record.merge.mode`. Older ones do not, and this reader guessed — from
`hoodie.table.record.merge.strategy`, a key **no Hudi table writes** (zero
occurrences across every fixture). It always fell through to a derivation that
returns `append_only` whenever meta fields are off or no ordering field is set.
`append_only` has no merge-mode counterpart, so the read was **refused**.
## What Hudi does
`HoodieTableConfig.inferMergingConfigsForPreV9Table` — three inputs, in
precedence order:
```
payload class or strategy id set?
DefaultHoodieRecordPayload | EventTimeAvroPayload → EVENT_TIME_ORDERING
OverwriteWithLatestAvroPayload → COMMIT_TIME_ORDERING
strategy eeb8d96f-… → EVENT_TIME ce9acb64-… → COMMIT_TIME
anything else → CUSTOM
(v8+: strategy id wins; before: payload class wins)
otherwise
ordering field set ? EVENT_TIME_ORDERING : COMMIT_TIME_ORDERING
```
**The inputs were always present.** The strategy ids in our fixtures match
Hudi's constants exactly (`eeb8d96f-…`, `ce9acb64-…`, and the payload-based
sentinel `00000000-…`), and 37 fixtures carry a payload class. This reader
consulted none of them.
I confirmed the same rule is what the engine integration applies: gluten's
`Hudi1xMergeConfigResolver.resolveMergeConfigs` delegates straight to
`inferMergingConfigsForPreV9Table`, gated on `tableVersion < NINE` — which is
why a v9 table passes through untouched.
## Two consequences worth naming
**Tables that were refused now read.** `v6_empty` and
`v6_simplekeygen_hivestyle_no_metafields` are the fixtures that hit the old
fallback; both now merge by commit time.
**A v6 `OverwriteWithLatestAvroPayload` table now merges by commit time, not
event time.** Its payload class says so, and it outranks the ordering-field
guess. That is a semantics change for those tables — and the correct one:
"overwrite with latest" means latest by commit, not by ordering field.
## Why `CUSTOM` is still refused
A table with a merger of its own is rejected rather than merged as if it had
none.
Gluten *does* remap one case — a Debezium payload becomes
`EVENT_TIME_ORDERING` so it can offload — **but only after injecting the delete
marker and, for MySQL, substituting the ordering field with the composite
`(_event_bin_file, _event_pos)` this reader can actually compare.** Those
configs are not persisted on the table. Inferring the same remap here would
read such a table without them and drop its deletes silently.
An engine that has done that work says so by setting
`hoodie.record.merge.mode` outright, which is read before any inference. That
is the right seam.
## Scope
**The existing reader is untouched**, per the constraint on this change. It
still derives its own strategy, so the two readers now disagree on these tables
— the merge-on-read one being correct. A differential comparison between them
still has to wait for the legacy path to be brought across.
## Tests
An 11-case matrix mirroring the cases Java's own inference is tested
against: the ordering-field fallback both ways, each built-in payload class,
each built-in strategy id, the payload-based sentinel, and the version-8
tie-break in both directions.
Plus: a real fixture that was refused before and now resolves to commit-time
ordering, and a table with its own merger still refused with a reason.
The two tests that asserted the old behavior are replaced — they encoded the
bug.
Full workspace green: 1208 lib + 79 table-read + 39 datafusion + 21 + 12.
Clippy clean in the changed file.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
--
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]