cshuo opened a new issue, #19314:
URL: https://github.com/apache/hudi/issues/19314

   ### Problem
   
   `HoodieSourceReader` creates a new `HoodieSourceSplitReader` for each 
fetcher, but its supplier captures and reuses the same stateful 
`SplitReaderFunction` instance:
   
   
`hudi-flink-datasource/hudi-flink/src/main/java/org/apache/hudi/source/reader/HoodieSourceReader.java`
   
   This allows two consecutive split fetchers to access the same reader 
function during the fetcher handoff.
   
   ### Race condition
   
   The race can occur as follows:
   
   1. Flink detects that a fetcher is idle, calls `shutdown(true)`, and 
immediately removes it from the fetcher map. The old fetcher may not have 
completed its final shutdown yet.
   2. A new split arrives. Because the fetcher map is empty, 
`SingleThreadFetcherManager.addSplits()` creates and starts a new fetcher with 
a new `HoodieSourceSplitReader`.
   3. The old fetcher exits on its own thread and calls:
      `SplitReader.close() -> HoodieSourceSplitReader.close() -> 
SplitReaderFunction.close()`.
   4. Meanwhile, the new fetcher may already be using that same 
`SplitReaderFunction` instance in `readBatch()`.
   5. The old fetcher's asynchronous `close()` clears state belonging to the 
new fetcher, such as the cursor's `currentIterator`.
   
   The close delegation is in:
   
   
`hudi-flink-datasource/hudi-flink/src/main/java/org/apache/hudi/source/reader/HoodieSourceSplitReader.java`
   
   This may cause the active fetcher to observe an unexpectedly cleared 
iterator and fail or stop reading prematurely.
   
   ### Root cause
   
   Consecutive `HoodieSourceSplitReader` instances share one stateful 
`SplitReaderFunction`. Fetcher generations have overlapping lifetimes during 
idle shutdown, so ownership of that function is not exclusive.
   
   ### Why synchronization is insufficient
   
   Synchronizing `hasNext()`, `next()`, and `close()` can prevent the iterator 
from being cleared between `hasNext()` and `next()`, but it does not eliminate 
the lifecycle race. The old fetcher's `close()` can still run after the new 
fetcher has called `open()` and before its next `readBatch()`.
   
   ### Expected fix
   
   Each `HoodieSourceSplitReader` should own an independent 
`SplitReaderFunction` instance. Pass a serializable factory/supplier through 
the source construction path and instantiate a fresh function whenever Flink 
creates a split reader.
   
   The fix should cover both regular and CDC split reader functions and include 
a regression test proving that closing one split reader does not close or 
mutate the function owned by another split reader.
   


-- 
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