linliu-code opened a new pull request, #659:
URL: https://github.com/apache/hudi-rs/pull/659

   **Stacked on #639–#658** — their commits appear here until they merge. 
**Review only the last commit.**
   
   ## What
   
   `hoodie.read.merge.engine = legacy | v2`, defaulting to `legacy`, dispatched 
inside the file group reader. **Nothing changes for anyone** — the default is 
the reader that has always served reads.
   
   ## Why land it now, before parity
   
   The ported reader has been unreferenced across sixteen changes. This is the 
first one that shows **how it is meant to be reached, and from where** — which 
is the part of the replacement worth reviewing as architecture rather than as 
sixteen file moves.
   
   ```
   read_file_slice_from_paths(..)
     ├─ is_metadata_table()   → existing reader   (always, regardless of 
setting)
     ├─ engine == legacy      → existing reader   (default)
     └─ engine == v2          → adapter → ported reader
   ```
   
   One seam. `Table`, DataFusion, the Python binding and the cxx bridge are 
untouched — the ported reader was given a matching operation set precisely so 
the switch could live here.
   
   ## Design points worth review
   
   **Filters and projection are not in the adapter.** Both engines' results run 
through the same `apply_eager_options`, so they cannot drift on what a filter 
means or which columns come back. That also closes three of the parity gaps for 
free.
   
   **Two refusals rather than fallbacks:**
   
   - A **metadata table** always uses the existing reader, whatever the setting 
says — its base files and log blocks are HFile, which the ported reader has no 
support for. This is permanent, not transitional (see #658, which separates 
that path).
   - A read with **no resolvable table schema** is refused. The existing reader 
derives its schema from the data; the ported one needs it up front, and 
guessing would be worse than saying so. The schema comes from 
`hoodie.table.create.schema`, which `OptionResolver` already loads, so this 
costs no extra I/O.
   
   **An unparseable engine name is an error, not a fallback.** `get_or_default` 
would have silently swallowed a typo — leaving a caller convinced they were 
exercising one engine while actually reading with the other. That is the one 
outcome a switch like this must not produce, so the value is read raw and 
parsed strictly.
   
   ## Not yet
   
   `v2` stays opt-in. It is not at parity — the gap list lives in the fixture 
tests (#657), and the outstanding items are tracked separately. This PR is the 
plumbing and the decision points, not the cutover.
   
   ## Tests
   
   Four, asserting what the rest of the suite cannot say because no other test 
names an engine:
   
   - the default is `legacy`
   - a metadata table stays on `legacy` even when `v2` is asked for
   - asking for `v2` actually selects it — without this the switch could be 
wired to nothing and everything would still pass
   - an unknown value errors
   
   Full workspace suite green (1113 lib + 79 table-read); build warning-free.
   
   🤖 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]

Reply via email to