linliu-code opened a new pull request, #703:
URL: https://github.com/apache/hudi-rs/pull/703
## Description
hudi-rs refused to read a merge-on-read table whose base file and log blocks
are HFile unless the table sat at a metadata-table path. The version two engine
reads such a table correctly — the refusals gated on **where the table lived**,
not on what the reader could do.
This was established before anything was changed, by building such a table
and reading it. The sharpest demonstration: the only difference between the
read that was refused and the read that succeeded was the directory the table
sat in. Identical bytes, identical `hoodie.properties`, identical reader.
The configuration is reachable rather than hypothetical. Java's
`HoodieFileWriterFactory.getFileWriterByFormat` dispatches `HFILE` by extension
to `newHFileFileWriter`, and `HoodieTableConfig.BASE_FILE_FORMAT` has a
`PARQUET` default with no valid-values restriction.
Three gates decided this, and **all three are needed** for the read to work
— fixing any subset leaves it broken at a different line, which is why they
move together:
| Site | Was | Now |
| --- | --- | --- |
| `table/validation.rs` | refused the format when the base path was not a
metadata-table path, before any reader existed | removed |
| `file_group/base_file/reader.rs` | the shared factory returned an error
for HFile | returns `HFileBaseFileReader` |
| `file_group/reader.rs` | diverted every HFile slice to file group reader
version 1 | removed; version 2 serves it |
Version 1 has no HFile base file reader and its log decoder refuses HFile
blocks outright, so that third fallback turned a readable slice into
`Unexpected HFile records in regular table log file`.
Two refusals are deliberately kept. Version 1's log-block refusal stays,
because that reader genuinely cannot decode an HFile block into Arrow — it is
simply no longer reached for these tables. The metadata-table refusal in
`reader_v2/adapter.rs` stays too, but its message claimed the engine had no
HFile support, which this change contradicts; it now gives the real reason,
that the metadata table's record key, merge rule and partition come from its
own configuration.
Removing the format gate also lost the only consumer of `base_file_path` in
`version_two_unsupported_reason`, so that parameter is gone and its call sites
updated.
**Known gap, filed rather than bundled:** schema resolution still has no
HFile arm (`schema/resolver.rs`), so an HFile table whose commit metadata
carries no schema reports "no file path found" — false, since a path was found.
This PR makes that reachable. The one-line arm does not compile: `get_schema`
lives on the concrete parquet and Lance readers, not on the `BaseFileReader`
trait, so `HFileBaseFileReader` needs its own accessor doing its own I/O.
Tracked separately.
## How are the changes test-covered
- [ ] N/A
- [x] Automated tests (unit and/or integration tests)
- [ ] Manual tests
- [ ] Details are described below
A new fixture, `crates/test/data/hfile_base_file_table`: a non-metadata MOR
table with an HFile base file and an HFile log block, shaped so that **the
failure modes look different from each other**.
| key | base fare / `ts` | log fare / `ts` | `COMMIT_TIME` → | `EVENT_TIME`
→ |
| --- | --- | --- | --- | --- |
| `uuid0001` | 11 / 5001 | — | 11 | 11 |
| `uuid0002` | 12 / 5002 | — | 12 | 12 |
| `uuid0003` | 13 / 5003 | 102 / **1000** | **102** | **13** |
| `uuid0004` | 14 / 5004 | 103 / **9000** | 103 | 103 |
| `uuid0005` | — | 104 / 5005 | 104 | 104 |
| `uuid0006` | — | 105 / 5006 | 105 | 105 |
The log block is always the later commit. `uuid0003` is the discriminator
between merge modes: commit-time takes the log's value, event-time keeps the
base's because the log's event time is older. `uuid0004` runs the other way, so
a read that ignored the log block entirely still fails. Values are asserted,
never a row count — dropping the log block returns four rows at 11–14, and
losing the base returns four rows from `uuid0003`.
Mutation-checked, every mutation with a positive control on the restored
tree:
| mutation | caught by |
| --- | --- |
| re-divert HFile to version 1 | the merge tests, with the old log-block
error |
| drop the log block from the read | values: `uuid0003` = 13 instead of 102 |
| read event-time as commit-time | `uuid0003` = 102 against expected 13 |
| flatten the fixture's event times so the modes converge | the mode tests |
| restore the format refusal, error and swallow arm together |
`an_hfile_base_file_is_not_refused_for_its_format` |
Five existing tests pinned the old refusals and were **inverted rather than
deleted**, so each now pins the opposite claim.
A fresh-agent correctness review ran before this PR was opened. It found no
case where removing the three refusals produces a panic, a silent wrong result,
or a lost guard — verified by building a complete table-version-6 HFile table
with a real timeline and reading it end-to-end through `Table`, and by probing
copy-on-write, read-optimized, streaming, layout version 1, and
`drop.partition.columns` paths. Its findings are fixed here, including one test
that could not fail: it asserted the *absence* of a retired error string, and
passed even with the pre-change refusal fully restored. It now asserts what the
failure is.
```
cargo test -p hudi-core --lib 1391
passed, 0 failed
cargo test -p hudi-core --lib --no-default-features 1371
passed, 0 failed
cargo test --workspace --all-targets --all-features 0
failing suites
cargo clippy -p hudi-core --all-targets -- -D warnings clean
cargo clippy -p hudi-core --lib --no-default-features -- -D warnings clean
cargo fmt --all -- --check clean
```
**Not covered, stated rather than implied:** partitioned HFile tables,
multiple log blocks in one log file, and a compacted slice. The fixture is one
non-partitioned single-slice table, and the removed fallback used to be those
shapes' safety net.
--
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]