Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a Server API to list segments that need to be refreshed for a table #14451

Open
wants to merge 21 commits into
base: master
Choose a base branch
from

Conversation

vrajat
Copy link
Collaborator

@vrajat vrajat commented Nov 14, 2024

The core feature in this PR is a function BaseTableDataManager.getSegmentsForRefresh which finds all the segments of a table that requires a refresh. It accepts a Table Config and Schema and compares that with the current state of a segment.

This functionality will be used by other components such as minion tasks to decide which segments have to be refreshed.

The function is exposed by the following server API:

/tables/{tableName}/segments/needRefresh

Response is:
[
  {
     "segmentName":"...",
     "reason":"..."
  },
...
]

segmentName is the name of the segment.
reason contains a simple message for why the segment needs to be refreshed.

There is also a controller API that consolidates the responses from all servers.

/segments/orders_OFFLINE/needRefresh

Response is:
{
  "<server name>" : [{
     "segmentName":"...",
     "reason":"..."
  }],
...
]

Example:

{
  "http://192.168.0.111:7500/tables/orders_OFFLINE/segments/needRefresh__1": [
    {
      "segmentName": "orders_OFFLINE_0",
      "reason": "column added"
    }
  ]
}

Fix for #14450

@yashmayya
Copy link
Collaborator

What's the difference between this and #13789?

@vrajat
Copy link
Collaborator Author

vrajat commented Nov 15, 2024 via email

@codecov-commenter
Copy link

codecov-commenter commented Nov 19, 2024

Codecov Report

Attention: Patch coverage is 49.74619% with 99 lines in your changes missing coverage. Please review.

Project coverage is 63.82%. Comparing base (59551e4) to head (621a816).
Report is 1383 commits behind head on master.

Files with missing lines Patch % Lines
.../pinot/core/data/manager/BaseTableDataManager.java 66.42% 37 Missing and 9 partials ⚠️
...t/controller/util/ServerSegmentMetadataReader.java 0.00% 25 Missing ⚠️
...ler/api/resources/PinotSegmentRestletResource.java 0.00% 9 Missing ⚠️
...che/pinot/controller/util/TableMetadataReader.java 0.00% 6 Missing ⚠️
...egment/local/data/manager/NeedRefreshResponse.java 53.84% 6 Missing ⚠️
...che/pinot/server/api/resources/TablesResource.java 0.00% 6 Missing ⚠️
...spi/utils/builder/ControllerRequestURLBuilder.java 0.00% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##             master   #14451      +/-   ##
============================================
+ Coverage     61.75%   63.82%   +2.07%     
- Complexity      207     1570    +1363     
============================================
  Files          2436     2674     +238     
  Lines        133233   146983   +13750     
  Branches      20636    22548    +1912     
============================================
+ Hits          82274    93816   +11542     
- Misses        44911    46224    +1313     
- Partials       6048     6943     +895     
Flag Coverage Δ
custom-integration1 100.00% <ø> (+99.99%) ⬆️
integration 100.00% <ø> (+99.99%) ⬆️
integration1 100.00% <ø> (+99.99%) ⬆️
integration2 0.00% <ø> (ø)
java-11 63.80% <49.74%> (+2.10%) ⬆️
java-21 63.71% <49.74%> (+2.09%) ⬆️
skip-bytebuffers-false 63.81% <49.74%> (+2.07%) ⬆️
skip-bytebuffers-true 63.69% <49.74%> (+35.97%) ⬆️
temurin 63.82% <49.74%> (+2.07%) ⬆️
unittests 63.82% <49.74%> (+2.07%) ⬆️
unittests1 55.60% <64.90%> (+8.71%) ⬆️
unittests2 34.53% <0.00%> (+6.79%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.


🚨 Try these New Features:

@vrajat vrajat changed the title Add a server API to list segments out of date with table config Add a Server API to list segments that need to be refreshed for a table Nov 20, 2024
@vrajat vrajat marked this pull request as ready for review November 21, 2024 07:10
}

if (Objects.isNull(source.getH3Index()) == h3Indexes.contains(columnName)) {
LOGGER.debug("tableNameWithType: {}, segmentName: {}, change: h3 index changed", tableNameWithType,
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: Can we improve this log to also have columnName for which the index was changed

Copy link
Collaborator Author

@vrajat vrajat Nov 22, 2024

Choose a reason for hiding this comment

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

Added columnName to all debug logs

@Override
public List<NeedRefreshResponse> getSegmentsForRefresh(TableConfig tableConfig, Schema schema) {
List<NeedRefreshResponse> segmentsRequiringRefresh = new ArrayList<>();
List<SegmentDataManager> segmentDataManagers = acquireAllSegments();
Copy link
Contributor

Choose a reason for hiding this comment

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

acquireAllSegments also increases the ref count
so we need to decrease it as well once we get the list

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, since we are running a for loop, wouldn't a better way be to acquire each segment one by one

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I am releasing the segments now. To acquire a segment, how do I get the segment name ? One option is to acquire all segments, convert that into a list of names and then reacquire one by one. Any other options ?

Copy link
Contributor

Choose a reason for hiding this comment

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

Good point about acquireAll. Yes thats one way. If we have a large table/with a large number of segments, this check can take time. However by the time you get to the segment, that can be released? I guess acquireSegment will return null in that case.

}
}
if (failedParses != 0) {
LOGGER.error("Unable to parse server {} / {} response due to an error: ", failedParses, serverURLs.size());
Copy link
Contributor

Choose a reason for hiding this comment

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

Please add table name to this msg

new TypeReference<List<NeedRefreshResponse>>() { }));
} catch (Exception e) {
failedParses++;
LOGGER.error("Unable to parse server {} response due to an error: ", streamResponse.getKey(), e);
Copy link
Contributor

Choose a reason for hiding this comment

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

Please add table name to this msg

public class NeedRefreshResponse {
private final String _segmentName;
private final boolean _needRefresh;
private final String _reason;
Copy link
Contributor

Choose a reason for hiding this comment

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

Good idea to add reason as well !

@Override
public List<NeedRefreshResponse> getSegmentsForRefresh(TableConfig tableConfig, Schema schema) {
List<NeedRefreshResponse> segmentsRequiringRefresh = new ArrayList<>();
List<SegmentDataManager> segmentDataManagers = acquireAllSegments();
Copy link
Contributor

Choose a reason for hiding this comment

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

Good point about acquireAll. Yes thats one way. If we have a large table/with a large number of segments, this check can take time. However by the time you get to the segment, that can be released? I guess acquireSegment will return null in that case.

@Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "Gets a list of segments that need to be refreshed from servers hosting the table", notes =
"Gets a list of segments that need to be refreshed from servers hosting the table")
public Map<String, List<NeedRefreshResponse>> getTableRefreshMetadata(
Copy link
Contributor

Choose a reason for hiding this comment

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

How will the user know if we got partial Vs full response.
Would it be useful to find out missing segments for which we never got a response?
After the getSegmentsForRefreshFromServer, we can get the list of segments from ideal state and do a diff. If there's a way to propagate that list, we can just retry that list in the subsequent call.
Or at least the client knows that it did not get a complete list.

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