summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHenning Baldersheim <balder@yahoo-inc.com>2020-04-25 18:57:12 +0000
committerHenning Baldersheim <balder@yahoo-inc.com>2020-04-25 18:57:12 +0000
commitc7b890535a3009e52e7227b883f2c9a16e59a740 (patch)
treebb68bdc548c6715a495e5aa910ea8e45ff1469ad
parent35decca41db6b9a44b24b6f7501c84d159ebd6a7 (diff)
Let size of thread pool and Q follow number of cores on the machine where it is running.
If auto detected num worker threads will use number of #cores * 4, quesize will use #numWorkers * 4. No changes of the default value in this commit.
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java6
-rw-r--r--config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java20
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/ApplicationContainer.java18
-rwxr-xr-xconfig-model/src/main/java/com/yahoo/vespa/model/container/ContainerCluster.java14
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/NodeFlavorTuning.java30
-rwxr-xr-xconfig-model/src/test/java/com/yahoo/vespa/model/container/ContainerClusterTest.java39
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java18
-rw-r--r--container-core/abi-spec.json2
-rw-r--r--container-core/src/main/java/com/yahoo/container/handler/ThreadPoolProvider.java30
-rw-r--r--container-core/src/main/resources/configdefinitions/threadpool.def8
-rw-r--r--container-core/src/test/java/com/yahoo/container/handler/ThreadPoolProviderTestCase.java34
-rw-r--r--flags/src/main/java/com/yahoo/vespa/flags/Flags.java11
12 files changed, 220 insertions, 10 deletions
diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java
index c406fa80434..86360d482a6 100644
--- a/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java
+++ b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java
@@ -72,6 +72,12 @@ public interface ModelContext {
double defaultTermwiseLimit();
// TODO Revisit in May or June 2020
+ double threadPoolSizeFactor();
+
+ // TODO Revisit in May or June 2020
+ double queueSizeFactor();
+
+ // TODO Revisit in May or June 2020
double defaultSoftStartSeconds();
// TODO Revisit in May or June 2020
diff --git a/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java b/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java
index 99225beba4f..d799af36c3b 100644
--- a/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java
+++ b/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java
@@ -43,6 +43,8 @@ public class TestProperties implements ModelContext.Properties {
private double topKProbability = 1.0;
private double defaultTermwiseLimit = 1.0;
private double softStartSeconds = 0.0;
+ private double threadPoolSizeFactor = 0.0;
+ private double queueSizeFactor = 0.0;
private Optional<EndpointCertificateSecrets> endpointCertificateSecrets = Optional.empty();
private AthenzDomain athenzDomain;
@@ -65,6 +67,16 @@ public class TestProperties implements ModelContext.Properties {
@Override public double defaultTermwiseLimit() { return defaultTermwiseLimit; }
@Override
+ public double threadPoolSizeFactor() {
+ return threadPoolSizeFactor;
+ }
+
+ @Override
+ public double queueSizeFactor() {
+ return queueSizeFactor;
+ }
+
+ @Override
public double defaultSoftStartSeconds() {
return softStartSeconds;
}
@@ -86,7 +98,15 @@ public class TestProperties implements ModelContext.Properties {
this.softStartSeconds = softStartSeconds;
return this;
}
+ public TestProperties setThreadPoolSizeFactor(double threadPoolSizeFactor) {
+ this.threadPoolSizeFactor = threadPoolSizeFactor;
+ return this;
+ }
+ public TestProperties setQueueSizeFactor(double queueSizeFactor) {
+ this.queueSizeFactor = queueSizeFactor;
+ return this;
+ }
public TestProperties setApplicationId(ApplicationId applicationId) {
this.applicationId = applicationId;
return this;
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/ApplicationContainer.java b/config-model/src/main/java/com/yahoo/vespa/model/container/ApplicationContainer.java
index e59baf88422..29bb578a67b 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/ApplicationContainer.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/ApplicationContainer.java
@@ -5,6 +5,7 @@ import com.yahoo.config.model.api.container.ContainerServiceType;
import com.yahoo.config.model.producer.AbstractConfigProducer;
import com.yahoo.config.provision.Flavor;
import com.yahoo.container.bundle.BundleInstantiationSpecification;
+import com.yahoo.container.handler.ThreadpoolConfig;
import com.yahoo.osgi.provider.model.ComponentModel;
import com.yahoo.prelude.fastsearch.FS4ResourcePool;
import com.yahoo.search.config.QrStartConfig;
@@ -15,7 +16,10 @@ import com.yahoo.vespa.model.container.component.Component;
*
* @author gjoranv
*/
-public final class ApplicationContainer extends Container implements QrStartConfig.Producer {
+public final class ApplicationContainer extends Container implements
+ QrStartConfig.Producer,
+ ThreadpoolConfig.Producer
+{
private static final String defaultHostedJVMArgs = "-XX:+UseOSErrorReporting -XX:+SuppressFatalErrorMessage";
@@ -73,4 +77,16 @@ public final class ApplicationContainer extends Container implements QrStartConf
return (parent instanceof ContainerCluster) && (((ContainerCluster)parent).getDocproc() != null);
}
+ @Override
+ public void getConfig(ThreadpoolConfig.Builder builder) {
+ if (! (parent instanceof ContainerCluster)) return;
+ if ((getHostResource() == null) || getHostResource().getFlavor().isEmpty()) return;
+ ContainerCluster containerCluster = (ContainerCluster) parent;
+ if (containerCluster.getThreadPoolSizeFactor() <= 0.0) return;
+
+ NodeFlavorTuning flavorTuning = new NodeFlavorTuning(getHostResource().getFlavor().get())
+ .setThreadPoolSizeFactor(containerCluster.getThreadPoolSizeFactor())
+ .setQueueSizeFactor(containerCluster.getQueueSizeFactor());
+ flavorTuning.getConfig(builder);
+ }
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/ContainerCluster.java b/config-model/src/main/java/com/yahoo/vespa/model/container/ContainerCluster.java
index 833f6688fbc..b35b7562704 100755
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/ContainerCluster.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/ContainerCluster.java
@@ -160,12 +160,18 @@ public abstract class ContainerCluster<CONTAINER extends Container>
private String jvmGCOptions = null;
private String environmentVars = null;
+ private final double threadPoolSizeFactor;
+ private final double queueSizeFactor;
+
public ContainerCluster(AbstractConfigProducer<?> parent, String subId, String name, DeployState deployState) {
super(parent, subId);
this.name = name;
this.isHostedVespa = stateIsHosted(deployState);
this.zone = (deployState != null) ? deployState.zone() : Zone.defaultZone();
+ this.threadPoolSizeFactor = deployState.getProperties().threadPoolSizeFactor();
+ this.queueSizeFactor = deployState.getProperties().queueSizeFactor();
+
componentGroup = new ComponentGroup<>(this, "component");
addComponent(new StatisticsComponent());
@@ -186,6 +192,14 @@ public abstract class ContainerCluster<CONTAINER extends Container>
addJaxProviders();
}
+ public double getThreadPoolSizeFactor() {
+ return threadPoolSizeFactor;
+ }
+
+ public double getQueueSizeFactor() {
+ return queueSizeFactor;
+ }
+
public void setZone(Zone zone) {
this.zone = zone;
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/NodeFlavorTuning.java b/config-model/src/main/java/com/yahoo/vespa/model/container/NodeFlavorTuning.java
index 67938b36fd9..f9b50d0e641 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/NodeFlavorTuning.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/NodeFlavorTuning.java
@@ -2,6 +2,7 @@
package com.yahoo.vespa.model.container;
import com.yahoo.config.provision.Flavor;
+import com.yahoo.container.handler.ThreadpoolConfig;
import com.yahoo.search.config.QrStartConfig;
/**
@@ -9,10 +10,26 @@ import com.yahoo.search.config.QrStartConfig;
*
* @author balder
*/
-public class NodeFlavorTuning implements QrStartConfig.Producer {
+public class NodeFlavorTuning implements
+ QrStartConfig.Producer,
+ ThreadpoolConfig.Producer
+{
private final Flavor flavor;
+ public NodeFlavorTuning setThreadPoolSizeFactor(double threadPoolSizeFactor) {
+ this.threadPoolSizeFactor = threadPoolSizeFactor;
+ return this;
+ }
+
+ public NodeFlavorTuning setQueueSizeFactor(double queueSizeFactor) {
+ this.queueSizeFactor = queueSizeFactor;
+ return this;
+ }
+
+ private double threadPoolSizeFactor = 8.0;
+ private double queueSizeFactor = 8.0;
+
NodeFlavorTuning(Flavor flavor) {
this.flavor = flavor;
}
@@ -22,4 +39,15 @@ public class NodeFlavorTuning implements QrStartConfig.Producer {
builder.jvm.availableProcessors(Math.max(2, (int)Math.ceil(flavor.getMinCpuCores())));
}
+ @Override
+ public void getConfig(ThreadpoolConfig.Builder builder) {
+ // Controls max number of concurrent requests per container
+ int workerThreads = Math.max(2, (int)Math.ceil(flavor.getMinCpuCores() * threadPoolSizeFactor));
+ builder.maxthreads(workerThreads);
+
+ // This controls your burst handling capability.
+ // 0 => No extra burst handling beyond you max concurrent requests (maxthreads).
+ // N => N times max concurrent requests as a buffer for handling bursts
+ builder.queueSize((int)(workerThreads * queueSizeFactor));
+ }
}
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/container/ContainerClusterTest.java b/config-model/src/test/java/com/yahoo/vespa/model/container/ContainerClusterTest.java
index 33cf0635349..0f94df80421 100755
--- a/config-model/src/test/java/com/yahoo/vespa/model/container/ContainerClusterTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/container/ContainerClusterTest.java
@@ -9,9 +9,11 @@ import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.config.model.deploy.TestProperties;
import com.yahoo.config.model.test.MockRoot;
import com.yahoo.config.provision.Environment;
+import com.yahoo.config.provision.Flavor;
import com.yahoo.config.provision.RegionName;
import com.yahoo.config.provision.SystemName;
import com.yahoo.config.provision.Zone;
+import com.yahoo.config.provisioning.FlavorsConfig;
import com.yahoo.container.handler.ThreadpoolConfig;
import com.yahoo.search.config.QrStartConfig;
import com.yahoo.vespa.model.Host;
@@ -164,6 +166,8 @@ public class ContainerClusterTest {
cluster.getConfig(tpBuilder);
ThreadpoolConfig threadpoolConfig = new ThreadpoolConfig(tpBuilder);
assertEquals(10, threadpoolConfig.maxthreads());
+ assertEquals(0, threadpoolConfig.queueSize());
+ assertEquals(0, threadpoolConfig.softStartSeconds(), 0);
}
@Test
@@ -213,10 +217,44 @@ public class ContainerClusterTest {
cluster.getConfig(tpBuilder);
ThreadpoolConfig threadpoolConfig = new ThreadpoolConfig(tpBuilder);
assertEquals(500, threadpoolConfig.maxthreads());
+ assertEquals(0, threadpoolConfig.queueSize());
assertEquals(300.0, threadpoolConfig.softStartSeconds(), 0.0);
}
@Test
+ public void requireThatPoolAndQueueCanNotBeControlledByPropertiesWhenNoFlavor() {
+ DeployState state = new DeployState.Builder().properties(new TestProperties()
+ .setThreadPoolSizeFactor(8.5)
+ .setQueueSizeFactor(13.3))
+ .build();
+ MockRoot root = new MockRoot("foo", state);
+ ApplicationContainerCluster cluster = createContainerCluster(root, false);
+ addContainer(root.deployLogger(), cluster, "c1", "host-c1");
+
+ ThreadpoolConfig.Builder tpBuilder = new ThreadpoolConfig.Builder();
+ cluster.getConfig(tpBuilder);
+ ThreadpoolConfig threadpoolConfig = new ThreadpoolConfig(tpBuilder);
+ assertEquals(500, threadpoolConfig.maxthreads());
+ assertEquals(0, threadpoolConfig.queueSize());
+ assertEquals(0.0, threadpoolConfig.softStartSeconds(), 0.0);
+ }
+
+ @Test
+ public void requireThatPoolAndQueueCanBeControlledByPropertiesAndFlavor() {
+ FlavorsConfig.Flavor.Builder flavorBuilder = new FlavorsConfig.Flavor.Builder().name("my_flavor").minCpuCores(3);
+ NodeFlavorTuning nodeFlavorTuning = new NodeFlavorTuning(new Flavor(new FlavorsConfig.Flavor(flavorBuilder)))
+ .setThreadPoolSizeFactor(13.3)
+ .setQueueSizeFactor(17.5);
+
+ ThreadpoolConfig.Builder tpBuilder = new ThreadpoolConfig.Builder();
+ nodeFlavorTuning.getConfig(tpBuilder);
+ ThreadpoolConfig threadpoolConfig = new ThreadpoolConfig(tpBuilder);
+ assertEquals(40, threadpoolConfig.maxthreads());
+ assertEquals(700, threadpoolConfig.queueSize());
+ assertEquals(0.0, threadpoolConfig.softStartSeconds(), 0.0);
+ }
+
+ @Test
public void requireThatDefaultThreadPoolConfigIsSane() {
MockRoot root = new MockRoot("foo");
ApplicationContainerCluster cluster = createContainerCluster(root, false);
@@ -226,6 +264,7 @@ public class ContainerClusterTest {
cluster.getConfig(tpBuilder);
ThreadpoolConfig threadpoolConfig = new ThreadpoolConfig(tpBuilder);
assertEquals(500, threadpoolConfig.maxthreads());
+ assertEquals(0, threadpoolConfig.queueSize());
assertEquals(0.0, threadpoolConfig.softStartSeconds(), 0.0);
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java
index 2773659559b..0f141dee5b4 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java
@@ -150,6 +150,8 @@ public class ModelContextImpl implements ModelContext {
private final Optional<EndpointCertificateSecrets> endpointCertificateSecrets;
private final double defaultTermwiseLimit;
private final double defaultSoftStartSeconds;
+ private final double threadPoolSizeFactor;
+ private final double queueSizefactor;
private final Optional<AthenzDomain> athenzDomain;
public Properties(ApplicationId applicationId,
@@ -186,6 +188,10 @@ public class ModelContextImpl implements ModelContext {
.with(FetchVector.Dimension.APPLICATION_ID, applicationId.serializedForm()).value();
defaultTopKprobability = Flags.DEFAULT_TOP_K_PROBABILITY.bindTo(flagSource)
.with(FetchVector.Dimension.APPLICATION_ID, applicationId.serializedForm()).value();
+ threadPoolSizeFactor = Flags.DEFAULT_THREADPOOL_SIZE_FACTOR.bindTo(flagSource)
+ .with(FetchVector.Dimension.APPLICATION_ID, applicationId.serializedForm()).value();
+ queueSizefactor = Flags.DEFAULT_QUEUE_SIZE_FACTOR.bindTo(flagSource)
+ .with(FetchVector.Dimension.APPLICATION_ID, applicationId.serializedForm()).value();
this.athenzDomain = athenzDomain;
}
@@ -238,8 +244,18 @@ public class ModelContextImpl implements ModelContext {
@Override
public double defaultTermwiseLimit() { return defaultTermwiseLimit; }
+ @Override
+ public double threadPoolSizeFactor() {
+ return threadPoolSizeFactor;
+ }
+
+ @Override
+ public double queueSizeFactor() {
+ return queueSizefactor;
+ }
+
public double defaultSoftStartSeconds() {
- return 0;
+ return defaultSoftStartSeconds;
}
@Override
diff --git a/container-core/abi-spec.json b/container-core/abi-spec.json
index 6d683c53984..82d34d88b99 100644
--- a/container-core/abi-spec.json
+++ b/container-core/abi-spec.json
@@ -171,6 +171,7 @@
"public void <init>()",
"public void <init>(com.yahoo.container.handler.ThreadpoolConfig)",
"public com.yahoo.container.handler.ThreadpoolConfig$Builder maxthreads(int)",
+ "public com.yahoo.container.handler.ThreadpoolConfig$Builder queueSize(int)",
"public com.yahoo.container.handler.ThreadpoolConfig$Builder maxThreadExecutionTimeSeconds(int)",
"public com.yahoo.container.handler.ThreadpoolConfig$Builder softStartSeconds(double)",
"public final boolean dispatchGetConfig(com.yahoo.config.ConfigInstance$Producer)",
@@ -210,6 +211,7 @@
"public static java.lang.String getDefVersion()",
"public void <init>(com.yahoo.container.handler.ThreadpoolConfig$Builder)",
"public int maxthreads()",
+ "public int queueSize()",
"public int maxThreadExecutionTimeSeconds()",
"public double softStartSeconds()"
],
diff --git a/container-core/src/main/java/com/yahoo/container/handler/ThreadPoolProvider.java b/container-core/src/main/java/com/yahoo/container/handler/ThreadPoolProvider.java
index b427a58c9b7..0e786cfbc8f 100644
--- a/container-core/src/main/java/com/yahoo/container/handler/ThreadPoolProvider.java
+++ b/container-core/src/main/java/com/yahoo/container/handler/ThreadPoolProvider.java
@@ -10,6 +10,7 @@ import com.yahoo.container.protect.ProcessTerminator;
import com.yahoo.jdisc.Metric;
import java.util.Map;
+import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
@@ -33,17 +34,30 @@ public class ThreadPoolProvider extends AbstractComponent implements Provider<Ex
private final ExecutorServiceWrapper threadpool;
+ private static BlockingQueue<Runnable> createQ(int queueSize, int maxThreads) {
+ return (queueSize == 0)
+ ? new SynchronousQueue<>(false)
+ : (queueSize < 0)
+ ? new ArrayBlockingQueue<>(maxThreads*4)
+ : new ArrayBlockingQueue<>(queueSize);
+ }
+
+ private static int computeThreadPoolSize(int maxNumThreads) {
+ return (maxNumThreads <= 0)
+ ? Runtime.getRuntime().availableProcessors() * 4
+ : maxNumThreads;
+ }
@Inject
public ThreadPoolProvider(ThreadpoolConfig threadpoolConfig, Metric metric) {
this(threadpoolConfig, metric, new ProcessTerminator());
}
public ThreadPoolProvider(ThreadpoolConfig threadpoolConfig, Metric metric, ProcessTerminator processTerminator) {
+ int maxNumThreads = computeThreadPoolSize(threadpoolConfig.maxthreads());
WorkerCompletionTimingThreadPoolExecutor executor =
- new WorkerCompletionTimingThreadPoolExecutor(threadpoolConfig.maxthreads(),
- threadpoolConfig.maxthreads(),
+ new WorkerCompletionTimingThreadPoolExecutor(maxNumThreads, maxNumThreads,
0L, TimeUnit.SECONDS,
- new SynchronousQueue<>(false),
+ createQ(threadpoolConfig.queueSize(), maxNumThreads),
ThreadFactoryFactory.getThreadFactory("threadpool"),
metric);
// Prestart needed, if not all threads will be created by the fist N tasks and hence they might also
@@ -87,8 +101,9 @@ public class ThreadPoolProvider extends AbstractComponent implements Provider<Ex
/**
* A service executor wrapper which emits metrics and
* shuts down the vm when no workers are available for too long to avoid containers lingering in a blocked state.
+ * Package private for testing
*/
- private final static class ExecutorServiceWrapper extends ForwardingExecutorService {
+ final static class ExecutorServiceWrapper extends ForwardingExecutorService {
private final WorkerCompletionTimingThreadPoolExecutor wrapped;
private final Metric metric;
@@ -160,8 +175,11 @@ public class ThreadPoolProvider extends AbstractComponent implements Provider<Ex
}
- /** A thread pool executor which maintains the last time a worker completed */
- private final static class WorkerCompletionTimingThreadPoolExecutor extends ThreadPoolExecutor {
+ /**
+ * A thread pool executor which maintains the last time a worker completed
+ * package private for testing
+ **/
+ final static class WorkerCompletionTimingThreadPoolExecutor extends ThreadPoolExecutor {
private static final String UNHANDLED_EXCEPTIONS_METRIC = "jdisc.thread_pool.unhandled_exceptions";
diff --git a/container-core/src/main/resources/configdefinitions/threadpool.def b/container-core/src/main/resources/configdefinitions/threadpool.def
index 9bb9badd9b5..abc60f9f06d 100644
--- a/container-core/src/main/resources/configdefinitions/threadpool.def
+++ b/container-core/src/main/resources/configdefinitions/threadpool.def
@@ -2,8 +2,16 @@
namespace=container.handler
+## Num ber of thread in the thread pool
+## Setting it to 0 or negative number will cause it to be set to #cores * 4
maxthreads int default=500
+## max queue size
+## There can be queueSize + maxthreads requests inflight concurrently
+## The container will start replying 503
+## Negative value will cause it to set to maxthreads*4
+queueSize int default=0
+
# The max time the container tolerates having no threads available before it shuts down to
# get out of a bad state. This should be set a bit higher than the expected max execution
# time of each request when in a state of overload, i.e about "worst case execution time*2"
diff --git a/container-core/src/test/java/com/yahoo/container/handler/ThreadPoolProviderTestCase.java b/container-core/src/test/java/com/yahoo/container/handler/ThreadPoolProviderTestCase.java
index 918863f6dda..761ed40763c 100644
--- a/container-core/src/test/java/com/yahoo/container/handler/ThreadPoolProviderTestCase.java
+++ b/container-core/src/test/java/com/yahoo/container/handler/ThreadPoolProviderTestCase.java
@@ -5,6 +5,7 @@ import static org.junit.Assert.fail;
import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.ThreadPoolExecutor;
import com.yahoo.container.protect.ProcessTerminator;
import org.junit.Ignore;
@@ -58,6 +59,39 @@ public class ThreadPoolProviderTestCase {
fail("Pool did not reject tasks after shutdown.");
}
+ private ThreadPoolExecutor createPool(int maxThreads, int queueSize) {
+ ThreadpoolConfig config = new ThreadpoolConfig(new ThreadpoolConfig.Builder().maxthreads(maxThreads).queueSize(queueSize));
+ ThreadPoolProvider provider = new ThreadPoolProvider(config, Mockito.mock(Metric.class));
+ ThreadPoolProvider.ExecutorServiceWrapper wrapper = (ThreadPoolProvider.ExecutorServiceWrapper) provider.get();
+ ThreadPoolProvider.WorkerCompletionTimingThreadPoolExecutor executor = (ThreadPoolProvider.WorkerCompletionTimingThreadPoolExecutor)wrapper.delegate();
+ return executor;
+ }
+
+ @Test
+ public void testThatThreadPoolSizeFollowsConfig() {
+ ThreadPoolExecutor executor = createPool(3, 9);
+ assertEquals(3, executor.getMaximumPoolSize());
+ assertEquals(9, executor.getQueue().remainingCapacity());
+ }
+ @Test
+ public void testThatThreadPoolSizeAutoDetected() {
+ ThreadPoolExecutor executor = createPool(0, 0);
+ assertEquals(Runtime.getRuntime().availableProcessors()*4, executor.getMaximumPoolSize());
+ assertEquals(0, executor.getQueue().remainingCapacity());
+ }
+ @Test
+ public void testThatQueueSizeAutoDetected() {
+ ThreadPoolExecutor executor = createPool(3, -1);
+ assertEquals(3, executor.getMaximumPoolSize());
+ assertEquals(executor.getMaximumPoolSize()*4, executor.getQueue().remainingCapacity());
+ }
+ @Test
+ public void testThatThreadPoolSizeAndQueueSizeAutoDetected() {
+ ThreadPoolExecutor executor = createPool(0, -1);
+ assertEquals(Runtime.getRuntime().availableProcessors()*4, executor.getMaximumPoolSize());
+ assertEquals(executor.getMaximumPoolSize()*4, executor.getQueue().remainingCapacity());
+ }
+
private class FlipIt implements Runnable {
public final Receiver<Boolean> didItRun = new Receiver<>();
diff --git a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java
index 76206996207..85d841e4bb0 100644
--- a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java
+++ b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java
@@ -150,7 +150,16 @@ public class Flags {
"Default number of seconds that a soft start shall use",
"Takes effect at redeployment",
ZONE_ID, APPLICATION_ID);
-
+ public static final UnboundDoubleFlag DEFAULT_THREADPOOL_SIZE_FACTOR = defineDoubleFlag(
+ "default-threadpool-size-factor", 0.0,
+ "Default multiplication factor when computing maxthreads for main container threadpool based on available cores",
+ "Takes effect at redeployment",
+ ZONE_ID, APPLICATION_ID);
+ public static final UnboundDoubleFlag DEFAULT_QUEUE_SIZE_FACTOR = defineDoubleFlag(
+ "default-queue-size-factor", 0.0,
+ "Default multiplication factor when computing queuesize for burst handling",
+ "Takes effect at redeployment",
+ ZONE_ID, APPLICATION_ID);
public static final UnboundDoubleFlag DEFAULT_TOP_K_PROBABILITY = defineDoubleFlag(
"default-top-k-probability", 1.0,
"Default probability that you will get the globally top K documents when merging many partitions.",