Skip to content

Commit 4d528e9

Browse files
jimczidnhatn
andcommitted
Ensure validation of the reader context is executed first (#61831)
This change makes sure that reader context is validated (`SearchOperationListener#validateReaderContext) before any other operation and that it is correctly recycled or removed at the end of the operation. This commit also fixes a race condition bug that would allocate the security reader for scrolls more than once. Relates #61446 Co-authored-by: Nhat Nguyen <[email protected]>
1 parent 44bd4a6 commit 4d528e9

File tree

10 files changed

+146
-130
lines changed

10 files changed

+146
-130
lines changed

server/src/main/java/org/elasticsearch/action/search/AbstractSearchAsyncAction.java

+16-13
Original file line numberDiff line numberDiff line change
@@ -547,24 +547,27 @@ public final void onPhaseFailure(SearchPhase phase, String msg, Throwable cause)
547547
}
548548

549549
/**
550-
* This method should be called if a search phase failed to ensure all relevant search contexts and resources are released.
551-
* this method will also notify the listener and sends back a failure to the user.
550+
* This method should be called if a search phase failed to ensure all relevant reader contexts are released.
551+
* This method will also notify the listener and sends back a failure to the user.
552552
*
553553
* @param exception the exception explaining or causing the phase failure
554554
*/
555555
private void raisePhaseFailure(SearchPhaseExecutionException exception) {
556-
results.getSuccessfulResults().forEach((entry) -> {
557-
if (entry.getContextId() != null) {
558-
try {
559-
SearchShardTarget searchShardTarget = entry.getSearchShardTarget();
560-
Transport.Connection connection = getConnection(searchShardTarget.getClusterAlias(), searchShardTarget.getNodeId());
561-
sendReleaseSearchContext(entry.getContextId(), connection, searchShardTarget.getOriginalIndices());
562-
} catch (Exception inner) {
563-
inner.addSuppressed(exception);
564-
logger.trace("failed to release context", inner);
556+
// we don't release persistent readers (point in time).
557+
if (request.pointInTimeBuilder() == null) {
558+
results.getSuccessfulResults().forEach((entry) -> {
559+
if (entry.getContextId() != null) {
560+
try {
561+
SearchShardTarget searchShardTarget = entry.getSearchShardTarget();
562+
Transport.Connection connection = getConnection(searchShardTarget.getClusterAlias(), searchShardTarget.getNodeId());
563+
sendReleaseSearchContext(entry.getContextId(), connection, searchShardTarget.getOriginalIndices());
564+
} catch (Exception inner) {
565+
inner.addSuppressed(exception);
566+
logger.trace("failed to release context", inner);
567+
}
565568
}
566-
}
567-
});
569+
});
570+
}
568571
listener.onFailure(exception);
569572
}
570573

server/src/main/java/org/elasticsearch/action/search/DfsQueryPhase.java

+7-5
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,13 @@ public void onFailure(Exception exception) {
9898
progressListener.notifyQueryFailure(shardIndex, searchShardTarget, exception);
9999
counter.onFailure(shardIndex, searchShardTarget, exception);
100100
} finally {
101-
// the query might not have been executed at all (for example because thread pool rejected
102-
// execution) and the search context that was created in dfs phase might not be released.
103-
// release it again to be in the safe side
104-
context.sendReleaseSearchContext(
105-
querySearchRequest.contextId(), connection, searchShardTarget.getOriginalIndices());
101+
if (context.getRequest().pointInTimeBuilder() == null) {
102+
// the query might not have been executed at all (for example because thread pool rejected
103+
// execution) and the search context that was created in dfs phase might not be released.
104+
// release it again to be in the safe side
105+
context.sendReleaseSearchContext(
106+
querySearchRequest.contextId(), connection, searchShardTarget.getOriginalIndices());
107+
}
106108
}
107109
}
108110
});

server/src/main/java/org/elasticsearch/action/search/FetchSearchPhase.java

+5-5
Original file line numberDiff line numberDiff line change
@@ -206,11 +206,11 @@ public void onFailure(Exception e) {
206206
* Releases shard targets that are not used in the docsIdsToLoad.
207207
*/
208208
private void releaseIrrelevantSearchContext(QuerySearchResult queryResult) {
209-
// we only release search context that we did not fetch from if we are not scrolling
210-
// and if it has at lease one hit that didn't make it to the global topDocs
211-
if (context.getRequest().scroll() == null &&
212-
context.getRequest().pointInTimeBuilder() == null &&
213-
queryResult.hasSearchContext()) {
209+
// we only release search context that we did not fetch from, if we are not scrolling
210+
// or using a PIT and if it has at least one hit that didn't make it to the global topDocs
211+
if (queryResult.hasSearchContext()
212+
&& context.getRequest().scroll() == null
213+
&& context.getRequest().pointInTimeBuilder() == null) {
214214
try {
215215
SearchShardTarget searchShardTarget = queryResult.getSearchShardTarget();
216216
Transport.Connection connection = context.getConnection(searchShardTarget.getClusterAlias(), searchShardTarget.getNodeId());

server/src/main/java/org/elasticsearch/index/shard/SearchOperationListener.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ default void onFreeScrollContext(ReaderContext readerContext) {}
113113
* @param readerContext The reader context used by this request.
114114
* @param transportRequest the request that is going to use the search context
115115
*/
116-
default void validateSearchContext(ReaderContext readerContext, TransportRequest transportRequest) {}
116+
default void validateReaderContext(ReaderContext readerContext, TransportRequest transportRequest) {}
117117

118118
/**
119119
* A Composite listener that multiplexes calls to each of the listeners methods.
@@ -238,11 +238,11 @@ public void onFreeScrollContext(ReaderContext readerContext) {
238238
}
239239

240240
@Override
241-
public void validateSearchContext(ReaderContext readerContext, TransportRequest request) {
241+
public void validateReaderContext(ReaderContext readerContext, TransportRequest request) {
242242
Exception exception = null;
243243
for (SearchOperationListener listener : listeners) {
244244
try {
245-
listener.validateSearchContext(readerContext, request);
245+
listener.validateReaderContext(readerContext, request);
246246
} catch (Exception e) {
247247
exception = ExceptionsHelper.useOrSuppress(exception, e);
248248
}

0 commit comments

Comments
 (0)