Skip to content

feat: Clean up deep storage after index parallel merge finishes #19187

Merged
GWphua merged 29 commits into
apache:masterfrom
GWphua:clean-up-deepstore
Mar 30, 2026
Merged

feat: Clean up deep storage after index parallel merge finishes #19187
GWphua merged 29 commits into
apache:masterfrom
GWphua:clean-up-deepstore

Conversation

@GWphua

@GWphua GWphua commented Mar 20, 2026

Copy link
Copy Markdown
Contributor

Fixes #19163

Description

In the context of multi-phase index_parallel tasks, intermediary files created onto deep storage are not being cleaned up.

Fixed the issue by triggering deepstore intermediary-data cleanup from the supervisor task after the merge in phase 2 completes.

This fix only works for HDFS.

Release note

Introduced a mechanism to automatically clean up intermediary files on HDFS Storage.


Key changed/added classes in this PR
  • ParallelIndexSupervisorTask

This PR has:

  • been self-reviewed.
  • added documentation for new or modified features or behaviors.
  • a release note entry in the PR description.
  • added Javadocs for most classes and all non-trivial methods. Linked related entities via Javadoc links.
  • added or updated version, license, or notice information in licenses.yaml
  • added comments explaining the "why" and the intent of the code wherever would not be obvious for an unfamiliar reader.
  • added unit tests or modified existing tests to cover new code paths, ensuring the threshold for code coverage is met.
  • added integration tests.
  • been tested in a test Druid cluster.

* may be null or empty if phase 1 produced no output.
*/
@VisibleForTesting
static void cleanupDeepStorageShuffleData(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

is the dir deleted?

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.

Depends on the implementation of the DataSegmentKiller.

From what I see, all file storage implementations like LocalDataSegmentKiller, HdfsDataSegmentKiller and AzureDataSegmentKiller will remove the dir if it is empty.

@GWphua GWphua Mar 23, 2026

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.

I did a test on HDFS. Here's some findings:

  1. The HDFS shuffle-data are stored in somewhere like the following:
segments/shuffle-data/<taskId>/<startInterval>/<endInterval>/<partition>/<PartialIndexGeneratorTaskId>/0_index.zip
  1. Current implementation of kill in HdfsDataSegmentKiller hard-codes removal depth of 2 to 3, meaning we will still see EMPTY directories of the following after all segments are killed:
-- Before --
segments/shuffle-data/<taskId>/<startInterval>/<endInterval>/<partition>/<PartialIndexGeneratorTaskId>/0_index.zip

-- After -- 
segments/shuffle-data/<taskId>/<startInterval>/<endInterval> (Deleted 2 layers up)
  1. I will add a new method in DataSegmentKiller interface solely for handling intermediary tasks, and implementations will default to the kill method. Users using other storage forms are welcome to implement their own methods.

@GWphua GWphua changed the title Clean up deep storage after index parallel merge finishes feat: Clean up deep storage after index parallel merge finishes Mar 23, 2026
@GWphua

GWphua commented Mar 24, 2026

Copy link
Copy Markdown
Contributor Author

Latest commit tested and works in cluster with HDFS implementation.

Comment thread docs/configuration/index.md Outdated
Comment thread processing/src/main/java/org/apache/druid/segment/loading/DataSegmentKiller.java Outdated
@GWphua

GWphua commented Mar 25, 2026

Copy link
Copy Markdown
Contributor Author

@FrankChen021

Thanks for the review, I have made the appropriate changes.

@FrankChen021
FrankChen021 requested a review from Copilot March 25, 2026 14:37

@FrankChen021 FrankChen021 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM.

@FrankChen021

Copy link
Copy Markdown
Member

Also requested review from copilot to see if there's anything I missed

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 addresses leaked deep-storage intermediary (“shuffle-data”) artifacts produced by multi-phase index_parallel ingestion by adding a best-effort recursive delete from the supervisor task’s cleanup path, with support currently implemented for HDFS.

Changes:

  • Added DataSegmentKiller#killRecursively(relativePath) (default no-op) and implemented delegation in OmniDataSegmentKiller.
  • Implemented recursive directory deletion in HdfsDataSegmentKiller and invoked it from ParallelIndexSupervisorTask#cleanUp for shuffle-data/<supervisorTaskId>.
  • Added/updated unit tests and updated documentation to reflect HDFS-only automated cleanup.

Reviewed changes

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

Show a summary per file
File Description
processing/src/main/java/org/apache/druid/segment/loading/DataSegmentKiller.java Adds killRecursively API (default no-op) for deep-storage prefix cleanup.
server/src/main/java/org/apache/druid/segment/loading/OmniDataSegmentKiller.java Delegates killRecursively to all registered killers and aggregates IOExceptions.
server/src/test/java/org/apache/druid/segment/loading/OmniDataSegmentKillerTest.java Verifies killRecursively delegation behavior.
indexing-service/src/main/java/org/apache/druid/indexing/worker/shuffle/DeepStorageIntermediaryDataManager.java Adds helper to compute the shuffle-data/<supervisorTaskId> prefix and clarifies cleanup responsibility.
indexing-service/src/main/java/org/apache/druid/indexing/common/task/batch/parallel/ParallelIndexSupervisorTask.java Calls deep-storage recursive cleanup during supervisor cleanUp, swallowing IOExceptions.
indexing-service/src/test/java/org/apache/druid/indexing/common/task/batch/parallel/ParallelIndexSupervisorTaskTest.java Adds tests around cleanup invoking killRecursively and handling failures.
extensions-core/hdfs-storage/src/main/java/org/apache/druid/storage/hdfs/HdfsDataSegmentKiller.java Implements killRecursively with path validation and recursive HDFS delete.
extensions-core/hdfs-storage/src/test/java/org/apache/druid/storage/hdfs/HdfsDataSegmentKillerTest.java Adds tests for killRecursively, including validation and colon normalization.
docs/configuration/index.md Updates config docs to state automated shuffle-data cleanup is supported for HDFS deep storage.

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

Comment thread docs/configuration/index.md Outdated
@jtuglu1

jtuglu1 commented Mar 26, 2026

Copy link
Copy Markdown
Contributor

This fix only works for HDFS.

Is there a reason we cannot extend to generic storage? Does the killRecursively need to be implemented on the storage type for this to be supported in other storage backends?

Also, is this limited to index_parallel? What about compaction, etc.

@GWphua

GWphua commented Mar 26, 2026

Copy link
Copy Markdown
Contributor Author

We are only using HDFS as deep store for our Druid clusters. Hence, I can only verify the behaviour for HDFS-based storages.

For other storages, creating a new PR to implement killRecursively will help to solve this issue.

Also, is this limited to index_parallel? What about compaction, etc.

This problem is only limited to multi-phase index_parallel tasks.

@jtuglu1
jtuglu1 requested review from jtuglu1 March 26, 2026 23:49
@jtuglu1

jtuglu1 commented Mar 26, 2026

Copy link
Copy Markdown
Contributor

We are only using HDFS as deep store for our Druid clusters. Hence, I can only verify the behaviour for HDFS-based storages.

For other storages, creating a new PR to implement killRecursively will help to solve this issue.

Also, is this limited to index_parallel? What about compaction, etc.

This problem is only limited to multi-phase index_parallel tasks.

We are only using HDFS as deep store for our Druid clusters. Hence, I can only verify the behaviour for HDFS-based storages.

For other storages, creating a new PR to implement killRecursively will help to solve this issue.

Also, is this limited to index_parallel? What about compaction, etc.

This problem is only limited to multi-phase index_parallel tasks.

I believe I have seen this also with compaction tasks which perform shuffle for perfect rollup.

@GWphua

GWphua commented Mar 27, 2026

Copy link
Copy Markdown
Contributor Author

For native compaction task: tasks will also create shuffle directories. If you look at how ParallelIndexSupervisorTask#cleanUp works, it will try to clean up the shuffle directory before the isCompactionTask check.

@GWphua
GWphua merged commit 3d1e0d0 into apache:master Mar 30, 2026
63 of 64 checks passed
@github-actions github-actions Bot added this to the 37.0.0 milestone Mar 30, 2026
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.

Parallel indexing with deepstore intermediary data does not clean up shuffle-data in deep storage

4 participants