Skip to content

Compaction: Fetch segments one at a time on main task; skip when possible. - #13280

Merged
abhishekagarwal87 merged 7 commits into
apache:masterfrom
gianm:compact-dont-always-fetch
Nov 7, 2022
Merged

abhishekagarwal87 merged 7 commits into
apache:masterfrom
gianm:compact-dont-always-fetch

Conversation

@gianm

@gianm gianm commented Oct 28, 2022

Copy link
Copy Markdown
Contributor

Compact tasks include the ability to fetch existing segments and determine
reasonable defaults for granularitySpec, dimensionsSpec, and metricsSpec.
This is a useful feature that makes compact tasks work well even when the
user running the compaction does not have a clear idea of what they want
the compacted segments to be like.

However, this comes at a cost: it takes time, and disk space, to do all
of these fetches. This patch improves the situation in two ways:

  1. When segments do need to be fetched, download them one at a time and
    delete them when we're done. This still takes time, but minimizes the
    required disk space.

  2. Don't fetch segments on the main compact task when they aren't needed.
    If the user provides a full granularitySpec, dimensionsSpec, and
    metricsSpec, we can skip it.

…ible.

Compact tasks include the ability to fetch existing segments and determine
reasonable defaults for granularitySpec, dimensionsSpec, and metricsSpec.
This is a useful feature that makes compact tasks work well even when the
user running the compaction does not have a clear idea of what they want
the compacted segments to be like.

However, this comes at a cost: it takes time, and disk space, to do all
of these fetches. This patch improves the situation in two ways:

1) When segments do need to be fetched, download them one at a time and
   delete them when we're done. This still takes time, but minimizes the
   required disk space.

2) Don't fetch segments on the main compact task when they aren't needed.
   If the user provides a full granularitySpec, dimensionsSpec, and
   metricsSpec, we can skip it.

@kfaraz kfaraz 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.

Looks good, added minor style suggestions.
Since the download of segments was already sequential, this shouldn't negatively impact the task run time either.

) throws IOException
{
NonnullPair<Map<DataSegment, File>, List<TimelineObjectHolder<String, DataSegment>>> pair = prepareSegments(
final List<TimelineObjectHolder<String, DataSegment>> timelineSegments = retrieveRelevantTimelineHolders(

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.

Thank you! The whole thing is much easier to read now after removing the Pairs.

Comment on lines +1059 to +1070
if (rollupIsValid) {
Boolean isRollup = index.getMetadata().isRollup();
if (isRollup == null) {
rollupIsValid = false;
rollup = false;
} else if (rollup == null) {
rollup = isRollup;
} else if (!isRollup.equals(rollup)) {
rollupIsValid = false;
rollup = false;
}
}

@kfaraz kfaraz Oct 29, 2022 •

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 can probably be simplified by having a single boolean rollup member field.

The field is initialized to true.

Then, this whole block becomes:

Suggested change
if (rollupIsValid) {
Boolean isRollup = index.getMetadata().isRollup();
if (isRollup == null) {
rollupIsValid = false;
rollup = false;
} else if (rollup == null) {
rollup = isRollup;
} else if (!isRollup.equals(rollup)) {
rollupIsValid = false;
rollup = false;
}
}
Boolean isIndexRollup = index.getMetadata().isRollup();
rollup = rollup && isIndexRollup != null && isIndexRollup.equals(rollup)

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 idea. Updated to similar but equivalent:

final Boolean isIndexRollup = index.getMetadata().isRollup();
rollup = rollup && Boolean.valueOf(true).equals(isIndexRollup);

private void sortSegmentsList()
{
segments.sort(
(o1, o2) -> Comparators.intervalsByStartThenEnd().compare(o2.lhs.getInterval(), o1.lhs.getInterval())

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.

Would this work?

Suggested change
(o1, o2) -> Comparators.intervalsByStartThenEnd().compare(o2.lhs.getInterval(), o1.lhs.getInterval())
Comparators.intervalsByStartThenEnd().reversed()

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.

Something still needs to extract the interval. I changed it to this to try to improve clarity:

      segments.sort(
          Comparator.comparing(
              o -> o.lhs.getInterval(),
              Comparators.intervalsByStartThenEnd().reversed()
          )
      );

* dimensions, as it allows us to take the latest value we see, and therefore prefer types from more recent
* segments, if there was a change.
*/
private void sortSegmentsList()

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:

Suggested change
private void sortSegmentsList()
private void sortSegmentsListNewestFirst()

// Check index metadata & decide which values to propagate (i.e. carry over) for rollup & queryGranularity
final ExistingSegmentAnalyzer existingSegmentAnalyzer = new ExistingSegmentAnalyzer(
segments,
granularitySpec.isRollup() == null,

@kfaraz kfaraz Oct 29, 2022 •

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.

I wonder if it would be cleaner to pass all these specs to the ExistingSegmentAnalyzer and let it decide whether it needs the spec or not. This way, only the ExistingSegmentAnalyzer would be doing the null checks.
But maybe this is better as ExistingSegmentAnalyzer only has to deal with the specs of the downloaded segments.

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.

"ExistingSegmentAnalyzer only has to deal with the specs of the downloaded segments" is what I was thinking. I wanted to pass in the minimal amount of information to ExistingSegmentAnalyzer, in order to keep its logic as simple as possible.

@abhishekagarwal87
abhishekagarwal87 merged commit 227b57d into apache:master Nov 7, 2022
@gianm
gianm deleted the compact-dont-always-fetch branch November 7, 2022 16:32
@kfaraz kfaraz added this to the 25.0 milestone Nov 22, 2022
@maytasm

maytasm commented Jul 4, 2023

Copy link
Copy Markdown
Contributor

@gianm What do you think of a option for the Compact task to fetch dimensionsSpec, metricsSpec, granularitySpec from the latest supervisor spec? (obviously only for datasource that was ingested via streaming ingestion)

riovic918data pushed a commit to riovic918data/druid that referenced this pull request Jun 12, 2026
…ible. (apache#13280)

* Compaction: Fetch segments one at a time on main task; skip when possible.

Compact tasks include the ability to fetch existing segments and determine
reasonable defaults for granularitySpec, dimensionsSpec, and metricsSpec.
This is a useful feature that makes compact tasks work well even when the
user running the compaction does not have a clear idea of what they want
the compacted segments to be like.

However, this comes at a cost: it takes time, and disk space, to do all
of these fetches. This patch improves the situation in two ways:

1) When segments do need to be fetched, download them one at a time and
   delete them when we're done. This still takes time, but minimizes the
   required disk space.

2) Don't fetch segments on the main compact task when they aren't needed.
   If the user provides a full granularitySpec, dimensionsSpec, and
   metricsSpec, we can skip it.

* Adjustments.

* Changes from code review.

* Fix logic for determining rollup.
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.

4 participants