Skip to content

perf(index): keep tables and timeline reloads out of index lookup tasks - #20095

Draft
yihua wants to merge 4 commits into
apache:masterfrom
yihua:perf-index-task-payload
Draft

yihua wants to merge 4 commits into
apache:masterfrom
yihua:perf-index-task-payload

Conversation

@yihua

@yihua yihua commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

Describe the issue this Pull Request addresses

closes #20091
part of #20064

Stacked on #20069 (HoodieEngineContext#broadcast), review that first.

Index lookups capture the whole HoodieTable (and the index with its write config) in their task functions. The simple and global simple indexes ship it in one task per base file to read record keys; HoodieIndexUtils#getLatestBaseFilesForAllPartitions runs one task per partition, each building a view; the simple bucket index reloads the timeline in tasks for every partition; global index partition updates fetch every merged slice of a partition per file group; the consistent bucket row writer builds two views per task.

Summary and Changelog

  • Simple and global simple lookups run static task functions that capture only the base file, base path, key generator and a broadcast storage configuration (HoodieKeyLocationFetchHandle#locations / #globalLocations).
  • getLatestBaseFilesForAllPartitions: with the metadata table, no tasks: the driver reads the table's view with one refresh-checked read, then loads the remaining partitions in batches bounded by path length, so the embedded timeline server stays synced to the write's timeline; without it, one task per partition as before.
  • HoodieSimpleBucketIndex#tagLocation uses a broadcast BucketLocationLoader built from the writer's latest completed commit and pending instants; each worker builds one view and caches each partition's bucket mapping. No timeline reload in tasks. Subclasses keep the per-partition path and their hooks.
  • getExistingRecords looks up only the requested file group's merged slice and parses the internal schema once.
  • The consistent bucket row writer reads pending clustering file groups from the timeline and builds at most one view per task.
  • Tests: task lineage checks that fail when a task carries a table, config, meta client or index, an executor timeline listing counter, a single file group lookup check and a view count check. Each fails on master. Two bloom tests and one bucket test now reload their meta client before looking up files written after the table was built.

Impact

Fewer bytes deserialized per index task and no per-task view, metadata table reader or timeline listing for these lookups; results are unchanged. Bucket index tagging follows the timeline snapshot the write started with instead of a per-task reload. For tables with an HFile base file format, the key-read file opens no longer go through HoodieWrapperFileSystem, so they lose the hoodie.filesystem.operation.retry.* retries.

Risk Level

medium. Touches tagging for the simple, global simple, bloom and simple bucket indexes. Covered by the new tests and the existing simple, global simple, bloom, global bloom, bucket, consistent bucket and global index partition update suites.

Documentation Update

none

Contributor's checklist

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

Add HoodieBroadcast and HoodieEngineContext#broadcast so engine-agnostic code can share read-only state with tasks. Spark ships the value's bytes as a broadcast deserialized once per executor; other engines hold the value in the handle.
Simple and global simple lookups run static task functions that capture only the base file, base path, key generator and a broadcast storage configuration. With the metadata table, the latest base files of all requested partitions come from one batched metadata lookup on the driver instead of one task per partition. The simple bucket index tags through a broadcast loader built from the writer's timeline, so tasks no longer reload the timeline. Global index partition updates look up one file group's merged slice, and the consistent bucket row writer builds at most one view per task.
@codecov-commenter

codecov-commenter commented Sep 27, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.17834% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 78.58%. Comparing base (463b615) to head (7898a7d).
⚠️ Report is 2 commits behind head on master.

Files with missing lines Patch % Lines
...che/hudi/index/bucket/HoodieSimpleBucketIndex.java 95.23% 2 Missing and 1 partial ⚠️
...n/java/org/apache/hudi/index/HoodieIndexUtils.java 97.22% 0 Missing and 1 partial ⚠️
...g/apache/hudi/io/HoodieKeyLocationFetchHandle.java 87.50% 1 Missing ⚠️
...a/org/apache/hudi/common/data/HoodieBroadcast.java 0.00% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##             master   #20095      +/-   ##
============================================
- Coverage     80.40%   78.58%   -1.82%     
+ Complexity    34863    34118     -745     
============================================
  Files          2546     2549       +3     
  Lines        142888   143012     +124     
  Branches      17373    17410      +37     
============================================
- Hits         114891   112390    -2501     
- Misses        20079    22595    +2516     
- Partials       7918     8027     +109     
Components Coverage Δ
hudi-common 82.91% <85.71%> (-1.05%) ⬇️
hudi-client 80.63% <96.66%> (-2.83%) ⬇️
hudi-flink 85.74% <ø> (+0.01%) ⬆️
hudi-spark-datasource 68.14% <ø> (-5.71%) ⬇️
hudi-utilities 78.19% <ø> (+0.01%) ⬆️
hudi-cli 70.05% <ø> (+0.18%) ⬆️
hudi-hadoop 69.91% <ø> (-1.07%) ⬇️
hudi-sync 76.02% <ø> (ø)
hudi-io 81.26% <ø> (-0.27%) ⬇️
hudi-timeline-service 83.14% <ø> (+0.08%) ⬆️
hudi-cloud 81.00% <ø> (ø)
hudi-kafka-connect 53.96% <ø> (ø)
Flag Coverage Δ
common-and-other-modules 52.34% <56.05%> (+0.01%) ⬆️
flink-integration-tests 49.43% <0.00%> (-0.05%) ⬇️
hadoop-mr-java-client 43.96% <37.30%> (-0.02%) ⬇️
integration-tests 13.51% <13.37%> (+0.06%) ⬆️
spark-client-hadoop-common 38.70% <85.35%> (+0.13%) ⬆️
spark-java-tests 41.14% <81.52%> (-11.29%) ⬇️
spark-scala-tests 46.97% <80.25%> (+0.03%) ⬆️
utilities 36.87% <71.97%> (+<0.01%) ⬆️

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

Files with missing lines Coverage Δ
...org/apache/hudi/index/HoodieGlobalSimpleIndex.java 88.46% <100.00%> (+1.50%) ⬆️
.../java/org/apache/hudi/index/HoodieSimpleIndex.java 94.73% <100.00%> (+0.45%) ⬆️
...e/hudi/client/common/HoodieSparkEngineContext.java 75.91% <100.00%> (+0.17%) ⬆️
...ava/org/apache/hudi/data/HoodieSparkBroadcast.java 100.00% <100.00%> (ø)
...stentBucketBulkInsertDataInternalWriterHelper.java 97.36% <100.00%> (+5.26%) ⬆️
.../apache/hudi/common/data/HoodieLocalBroadcast.java 100.00% <100.00%> (ø)
...apache/hudi/common/engine/HoodieEngineContext.java 85.71% <100.00%> (+1.09%) ⬆️
...n/java/org/apache/hudi/index/HoodieIndexUtils.java 92.61% <97.22%> (-0.14%) ⬇️
...g/apache/hudi/io/HoodieKeyLocationFetchHandle.java 95.00% <87.50%> (-5.00%) ⬇️
...a/org/apache/hudi/common/data/HoodieBroadcast.java 0.00% <0.00%> (ø)
... and 1 more

... and 255 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.

…rver syncs to the write's timeline

With the metadata table, the base files for index lookups came from a new view over a
fresh metadata reader, so tagging sent no request to the embedded timeline server. The
write handles then made the first requests, with the timeline the table carried at tagging
time. When a table service moved the timeline on in between (a compaction going inflight),
the server synced to the newer timeline and rejected the handles with a 400. Tagging and
the handles could also see different file groups.

The lookup now loads the partitions into the table's view in batches and reads the base
files from it, as the handles do.
…partitions and bound each load request by path length
@hudi-bot

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

This branch has not been deployed

No deployments
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.

Index lookup tasks ship the table and reload the timeline on executors

3 participants