[Spark] List _change_data separately to speed up VACUUM listing - #14
Open
sezruby wants to merge 1 commit into
Open
[Spark] List _change_data separately to speed up VACUUM listing#14sezruby wants to merge 1 commit into
sezruby wants to merge 1 commit into
Conversation
VACUUM discovers files by shallow-listing the table root, distributing that first level across the cluster, and then recursing each first-level directory in a single task. The `_change_data` directory (Change Data Feed files) is one of those first-level directories and mirrors the table's partitioning, so it can hold a large fraction of the table's files. Recursing it inline leaves a single task listing that entire subtree while the rest of the cluster is idle -- often the tail of VACUUM on tables with CDF enabled. This lists `_change_data` as a separate listing branch: it is excluded from the main table listing and listed via its own `recursiveListDirs` call. Its sub-directories then get their own repartition + parallel recursion, and because the two branches are unioned Spark schedules them concurrently. The `_change_data` directory entry itself is emitted so empty-directory cleanup behaves exactly as before. The set of files considered by VACUUM is identical; only the listing parallelism differs. Gated by spark.databricks.delta.vacuum.listing.changeDataDirSeparately.enabled (default true); when the table has no `_change_data` directory the original single-call listing path is used unchanged. Tests: a listing test asserts the separate-branch decomposition returns exactly the same files and directories as the inline listing, and an end-to-end VACUUM test asserts the same untracked files (including one nested deep under `_change_data`) are removed whether the config is on or off. Relates to delta-io#2201 (improving VACUUM listing parallelism). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
VACUUM now lists the table's
_change_datadirectory as its own listingbranch instead of recursing into it inline. Gated by
spark.databricks.delta.vacuum.listing.changeDataDirSeparately.enabled(default
true).Relates to delta-io#2201 (improving VACUUM listing parallelism).
Why
VACUUM discovers files by:
_change_datais one of those first-level directories, and it mirrorsthe table's partitioning (or is a single large flat directory), so it can
hold a large fraction of the table's files. Recursing it inline leaves
one task listing that entire subtree while the rest of the cluster is
idle — typically the tail of VACUUM on tables with Change Data Feed
enabled. Simply deepening the initial listing does not help the common
case where
_change_datais a flat directory: there are nosub-directories to spread, so it is still a single
listStatus.What changed
VacuumCommand.getFilesFromFilesystemexcludes_change_datafrom themain listing (via the dir-name filter) and lists it through a separate
recursiveListDirscall. Its sub-directories then get their ownrepartition + parallel recursion, and because the two branches are
unioned Spark schedules them concurrently._change_datadirectory entry itself is emitted explicitly (thelisting helper emits the contents of its roots, not the roots), so
empty-directory cleanup behaves exactly as before.
_change_datadirectory, or the config is off, theoriginal single-call listing path is used unchanged.
recursiveListDirsis left as-is (no signature change).The set of files considered by VACUUM is identical; only the listing
parallelism differs.
Tests
listing _change_data as a separate branch yields the same files and directories— builds a table-shaped tree (data partitions + a_change_datadir that mirrors partitioning and nests deeper) andasserts the separate-branch decomposition returns exactly the same set
(paths + isDir) as the inline listing.
VACUUM removes the same untracked _change_data files whether listed separately or inline— end-to-end SQL VACUUM run with the config bothon and off, confirming the same untracked files (including one nested
deep under
_change_data) are removed and the tracked file retained.Both pass locally (
spark/testOnly ... DeltaVacuumSuite).🤖 Generated with Claude Code