|
@@ -112,6 +112,7 @@ import java.util.Map;
|
|
|
import java.util.Optional;
|
|
|
import java.util.concurrent.ExecutionException;
|
|
|
import java.util.concurrent.Executor;
|
|
|
+import java.util.concurrent.atomic.AtomicInteger;
|
|
|
import java.util.concurrent.atomic.AtomicLong;
|
|
|
import java.util.function.LongSupplier;
|
|
|
import java.util.function.Supplier;
|
|
@@ -145,6 +146,9 @@ public class SearchService extends AbstractLifecycleComponent implements IndexEv
|
|
|
public static final Setting<Boolean> DEFAULT_ALLOW_PARTIAL_SEARCH_RESULTS =
|
|
|
Setting.boolSetting("search.default_allow_partial_results", true, Property.Dynamic, Property.NodeScope);
|
|
|
|
|
|
+ public static final Setting<Integer> MAX_OPEN_SCROLL_CONTEXT =
|
|
|
+ Setting.intSetting("search.max_open_scroll_context", 500, 0, Property.Dynamic, Property.NodeScope);
|
|
|
+
|
|
|
|
|
|
private final ThreadPool threadPool;
|
|
|
|
|
@@ -174,6 +178,8 @@ public class SearchService extends AbstractLifecycleComponent implements IndexEv
|
|
|
|
|
|
private volatile boolean lowLevelCancellation;
|
|
|
|
|
|
+ private volatile int maxOpenScrollContext;
|
|
|
+
|
|
|
private final Cancellable keepAliveReaper;
|
|
|
|
|
|
private final AtomicLong idGenerator = new AtomicLong();
|
|
@@ -182,6 +188,8 @@ public class SearchService extends AbstractLifecycleComponent implements IndexEv
|
|
|
|
|
|
private final MultiBucketConsumerService multiBucketConsumerService;
|
|
|
|
|
|
+ private final AtomicInteger openScrollContexts = new AtomicInteger();
|
|
|
+
|
|
|
public SearchService(ClusterService clusterService, IndicesService indicesService,
|
|
|
ThreadPool threadPool, ScriptService scriptService, BigArrays bigArrays, FetchPhase fetchPhase,
|
|
|
ResponseCollectorService responseCollectorService) {
|
|
@@ -212,6 +220,8 @@ public class SearchService extends AbstractLifecycleComponent implements IndexEv
|
|
|
clusterService.getClusterSettings().addSettingsUpdateConsumer(DEFAULT_ALLOW_PARTIAL_SEARCH_RESULTS,
|
|
|
this::setDefaultAllowPartialSearchResults);
|
|
|
|
|
|
+ maxOpenScrollContext = MAX_OPEN_SCROLL_CONTEXT.get(settings);
|
|
|
+ clusterService.getClusterSettings().addSettingsUpdateConsumer(MAX_OPEN_SCROLL_CONTEXT, this::setMaxOpenScrollContext);
|
|
|
|
|
|
lowLevelCancellation = LOW_LEVEL_CANCELLATION_SETTING.get(settings);
|
|
|
clusterService.getClusterSettings().addSettingsUpdateConsumer(LOW_LEVEL_CANCELLATION_SETTING, this::setLowLevelCancellation);
|
|
@@ -243,6 +253,10 @@ public class SearchService extends AbstractLifecycleComponent implements IndexEv
|
|
|
return defaultAllowPartialSearchResults;
|
|
|
}
|
|
|
|
|
|
+ private void setMaxOpenScrollContext(int maxOpenScrollContext) {
|
|
|
+ this.maxOpenScrollContext = maxOpenScrollContext;
|
|
|
+ }
|
|
|
+
|
|
|
private void setLowLevelCancellation(Boolean lowLevelCancellation) {
|
|
|
this.lowLevelCancellation = lowLevelCancellation;
|
|
|
}
|
|
@@ -592,11 +606,19 @@ public class SearchService extends AbstractLifecycleComponent implements IndexEv
|
|
|
}
|
|
|
|
|
|
final SearchContext createAndPutContext(ShardSearchRequest request) throws IOException {
|
|
|
+ if (request.scroll() != null && openScrollContexts.get() >= maxOpenScrollContext) {
|
|
|
+ throw new ElasticsearchException(
|
|
|
+ "Trying to create too many scroll contexts. Must be less than or equal to: [" +
|
|
|
+ maxOpenScrollContext + "]. " + "This limit can be set by changing the ["
|
|
|
+ + MAX_OPEN_SCROLL_CONTEXT.getKey() + "] setting.");
|
|
|
+ }
|
|
|
+
|
|
|
SearchContext context = createContext(request);
|
|
|
boolean success = false;
|
|
|
try {
|
|
|
putContext(context);
|
|
|
if (request.scroll() != null) {
|
|
|
+ openScrollContexts.incrementAndGet();
|
|
|
context.indexShard().getSearchOperationListener().onNewScrollContext(context);
|
|
|
}
|
|
|
context.indexShard().getSearchOperationListener().onNewContext(context);
|
|
@@ -696,6 +718,7 @@ public class SearchService extends AbstractLifecycleComponent implements IndexEv
|
|
|
assert context.refCount() > 0 : " refCount must be > 0: " + context.refCount();
|
|
|
context.indexShard().getSearchOperationListener().onFreeContext(context);
|
|
|
if (context.scrollContext() != null) {
|
|
|
+ openScrollContexts.decrementAndGet();
|
|
|
context.indexShard().getSearchOperationListener().onFreeScrollContext(context);
|
|
|
}
|
|
|
return true;
|