-
Notifications
You must be signed in to change notification settings - Fork 25.6k
Remove early phase failure in batched #136889
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
Remove early phase failure in batched #136889
Conversation
|
Pinging @elastic/es-search-foundations (Team:Search Foundations) |
|
Hi @benchaplin, I've created a changelog YAML for you. |
| this.results = in.readArray(i -> i.readBoolean() ? new QuerySearchResult(i) : i.readException(), Object[]::new); | ||
| this.mergeResult = QueryPhaseResultConsumer.MergeResult.readFrom(in); | ||
| this.topDocsStats = SearchPhaseController.TopDocsStats.readFrom(in); | ||
| boolean hasReductionFailure = in.readBoolean(); |
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.
Since we're changing the shape of this message, do we need to create a new transport version or is that taken care of for us?
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.
Yes I believe I do, once I learn how 😂
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.
LGTM
server/src/main/java/org/elasticsearch/action/search/SearchQueryThenFetchAsyncAction.java
Show resolved
Hide resolved
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 left a couple of minor comments. LGTM otherwise
| ); | ||
| } | ||
|
|
||
| private void writeSuccessfulResponse(RecyclerBytesStreamOutput out) throws IOException { |
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.
Is it necessary to refactor this serialization code? Moving it around makes it more difficult to eye ball it somehow.
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.
disregard this previous comment. I understand why you did things the way you did. It's fine as-is. As for the review, I simply trust that the successful writing is a plain copy of the previous code we had, with no changes.
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.
That's right, same as the previous code except for the additional out.writeBoolean(false);, telling us there's no reduction failure.
| } | ||
| out.writeBoolean(true); // does have a reduction failure | ||
| out.writeException(reductionFailure); | ||
| releaseAllResultsContexts(); |
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 in a finally block ?
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.
In the case of an IOException, the caller releases contexts in a catch block. So I think this is alright, else we'll be releasing twice?
| NodeQueryResponse.writeMergeResult(out, mergeResult, queryPhaseResultConsumer.topDocsStats); | ||
| } | ||
|
|
||
| private void writeReductionFailureResponse(RecyclerBytesStreamOutput out, Exception reductionFailure) throws IOException { |
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.
Maybe add a comment about where the corresponding read code for this can be found? future readers may be looking for it and not easily finding it, due to the fact that we write to an opaque bytes transport response.
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.
Good idea, done.
| if (failure != null) { | ||
| handleMergeFailure(failure, channelListener, namedWriteableRegistry); | ||
| releaseAllResultsContexts(); | ||
| channelListener.onFailure(failure); |
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 wonder if I am missing something: is this doing the same that handleMergeFailure was previously doing?
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.
Yes, the exact same. handleMergeFailure doesn't make sense to keep in the new serialization scheme, so I decided to remove the method.
| out.writeBoolean(true); | ||
| writeTopDocs(out, topDocsAndMaxScore); | ||
| } else { | ||
| assert isPartiallyReduced(); |
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.
A failure might occur during the final data node reduction. In this case, due to the central change of this PR, we still send back QuerySearchResults to sit on the coord node. Therefore we can no longer assert that a QuerySearchResult has been reduced when serializing it.
💔 Backport failed
You can use sqren/backport to manually backport by running |
* Backport #136889 * Fix * [CI] Auto commit changes from spotless --------- Co-authored-by: elasticsearchmachine <[email protected]>
* Backport #136889 * [CI] Auto commit changes from spotless --------- Co-authored-by: elasticsearchmachine <[email protected]>
elastic#121885 attempted to shortcut a phase failure caused by a reduction failure on the data node by failing the query phase in the batched query action response listener. Before batching the query phase, we did not fail the phase immediately upon a reduction failure. We held on to the failure and continued querying all shards, only failing during final reduction at the beginning of the fetch phase. I can't think of anything inherently wrong with this approach, besides the fact that the phase cannot be failed multiple times (elastic#134151). However certain cleanup aspects of the code (specifically releasing reader contexts and query search results, see: elastic#130821, elastic#122707) rely on the assumption that all shards are queried before failing the phase. This commit reworks batched requests to fail in the same way: only after all shards are queried. To do this, we must include results in transport response even when a reduction failure occurred.
…-json
* upstream/main:
Mute org.elasticsearch.xpack.inference.action.filter.ShardBulkInferenceActionFilterBasicLicenseIT testLicenseInvalidForInference {p0=false} elastic#137691
Mute org.elasticsearch.xpack.inference.action.filter.ShardBulkInferenceActionFilterBasicLicenseIT testLicenseInvalidForInference {p0=true} elastic#137690
[LTR] Fix feature display order when using explain. (elastic#137671)
Remove extra RemoteClusterService instances in unit test (elastic#137647)
Fix `ComponentTemplatesFileSettingsIT.testSettingsApplied` (elastic#137669)
Consolidates troubleshooting content into the "Returning semantic field embeddings in _source" section (elastic#137233)
Update bundled JDK to 25.0.1 (elastic#137640)
resolve indices for prefixed _all expressions (elastic#137330)
ESQL: Add TopN support for exponential histograms (elastic#137313)
allows field caps to be cross project (elastic#137530)
ESQL: Add exponential histogram percentile function (elastic#137553)
Wait for nodes to have downloaded databases in `GeoIpDownloaderIT` (elastic#137636)
Tighten on when THROTTLE decision can be returned (elastic#136794)
Mute org.elasticsearch.xpack.esql.qa.single_node.GenerativeMetricsIT test elastic#137655
Add a test for two little known conditional processor paths (elastic#137645)
Extract a common ORIGIN constant (elastic#137612)
Remove early phase failure in batched (elastic#136889)
Returning correct index mode from get data streams api (elastic#137646)
[ML] Manage AD results indices (elastic#136065)
…-json
* upstream/main:
Mute org.elasticsearch.xpack.inference.action.filter.ShardBulkInferenceActionFilterBasicLicenseIT testLicenseInvalidForInference {p0=false} elastic#137691
Mute org.elasticsearch.xpack.inference.action.filter.ShardBulkInferenceActionFilterBasicLicenseIT testLicenseInvalidForInference {p0=true} elastic#137690
[LTR] Fix feature display order when using explain. (elastic#137671)
Remove extra RemoteClusterService instances in unit test (elastic#137647)
Fix `ComponentTemplatesFileSettingsIT.testSettingsApplied` (elastic#137669)
Consolidates troubleshooting content into the "Returning semantic field embeddings in _source" section (elastic#137233)
Update bundled JDK to 25.0.1 (elastic#137640)
resolve indices for prefixed _all expressions (elastic#137330)
ESQL: Add TopN support for exponential histograms (elastic#137313)
allows field caps to be cross project (elastic#137530)
ESQL: Add exponential histogram percentile function (elastic#137553)
Wait for nodes to have downloaded databases in `GeoIpDownloaderIT` (elastic#137636)
Tighten on when THROTTLE decision can be returned (elastic#136794)
Mute org.elasticsearch.xpack.esql.qa.single_node.GenerativeMetricsIT test elastic#137655
Add a test for two little known conditional processor paths (elastic#137645)
Extract a common ORIGIN constant (elastic#137612)
Remove early phase failure in batched (elastic#136889)
Returning correct index mode from get data streams api (elastic#137646)
[ML] Manage AD results indices (elastic#136065)
Resolves #134151, #130821.
Background
A bug was introduced by #121885 due to the following code, which handles batched query exceptions due to a batched partial reduction failure:
elasticsearch/server/src/main/java/org/elasticsearch/action/search/SearchQueryThenFetchAsyncAction.java
Lines 525 to 544 in bd35649
Raising a phase failure in this way leads to a couple issues:
Solution
Problem 1 could be resolved with a simple flag, as proposed in #131085. Problem 2 could be resolved with some careful use of the same flag to clean contexts upon receiving stale query results. However, in the interest of stability, I propose a solution that more closely resembles how a reduction failure is handled by a non-batched query phase. In non-batched, a reduction failure is held in the QueryPhaseResultConsumer until shard fanout is complete. Only later, during final reduction at the beginning of the fetch phase, do we fail the search.
Fast failure + proper task cancellation are worthy goals for the future. I am tracking these as follow-up improvements for after the release of batched query execution.
This PR: