Skip to content

[GLUTEN][VL] Use authoritative TahoeFileIndex table root for Delta deletion vectors#12612

Open
iemejia wants to merge 3 commits into
apache:mainfrom
iemejia:gluten-delta-tablepath-from-fileindex
Open

[GLUTEN][VL] Use authoritative TahoeFileIndex table root for Delta deletion vectors#12612
iemejia wants to merge 3 commits into
apache:mainfrom
iemejia:gluten-delta-tablepath-from-fileindex

Conversation

@iemejia

@iemejia iemejia commented Jul 23, 2026

Copy link
Copy Markdown
Member

What changes are proposed in this pull request?

(Note: apache/gluten has no master branch, so this PR targets the default branch main.)

This is a follow-up to #12390 that makes native Delta deletion-vector (DV) materialization both correct and cheaper by sourcing the Delta table root from the authoritative place instead of inferring it.

Background

Delta DV descriptors reference the on-disk bitmap using a table-root-relative UUID path. To read those bitmaps during planning, DeltaDeletionVectorScanInfo.normalize needs the Delta table root. Previously the root was inferred from each data file path via a heuristic resolveTablePath:

  1. take the data file's parent directory,
  2. walk up one level per partition column,
  3. probe the filesystem for a _delta_log directory,
  4. if that failed, keep walking parents probing _delta_log at each level,
  5. and custom-unescape %-encoded path characters along the way.

This is fragile (it depends on file layout and partition depth, and can resolve the wrong root for non-trivial paths) and it performs at least one FileSystem.exists("_delta_log") call per normalize invocation.

This change

  • DeltaScanTransformer.getSplitInfosFromPartitions now reads the table root directly from relation.location when it is a TahoeFileIndex (which also covers PreparedDeltaFileIndex and the other Tahoe subclasses used for time travel, path-based reads, DML, and CDC). TahoeFileIndex.path is the authoritative Delta table root.
  • That root is threaded into DeltaDeletionVectorScanInfo.normalize(partitionFiles, tablePath) and extract(...) across all Delta profiles (2.3 / 2.4 / 3.3 / 4.0).
  • The heuristic resolveTablePath, isDeltaTablePath (the _delta_log filesystem probe), and the manual unescapePathName helper are removed.
  • Non-Tahoe, format-only scans keep the generic split representation unchanged. Delta does not attach per-file DV metadata to such scans, so this is safe.
  • The DeltaPlanningBenchmark is updated to the explicit table-root API.

Why this is an improvement

  • Correctness: the table root now comes from Delta itself rather than being guessed from partition nesting and filesystem probing. This removes a class of latent mis-resolution bugs for partitioned tables and tables at non-standard paths.
  • Performance (planning): one filesystem existence probe per normalize call is eliminated. On local storage this is a small, consistent win; on remote object stores (S3/ABFS/HDFS) an exists() is a network round-trip per DV split, so the saving is proportionally larger there — consistent with the remote-storage motivation of the parent tracking issue [VL] Optimize Delta Lake Deletion Vector processing on remote storage #12399.

Test hardening

The DV unit tests were strengthened so they actually prove the supplied root is used: the synthetic PartitionedFile now points at an unrelated directory while the real table root is supplied separately, and the tests require a table-root-relative UUID (storageType == "u") DV. The native partitioned-table integration test now asserts that the DELETE really produced an on-disk DV before validating query results, guarding the removal of the old partition-count walk-up.

How was this patch tested?

  • Scala formatting via ./dev/format-scala-code.sh (JDK 17).
  • Compilation across Delta 2.3 (compat), Velox Delta 3.3 / Spark 3.5, and Velox Delta 4.0 / Spark 4.0, including backend test sources.
  • DeltaDeletionVectorScanInfoSuite on Delta 3.3 and Delta 4.0: 4/4 tests pass on each.
  • git diff --check clean.
  • DeltaPlanningBenchmark (normalize, 100 DV files x 10k rows, 200 timed iters, alternating fresh JVMs) comparing current main vs main + this change: median 61.40 µs/file vs 61.91 µs/file (~0.8% faster, ~51 µs saved per 100-file call) on local storage, with every run of the change faster than every baseline run. Larger gains are expected on remote filesystems where the removed exists() probe is a network round-trip.

Was this patch authored or co-authored using generative AI tooling?

Generated-by: OpenCode github-copilot/gpt-5.6-sol

@github-actions

Copy link
Copy Markdown

Run Gluten Clickhouse CI on x86

Copilot AI 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.

Pull request overview

This PR improves native Delta Lake deletion-vector (DV) materialization correctness and planning efficiency by sourcing the Delta table root from Delta’s authoritative TahoeFileIndex.path rather than inferring it from data-file paths.

Changes:

  • Read the Delta table root from relation.location when it is a TahoeFileIndex, and thread that root into DV normalization.
  • Update DeltaDeletionVectorScanInfo.normalize/extract across Delta profiles (2.3 / 2.4 / 3.3 / 4.0) to take an explicit tablePath: Path, and remove the heuristic table-path resolution (partition-walk + _delta_log exists probe + manual unescape).
  • Harden tests/benchmarks to validate the supplied table root is actually used, and add a partitioned-table DV integration assertion.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated no comments.

Show a summary per file
File Description
gluten-delta/src/main/scala/org/apache/gluten/execution/DeltaScanTransformer.scala Uses TahoeFileIndex.path as the authoritative table root and passes it into DV normalization only for Tahoe-backed Delta scans.
gluten-delta/src-delta40/main/scala/org/apache/gluten/delta/DeltaDeletionVectorScanInfo.scala Switches DV normalization/extraction to require an explicit tablePath and removes heuristic root resolution helpers.
gluten-delta/src-delta33/main/scala/org/apache/gluten/delta/DeltaDeletionVectorScanInfo.scala Same explicit-root API and heuristic-removal as delta40 profile.
gluten-delta/src-delta24/main/scala/org/apache/gluten/delta/DeltaDeletionVectorScanInfo.scala Updates API signature to accept tablePath (no-op behavior remains for pre-3.3).
gluten-delta/src-delta23/main/scala/org/apache/gluten/delta/DeltaDeletionVectorScanInfo.scala Updates API signature to accept tablePath (no-op behavior remains for pre-3.3).
gluten-delta/src/test/scala/org/apache/gluten/execution/DeltaSuite.scala Adds an integration test ensuring partitioned-table DELETE produces UUID-based DVs and validates native scan presence where applicable.
backends-velox/src-delta40/test/scala/org/apache/gluten/delta/DeltaDeletionVectorScanInfoSuite.scala Updates DV tests for new extract signature and adds a test proving the supplied table root is used for DV materialization.
backends-velox/src-delta33/test/scala/org/apache/gluten/delta/DeltaDeletionVectorScanInfoSuite.scala Same as delta40 test updates/hardening.
backends-velox/src-delta33/test/scala/org/apache/spark/sql/execution/benchmark/DeltaPlanningBenchmark.scala Updates benchmark to use the explicit table-root API for normalize().

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

iemejia added 3 commits July 24, 2026 07:04
…ization

DeltaScanTransformer already knows the Delta table root via
relation.location (a TahoeFileIndex, which PreparedDeltaFileIndex also
extends). Thread that path into DeltaDeletionVectorScanInfo.normalize so
it no longer re-derives the root from a file path via _delta_log
existence probing -- one FileSystem.exists() (an HTTP HEAD on object
stores) per partition.

normalize gains an optional tablePath parameter; when absent it falls
back to the previous resolveTablePath heuristic, so non-TahoeFileIndex
locations (e.g. DeltaParquetFileFormat scans without a Tahoe index) and
the public single-file extract entry point are unchanged.

Add a test to DeltaDeletionVectorScanInfoSuite (delta33 and delta40)
asserting the supplied-path and derived-path branches materialize an
identical DV payload.
…blePath fallback

Now that DeltaScanTransformer passes the table root from
TahoeFileIndex.path, make it the single source of truth for DV
materialization and remove the previous file-path-derivation fallback.

- DeltaDeletionVectorScanInfo.normalize takes a required tablePath: Path
  (no Option, no fallback); partitionColumnCount is dropped since only
  the walk-up used it.
- Delete resolveTablePath / isDeltaTablePath / unescapePathName and their
  per-partition _delta_log FileSystem.exists() probing.
- DeltaScanTransformer materializes DVs only when relation.location is a
  TahoeFileIndex (which also covers PreparedDeltaFileIndex); other
  locations carry no Delta DV metadata and keep the generic split.
- Update the public single-file extract(spark, file, tablePath), the
  delta23/24 stubs, the benchmark, and the suites accordingly.

Net ~160 fewer lines. The Hadoop-conf caching and raw on-disk DV byte
reading optimizations are retained.
@iemejia
iemejia force-pushed the gluten-delta-tablepath-from-fileindex branch from c5795ce to 10988b1 Compare July 24, 2026 05:04
@github-actions

Copy link
Copy Markdown

Run Gluten Clickhouse CI on x86

@iemejia

iemejia commented Jul 24, 2026

Copy link
Copy Markdown
Member Author

The failing build-fast-build-test check is unrelated to this PR — it timed out pulling its image from Docker Hub, before any code was built. A transient infra flake; just needs a re-run. All build/test jobs are green.

PTAL when you get a chance, thanks!

@iemejia

iemejia commented Jul 24, 2026

Copy link
Copy Markdown
Member Author

The spark-test-spark41 failure is also unrelated to this PR. It is a native SIGSEGV in libgluten.so during the Spark ScriptTransformation tests (gluten-ut-spark41 module), not the Delta path. This PR is Scala-only with no native changes, and the module containing the Delta tests (backends-velox) passed.

Both failing jobs are environment/native flakes and just need a re-run. PTAL, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants