Skip to content

Improve fetch of pending segments from metadata store#13310

Merged
gianm merged 5 commits intoapache:masterfrom
kfaraz:get_pending_segments
Nov 8, 2022
Merged

Improve fetch of pending segments from metadata store#13310
gianm merged 5 commits intoapache:masterfrom
kfaraz:get_pending_segments

Conversation

@kfaraz
Copy link
Copy Markdown
Contributor

@kfaraz kfaraz commented Nov 4, 2022

The fetch of pending segments happens behind a lock and can cause others threads to remain stuck while deserializing the payload fetched from the metadata store.

The query to fetch the payload uses a <= and >= on the start and end intervals.

SELECT payload FROM pending_segments 
WHERE datasource = 'search-ds'
AND start <= 'search-end-time'
AND end >= 'search-start-time'

This might often end up fetching more segments than would actually have an overlap.
For example, when searching for the interval 10am to 11am, a segment with interval
9am to 10am would also satisfy this query.

start <= search-end AND end >= search-start
9 <= 11 AND 10 >= 10

But in reality, the interval 9am to 10am doesn't have any overlap with our search interval 10am to 11am.
This is because the end time of a segment interval is always exclusive.

Such results eventually get filtered out by the check on interval interval.overlaps(identifier.getInterval())
but only after the costly deserialization.

Changes:

  • Improve select query to fetch only segments that can overlap.
    Use the same condition as present in Interval.overlaps

Notes:
This query (and also the original query) can give incorrect results in cases where a string comparison
of the two intervals is not feasible, typically if the search year and interval year are far apart.
See #11582 for a related fix.
A long-term fix for this could be to migrate these timestamps to use longs rather than varchars.


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.

return new SegmentIdWithShardSpec(
dataSource,
overallMaxId.getInterval(),
interval,
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.

Changed to emphasize that the interval used in the SegmentIdWithShardSpec is always the same as the one passed to the method createNewSegment.

Copy link
Copy Markdown
Contributor

@abhishekagarwal87 abhishekagarwal87 left a comment

Choose a reason for hiding this comment

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

LGTM. are there tests already for this method?

@rohangarg
Copy link
Copy Markdown
Member

Regarding the suggested query improvement, I think BETWEEN is an inclusive operator on both sides so it might also bring the same results as the current query. Also, the performance in worst case might be slower.
Incase we want to eventually do a Interval#overlaps over the queried interval with the intervals in the pending segments table rows, we could follow the logic in that method and push it down in the metadata store query. The Interval#overlaps function is as follows :

public boolean overlaps(ReadableInterval interval) {
        long thisStart = getStartMillis();
        long thisEnd = getEndMillis();
        if (interval == null) {
            long now = DateTimeUtils.currentTimeMillis();
            return (thisStart < now && now < thisEnd);
        }  else {
            long otherStart = interval.getStartMillis();
            long otherEnd = interval.getEndMillis();
            return (thisStart < otherEnd && otherStart < thisEnd);
        }
}

@kfaraz
Copy link
Copy Markdown
Contributor Author

kfaraz commented Nov 4, 2022

Thanks for the suggestion, @rohangarg !
So, I guess we can just remove the equals from both the operators.

@kfaraz
Copy link
Copy Markdown
Contributor Author

kfaraz commented Nov 5, 2022

With the suggested change to the query, I don't think we even need the other changes. What do you think @abhishekagarwal87 , @AmatyaAvadhanula ?

@abhishekagarwal87
Copy link
Copy Markdown
Contributor

I feel that there might be some nuances being missed here. The comparison in java code, that @rohangarg is referring to, is done on long millis representation of start and end. The start and end in the table are strings in yyyy-MM-ddTHH:mm:ss.SSSZZ. You should refer to https://github.com/apache/druid/pull/11582/files and try out some whacky dates in that PR. The string-based comparison doesn't work for all kinds of dates.

@kfaraz
Copy link
Copy Markdown
Contributor Author

kfaraz commented Nov 5, 2022

That makes sense, @abhishekagarwal87 . Looking at the other linked PR though, it is possible that even the current query would fail for dates with years that have more or less than 4 digits or even negative years (which would happen with ALL granularity). I will put all of this to the test and fix up the PR accordingly.

@kfaraz kfaraz added the WIP label Nov 5, 2022
@rohangarg
Copy link
Copy Markdown
Member

It seems like VARCHAR column based comparison for date-times in pendingSegments table could provide incorrect results in the current code as well. For correctness, the utilities introduced by #11582 could be used to fetch rows from pendingSegments table as well.
Although, I think for long run the schema of the tables could be augmented to have the date-time columns as TIMESTAMP or long to represent a UTC time instant (the augmentation could follow the approach implemented by @AmatyaAvadhanula in #12404)

@kfaraz kfaraz removed the WIP label Nov 7, 2022
// This query might fail if the year has a different number of digits
// See https://github.com/apache/druid/pull/11582 for a similar issue
// Using long for these timestamps instead of varchar would give correct time comparisons
"SELECT start, %2$send%2$s, payload FROM %1$s "
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: Do start and end still need to be selected in the query?

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.

Thanks for catching it, yeah, we can remove this now.

@gianm
Copy link
Copy Markdown
Contributor

gianm commented Nov 7, 2022

It looks like this PR has changed a bunch since the original description; it doesn't accurately describe the change anymore. @kfaraz could you please update it?

// This query might fail if the year has a different number of digits
// See https://github.com/apache/druid/pull/11582 for a similar issue
// Using long for these timestamps instead of varchar would give correct time comparisons
"SELECT payload FROM %1$s WHERE dataSource = :dataSource AND start < :end and %2$send%2$s > :start",
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 looks like the only material change in the patch: what's the idea behind changing <= to < and what's the expected benefit?

Copy link
Copy Markdown
Contributor Author

@kfaraz kfaraz Nov 7, 2022

Choose a reason for hiding this comment

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

We are trying to avoid selecting segments with intervals that only abut the search interval and don't have an actual overlap. Such intervals eventually get filtered out via the check on interval.overlaps(identifier.getInterval()) but only after the costly deserialization.

I have updated the description, which gives an example of such an interval.
This is still not a complete fix as the query can return incorrect results in cases where a string comparison of the two intervals is not feasible.

Copy link
Copy Markdown
Contributor

@gianm gianm left a comment

Choose a reason for hiding this comment

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

Thanks for clarifying.

@gianm gianm merged commit 9f7fd57 into apache:master Nov 8, 2022
@kfaraz kfaraz added this to the 25.0 milestone Nov 22, 2022
@kfaraz kfaraz deleted the get_pending_segments branch August 1, 2023 04:52
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.

5 participants