Skip to content

Commit 66123cf

Browse files
Remove SearchPhaseContext (#116471)
The only production implementation of this thing is AbstractSearchAsyncAction, no need to keep a separate interface around. This makes the logic a lot more obvious in terms of the lifeycle of "context" and how it's essentially just the "main" search phase. Plus it outright saves a lot of code, even though it adds a little on the test side.
1 parent 0f9ac9d commit 66123cf

17 files changed

+168
-226
lines changed

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

Lines changed: 71 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868
* The fan out and collect algorithm is traditionally used as the initial phase which can either be a query execution or collection of
6969
* distributed frequencies
7070
*/
71-
abstract class AbstractSearchAsyncAction<Result extends SearchPhaseResult> extends SearchPhase implements SearchPhaseContext {
71+
abstract class AbstractSearchAsyncAction<Result extends SearchPhaseResult> extends SearchPhase {
7272
private static final float DEFAULT_INDEX_BOOST = 1.0f;
7373
private final Logger logger;
7474
private final NamedWriteableRegistry namedWriteableRegistry;
@@ -106,7 +106,8 @@ abstract class AbstractSearchAsyncAction<Result extends SearchPhaseResult> exten
106106
private final boolean throttleConcurrentRequests;
107107
private final AtomicBoolean requestCancelled = new AtomicBoolean();
108108

109-
private final List<Releasable> releasables = new ArrayList<>();
109+
// protected for tests
110+
protected final List<Releasable> releasables = new ArrayList<>();
110111

111112
AbstractSearchAsyncAction(
112113
String name,
@@ -194,7 +195,9 @@ protected void notifyListShards(
194195
);
195196
}
196197

197-
@Override
198+
/**
199+
* Registers a {@link Releasable} that will be closed when the search request finishes or fails.
200+
*/
198201
public void addReleasable(Releasable releasable) {
199202
releasables.add(releasable);
200203
}
@@ -333,8 +336,12 @@ protected abstract void executePhaseOnShard(
333336
SearchActionListener<Result> listener
334337
);
335338

336-
@Override
337-
public final void executeNextPhase(SearchPhase currentPhase, Supplier<SearchPhase> nextPhaseSupplier) {
339+
/**
340+
* Processes the phase transition from on phase to another. This method handles all errors that happen during the initial run execution
341+
* of the next phase. If there are no successful operations in the context when this method is executed the search is aborted and
342+
* a response is returned to the user indicating that all shards have failed.
343+
*/
344+
protected void executeNextPhase(SearchPhase currentPhase, Supplier<SearchPhase> nextPhaseSupplier) {
338345
/* This is the main search phase transition where we move to the next phase. If all shards
339346
* failed or if there was a failure and partial results are not allowed, then we immediately
340347
* fail. Otherwise we continue to the next phase.
@@ -470,8 +477,7 @@ protected void onShardGroupFailure(int shardIndex, SearchShardTarget shardTarget
470477
* @param shardTarget the shard target for this failure
471478
* @param e the failure reason
472479
*/
473-
@Override
474-
public final void onShardFailure(final int shardIndex, SearchShardTarget shardTarget, Exception e) {
480+
void onShardFailure(final int shardIndex, SearchShardTarget shardTarget, Exception e) {
475481
if (TransportActions.isShardNotAvailableException(e)) {
476482
// Groups shard not available exceptions under a generic exception that returns a SERVICE_UNAVAILABLE(503)
477483
// temporary error.
@@ -568,32 +574,45 @@ private void successfulShardExecution(SearchShardIterator shardsIt) {
568574
}
569575
}
570576

571-
@Override
577+
/**
578+
* Returns the total number of shards to the current search across all indices
579+
*/
572580
public final int getNumShards() {
573581
return results.getNumShards();
574582
}
575583

576-
@Override
584+
/**
585+
* Returns a logger for this context to prevent each individual phase to create their own logger.
586+
*/
577587
public final Logger getLogger() {
578588
return logger;
579589
}
580590

581-
@Override
591+
/**
592+
* Returns the currently executing search task
593+
*/
582594
public final SearchTask getTask() {
583595
return task;
584596
}
585597

586-
@Override
598+
/**
599+
* Returns the currently executing search request
600+
*/
587601
public final SearchRequest getRequest() {
588602
return request;
589603
}
590604

591-
@Override
605+
/**
606+
* Returns the targeted {@link OriginalIndices} for the provided {@code shardIndex}.
607+
*/
592608
public OriginalIndices getOriginalIndices(int shardIndex) {
593609
return shardIterators[shardIndex].getOriginalIndices();
594610
}
595611

596-
@Override
612+
/**
613+
* Checks if the given context id is part of the point in time of this search (if exists).
614+
* We should not release search contexts that belong to the point in time during or after searches.
615+
*/
597616
public boolean isPartOfPointInTime(ShardSearchContextId contextId) {
598617
final PointInTimeBuilder pointInTimeBuilder = request.pointInTimeBuilder();
599618
if (pointInTimeBuilder != null) {
@@ -630,7 +649,12 @@ boolean buildPointInTimeFromSearchResults() {
630649
return false;
631650
}
632651

633-
@Override
652+
/**
653+
* Builds and sends the final search response back to the user.
654+
*
655+
* @param internalSearchResponse the internal search response
656+
* @param queryResults the results of the query phase
657+
*/
634658
public void sendSearchResponse(SearchResponseSections internalSearchResponse, AtomicArray<SearchPhaseResult> queryResults) {
635659
ShardSearchFailure[] failures = buildShardFailures();
636660
Boolean allowPartialResults = request.allowPartialSearchResults();
@@ -655,8 +679,14 @@ public void sendSearchResponse(SearchResponseSections internalSearchResponse, At
655679
}
656680
}
657681

658-
@Override
659-
public final void onPhaseFailure(SearchPhase phase, String msg, Throwable cause) {
682+
/**
683+
* This method will communicate a fatal phase failure back to the user. In contrast to a shard failure
684+
* will this method immediately fail the search request and return the failure to the issuer of the request
685+
* @param phase the phase that failed
686+
* @param msg an optional message
687+
* @param cause the cause of the phase failure
688+
*/
689+
public void onPhaseFailure(SearchPhase phase, String msg, Throwable cause) {
660690
raisePhaseFailure(new SearchPhaseExecutionException(phase.getName(), msg, cause, buildShardFailures()));
661691
}
662692

@@ -683,6 +713,19 @@ private void raisePhaseFailure(SearchPhaseExecutionException exception) {
683713
listener.onFailure(exception);
684714
}
685715

716+
/**
717+
* Releases a search context with the given context ID on the node the given connection is connected to.
718+
* @see org.elasticsearch.search.query.QuerySearchResult#getContextId()
719+
* @see org.elasticsearch.search.fetch.FetchSearchResult#getContextId()
720+
*
721+
*/
722+
void sendReleaseSearchContext(ShardSearchContextId contextId, Transport.Connection connection, OriginalIndices originalIndices) {
723+
assert isPartOfPointInTime(contextId) == false : "Must not release point in time context [" + contextId + "]";
724+
if (connection != null) {
725+
searchTransportService.sendFreeContext(connection, contextId, originalIndices);
726+
}
727+
}
728+
686729
/**
687730
* Executed once all shard results have been received and processed
688731
* @see #onShardFailure(int, SearchShardTarget, Exception)
@@ -692,23 +735,29 @@ final void onPhaseDone() { // as a tribute to @kimchy aka. finishHim()
692735
executeNextPhase(this, this::getNextPhase);
693736
}
694737

695-
@Override
738+
/**
739+
* Returns a connection to the node if connected otherwise and {@link org.elasticsearch.transport.ConnectTransportException} will be
740+
* thrown.
741+
*/
696742
public final Transport.Connection getConnection(String clusterAlias, String nodeId) {
697743
return nodeIdToConnection.apply(clusterAlias, nodeId);
698744
}
699745

700-
@Override
701-
public final SearchTransportService getSearchTransport() {
746+
/**
747+
* Returns the {@link SearchTransportService} to send shard request to other nodes
748+
*/
749+
public SearchTransportService getSearchTransport() {
702750
return searchTransportService;
703751
}
704752

705-
@Override
706753
public final void execute(Runnable command) {
707754
executor.execute(command);
708755
}
709756

710-
@Override
711-
public final void onFailure(Exception e) {
757+
/**
758+
* Notifies the top-level listener of the provided exception
759+
*/
760+
public void onFailure(Exception e) {
712761
listener.onFailure(e);
713762
}
714763

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ final class CountedCollector<R extends SearchPhaseResult> {
2222
private final SearchPhaseResults<R> resultConsumer;
2323
private final CountDown counter;
2424
private final Runnable onFinish;
25-
private final SearchPhaseContext context;
25+
private final AbstractSearchAsyncAction<?> context;
2626

27-
CountedCollector(SearchPhaseResults<R> resultConsumer, int expectedOps, Runnable onFinish, SearchPhaseContext context) {
27+
CountedCollector(SearchPhaseResults<R> resultConsumer, int expectedOps, Runnable onFinish, AbstractSearchAsyncAction<?> context) {
2828
this.resultConsumer = resultConsumer;
2929
this.counter = new CountDown(expectedOps);
3030
this.onFinish = onFinish;
@@ -50,7 +50,7 @@ void onResult(R result) {
5050
}
5151

5252
/**
53-
* Escalates the failure via {@link SearchPhaseContext#onShardFailure(int, SearchShardTarget, Exception)}
53+
* Escalates the failure via {@link AbstractSearchAsyncAction#onShardFailure(int, SearchShardTarget, Exception)}
5454
* and then runs {@link #countDown()}
5555
*/
5656
void onFailure(final int shardIndex, @Nullable SearchShardTarget shardTarget, Exception e) {

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ final class DfsQueryPhase extends SearchPhase {
4444
private final AggregatedDfs dfs;
4545
private final List<DfsKnnResults> knnResults;
4646
private final Function<SearchPhaseResults<SearchPhaseResult>, SearchPhase> nextPhaseFactory;
47-
private final SearchPhaseContext context;
47+
private final AbstractSearchAsyncAction<?> context;
4848
private final SearchTransportService searchTransportService;
4949
private final SearchProgressListener progressListener;
5050

@@ -54,7 +54,7 @@ final class DfsQueryPhase extends SearchPhase {
5454
List<DfsKnnResults> knnResults,
5555
SearchPhaseResults<SearchPhaseResult> queryResult,
5656
Function<SearchPhaseResults<SearchPhaseResult>, SearchPhase> nextPhaseFactory,
57-
SearchPhaseContext context
57+
AbstractSearchAsyncAction<?> context
5858
) {
5959
super("dfs_query");
6060
this.progressListener = context.getTask().getProgressListener();

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@
3131
* forwards to the next phase immediately.
3232
*/
3333
final class ExpandSearchPhase extends SearchPhase {
34-
private final SearchPhaseContext context;
34+
private final AbstractSearchAsyncAction<?> context;
3535
private final SearchHits searchHits;
3636
private final Supplier<SearchPhase> nextPhase;
3737

38-
ExpandSearchPhase(SearchPhaseContext context, SearchHits searchHits, Supplier<SearchPhase> nextPhase) {
38+
ExpandSearchPhase(AbstractSearchAsyncAction<?> context, SearchHits searchHits, Supplier<SearchPhase> nextPhase) {
3939
super("expand");
4040
this.context = context;
4141
this.searchHits = searchHits;

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,15 @@
3333
* @see org.elasticsearch.index.mapper.LookupRuntimeFieldType
3434
*/
3535
final class FetchLookupFieldsPhase extends SearchPhase {
36-
private final SearchPhaseContext context;
36+
private final AbstractSearchAsyncAction<?> context;
3737
private final SearchResponseSections searchResponse;
3838
private final AtomicArray<SearchPhaseResult> queryResults;
3939

40-
FetchLookupFieldsPhase(SearchPhaseContext context, SearchResponseSections searchResponse, AtomicArray<SearchPhaseResult> queryResults) {
40+
FetchLookupFieldsPhase(
41+
AbstractSearchAsyncAction<?> context,
42+
SearchResponseSections searchResponse,
43+
AtomicArray<SearchPhaseResult> queryResults
44+
) {
4145
super("fetch_lookup_fields");
4246
this.context = context;
4347
this.searchResponse = searchResponse;

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
final class FetchSearchPhase extends SearchPhase {
3737
private final AtomicArray<SearchPhaseResult> searchPhaseShardResults;
3838
private final BiFunction<SearchResponseSections, AtomicArray<SearchPhaseResult>, SearchPhase> nextPhaseFactory;
39-
private final SearchPhaseContext context;
39+
private final AbstractSearchAsyncAction<?> context;
4040
private final Logger logger;
4141
private final SearchProgressListener progressListener;
4242
private final AggregatedDfs aggregatedDfs;
@@ -47,7 +47,7 @@ final class FetchSearchPhase extends SearchPhase {
4747
FetchSearchPhase(
4848
SearchPhaseResults<SearchPhaseResult> resultConsumer,
4949
AggregatedDfs aggregatedDfs,
50-
SearchPhaseContext context,
50+
AbstractSearchAsyncAction<?> context,
5151
@Nullable SearchPhaseController.ReducedQueryPhase reducedQueryPhase
5252
) {
5353
this(
@@ -66,7 +66,7 @@ final class FetchSearchPhase extends SearchPhase {
6666
FetchSearchPhase(
6767
SearchPhaseResults<SearchPhaseResult> resultConsumer,
6868
AggregatedDfs aggregatedDfs,
69-
SearchPhaseContext context,
69+
AbstractSearchAsyncAction<?> context,
7070
@Nullable SearchPhaseController.ReducedQueryPhase reducedQueryPhase,
7171
BiFunction<SearchResponseSections, AtomicArray<SearchPhaseResult>, SearchPhase> nextPhaseFactory
7272
) {

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

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
public class RankFeaturePhase extends SearchPhase {
3939

4040
private static final Logger logger = LogManager.getLogger(RankFeaturePhase.class);
41-
private final SearchPhaseContext context;
41+
private final AbstractSearchAsyncAction<?> context;
4242
final SearchPhaseResults<SearchPhaseResult> queryPhaseResults;
4343
final SearchPhaseResults<SearchPhaseResult> rankPhaseResults;
4444
private final AggregatedDfs aggregatedDfs;
@@ -48,7 +48,7 @@ public class RankFeaturePhase extends SearchPhase {
4848
RankFeaturePhase(
4949
SearchPhaseResults<SearchPhaseResult> queryPhaseResults,
5050
AggregatedDfs aggregatedDfs,
51-
SearchPhaseContext context,
51+
AbstractSearchAsyncAction<?> context,
5252
RankFeaturePhaseRankCoordinatorContext rankFeaturePhaseRankCoordinatorContext
5353
) {
5454
super("rank-feature");
@@ -179,22 +179,25 @@ private void onPhaseDone(
179179
RankFeaturePhaseRankCoordinatorContext rankFeaturePhaseRankCoordinatorContext,
180180
SearchPhaseController.ReducedQueryPhase reducedQueryPhase
181181
) {
182-
ThreadedActionListener<RankFeatureDoc[]> rankResultListener = new ThreadedActionListener<>(context, new ActionListener<>() {
183-
@Override
184-
public void onResponse(RankFeatureDoc[] docsWithUpdatedScores) {
185-
RankFeatureDoc[] topResults = rankFeaturePhaseRankCoordinatorContext.rankAndPaginate(docsWithUpdatedScores);
186-
SearchPhaseController.ReducedQueryPhase reducedRankFeaturePhase = newReducedQueryPhaseResults(
187-
reducedQueryPhase,
188-
topResults
189-
);
190-
moveToNextPhase(rankPhaseResults, reducedRankFeaturePhase);
191-
}
182+
ThreadedActionListener<RankFeatureDoc[]> rankResultListener = new ThreadedActionListener<>(
183+
context::execute,
184+
new ActionListener<>() {
185+
@Override
186+
public void onResponse(RankFeatureDoc[] docsWithUpdatedScores) {
187+
RankFeatureDoc[] topResults = rankFeaturePhaseRankCoordinatorContext.rankAndPaginate(docsWithUpdatedScores);
188+
SearchPhaseController.ReducedQueryPhase reducedRankFeaturePhase = newReducedQueryPhaseResults(
189+
reducedQueryPhase,
190+
topResults
191+
);
192+
moveToNextPhase(rankPhaseResults, reducedRankFeaturePhase);
193+
}
192194

193-
@Override
194-
public void onFailure(Exception e) {
195-
context.onPhaseFailure(RankFeaturePhase.this, "Computing updated ranks for results failed", e);
195+
@Override
196+
public void onFailure(Exception e) {
197+
context.onPhaseFailure(RankFeaturePhase.this, "Computing updated ranks for results failed", e);
198+
}
196199
}
197-
});
200+
);
198201
rankFeaturePhaseRankCoordinatorContext.computeRankScoresForGlobalResults(
199202
rankPhaseResults.getAtomicArray().asList().stream().map(SearchPhaseResult::rankFeatureResult).toList(),
200203
rankResultListener

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ protected void doCheckNoMissingShards(String phaseName, SearchRequest request, G
7474
/**
7575
* Releases shard targets that are not used in the docsIdsToLoad.
7676
*/
77-
protected void releaseIrrelevantSearchContext(SearchPhaseResult searchPhaseResult, SearchPhaseContext context) {
77+
protected void releaseIrrelevantSearchContext(SearchPhaseResult searchPhaseResult, AbstractSearchAsyncAction<?> context) {
7878
// we only release search context that we did not fetch from, if we are not scrolling
7979
// or using a PIT and if it has at least one hit that didn't make it to the global topDocs
8080
if (searchPhaseResult == null) {

0 commit comments

Comments
 (0)