diff options
author | Bjørn Christian Seime <bjorncs@verizonmedia.com> | 2020-06-11 18:35:09 +0200 |
---|---|---|
committer | Bjørn Christian Seime <bjorncs@verizonmedia.com> | 2020-06-15 13:18:01 +0200 |
commit | a7fc7785961dafa2276c97d207d6a5af322ba2ea (patch) | |
tree | 1f1951b02e5b604eec010d1abc65098896a4de1d /config-model | |
parent | 7d49d61de65cea5fd8980c25c5c2356ee1f6b852 (diff) |
Add threadpool configuration after cluster nodes are populated
Add unit test as well
Diffstat (limited to 'config-model')
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(); } + } + } |