Skip to content

perf(flink): use a shared work-stealing split pool for Source V2 bounded reads - #19520

Merged
danny0405 merged 2 commits into
apache:masterfrom
ericyuan915:flink-bounded-shared-split-pool
Aug 7, 2026
Merged

perf(flink): use a shared work-stealing split pool for Source V2 bounded reads#19520
danny0405 merged 2 commits into
apache:masterfrom
ericyuan915:flink-bounded-shared-split-pool

Conversation

@ericyuan915

Copy link
Copy Markdown
Contributor

Describe the issue this Pull Request addresses

Closes #19516

Bounded (batch) reads in the Flink Source V2 inherit the streaming path's split provider, which pins every split to one subtask at discovery and never rebalances. DefaultHoodieSplitProvider keeps one queue per subtask and assigns on arrival, and getNext serves a reader only from its own queue, so a subtask that drew a heavier share keeps working while its peers sit idle. The assignment also balances split count, not bytes or records, so the imbalance is decided before any reading happens and cannot be recovered.

On a bounded backfill of one date partition of a COW table (~16.4K base files, parallelism 32, Flink 1.18), the 32 reader subtasks finished 78 minutes apart (fastest 125 min, slowest 203 min) and one subtask read alone for the last ~28 minutes. Results were correct; the loss was pure idle capacity.

Note that createEnumerator builds the provider before branching on streaming vs bounded, so the bounded path inherits the streaming provider structurally rather than by explicit choice.

Summary and Changelog

Bounded reads now serve splits from a single shared, work-stealing pool, so whichever reader finishes first takes the next split and all readers stay busy until the pool is drained. Streaming behaviour is unchanged.

  • GlobalHoodieSplitProvider (new) — a HoodieSplitProvider backed by one PriorityBlockingQueue ordered by the existing HoodieSourceSplitComparator (oldest commit first, the same ordering the per-subtask queues use). getNext(taskId, hostname) ignores both arguments. onUnassignedSplits (the addSplitsBack path) returns splits to the same pool.
  • HoodieSource.createEnumerator — the provider is now chosen on the streaming/bounded branch rather than before it: streaming keeps DefaultHoodieSplitProvider plus the existing assigners, bounded gets the shared pool. Restore then replays the checkpointed pending splits into whichever provider was chosen. The split assigner is only constructed on the streaming branch.

No enumerator change is required. With one shared pool, getNext returning empty already means "globally drained", so HoodieStaticSplitEnumerator's existing signalNoMoreSplits logic stays correct.

Why the affinity is load-bearing for streaming but not for bounded. DefaultHoodieSplitAssigner uses Flink's own KeyGroupRangeAssignment.assignKeyToParallelOperator(split.getFileId(), ...). For a continuous read that matters: a MOR file group accumulates log files across commits and the continuous enumerator keeps emitting new splits for the same file id, so pinning keeps successive splits of one file group on one reader; HoodieSplitBucketAssigner similarly aligns bucket id to subtask. A bounded read has none of that: exactly one split per file group, no cross-commit continuation, and no ordering relationship between splits.

That claim covers every mode createBatchHoodieSplits() routes to the static enumerator, not just the COW snapshot case that was measured:

Bounded mode Split builder One split per file group because
COW snapshot FileIndexReader.baseFileOnlyHoodieSourceSplits fsView.getLatestBaseFiles(par) yields one latest base file per file group
Read-optimized same builder as above
MOR snapshot FileIndexReader.buildHoodieSplitsreadFileSlice getLatestMergedFileSlicesBeforeOrOn yields one merged slice per file group
Bounded incremental IncrementalInputSplits.inputSplitsgetInputSplits slices also come from getLatestMergedFileSlicesBeforeOrOn, one split per slice
Bounded incremental CDC IncrementalInputSplits.getCdcInputSplits the extractor returns Map<HoodieFileGroupId, List<HoodieCDCFileSplit>>, so one split per file group with the file group's changes[] sorted by instant inside the split — cross-commit order is intra-split, never cross-split

TestHoodieSourceEnumeratorRouting asserts this invariant (distinct file ids) for each of those five modes rather than leaving it as prose, so a future change that starts emitting multiple splits per file group in a bounded mode fails the test.

I also could not find a Source V2 partitioning contract exposed to downstream operators that would make bucket/file-id affinity load-bearing for a bounded scan: HoodieTableSource.addFileDistributionStrategy is applied only to the V1 DataStream<MergeOnReadInputSplit> monitoring stream, never to HoodieSource.

Consistency with the V1 source and with this provider's own history. V1 bounded reads already use a shared pool — MOR/incremental/CDC via DefaultInputSplitAssigner, COW via the locality-aware LocatableInputSplitAssigner — pulling splits as readers finish rather than pinning them. And DefaultHoodieSplitProvider itself was a single shared queue before #18082, which introduced per-subtask assignment for streaming distribution parity and applied it to the bounded branch as well. This PR restores shared pulling for bounded only. Thanks @cshuo for both data points.

Tests

  • TestGlobalHoodieSplitProvider (new, 15 cases): work stealing across arbitrary subtask ids, a single subtask draining the whole pool, oldest-commit-first ordering regardless of requester, onUnassignedSplits returning a split that a different subtask claims, checkpoint state round-trip, isAvailable() completion, and a concurrent 8-thread drain of 500 splits asserting each split is served exactly once.
  • TestHoodieStaticSplitEnumerator (+3): work stealing at the enumerator level; no-more-splits fires only when the pool is globally drained; and the failure case @danny0405 asked for — addSplitsBack after another reader has already received NoMoreSplits, asserting the returned split lands in the shared pool and is claimed by a third subtask that has neither failed nor finished.
  • TestHoodieSourceEnumeratorRouting (new, 16 cases): parameterized over the five bounded modes above, asserting fresh creation and restore both produce HoodieStaticSplitEnumerator + GlobalHoodieSplitProvider; that restore replays exactly the checkpointed splits and does not re-run discovery; and, parameterized over the requesting subtask 0-3, that a restored pending split goes to whichever subtask asks (under pinning only the one subtask its file id hashes to could ever receive it). Streaming fresh and restore are asserted to still produce HoodieContinuousSplitEnumerator + DefaultHoodieSplitProvider.

Impact

Performance only for bounded Source V2 reads; no config, no API change, no change to checkpoint contents or format. Same table, partition, and parallelism as the run above, with only the split provider changed:

pinned (current) shared pool
Per-subtask finish spread 78 min (125–203 min) 0 min (all 32 at 166 min)
Splits per subtask 491–608 364–644
corr(splits taken, read rate) −0.37 +0.997
Wall clock 3.80 h 2.77 h

All 16,395 splits processed in both runs, 0 restarts.

Answering @danny0405's question on the intervals: wall clock is job submission to job FINISHED, so it includes resource allocation, split discovery, DAG deployment and teardown; reader minutes are per-subtask, first record to last record. That is the 228 vs 203 min gap in the pinned run (~25 min of setup); the shared run's 166 / 166 line up because its setup overlapped the read.

The correlation flip is the clearest signal: under a shared pool the split count becomes an output (faster readers pull more, everyone finishes together) instead of a hash-fixed input. The residual tail is then bounded by the duration of a single in-flight split rather than by accumulated imbalance — stealing cannot preempt a split already being read, so one pathologically large file group remains the only exposure.

Checkpoint size and restore semantics are unchanged: the enumerator still snapshots the same set of pending splits, in one queue instead of N. On restore a pending split may be picked up by a different subtask, which is safe precisely because bounded splits are independent.

Risk Level

low

Scoped to the non-streaming branch of HoodieSource.createEnumerator; streaming keeps DefaultHoodieSplitProvider and the existing assigners byte for byte. The enumerator, split serialization and checkpoint state are untouched. Restore is the one place this could regress quietly, since the provider used to be built before the streaming/bounded branch, so both fresh creation and restore are covered for every mode, including the failed-reader path after other readers have finished. Verified with the unit tests above plus the existing TestHoodieSource, TestDefaultHoodieSplitProvider, TestHoodieContinuousSplitEnumerator and TestHoodieEnumeratorStateSerializer suites, and the read.source-v2.enabled batch-read integration tests in ITTestHoodieDataSource.

Documentation Update

none — no new config and no user-facing behaviour change beyond the scheduling of bounded reads.

Contributor's checklist

  • Read through contributor's guide
  • Enough context is provided in the sections above
  • Adequate tests were added if applicable

@ericyuan915 ericyuan915 changed the title perf(flink): use a shared work-stealing split pool for Source V2 boun… perf(flink): use a shared work-stealing split pool for Source V2 bounded reads Aug 5, 2026

@hudi-agent hudi-agent left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ 🤖 This review was generated by an AI agent and may contain mistakes. Please verify any suggestions before applying.

Thanks for the contribution! This PR introduces a shared work-stealing split pool (GlobalHoodieSplitProvider) for bounded Flink Source V2 reads so readers stay busy until the pool drains, while leaving the streaming path on per-subtask assignment. I traced the threading model (PBQ makes the concurrent pendingSplitCount() gauge read safe), the fresh/restore branches in createEnumerator (no double-discovery, checkpoint state format unchanged), the work-stealing drain and signalNoMoreSplits logic, and the addSplitsBack recovery path — the last is actually more robust than the existing Default provider's re-pinning. The one-split-per-file-group safety invariant is enforced by the added routing tests across all bounded modes. No correctness issues found. A few style/readability suggestions in the inline comments. Please take a look, and this should be ready for a Hudi committer or PMC member to take it from here. A couple of minor naming and visibility nits in GlobalHoodieSplitProvider; the rest of the code is clean and well-documented.

cc @yihua

"Pending records is not supported in GlobalHoodieSplitProvider.");
}

private synchronized void completeAvailableFuturesIfNeeded() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 nit: the method name says Futures (plural) but there is only one availableFuture field and it completes exactly one future per call — could you rename it to completeAvailableFutureIfNeeded?

⚠️ AI-generated; verify before applying. React 👍/👎 to flag quality.

* while the coordinator thread assigns.
*/
public class GlobalHoodieSplitProvider implements HoodieSplitProvider {
public static final int INITIAL_POOL_CAPACITY = 20;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 nit: INITIAL_POOL_CAPACITY is public but it is only an internal queue-sizing detail with no meaningful contract for callers — would private (or at most package-private) be more appropriate here?

⚠️ AI-generated; verify before applying. React 👍/👎 to flag quality.

// Reading from earliest triggers a full table scan, which bypasses the CDC branch, so the
// CDC mode starts from the last completed commit instead.
conf.set(FlinkOptions.READ_START_COMMIT,
mode.cdcEnabled ? lastCompletionTime() : FlinkOptions.START_COMMIT_EARLIEST);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

COW_INCREMENTAL sets READ_START_COMMIT to earliest here, which makes IncrementalInputSplits.inputSplits() take its fullTableScan branch. As a result, this case does not exercise the non-full-scan bounded incremental path cited in the PR one-split-per-file-group safety argument. Could this use an actual completed commit (and, if needed, a bounded end commit) so that fullTableScan is false? A separate earliest case can remain if that fallback also needs coverage.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, you're right — earliest leaves the analyzer's startInstant empty (IncrementalQueryAnalyzer:205, isConsumingFromEarliest() is startInstant.isEmpty()), so fullTableScan was true and that parameter never reached the metadata-driven branch the safety argument cites. Fixed in 4d55875.

COW_INCREMENTAL now starts from a real completed commit, and I added COW_INCREMENTAL_FROM_EARLIEST so the full-scan fallback stays covered — as you suggested, both sides of the branch.

I also wanted the parameter to fail loudly rather than silently stop covering the branch again, so the modes that start from a real commit now write a last commit touching only par5/par6. The metadata-driven branch derives its read partitions from that commit's metadata alone, while a full table scan lists par1 through par6, so asserting the split partitions pins which branch actually produced them:

if (mode.incrementalStart == IncrementalStart.LAST_COMMIT) {
  assertEquals(new HashSet<>(Arrays.asList("par5", "par6")),
      splits.stream().map(HoodieSourceSplit::getPartitionPath).collect(Collectors.toSet()),
      "Mode " + mode + " should read only the partitions written by the start commit, "
          + "which is what distinguishes the incremental branch from a full table scan");
}

I verified the assertion actually bites by temporarily pointing the start commit back at earliest: COW_INCREMENTAL and COW_INCREMENTAL_CDC both fail with expected: <[par5, par6]> but was: <[par5, par6, par1, par2, par3, par4]>.

For the record, all three incremental shapes end at the same getInputSplits(fileSlices, ...), one split per slice, and both branches source their slices from getLatestMergedFileSlicesBeforeOrOn; the difference is only how the partition/file set is derived. So the one-split-per-file-group claim held either way, but the test now demonstrates it on both paths instead of asserting it on one and claiming it for the other.

18 routing cases green, and 135 tests across the touched source suites with checkstyle clean.

@github-actions github-actions Bot added the size:XL PR with lines of changes > 1000 label Aug 5, 2026
@codecov-commenter

codecov-commenter commented Aug 5, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.96970% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 76.61%. Comparing base (b88f235) to head (44bb694).

Files with missing lines Patch % Lines
...e/hudi/source/split/GlobalHoodieSplitProvider.java 96.15% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff            @@
##             master   #19520   +/-   ##
=========================================
  Coverage     76.60%   76.61%           
- Complexity    32238    32262   +24     
=========================================
  Files          2520     2521    +1     
  Lines        139052   139081   +29     
  Branches      16708    16710    +2     
=========================================
+ Hits         106527   106560   +33     
+ Misses        24913    24912    -1     
+ Partials       7612     7609    -3     
Components Coverage Δ
hudi-common 83.23% <ø> (+0.01%) ⬆️
hudi-client 81.97% <ø> (ø)
hudi-flink 84.00% <96.96%> (+0.01%) ⬆️
hudi-spark-datasource 70.61% <ø> (+<0.01%) ⬆️
hudi-utilities 73.67% <ø> (+0.02%) ⬆️
hudi-cli 15.32% <ø> (ø)
hudi-hadoop 63.49% <ø> (ø)
hudi-sync 70.92% <ø> (-0.03%) ⬇️
hudi-io 79.36% <ø> (-0.10%) ⬇️
hudi-timeline-service 83.44% <ø> (ø)
hudi-cloud 64.06% <ø> (ø)
hudi-kafka-connect 53.20% <ø> (ø)
Flag Coverage Δ
common-and-other-modules 49.85% <96.96%> (+0.01%) ⬆️
flink-integration-tests 48.79% <96.96%> (+0.02%) ⬆️
hadoop-mr-java-client 43.73% <ø> (-0.01%) ⬇️
integration-tests 13.57% <0.00%> (-0.01%) ⬇️
spark-client-hadoop-common 49.63% <ø> (+<0.01%) ⬆️
spark-java-tests 51.53% <ø> (+<0.01%) ⬆️
spark-scala-tests 45.98% <ø> (+<0.01%) ⬆️
utilities 36.59% <ø> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
...main/java/org/apache/hudi/source/HoodieSource.java 91.78% <100.00%> (+1.78%) ⬆️
...e/hudi/source/split/GlobalHoodieSplitProvider.java 96.15% <96.15%> (ø)

... and 22 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@danny0405
danny0405 enabled auto-merge (squash) August 6, 2026 00:36
@voonhous
voonhous disabled auto-merge August 6, 2026 03:23
@voonhous
voonhous enabled auto-merge (squash) August 6, 2026 03:23

@hudi-agent hudi-agent left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ 🤖 This review was generated by an AI agent and may contain mistakes. Please verify any suggestions before applying.

Thanks for the contribution! This PR adds a GlobalHoodieSplitProvider — a shared, work-stealing PriorityBlockingQueue-backed split pool for bounded (batch) Source V2 reads — and routes the enumerator so streaming keeps per-subtask affinity while bounded reads drain a single pool, eliminating the straggler tail. I traced the routing/restore logic in createEnumerator, verified the "one split per file group / no cross-commit continuation" safety invariant against IncrementalInputSplits.getInputSplits/getCdcInputSplits, and checked the coordinator-thread concurrency model and the addSplitsBack failover path; the design mirrors Flink's canonical bounded-source pattern and the tests exercise every bounded mode. No issues flagged from this automated pass — a Hudi committer or PMC member can take it from here for a final review.

cc @yihua

@danny0405

Copy link
Copy Markdown
Contributor

@ericyuan915 can you rebase with the latest master to make the CI pass.

…ded reads

Bounded reads inherit the streaming split provider, which pins every split
to one subtask at discovery and never rebalances, so a subtask that drew a
heavier share keeps working while its peers sit idle. On a bounded COW
backfill (~16.4K splits, parallelism 32) the readers finished 78 minutes
apart and the job took 3.80 h instead of 2.77 h.

The affinity pays for itself only in streaming, where a file group
accumulates log files across commits and successive splits of one file id
must stay on one reader. A bounded read has exactly one split per file
group, no cross-commit continuation and no ordering relationship between
splits, so any reader can read any split.

Add GlobalHoodieSplitProvider, a single shared pool ordered by the existing
HoodieSourceSplitComparator whose getNext ignores the subtask id, and select
it on the non-streaming branch of HoodieSource.createEnumerator. Streaming
keeps DefaultHoodieSplitProvider and the existing assigners. The provider is
now chosen on the streaming/bounded branch rather than before it, so restore
replays checkpointed splits into whichever provider was chosen. No enumerator
change is needed: with one pool, getNext returning empty already means
globally drained.

Closes apache#19516
…t just full scan

READ_START_COMMIT=earliest leaves the analyzer's startInstant empty, so
IncrementalInputSplits.inputSplits() took its fullTableScan branch and the
COW_INCREMENTAL parameter never reached the metadata-driven branch that the
one-split-per-file-group argument cites.

Split the parameter in two: COW_INCREMENTAL now starts from a real completed
commit so fullTableScan is false, and COW_INCREMENTAL_FROM_EARLIEST keeps the
full-scan fallback covered.

To make the branch observable, the modes that start from a real commit write a
last commit that only touches par5 and par6. The metadata-driven branch derives
its read partitions from that commit alone, while a full table scan lists par1
through par6, so asserting the split partitions pins which branch produced them.
auto-merge was automatically disabled August 7, 2026 06:13

Head branch was pushed to by a user without write access

@ericyuan915
ericyuan915 force-pushed the flink-bounded-shared-split-pool branch from 4d55875 to 44bb694 Compare August 7, 2026 06:13
@hudi-bot

hudi-bot commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

CI report:

Bot commands @hudi-bot supports the following commands:
  • @hudi-bot run azure re-run the last Azure build

@danny0405
danny0405 merged commit 2490309 into apache:master Aug 7, 2026
23 checks passed
voonhous pushed a commit that referenced this pull request Aug 7, 2026
…ded reads (#19520)

* perf(flink): use a shared work-stealing split pool for Source V2 bounded reads

Bounded reads inherit the streaming split provider, which pins every split
to one subtask at discovery and never rebalances, so a subtask that drew a
heavier share keeps working while its peers sit idle. On a bounded COW
backfill (~16.4K splits, parallelism 32) the readers finished 78 minutes
apart and the job took 3.80 h instead of 2.77 h.

The affinity pays for itself only in streaming, where a file group
accumulates log files across commits and successive splits of one file id
must stay on one reader. A bounded read has exactly one split per file
group, no cross-commit continuation and no ordering relationship between
splits, so any reader can read any split.

Add GlobalHoodieSplitProvider, a single shared pool ordered by the existing
HoodieSourceSplitComparator whose getNext ignores the subtask id, and select
it on the non-streaming branch of HoodieSource.createEnumerator. Streaming
keeps DefaultHoodieSplitProvider and the existing assigners. The provider is
now chosen on the streaming/bounded branch rather than before it, so restore
replays checkpointed splits into whichever provider was chosen. No enumerator
change is needed: with one pool, getNext returning empty already means
globally drained.

Closes #19516

* test(flink): cover the metadata-driven bounded incremental branch, not just full scan

READ_START_COMMIT=earliest leaves the analyzer's startInstant empty, so
IncrementalInputSplits.inputSplits() took its fullTableScan branch and the
COW_INCREMENTAL parameter never reached the metadata-driven branch that the
one-split-per-file-group argument cites.

Split the parameter in two: COW_INCREMENTAL now starts from a real completed
commit so fullTableScan is false, and COW_INCREMENTAL_FROM_EARLIEST keeps the
full-scan fallback covered.

To make the branch observable, the modes that start from a real commit write a
last commit that only touches par5 and par6. The metadata-driven branch derives
its read partitions from that commit alone, while a full table scan lists par1
through par6, so asserting the split partitions pins which branch produced them.

(cherry picked from commit 2490309)

Adaptations for release-1.2.1:
- HoodieSource keeps its LOG field. Master converted the class to Lombok @slf4j,
  so the diff's log.info collided with LOG.info. The restructure itself applies
  unchanged, and the per-file delta is identical to upstream.
- Two tests in the TestHoodieStaticSplitEnumerator conflict region,
  testConstructorWithNullMetricGroup and testHandleSourceEventWithUnknownEventThrows,
  are master context rather than additions of this commit, so they are not taken.
  The first would not compile here: it needs a MockSplitEnumeratorContext(boolean)
  constructor that this branch's mock does not have.
- Added a static import for assertFalse. The three new tests use it, but master
  already imported it for testConstructorWithNullMetricGroup above, so it arrived
  as context rather than as an added line. This is the only line in which the
  applied delta differs from upstream.
voonhous pushed a commit that referenced this pull request Aug 7, 2026
…ded reads (#19520)

* perf(flink): use a shared work-stealing split pool for Source V2 bounded reads

Bounded reads inherit the streaming split provider, which pins every split
to one subtask at discovery and never rebalances, so a subtask that drew a
heavier share keeps working while its peers sit idle. On a bounded COW
backfill (~16.4K splits, parallelism 32) the readers finished 78 minutes
apart and the job took 3.80 h instead of 2.77 h.

The affinity pays for itself only in streaming, where a file group
accumulates log files across commits and successive splits of one file id
must stay on one reader. A bounded read has exactly one split per file
group, no cross-commit continuation and no ordering relationship between
splits, so any reader can read any split.

Add GlobalHoodieSplitProvider, a single shared pool ordered by the existing
HoodieSourceSplitComparator whose getNext ignores the subtask id, and select
it on the non-streaming branch of HoodieSource.createEnumerator. Streaming
keeps DefaultHoodieSplitProvider and the existing assigners. The provider is
now chosen on the streaming/bounded branch rather than before it, so restore
replays checkpointed splits into whichever provider was chosen. No enumerator
change is needed: with one pool, getNext returning empty already means
globally drained.

Closes #19516

* test(flink): cover the metadata-driven bounded incremental branch, not just full scan

READ_START_COMMIT=earliest leaves the analyzer's startInstant empty, so
IncrementalInputSplits.inputSplits() took its fullTableScan branch and the
COW_INCREMENTAL parameter never reached the metadata-driven branch that the
one-split-per-file-group argument cites.

Split the parameter in two: COW_INCREMENTAL now starts from a real completed
commit so fullTableScan is false, and COW_INCREMENTAL_FROM_EARLIEST keeps the
full-scan fallback covered.

To make the branch observable, the modes that start from a real commit write a
last commit that only touches par5 and par6. The metadata-driven branch derives
its read partitions from that commit alone, while a full table scan lists par1
through par6, so asserting the split partitions pins which branch produced them.

(cherry picked from commit 2490309)

Adaptations for release-1.2.1:
- HoodieSource keeps its LOG field. Master converted the class to Lombok @slf4j,
  so the diff's log.info collided with LOG.info. The restructure itself applies
  unchanged, and the per-file delta is identical to upstream.
- Two tests in the TestHoodieStaticSplitEnumerator conflict region,
  testConstructorWithNullMetricGroup and testHandleSourceEventWithUnknownEventThrows,
  are master context rather than additions of this commit, so they are not taken.
  The first would not compile here: it needs a MockSplitEnumeratorContext(boolean)
  constructor that this branch's mock does not have.
- Added a static import for assertFalse. The three new tests use it, but master
  already imported it for testConstructorWithNullMetricGroup above, so it arrived
  as context rather than as an added line. This is the only line in which the
  applied delta differs from upstream.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL PR with lines of changes > 1000

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Flink] Source V2: use a shared work-stealing split pool for bounded reads

5 participants