[CORE] Unify search context cleanup
Today there are two different ways to cleanup search contexts which can potentially lead to double releasing of a context. This commit unifies the methods and prevents double closing. Closes #7625
This commit is contained in:
parent
80a3038f83
commit
72c4cb51cc
|
@ -175,8 +175,8 @@ public class SearchService extends AbstractLifecycleComponent<SearchService> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doStop() throws ElasticsearchException {
|
protected void doStop() throws ElasticsearchException {
|
||||||
for (SearchContext context : activeContexts.values()) {
|
for (final SearchContext context : activeContexts.values()) {
|
||||||
freeContext(context);
|
freeContext(context.id());
|
||||||
}
|
}
|
||||||
activeContexts.clear();
|
activeContexts.clear();
|
||||||
}
|
}
|
||||||
|
@ -187,7 +187,7 @@ public class SearchService extends AbstractLifecycleComponent<SearchService> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public DfsSearchResult executeDfsPhase(ShardSearchRequest request) throws ElasticsearchException {
|
public DfsSearchResult executeDfsPhase(ShardSearchRequest request) throws ElasticsearchException {
|
||||||
SearchContext context = createAndPutContext(request);
|
final SearchContext context = createAndPutContext(request);
|
||||||
try {
|
try {
|
||||||
contextProcessing(context);
|
contextProcessing(context);
|
||||||
dfsPhase.execute(context);
|
dfsPhase.execute(context);
|
||||||
|
@ -195,7 +195,7 @@ public class SearchService extends AbstractLifecycleComponent<SearchService> {
|
||||||
return context.dfsResult();
|
return context.dfsResult();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
logger.trace("Dfs phase failed", e);
|
logger.trace("Dfs phase failed", e);
|
||||||
freeContext(context);
|
freeContext(context.id());
|
||||||
throw ExceptionsHelper.convertToRuntime(e);
|
throw ExceptionsHelper.convertToRuntime(e);
|
||||||
} finally {
|
} finally {
|
||||||
cleanContext(context);
|
cleanContext(context);
|
||||||
|
@ -203,7 +203,7 @@ public class SearchService extends AbstractLifecycleComponent<SearchService> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public QuerySearchResult executeScan(ShardSearchRequest request) throws ElasticsearchException {
|
public QuerySearchResult executeScan(ShardSearchRequest request) throws ElasticsearchException {
|
||||||
SearchContext context = createAndPutContext(request);
|
final SearchContext context = createAndPutContext(request);
|
||||||
try {
|
try {
|
||||||
if (context.aggregations() != null) {
|
if (context.aggregations() != null) {
|
||||||
throw new ElasticsearchIllegalArgumentException("aggregations are not supported with search_type=scan");
|
throw new ElasticsearchIllegalArgumentException("aggregations are not supported with search_type=scan");
|
||||||
|
@ -221,7 +221,7 @@ public class SearchService extends AbstractLifecycleComponent<SearchService> {
|
||||||
return context.queryResult();
|
return context.queryResult();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
logger.trace("Scan phase failed", e);
|
logger.trace("Scan phase failed", e);
|
||||||
freeContext(context);
|
freeContext(context.id());
|
||||||
throw ExceptionsHelper.convertToRuntime(e);
|
throw ExceptionsHelper.convertToRuntime(e);
|
||||||
} finally {
|
} finally {
|
||||||
cleanContext(context);
|
cleanContext(context);
|
||||||
|
@ -229,7 +229,7 @@ public class SearchService extends AbstractLifecycleComponent<SearchService> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScrollQueryFetchSearchResult executeScan(InternalScrollSearchRequest request) throws ElasticsearchException {
|
public ScrollQueryFetchSearchResult executeScan(InternalScrollSearchRequest request) throws ElasticsearchException {
|
||||||
SearchContext context = findContext(request.id());
|
final SearchContext context = findContext(request.id());
|
||||||
contextProcessing(context);
|
contextProcessing(context);
|
||||||
try {
|
try {
|
||||||
processScroll(request, context);
|
processScroll(request, context);
|
||||||
|
@ -249,7 +249,7 @@ public class SearchService extends AbstractLifecycleComponent<SearchService> {
|
||||||
return new ScrollQueryFetchSearchResult(new QueryFetchSearchResult(context.queryResult(), context.fetchResult()), context.shardTarget());
|
return new ScrollQueryFetchSearchResult(new QueryFetchSearchResult(context.queryResult(), context.fetchResult()), context.shardTarget());
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
logger.trace("Scan phase failed", e);
|
logger.trace("Scan phase failed", e);
|
||||||
freeContext(context);
|
freeContext(context.id());
|
||||||
throw ExceptionsHelper.convertToRuntime(e);
|
throw ExceptionsHelper.convertToRuntime(e);
|
||||||
} finally {
|
} finally {
|
||||||
cleanContext(context);
|
cleanContext(context);
|
||||||
|
@ -257,7 +257,7 @@ public class SearchService extends AbstractLifecycleComponent<SearchService> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public QuerySearchResultProvider executeQueryPhase(ShardSearchRequest request) throws ElasticsearchException {
|
public QuerySearchResultProvider executeQueryPhase(ShardSearchRequest request) throws ElasticsearchException {
|
||||||
SearchContext context = createAndPutContext(request);
|
final SearchContext context = createAndPutContext(request);
|
||||||
try {
|
try {
|
||||||
context.indexShard().searchService().onPreQueryPhase(context);
|
context.indexShard().searchService().onPreQueryPhase(context);
|
||||||
long time = System.nanoTime();
|
long time = System.nanoTime();
|
||||||
|
@ -287,7 +287,7 @@ public class SearchService extends AbstractLifecycleComponent<SearchService> {
|
||||||
}
|
}
|
||||||
context.indexShard().searchService().onFailedQueryPhase(context);
|
context.indexShard().searchService().onFailedQueryPhase(context);
|
||||||
logger.trace("Query phase failed", e);
|
logger.trace("Query phase failed", e);
|
||||||
freeContext(context);
|
freeContext(context.id());
|
||||||
throw ExceptionsHelper.convertToRuntime(e);
|
throw ExceptionsHelper.convertToRuntime(e);
|
||||||
} finally {
|
} finally {
|
||||||
cleanContext(context);
|
cleanContext(context);
|
||||||
|
@ -295,7 +295,7 @@ public class SearchService extends AbstractLifecycleComponent<SearchService> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScrollQuerySearchResult executeQueryPhase(InternalScrollSearchRequest request) throws ElasticsearchException {
|
public ScrollQuerySearchResult executeQueryPhase(InternalScrollSearchRequest request) throws ElasticsearchException {
|
||||||
SearchContext context = findContext(request.id());
|
final SearchContext context = findContext(request.id());
|
||||||
try {
|
try {
|
||||||
context.indexShard().searchService().onPreQueryPhase(context);
|
context.indexShard().searchService().onPreQueryPhase(context);
|
||||||
long time = System.nanoTime();
|
long time = System.nanoTime();
|
||||||
|
@ -308,7 +308,7 @@ public class SearchService extends AbstractLifecycleComponent<SearchService> {
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
context.indexShard().searchService().onFailedQueryPhase(context);
|
context.indexShard().searchService().onFailedQueryPhase(context);
|
||||||
logger.trace("Query phase failed", e);
|
logger.trace("Query phase failed", e);
|
||||||
freeContext(context);
|
freeContext(context.id());
|
||||||
throw ExceptionsHelper.convertToRuntime(e);
|
throw ExceptionsHelper.convertToRuntime(e);
|
||||||
} finally {
|
} finally {
|
||||||
cleanContext(context);
|
cleanContext(context);
|
||||||
|
@ -316,12 +316,12 @@ public class SearchService extends AbstractLifecycleComponent<SearchService> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public QuerySearchResult executeQueryPhase(QuerySearchRequest request) throws ElasticsearchException {
|
public QuerySearchResult executeQueryPhase(QuerySearchRequest request) throws ElasticsearchException {
|
||||||
SearchContext context = findContext(request.id());
|
final SearchContext context = findContext(request.id());
|
||||||
contextProcessing(context);
|
contextProcessing(context);
|
||||||
try {
|
try {
|
||||||
context.searcher().dfSource(new CachedDfSource(context.searcher().getIndexReader(), request.dfs(), context.similarityService().similarity()));
|
context.searcher().dfSource(new CachedDfSource(context.searcher().getIndexReader(), request.dfs(), context.similarityService().similarity()));
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
freeContext(context);
|
freeContext(context.id());
|
||||||
cleanContext(context);
|
cleanContext(context);
|
||||||
throw new QueryPhaseExecutionException(context, "Failed to set aggregated df", e);
|
throw new QueryPhaseExecutionException(context, "Failed to set aggregated df", e);
|
||||||
}
|
}
|
||||||
|
@ -335,7 +335,7 @@ public class SearchService extends AbstractLifecycleComponent<SearchService> {
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
context.indexShard().searchService().onFailedQueryPhase(context);
|
context.indexShard().searchService().onFailedQueryPhase(context);
|
||||||
logger.trace("Query phase failed", e);
|
logger.trace("Query phase failed", e);
|
||||||
freeContext(context);
|
freeContext(context.id());
|
||||||
throw ExceptionsHelper.convertToRuntime(e);
|
throw ExceptionsHelper.convertToRuntime(e);
|
||||||
} finally {
|
} finally {
|
||||||
cleanContext(context);
|
cleanContext(context);
|
||||||
|
@ -343,7 +343,7 @@ public class SearchService extends AbstractLifecycleComponent<SearchService> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public QueryFetchSearchResult executeFetchPhase(ShardSearchRequest request) throws ElasticsearchException {
|
public QueryFetchSearchResult executeFetchPhase(ShardSearchRequest request) throws ElasticsearchException {
|
||||||
SearchContext context = createAndPutContext(request);
|
final SearchContext context = createAndPutContext(request);
|
||||||
contextProcessing(context);
|
contextProcessing(context);
|
||||||
try {
|
try {
|
||||||
context.indexShard().searchService().onPreQueryPhase(context);
|
context.indexShard().searchService().onPreQueryPhase(context);
|
||||||
|
@ -373,7 +373,7 @@ public class SearchService extends AbstractLifecycleComponent<SearchService> {
|
||||||
return new QueryFetchSearchResult(context.queryResult(), context.fetchResult());
|
return new QueryFetchSearchResult(context.queryResult(), context.fetchResult());
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
logger.trace("Fetch phase failed", e);
|
logger.trace("Fetch phase failed", e);
|
||||||
freeContext(context);
|
freeContext(context.id());
|
||||||
throw ExceptionsHelper.convertToRuntime(e);
|
throw ExceptionsHelper.convertToRuntime(e);
|
||||||
} finally {
|
} finally {
|
||||||
cleanContext(context);
|
cleanContext(context);
|
||||||
|
@ -381,12 +381,12 @@ public class SearchService extends AbstractLifecycleComponent<SearchService> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public QueryFetchSearchResult executeFetchPhase(QuerySearchRequest request) throws ElasticsearchException {
|
public QueryFetchSearchResult executeFetchPhase(QuerySearchRequest request) throws ElasticsearchException {
|
||||||
SearchContext context = findContext(request.id());
|
final SearchContext context = findContext(request.id());
|
||||||
contextProcessing(context);
|
contextProcessing(context);
|
||||||
try {
|
try {
|
||||||
context.searcher().dfSource(new CachedDfSource(context.searcher().getIndexReader(), request.dfs(), context.similarityService().similarity()));
|
context.searcher().dfSource(new CachedDfSource(context.searcher().getIndexReader(), request.dfs(), context.similarityService().similarity()));
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
freeContext(context);
|
freeContext(context.id());
|
||||||
cleanContext(context);
|
cleanContext(context);
|
||||||
throw new QueryPhaseExecutionException(context, "Failed to set aggregated df", e);
|
throw new QueryPhaseExecutionException(context, "Failed to set aggregated df", e);
|
||||||
}
|
}
|
||||||
|
@ -418,7 +418,7 @@ public class SearchService extends AbstractLifecycleComponent<SearchService> {
|
||||||
return new QueryFetchSearchResult(context.queryResult(), context.fetchResult());
|
return new QueryFetchSearchResult(context.queryResult(), context.fetchResult());
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
logger.trace("Fetch phase failed", e);
|
logger.trace("Fetch phase failed", e);
|
||||||
freeContext(context);
|
freeContext(context.id());
|
||||||
throw ExceptionsHelper.convertToRuntime(e);
|
throw ExceptionsHelper.convertToRuntime(e);
|
||||||
} finally {
|
} finally {
|
||||||
cleanContext(context);
|
cleanContext(context);
|
||||||
|
@ -426,7 +426,7 @@ public class SearchService extends AbstractLifecycleComponent<SearchService> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScrollQueryFetchSearchResult executeFetchPhase(InternalScrollSearchRequest request) throws ElasticsearchException {
|
public ScrollQueryFetchSearchResult executeFetchPhase(InternalScrollSearchRequest request) throws ElasticsearchException {
|
||||||
SearchContext context = findContext(request.id());
|
final SearchContext context = findContext(request.id());
|
||||||
contextProcessing(context);
|
contextProcessing(context);
|
||||||
try {
|
try {
|
||||||
processScroll(request, context);
|
processScroll(request, context);
|
||||||
|
@ -457,7 +457,7 @@ public class SearchService extends AbstractLifecycleComponent<SearchService> {
|
||||||
return new ScrollQueryFetchSearchResult(new QueryFetchSearchResult(context.queryResult(), context.fetchResult()), context.shardTarget());
|
return new ScrollQueryFetchSearchResult(new QueryFetchSearchResult(context.queryResult(), context.fetchResult()), context.shardTarget());
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
logger.trace("Fetch phase failed", e);
|
logger.trace("Fetch phase failed", e);
|
||||||
freeContext(context);
|
freeContext(context.id());
|
||||||
throw ExceptionsHelper.convertToRuntime(e);
|
throw ExceptionsHelper.convertToRuntime(e);
|
||||||
} finally {
|
} finally {
|
||||||
cleanContext(context);
|
cleanContext(context);
|
||||||
|
@ -465,7 +465,7 @@ public class SearchService extends AbstractLifecycleComponent<SearchService> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public FetchSearchResult executeFetchPhase(FetchSearchRequest request) throws ElasticsearchException {
|
public FetchSearchResult executeFetchPhase(FetchSearchRequest request) throws ElasticsearchException {
|
||||||
SearchContext context = findContext(request.id());
|
final SearchContext context = findContext(request.id());
|
||||||
contextProcessing(context);
|
contextProcessing(context);
|
||||||
try {
|
try {
|
||||||
if (request.lastEmittedDoc() != null) {
|
if (request.lastEmittedDoc() != null) {
|
||||||
|
@ -485,7 +485,7 @@ public class SearchService extends AbstractLifecycleComponent<SearchService> {
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
context.indexShard().searchService().onFailedFetchPhase(context);
|
context.indexShard().searchService().onFailedFetchPhase(context);
|
||||||
logger.trace("Fetch phase failed", e);
|
logger.trace("Fetch phase failed", e);
|
||||||
freeContext(context); // we just try to make sure this is freed - rethrow orig exception.
|
freeContext(context.id()); // we just try to make sure this is freed - rethrow orig exception.
|
||||||
throw ExceptionsHelper.convertToRuntime(e);
|
throw ExceptionsHelper.convertToRuntime(e);
|
||||||
} finally {
|
} finally {
|
||||||
cleanContext(context);
|
cleanContext(context);
|
||||||
|
@ -511,7 +511,7 @@ public class SearchService extends AbstractLifecycleComponent<SearchService> {
|
||||||
return context;
|
return context;
|
||||||
} finally {
|
} finally {
|
||||||
if (!success) {
|
if (!success) {
|
||||||
freeContext(context);
|
freeContext(context.id());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -561,27 +561,22 @@ public class SearchService extends AbstractLifecycleComponent<SearchService> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean freeContext(long id) {
|
public boolean freeContext(long id) {
|
||||||
SearchContext context = activeContexts.remove(id);
|
final SearchContext context = activeContexts.remove(id);
|
||||||
if (context == null) {
|
if (context != null) {
|
||||||
return false;
|
try {
|
||||||
|
context.indexShard().searchService().onFreeContext(context);
|
||||||
|
} finally {
|
||||||
|
context.close();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
context.indexShard().searchService().onFreeContext(context);
|
return false;
|
||||||
context.close();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void freeContext(SearchContext context) {
|
|
||||||
SearchContext removed = activeContexts.remove(context.id());
|
|
||||||
if (removed != null) {
|
|
||||||
removed.indexShard().searchService().onFreeContext(removed);
|
|
||||||
}
|
|
||||||
context.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void freeAllScrollContexts() {
|
public void freeAllScrollContexts() {
|
||||||
for (SearchContext searchContext : activeContexts.values()) {
|
for (SearchContext searchContext : activeContexts.values()) {
|
||||||
if (searchContext.scroll() != null) {
|
if (searchContext.scroll() != null) {
|
||||||
freeContext(searchContext);
|
freeContext(searchContext.id());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -969,7 +964,7 @@ public class SearchService extends AbstractLifecycleComponent<SearchService> {
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
if (context != null) {
|
if (context != null) {
|
||||||
freeContext(context);
|
freeContext(context.id());
|
||||||
cleanContext(context);
|
cleanContext(context);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -1002,7 +997,7 @@ public class SearchService extends AbstractLifecycleComponent<SearchService> {
|
||||||
}
|
}
|
||||||
if ((time - lastAccessTime > context.keepAlive())) {
|
if ((time - lastAccessTime > context.keepAlive())) {
|
||||||
logger.debug("freeing search context [{}], time [{}], lastAccessTime [{}], keepAlive [{}]", context.id(), time, lastAccessTime, context.keepAlive());
|
logger.debug("freeing search context [{}], time [{}], lastAccessTime [{}], keepAlive [{}]", context.id(), time, lastAccessTime, context.keepAlive());
|
||||||
freeContext(context);
|
freeContext(context.id());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -145,7 +145,7 @@ public class SearchServiceTransportAction extends AbstractComponent {
|
||||||
|
|
||||||
public void sendFreeContext(DiscoveryNode node, long contextId, ClearScrollRequest request, final ActionListener<Boolean> actionListener) {
|
public void sendFreeContext(DiscoveryNode node, long contextId, ClearScrollRequest request, final ActionListener<Boolean> actionListener) {
|
||||||
if (clusterService.state().nodes().localNodeId().equals(node.id())) {
|
if (clusterService.state().nodes().localNodeId().equals(node.id())) {
|
||||||
boolean freed = searchService.freeContext(contextId);
|
final boolean freed = searchService.freeContext(contextId);
|
||||||
actionListener.onResponse(freed);
|
actionListener.onResponse(freed);
|
||||||
} else {
|
} else {
|
||||||
transportService.sendRequest(node, FREE_CONTEXT_ACTION_NAME, new SearchFreeContextRequest(request, contextId), new FreeContextResponseHandler(actionListener));
|
transportService.sendRequest(node, FREE_CONTEXT_ACTION_NAME, new SearchFreeContextRequest(request, contextId), new FreeContextResponseHandler(actionListener));
|
||||||
|
|
|
@ -64,6 +64,7 @@ import org.elasticsearch.search.suggest.SuggestionSearchContext;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
|
@ -87,12 +88,15 @@ public abstract class SearchContext implements Releasable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Multimap<Lifetime, Releasable> clearables = null;
|
private Multimap<Lifetime, Releasable> clearables = null;
|
||||||
|
private final AtomicBoolean closed = new AtomicBoolean(false);
|
||||||
|
|
||||||
public final void close() {
|
public final void close() {
|
||||||
try {
|
if (closed.compareAndSet(false, true)) { // prevent double release
|
||||||
clearReleasables(Lifetime.CONTEXT);
|
try {
|
||||||
} finally {
|
clearReleasables(Lifetime.CONTEXT);
|
||||||
doClose();
|
} finally {
|
||||||
|
doClose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue