From d1c8703477a396c15d51afe56d347e56522c3de5 Mon Sep 17 00:00:00 2001 From: Jason Tedor Date: Mon, 13 Jul 2015 13:58:51 -0400 Subject: [PATCH] Add global search timeout setting This commit adds a dynamically updatable cluster-level search timeout setting. Closes #12149 --- .../query/TransportValidateQueryAction.java | 4 +++- .../action/exists/TransportExistsAction.java | 5 +++- .../explain/TransportExplainAction.java | 4 +++- .../ClusterDynamicSettingsModule.java | 2 ++ .../cluster/settings/Validator.java | 19 +++++++++++++++ .../elasticsearch/search/SearchService.java | 24 +++++++++++++++++-- .../search/internal/ContextIndexSearcher.java | 3 ++- .../search/internal/DefaultSearchContext.java | 8 +++++-- .../test/search/MockSearchService.java | 5 ++-- 9 files changed, 64 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/org/elasticsearch/action/admin/indices/validate/query/TransportValidateQueryAction.java b/core/src/main/java/org/elasticsearch/action/admin/indices/validate/query/TransportValidateQueryAction.java index 6b3438dea13..4437e80d96d 100644 --- a/core/src/main/java/org/elasticsearch/action/admin/indices/validate/query/TransportValidateQueryAction.java +++ b/core/src/main/java/org/elasticsearch/action/admin/indices/validate/query/TransportValidateQueryAction.java @@ -46,6 +46,7 @@ import org.elasticsearch.index.query.QueryParsingException; import org.elasticsearch.index.shard.IndexShard; import org.elasticsearch.indices.IndicesService; import org.elasticsearch.script.ScriptService; +import org.elasticsearch.search.SearchService; import org.elasticsearch.search.internal.DefaultSearchContext; import org.elasticsearch.search.internal.SearchContext; import org.elasticsearch.search.internal.ShardSearchLocalRequest; @@ -172,7 +173,8 @@ public class TransportValidateQueryAction extends TransportBroadcastAction { public static final String NORMS_LOADING_KEY = "index.norms.loading"; public static final String DEFAULT_KEEPALIVE_KEY = "search.default_keep_alive"; public static final String KEEPALIVE_INTERVAL_KEY = "search.keep_alive_interval"; + public static final String DEFAULT_SEARCH_TIMEOUT = "search.default_search_timeout"; + public static final TimeValue NO_TIMEOUT = timeValueMillis(-1); private final ThreadPool threadPool; @@ -137,6 +141,8 @@ public class SearchService extends AbstractLifecycleComponent { private final long defaultKeepAlive; + private volatile TimeValue defaultSearchTimeout; + private final ScheduledFuture keepAliveReaper; private final AtomicLong idGenerator = new AtomicLong(); @@ -148,7 +154,7 @@ public class SearchService extends AbstractLifecycleComponent { private final ParseFieldMatcher parseFieldMatcher; @Inject - public SearchService(Settings settings, ClusterService clusterService, IndicesService indicesService,IndicesWarmer indicesWarmer, ThreadPool threadPool, + public SearchService(Settings settings, NodeSettingsService nodeSettingsService, ClusterService clusterService, IndicesService indicesService,IndicesWarmer indicesWarmer, ThreadPool threadPool, ScriptService scriptService, PageCacheRecycler pageCacheRecycler, BigArrays bigArrays, DfsPhase dfsPhase, QueryPhase queryPhase, FetchPhase fetchPhase, IndicesRequestCache indicesQueryCache) { super(settings); @@ -202,6 +208,20 @@ public class SearchService extends AbstractLifecycleComponent { this.indicesWarmer.addListener(new NormsWarmer()); this.indicesWarmer.addListener(new FieldDataWarmer()); this.indicesWarmer.addListener(new SearchWarmer()); + + defaultSearchTimeout = settings.getAsTime(DEFAULT_SEARCH_TIMEOUT, NO_TIMEOUT); + nodeSettingsService.addListener(new SearchSettingsListener()); + } + + class SearchSettingsListener implements NodeSettingsService.Listener { + @Override + public void onRefreshSettings(Settings settings) { + final TimeValue maybeNewDefaultSearchTimeout = settings.getAsTime(SearchService.DEFAULT_SEARCH_TIMEOUT, SearchService.this.defaultSearchTimeout); + if (!maybeNewDefaultSearchTimeout.equals(SearchService.this.defaultSearchTimeout)) { + logger.info("updating [{}] from [{}] to [{}]", SearchService.DEFAULT_SEARCH_TIMEOUT, SearchService.this.defaultSearchTimeout, maybeNewDefaultSearchTimeout); + SearchService.this.defaultSearchTimeout = maybeNewDefaultSearchTimeout; + } + } } protected void putContext(SearchContext context) { @@ -619,7 +639,7 @@ public class SearchService extends AbstractLifecycleComponent { Engine.Searcher engineSearcher = searcher == null ? indexShard.acquireSearcher("search") : searcher; - SearchContext context = new DefaultSearchContext(idGenerator.incrementAndGet(), request, shardTarget, engineSearcher, indexService, indexShard, scriptService, pageCacheRecycler, bigArrays, threadPool.estimatedTimeInMillisCounter(), parseFieldMatcher); + SearchContext context = new DefaultSearchContext(idGenerator.incrementAndGet(), request, shardTarget, engineSearcher, indexService, indexShard, scriptService, pageCacheRecycler, bigArrays, threadPool.estimatedTimeInMillisCounter(), parseFieldMatcher, defaultSearchTimeout); SearchContext.setCurrent(context); try { context.scroll(request.scroll()); diff --git a/core/src/main/java/org/elasticsearch/search/internal/ContextIndexSearcher.java b/core/src/main/java/org/elasticsearch/search/internal/ContextIndexSearcher.java index 3ad8ec39d94..2144d13a123 100644 --- a/core/src/main/java/org/elasticsearch/search/internal/ContextIndexSearcher.java +++ b/core/src/main/java/org/elasticsearch/search/internal/ContextIndexSearcher.java @@ -35,6 +35,7 @@ import org.elasticsearch.common.lucene.Lucene; import org.elasticsearch.common.lucene.MinimumScoreCollector; import org.elasticsearch.common.lucene.search.FilteredCollector; import org.elasticsearch.index.engine.Engine; +import org.elasticsearch.search.SearchService; import org.elasticsearch.search.dfs.CachedDfSource; import org.elasticsearch.search.internal.SearchContext.Lifetime; @@ -139,7 +140,7 @@ public class ContextIndexSearcher extends IndexSearcher implements Releasable { public void search(Query query, Collector collector) throws IOException { // Wrap the caller's collector with various wrappers e.g. those used to siphon // matches off for aggregation or to impose a time-limit on collection. - final boolean timeoutSet = searchContext.timeoutInMillis() != -1; + final boolean timeoutSet = searchContext.timeoutInMillis() != SearchService.NO_TIMEOUT.millis(); final boolean terminateAfterSet = searchContext.terminateAfter() != SearchContext.DEFAULT_TERMINATE_AFTER; if (timeoutSet) { diff --git a/core/src/main/java/org/elasticsearch/search/internal/DefaultSearchContext.java b/core/src/main/java/org/elasticsearch/search/internal/DefaultSearchContext.java index a9f0f368c0b..6023ab3d9e5 100644 --- a/core/src/main/java/org/elasticsearch/search/internal/DefaultSearchContext.java +++ b/core/src/main/java/org/elasticsearch/search/internal/DefaultSearchContext.java @@ -33,6 +33,7 @@ import org.elasticsearch.common.lease.Releasables; import org.elasticsearch.common.lucene.search.Queries; import org.elasticsearch.common.lucene.search.function.BoostScoreFunction; import org.elasticsearch.common.lucene.search.function.FunctionScoreQuery; +import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.util.BigArrays; import org.elasticsearch.index.IndexService; import org.elasticsearch.index.analysis.AnalysisService; @@ -90,7 +91,7 @@ public class DefaultSearchContext extends SearchContext { private ScanContext scanContext; private float queryBoost = 1.0f; // timeout in millis - private long timeoutInMillis = -1; + private long timeoutInMillis; // terminate after count private int terminateAfter = DEFAULT_TERMINATE_AFTER; private List groupStats; @@ -127,7 +128,9 @@ public class DefaultSearchContext extends SearchContext { public DefaultSearchContext(long id, ShardSearchRequest request, SearchShardTarget shardTarget, Engine.Searcher engineSearcher, IndexService indexService, IndexShard indexShard, ScriptService scriptService, PageCacheRecycler pageCacheRecycler, - BigArrays bigArrays, Counter timeEstimateCounter, ParseFieldMatcher parseFieldMatcher) { + BigArrays bigArrays, Counter timeEstimateCounter, ParseFieldMatcher parseFieldMatcher, + TimeValue timeout + ) { super(parseFieldMatcher); this.id = id; this.request = request; @@ -145,6 +148,7 @@ public class DefaultSearchContext extends SearchContext { this.indexService = indexService; this.searcher = new ContextIndexSearcher(this, engineSearcher); this.timeEstimateCounter = timeEstimateCounter; + this.timeoutInMillis = timeout.millis(); } @Override diff --git a/core/src/test/java/org/elasticsearch/test/search/MockSearchService.java b/core/src/test/java/org/elasticsearch/test/search/MockSearchService.java index 80b83affd28..dd6c972af00 100644 --- a/core/src/test/java/org/elasticsearch/test/search/MockSearchService.java +++ b/core/src/test/java/org/elasticsearch/test/search/MockSearchService.java @@ -27,6 +27,7 @@ import org.elasticsearch.common.util.BigArrays; import org.elasticsearch.indices.IndicesService; import org.elasticsearch.indices.IndicesWarmer; import org.elasticsearch.indices.cache.request.IndicesRequestCache; +import org.elasticsearch.node.settings.NodeSettingsService; import org.elasticsearch.script.ScriptService; import org.elasticsearch.search.SearchService; import org.elasticsearch.search.dfs.DfsPhase; @@ -52,10 +53,10 @@ public class MockSearchService extends SearchService { } @Inject - public MockSearchService(Settings settings, ClusterService clusterService, IndicesService indicesService, IndicesWarmer indicesWarmer, + public MockSearchService(Settings settings, NodeSettingsService nodeSettingsService, ClusterService clusterService, IndicesService indicesService, IndicesWarmer indicesWarmer, ThreadPool threadPool, ScriptService scriptService, PageCacheRecycler pageCacheRecycler, BigArrays bigArrays, DfsPhase dfsPhase, QueryPhase queryPhase, FetchPhase fetchPhase, IndicesRequestCache indicesQueryCache) { - super(settings, clusterService, indicesService, indicesWarmer, threadPool, scriptService, pageCacheRecycler, bigArrays, dfsPhase, + super(settings, nodeSettingsService, clusterService, indicesService, indicesWarmer, threadPool, scriptService, pageCacheRecycler, bigArrays, dfsPhase, queryPhase, fetchPhase, indicesQueryCache); }