summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjørn Christian Seime <bjorncs@verizonmedia.com>2020-06-11 18:35:09 +0200
committerBjørn Christian Seime <bjorncs@verizonmedia.com>2020-06-15 13:18:01 +0200
commita7fc7785961dafa2276c97d207d6a5af322ba2ea (patch)
tree1f1951b02e5b604eec010d1abc65098896a4de1d
parent7d49d61de65cea5fd8980c25c5c2356ee1f6b852 (diff)
Add threadpool configuration after cluster nodes are populated
Add unit test as well
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/clients/ContainerDocumentApi.java33
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java8
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerDocumentApiBuilderTest.java60
3 files changed, 88 insertions, 13 deletions
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/clients/ContainerDocumentApi.java b/config-model/src/main/java/com/yahoo/vespa/model/clients/ContainerDocumentApi.java
index 9ee62aca798..cdebf6a8c6c 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/clients/ContainerDocumentApi.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/clients/ContainerDocumentApi.java
@@ -22,28 +22,37 @@ public class ContainerDocumentApi {
private static final int FALLBACK_MAX_POOL_SIZE = 0; // Use fallback based on actual logical core count on host
private static final int FALLBACK_CORE_POOL_SIZE = 0; // Use fallback based on actual logical core count on host
+ private final ContainerCluster<?> cluster;
+ private final Options options;
+ private final Handler<AbstractConfigProducer<?>> feedHandler;
+ private final Handler<AbstractConfigProducer<?>> restApiHandler;
+
public ContainerDocumentApi(ContainerCluster<?> cluster, Options options) {
- setupHandlers(cluster, options);
+ this.cluster = cluster;
+ this.options = options;
+ this.restApiHandler = addRestApiHandler(cluster, options);
+ this.feedHandler = addFeedHandler(cluster, options);
}
- private static void setupHandlers(ContainerCluster<?> cluster, Options options) {
- addRestApiHandler(cluster, options);
- addFeedHandler(cluster, options);
+ public void addNodesDependentThreadpoolConfiguration() {
+ if (cluster.getContainers().isEmpty()) throw new IllegalStateException("Cluster is empty");
+ feedHandler.addComponent(newExecutorComponent("feedapi-handler", cluster, options));
+ restApiHandler.addComponent(newExecutorComponent("restapi-handler", cluster, options));
}
- private static void addFeedHandler(ContainerCluster<?> cluster, Options options) {
- var executorComponent = newExecutorComponent("feedapi-handler", cluster, options);
+ private static Handler<AbstractConfigProducer<?>> addFeedHandler(ContainerCluster<?> cluster, Options options) {
String bindingSuffix = ContainerCluster.RESERVED_URI_PREFIX + "/feedapi";
var handler = newVespaClientHandler(
- "com.yahoo.vespa.http.server.FeedHandler", bindingSuffix, options, executorComponent);
+ "com.yahoo.vespa.http.server.FeedHandler", bindingSuffix, options);
cluster.addComponent(handler);
+ return handler;
}
- private static void addRestApiHandler(ContainerCluster<?> cluster, Options options) {
- var executorComponent = newExecutorComponent("restapi-handler", cluster, options);
+ private static Handler<AbstractConfigProducer<?>> addRestApiHandler(ContainerCluster<?> cluster, Options options) {
var handler = newVespaClientHandler(
- "com.yahoo.document.restapi.resource.RestApi", "document/v1/*", options, executorComponent);
+ "com.yahoo.document.restapi.resource.RestApi", "document/v1/*", options);
cluster.addComponent(handler);
+ return handler;
}
private static ThreadPoolExecutorComponent newExecutorComponent(String name, ContainerCluster<?> cluster, Options options) {
@@ -58,14 +67,12 @@ public class ContainerDocumentApi {
private static Handler<AbstractConfigProducer<?>> newVespaClientHandler(
String componentId,
String bindingSuffix,
- Options options,
- ThreadPoolExecutorComponent executorComponent) {
+ Options options) {
Handler<AbstractConfigProducer<?>> handler = new Handler<>(new ComponentModel(
BundleInstantiationSpecification.getFromStrings(componentId, null, "vespaclient-container-plugin"), ""));
for (String rootBinding : options.bindings) {
handler.addServerBindings(rootBinding + bindingSuffix, rootBinding + bindingSuffix + '/');
}
- handler.addComponent(executorComponent);
return handler;
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java
index 2966e0e000d..4cf3108f928 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java
@@ -207,6 +207,7 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
addClientProviders(deployState, spec, cluster);
addServerProviders(deployState, spec, cluster);
+ addHandlerSpecificThreadpools(cluster);
addAthensCopperArgos(cluster, context); // Must be added after nodes.
}
@@ -221,6 +222,13 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
}
}
+ private void addHandlerSpecificThreadpools(ContainerCluster<?> cluster) {
+ ContainerDocumentApi documentApi = cluster.getDocumentApi();
+ if (documentApi != null) {
+ documentApi.addNodesDependentThreadpoolConfiguration();
+ }
+ }
+
private void addAthensCopperArgos(ApplicationContainerCluster cluster, ConfigModelContext context) {
if ( ! context.getDeployState().isHosted()) return;
app.getDeployment().map(DeploymentSpec::fromXml)
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerDocumentApiBuilderTest.java b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerDocumentApiBuilderTest.java
index 26154808580..15a995e08c7 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerDocumentApiBuilderTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerDocumentApiBuilderTest.java
@@ -1,21 +1,38 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.model.container.xml;
+import com.yahoo.config.model.api.HostProvisioner;
import com.yahoo.config.model.builder.xml.test.DomBuilderTest;
+import com.yahoo.config.model.provision.Host;
+import com.yahoo.config.model.test.MockApplicationPackage;
+import com.yahoo.config.model.test.MockRoot;
+import com.yahoo.config.provision.Capacity;
+import com.yahoo.config.provision.ClusterMembership;
+import com.yahoo.config.provision.ClusterSpec;
+import com.yahoo.config.provision.HostSpec;
+import com.yahoo.config.provision.NodeResources;
+import com.yahoo.config.provision.ProvisionLogger;
+import com.yahoo.container.handler.ThreadpoolConfig;
+import com.yahoo.net.HostName;
import com.yahoo.vespa.model.container.ContainerCluster;
+import com.yahoo.vespa.model.container.ThreadPoolExecutorComponent;
import com.yahoo.vespa.model.container.component.Handler;
import org.junit.Test;
import org.w3c.dom.Element;
import java.util.Collection;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
+import java.util.Optional;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.Matchers.hasItem;
+import static org.hamcrest.Matchers.hasSize;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
/**
@@ -80,4 +97,47 @@ public class ContainerDocumentApiBuilderTest extends ContainerModelBuilderTestBa
assertThat(handlerMap.get("com.yahoo.vespa.http.server.FeedHandler").getServerBindings().contains("http://*/" + ContainerCluster.RESERVED_URI_PREFIX + "/feedapi/"), is(true));
assertThat(handlerMap.get("com.yahoo.vespa.http.server.FeedHandler").getServerBindings().size(), equalTo(2));
}
+
+ @Test
+ public void feeding_api_have_separate_threadpools() {
+ Element elem = DomBuilderTest.parse(
+ "<container id='cluster1' version='1.0'>",
+ " <document-api />",
+ nodesXml,
+ "</container>");
+ root = new MockRoot("root", new MockApplicationPackage.Builder().build(), new HostProvisionerWithCustomRealResource());
+ createModel(root, elem);
+ Map<String, Handler<?>> handlers = getHandlers("cluster1");
+ Handler<?> feedApiHandler = handlers.get("com.yahoo.vespa.http.server.FeedHandler");
+ List<ThreadPoolExecutorComponent> feedApiExecutors = feedApiHandler.getChildrenByTypeRecursive(ThreadPoolExecutorComponent.class);
+ assertThat(feedApiExecutors, hasSize(1));
+ ThreadpoolConfig.Builder configBuilder = new ThreadpoolConfig.Builder();
+ feedApiExecutors.get(0).getConfig(configBuilder);
+ ThreadpoolConfig config = new ThreadpoolConfig(configBuilder);
+ assertEquals(4, config.maxthreads());
+ assertEquals(4, config.corePoolSize());
+ }
+
+ private static class HostProvisionerWithCustomRealResource implements HostProvisioner {
+
+ @Override
+ public HostSpec allocateHost(String alias) {
+ Host host = new Host(HostName.getLocalhost());
+ ClusterMembership membership = ClusterMembership.from(
+ ClusterSpec
+ .specification(
+ ClusterSpec.Type.container,
+ ClusterSpec.Id.from("id"))
+ .vespaVersion("")
+ .group(ClusterSpec.Group.from(0))
+ .build(),
+ 0);
+ return new HostSpec(
+ host.hostname(), new NodeResources(4, 0, 0, 0), NodeResources.unspecified(), NodeResources.unspecified(),
+ membership, Optional.empty(), Optional.empty(), Optional.empty());
+ }
+
+ @Override public List<HostSpec> prepare(ClusterSpec cluster, Capacity capacity, ProvisionLogger logger) { return List.of(); }
+ }
+
}