-
Notifications
You must be signed in to change notification settings - Fork 2k
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
Pagination #17638
base: main
Are you sure you want to change the base?
Pagination #17638
Conversation
❌ Gradle check result for ad612da: FAILURE Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change? |
❌ Gradle check result for baa30b0: FAILURE Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change? |
private final int pageSize; | ||
private final String nextToken; | ||
private final String sortBy; | ||
private final String sortOrder; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should make sortBy
and sortOrder
an Enum since this is going to be a limited set of values and move the switch case logic inside the enum.
enum SortBy {
case QUERY_GROUP, NODE_ID;
Comparator<WlmStats> comparator;
....
public Comparator<WlmStats> getComparator() {
return comparator;
}
}
enum SortOrder {
case ASC, DESC;
Function<Comparator<WlmStats>, Comparator<WlmStats>> transformer;
....
public Comparator<WlmStats> transform(Comparator<WlmStats> comp) {
return transformer.apply(comp);
}
}
return Collections.emptyList(); | ||
} | ||
|
||
List<WlmStats> allQueryGroups = new ArrayList<>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This var name is misleading as this holds the stats not the queryGroups.
} | ||
} | ||
|
||
allQueryGroups = sortStats(allQueryGroups, sortBy, sortOrder); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not needed given that we already have the sorted list of WLM stats.
|
||
int startIndex = 0; | ||
if (requestedToken != null) { | ||
OptionalInt foundIndex = findIndex(allQueryGroups, requestedToken.lastQueryGroupId); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Filtering based on repetitive filed can result into circular loops of results. for example the same set of query group id will be present on all WlmStats entries and if your pageSize and querygroup count are equal then it will always return first two pages worth of results.
@@ -245,6 +245,11 @@ public PageToken getPageToken() { | |||
return pageToken; | |||
} | |||
|
|||
public void setPageToken(PageToken pageToken) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is not needed, We can use the constructor to inject the token.
QueryGroupStats.ResourceStats cpuStats = statsHolder.getResourceStats().get(ResourceType.CPU); | ||
QueryGroupStats.ResourceStats memoryStats = statsHolder.getResourceStats().get(ResourceType.MEMORY); | ||
|
||
table.addCell(cpuStats != null ? cpuStats.getCurrentUsage() : 0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think 0 would be a misnomer here instead put a placeholder like _
or NA
.
if (paginationStrategy.getNextToken() == null) { | ||
table.startRow(); | ||
table.addCell("No more pages available"); | ||
for (int i = 1; i < 13; i++) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should make the literals as named constants
table.startRow(); | ||
table.addCell("No more pages available"); | ||
for (int i = 1; i < 13; i++) { | ||
table.addCell("-"); | ||
} | ||
table.endRow(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be conditional ? Additionally lets refactor a method for this footer .
String queryGroupId = entry.getKey(); | ||
QueryGroupStats.QueryGroupStatsHolder statsHolder = entry.getValue(); | ||
|
||
table.startRow(); | ||
table.addCell(wlmStats.getNode().getId()); | ||
table.addCell("|"); | ||
table.addCell(queryGroupId); | ||
table.addCell("|"); | ||
table.addCell(statsHolder.getCompletions()); | ||
table.addCell("|"); | ||
table.addCell(statsHolder.getRejections()); | ||
table.addCell("|"); | ||
table.addCell(statsHolder.getCancellations()); | ||
table.addCell("|"); | ||
|
||
QueryGroupStats.ResourceStats cpuStats = statsHolder.getResourceStats().get(ResourceType.CPU); | ||
QueryGroupStats.ResourceStats memoryStats = statsHolder.getResourceStats().get(ResourceType.MEMORY); | ||
|
||
table.addCell(cpuStats != null ? cpuStats.getCurrentUsage() : 0); | ||
table.addCell("|"); | ||
table.addCell(memoryStats != null ? memoryStats.getCurrentUsage() : 0); | ||
table.endRow(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can refactor these lines into a method named addRow(table);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this file is not needed as we can directly instantiate the DiscoverNode
instance with mock transport.
❌ Gradle check result for 0dd053d: FAILURE Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change? |
@@ -245,6 +245,7 @@ public PageToken getPageToken() { | |||
return pageToken; | |||
} | |||
|
|||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's remove this blank line
Objects.requireNonNull(token, "Token cannot be null"); | ||
String decrypted = PaginationStrategy.decryptStringToken(token); | ||
final String[] parts = decrypted.split(SPLIT_REGEX); | ||
if (parts.length != 4 || parts[0].isEmpty() || parts[1].isEmpty() || parts[3].isEmpty()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I saw you defined
private static final int NODE_ID_POS = 0;
private static final int QUERY_GROUP_ID_POS = 1;
private static final int QUERY_GROUP_COUNT_POS = 2;
private static final int HASH_POS = 3;
We should replace the numbers here with these static fields.
} | ||
} | ||
|
||
private List<WlmStats> applyPagination(List<WlmStats> rawStats, WlmStrategyToken requestedToken, String currentHash) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is too long. Let's break it into several shorter functions. Also add a javadoc to explain how the pagination works for better readability
return paginatedStats; | ||
} | ||
|
||
public PageToken getNextToken() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Duplication. The function getResponseToken()
returns responseToken as well.
builder.field("details", e.getMessage()); | ||
builder.endObject(); | ||
|
||
channel.sendResponse(new BytesRestResponse(RestStatus.BAD_REQUEST, builder)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should add logging information (using logger.error) before throwing an exception to provide better debugging information for clients.
try { | ||
WlmPaginationStrategy paginationStrategy = new WlmPaginationStrategy(pageSize, nextToken, sortBy, sortOrder, response); | ||
List<WlmStats> paginatedStats = paginationStrategy.getPaginatedStats(); | ||
PageToken nextPageToken = paginationStrategy.getNextToken(); | ||
|
||
// Use constructor to create Table with token | ||
Table paginatedTable = createTableWithHeaders(nextPageToken); | ||
buildTable(paginatedTable, paginatedStats, paginationStrategy); | ||
|
||
request.params().put("v", "true"); | ||
return RestTable.buildResponse(paginatedTable, channel); | ||
} catch (OpenSearchParseException e) { | ||
String userMessage = "Pagination state has changed (e.g., new query groups added or removed). " | ||
+ "Please restart pagination from the beginning by omitting the 'next_token' parameter."; | ||
|
||
XContentBuilder builder = XContentFactory.jsonBuilder(); | ||
builder.startObject(); | ||
builder.field("error", userMessage); | ||
builder.field("details", e.getMessage()); | ||
builder.endObject(); | ||
|
||
channel.sendResponse(new BytesRestResponse(RestStatus.BAD_REQUEST, builder)); | ||
return null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extract these lines in a new method to improve the readability of functionprepareRequest
Boolean breach = request.hasParam("breach") ? Boolean.parseBoolean(request.param("breach")) : null; | ||
WlmStatsRequest wlmStatsRequest = new WlmStatsRequest(nodeIds, queryGroupIds, breach); | ||
|
||
int pageSize = request.paramAsInt("size", 10); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have validation logic for pageSize? eg. greater than 0 and less than a certain value to ensure performance.
switch (input.toLowerCase()) { | ||
case "query_group": | ||
return QUERY_GROUP; | ||
case "node_id": | ||
return NODE_ID; | ||
default: | ||
throw new IllegalArgumentException("Invalid sort field: " + input); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we use this to avoid using switch? Same for SortOrder
try {
return SortBy.valueOf(input.toUpperCase());
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("Invalid sort field: " + input + ". Allowed values: query_group, node_id");
}
Can we provide a better name for this PR and add some description? A single word title is not descriptive |
Description
[Describe what this change achieves]
Related Issues
Resolves #[Issue number to be closed when this PR is merged]
Check List
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.