diff options
Diffstat (limited to 'config-model')
37 files changed, 539 insertions, 400 deletions
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 fc799449379..22bdf31350a 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 @@ -37,6 +37,7 @@ public class TestProperties implements ModelContext.Properties { private boolean useDedicatedNodeForLogserver = false; private boolean useContentNodeBtreeDb = false; private boolean useThreePhaseUpdates = false; + private boolean useDirectStorageApiRpc = false; private double defaultTermwiseLimit = 1.0; private double threadPoolSizeFactor = 0.0; private double queueSizeFactor = 0.0; @@ -73,6 +74,7 @@ public class TestProperties implements ModelContext.Properties { } @Override public boolean useContentNodeBtreeDb() { return useContentNodeBtreeDb; } @Override public boolean useThreePhaseUpdates() { return useThreePhaseUpdates; } + @Override public boolean useDirectStorageApiRpc() { return useDirectStorageApiRpc; } @Override public Optional<AthenzDomain> athenzDomain() { return Optional.ofNullable(athenzDomain); } @Override public Optional<ApplicationRoles> applicationRoles() { return Optional.ofNullable(applicationRoles); } @Override public String responseSequencerType() { return responseSequencerType; } @@ -113,6 +115,11 @@ public class TestProperties implements ModelContext.Properties { return this; } + public TestProperties setUseDirectStorageApiRpc(boolean useDirectStorageApiRpc) { + this.useDirectStorageApiRpc = useDirectStorageApiRpc; + return this; + } + public TestProperties setThreadPoolSizeFactor(double threadPoolSizeFactor) { this.threadPoolSizeFactor = threadPoolSizeFactor; return this; diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/Admin.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/Admin.java index 1b5be1c2f97..3f432620b90 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/admin/Admin.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/Admin.java @@ -31,7 +31,7 @@ import java.util.Collections; import java.util.List; import java.util.Optional; -import static com.yahoo.vespa.model.admin.monitoring.MetricSet.emptyMetricSet; +import static com.yahoo.vespa.model.admin.monitoring.MetricSet.empty; /** * This is the admin pseudo-plugin of the Vespa model, responsible for @@ -49,7 +49,7 @@ public class Admin extends AbstractConfigProducer implements Serializable { private final Metrics metrics; private MetricsProxyContainerCluster metricsProxyCluster; - private MetricSet additionalDefaultMetrics = emptyMetricSet(); + private MetricSet additionalDefaultMetrics = empty(); private final List<Slobrok> slobroks = new ArrayList<>(); private Configserver defaultConfigserver; diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/metricsproxy/ConsumersConfigGenerator.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/metricsproxy/ConsumersConfigGenerator.java index 3f9edae10c0..2c039118cb9 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/admin/metricsproxy/ConsumersConfigGenerator.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/metricsproxy/ConsumersConfigGenerator.java @@ -12,8 +12,6 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; -import static com.yahoo.vespa.model.admin.monitoring.VespaMetricsConsumer.VESPA_CONSUMER_ID; - /** * Helper class to generate config for metrics consumers. * @@ -22,14 +20,16 @@ import static com.yahoo.vespa.model.admin.monitoring.VespaMetricsConsumer.VESPA_ class ConsumersConfigGenerator { /** - * @param userConsumers The consumers set up by the user in services.xml - * @return A list of consumer builders (a mapping from consumer to its metrics) + * @param userConsumers the consumers set up by the user in services.xml + * @return a list of consumer builders (a mapping from consumer to its metrics) */ static List<Consumer.Builder> generateConsumers(MetricsConsumer defaultConsumer, Map<String, MetricsConsumer> userConsumers) { - // Normally, the user given consumers should not contain VESPA_CONSUMER_ID, but it's allowed for some internally used applications. + // Normally, the user given consumers should not contain VESPA_CONSUMER_ID, + // but it's allowed for some internally used applications. var allConsumers = new LinkedHashMap<>(userConsumers); - allConsumers.put(VESPA_CONSUMER_ID, combineConsumers(defaultConsumer, allConsumers.get(VESPA_CONSUMER_ID))); + allConsumers.put(MetricsConsumer.vespa.id(), + combineConsumers(defaultConsumer, allConsumers.get(MetricsConsumer.vespa.id()))); return allConsumers.values().stream() .map(ConsumersConfigGenerator::toConsumerBuilder) @@ -45,18 +45,18 @@ class ConsumersConfigGenerator { */ private static MetricsConsumer combineConsumers(MetricsConsumer original, MetricsConsumer overriding) { if (overriding == null) return original; - return addMetrics(original, overriding.getMetrics()); + return addMetrics(original, overriding.metrics()); } static MetricsConsumer addMetrics(MetricsConsumer original, Map<String, Metric> metrics) { if (metrics == null) return original; - Map<String, Metric> combinedMetrics = new LinkedHashMap<>(original.getMetrics()); + Map<String, Metric> combinedMetrics = new LinkedHashMap<>(original.metrics()); metrics.forEach((name, newMetric) -> - combinedMetrics.put(name, combineMetrics(original.getMetrics().get(name), newMetric))); + combinedMetrics.put(name, combineMetrics(original.metrics().get(name), newMetric))); - return new MetricsConsumer(original.getId(), - new MetricSet(original.getMetricSet().getId(), combinedMetrics.values())); + return new MetricsConsumer(original.id(), + new MetricSet(original.metricSet().getId(), combinedMetrics.values())); } private static Metric combineMetrics(Metric original, Metric newMetric) { @@ -64,8 +64,8 @@ class ConsumersConfigGenerator { } static Consumer.Builder toConsumerBuilder(MetricsConsumer consumer) { - Consumer.Builder builder = new Consumer.Builder().name(consumer.getId()); - consumer.getMetrics().values().forEach(metric -> builder.metric(toConsumerMetricBuilder(metric))); + Consumer.Builder builder = new Consumer.Builder().name(consumer.id()); + consumer.metrics().values().forEach(metric -> builder.metric(toConsumerMetricBuilder(metric))); return builder; } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsProxyContainerCluster.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsProxyContainerCluster.java index b5936887b50..fbf6dcfd5eb 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsProxyContainerCluster.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsProxyContainerCluster.java @@ -56,9 +56,7 @@ import static com.yahoo.vespa.model.admin.metricsproxy.MetricsProxyContainerClus import static com.yahoo.vespa.model.admin.metricsproxy.MetricsProxyContainerCluster.AppDimensionNames.LEGACY_APPLICATION; import static com.yahoo.vespa.model.admin.metricsproxy.MetricsProxyContainerCluster.AppDimensionNames.SYSTEM; import static com.yahoo.vespa.model.admin.metricsproxy.MetricsProxyContainerCluster.AppDimensionNames.TENANT; -import static com.yahoo.vespa.model.admin.monitoring.DefaultPublicConsumer.getDefaultPublicConsumer; -import static com.yahoo.vespa.model.admin.monitoring.MetricSet.emptyMetricSet; -import static com.yahoo.vespa.model.admin.monitoring.VespaMetricsConsumer.getVespaMetricsConsumer; +import static com.yahoo.vespa.model.admin.monitoring.MetricSet.empty; /** * Container cluster for metrics proxy containers. @@ -161,10 +159,10 @@ public class MetricsProxyContainerCluster extends ContainerCluster<MetricsProxyC @Override public void getConfig(ConsumersConfig.Builder builder) { - var amendedVespaConsumer = addMetrics(getVespaMetricsConsumer(), getAdditionalDefaultMetrics().getMetrics()); + var amendedVespaConsumer = addMetrics(MetricsConsumer.vespa, getAdditionalDefaultMetrics().getMetrics()); builder.consumer.addAll(generateConsumers(amendedVespaConsumer, getUserMetricsConsumers())); - builder.consumer.add(toConsumerBuilder(getDefaultPublicConsumer())); + builder.consumer.add(toConsumerBuilder(MetricsConsumer.defaultConsumer)); } @Override @@ -210,7 +208,7 @@ public class MetricsProxyContainerCluster extends ContainerCluster<MetricsProxyC private MetricSet getAdditionalDefaultMetrics() { return getAdmin() .map(Admin::getAdditionalDefaultMetrics) - .orElse(emptyMetricSet()); + .orElse(empty()); } // Returns the metrics consumers from services.xml diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/AutoscalingMetrics.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/AutoscalingMetrics.java new file mode 100644 index 00000000000..f6f51ed91fb --- /dev/null +++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/AutoscalingMetrics.java @@ -0,0 +1,26 @@ +// 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.admin.monitoring; + +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * Metrics used for autoscaling + * + * @author bratseth + */ +public class AutoscalingMetrics { + + public static final MetricSet autoscalingMetricSet = create(); + + private static MetricSet create() { + return new MetricSet("autoscaling", + metrics("cpu.util", "mem_total.util", "disk.util")); + } + + private static Set<Metric> metrics(String ... names) { + return Arrays.stream(names).map(Metric::new).collect(Collectors.toSet()); + } + +} diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/CloudWatch.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/CloudWatch.java index 5351c3fb3a7..66a278b3fb6 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/CloudWatch.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/CloudWatch.java @@ -8,6 +8,7 @@ import java.util.Optional; * @author gjoranv */ public class CloudWatch { + private final String region; private final String namespace; private final MetricsConsumer consumer; @@ -23,7 +24,7 @@ public class CloudWatch { public String region() { return region; } public String namespace() { return namespace; } - public String consumer() { return consumer.getId(); } + public String consumer() { return consumer.id(); } public Optional<HostedAuth> hostedAuth() {return Optional.ofNullable(hostedAuth); } public Optional<SharedCredentials> sharedCredentials() {return Optional.ofNullable(sharedCredentials); } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/DefaultPublicMetrics.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/DefaultMetrics.java index c80cebe3d5b..adc0d0b1db8 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/DefaultPublicMetrics.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/DefaultMetrics.java @@ -9,7 +9,6 @@ import java.util.LinkedHashSet; import java.util.Set; import static com.yahoo.vespa.model.admin.monitoring.DefaultVespaMetrics.defaultVespaMetricSet; -import static java.util.Collections.emptyList; import static java.util.Collections.singleton; /** @@ -18,14 +17,14 @@ import static java.util.Collections.singleton; * * @author gjoranv */ -public class DefaultPublicMetrics { +public class DefaultMetrics { - public static final String DEFAULT_METRIC_SET_ID = "default"; + public static final String defaultMetricSetId = "default"; - public static MetricSet defaultPublicMetricSet = createMetricSet(); + public static MetricSet defaultMetricSet = createMetricSet(); private static MetricSet createMetricSet() { - return new MetricSet(DEFAULT_METRIC_SET_ID, + return new MetricSet(defaultMetricSetId, getAllMetrics(), singleton(defaultVespaMetricSet)); } @@ -95,6 +94,6 @@ public class DefaultPublicMetrics { return metrics; } - private DefaultPublicMetrics() { } + private DefaultMetrics() { } } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/DefaultPublicConsumer.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/DefaultPublicConsumer.java deleted file mode 100644 index 68b1fc3c983..00000000000 --- a/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/DefaultPublicConsumer.java +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2020 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. - -package com.yahoo.vespa.model.admin.monitoring; - -import ai.vespa.metricsproxy.http.ValuesFetcher; -import com.google.common.collect.ImmutableList; - -import static com.yahoo.vespa.model.admin.monitoring.DefaultPublicMetrics.defaultPublicMetricSet; -import static com.yahoo.vespa.model.admin.monitoring.DefaultVespaMetrics.defaultVespaMetricSet; -import static com.yahoo.vespa.model.admin.monitoring.SystemMetrics.systemMetricSet; -import static java.util.Collections.emptyList; - -/** - * @author gjoranv - */ -public class DefaultPublicConsumer { - - public static final String DEFAULT_PUBLIC_CONSUMER_ID = ValuesFetcher.DEFAULT_PUBLIC_CONSUMER_ID.id; - - private static final MetricSet publicConsumerMetrics = new MetricSet("public-consumer-metrics", - emptyList(), - ImmutableList.of(defaultPublicMetricSet, - systemMetricSet)); - - public static MetricsConsumer getDefaultPublicConsumer() { - return new MetricsConsumer(DEFAULT_PUBLIC_CONSUMER_ID, publicConsumerMetrics); - } - -} diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/MetricSet.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/MetricSet.java index d879a6f445d..30797f27789 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/MetricSet.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/MetricSet.java @@ -24,21 +24,19 @@ public class MetricSet { private final Map<String, Metric> metrics; private final Set<MetricSet> children; + public MetricSet(String id, Collection<Metric> metrics) { + this(id, metrics, Collections.emptySet()); + } public MetricSet(String id, Collection<Metric> metrics, Collection<MetricSet> children) { - Objects.requireNonNull(id, "Id cannot be null or empty."); + this.id = Objects.requireNonNull(id, "Id cannot be null or empty."); - this.id = id; this.metrics = toMapByName(metrics); this.children = new LinkedHashSet<>(children); } - public MetricSet(String id, Collection<Metric> metrics) { - this(id, metrics, Collections.emptySet()); - } - - public static MetricSet emptyMetricSet() { - return new MetricSet("empty", Collections.emptySet()); + public static MetricSet empty() { + return new MetricSet("empty", Set.of()); } public final String getId() { return id; } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/MetricsConsumer.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/MetricsConsumer.java index a8fbcf50b02..698b01c306a 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/MetricsConsumer.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/MetricsConsumer.java @@ -1,26 +1,44 @@ // 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.admin.monitoring; -import javax.annotation.concurrent.Immutable; +import ai.vespa.metricsproxy.core.VespaMetrics; +import ai.vespa.metricsproxy.http.ValuesFetcher; + import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Objects; +import static com.yahoo.vespa.model.admin.monitoring.AutoscalingMetrics.autoscalingMetricSet; +import static com.yahoo.vespa.model.admin.monitoring.DefaultMetrics.defaultMetricSet; +import static com.yahoo.vespa.model.admin.monitoring.NetworkMetrics.networkMetricSet; +import static com.yahoo.vespa.model.admin.monitoring.SystemMetrics.systemMetricSet; +import static com.yahoo.vespa.model.admin.monitoring.VespaMetricSet.vespaMetricSet; import static java.util.Collections.unmodifiableList; /** - * Represents an arbitrary metric consumer + * A metric consumer is a set of metrics given an id that can be requested at runtime. * - * @author trygve + * @author Trygve Berdal * @author gjoranv */ -@Immutable +// TODO: This construct seems redundant when we have metrics sets public class MetricsConsumer { + // Pre-defined consumers + public static final MetricsConsumer vespa = + consumer(VespaMetrics.vespaMetricsConsumerId.id, vespaMetricSet, systemMetricSet, networkMetricSet); + public static final MetricsConsumer defaultConsumer = + consumer(ValuesFetcher.defaultMetricsConsumerId.id, defaultMetricSet, systemMetricSet); + // Referenced from com.yahoo.vespa.hosted.provision.autoscale.NodeMetricsFetcher + public static final MetricsConsumer autoscaling = + consumer("autoscaling", autoscalingMetricSet); + private final String id; private final MetricSet metricSet; + // TODO: This shouldn't be here private final List<CloudWatch> cloudWatches = new ArrayList<>(); /** @@ -32,16 +50,16 @@ public class MetricsConsumer { this.metricSet = Objects.requireNonNull(metricSet, "A consumer must have a non-null metric set."); } - public String getId() { + public String id() { return id; } - public MetricSet getMetricSet() { return metricSet; } + public MetricSet metricSet() { return metricSet; } /** - * @return Map of metric with metric name as key + * @return map of metric with metric name as key */ - public Map<String, Metric> getMetrics() { + public Map<String, Metric> metrics() { return metricSet.getMetrics(); } @@ -53,4 +71,8 @@ public class MetricsConsumer { return unmodifiableList(cloudWatches); } + private static MetricsConsumer consumer(String id, MetricSet ... metricSets) { + return new MetricsConsumer(id, new MetricSet(id + "-consumer-metrics", List.of(), Arrays.asList(metricSets))); + } + } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/VespaMetricsConsumer.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/VespaMetricsConsumer.java deleted file mode 100644 index 9f3bfdc8ae8..00000000000 --- a/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/VespaMetricsConsumer.java +++ /dev/null @@ -1,32 +0,0 @@ -// 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.admin.monitoring; - -import ai.vespa.metricsproxy.core.VespaMetrics; -import com.google.common.collect.ImmutableList; - -import static com.yahoo.vespa.model.admin.monitoring.NetworkMetrics.networkMetricSet; -import static com.yahoo.vespa.model.admin.monitoring.SystemMetrics.systemMetricSet; -import static com.yahoo.vespa.model.admin.monitoring.VespaMetricSet.vespaMetricSet; -import static java.util.Collections.emptyList; - -/** - * This class sets up the 'Vespa' metrics consumer, which is mainly used for Yamas in hosted Vespa. - * - * @author trygve - * @author gjoranv - */ -public class VespaMetricsConsumer { - - public static final String VESPA_CONSUMER_ID = VespaMetrics.VESPA_CONSUMER_ID.id; - - private static final MetricSet vespaConsumerMetrics = new MetricSet("vespa-consumer-metrics", - emptyList(), - ImmutableList.of(vespaMetricSet, - systemMetricSet, - networkMetricSet)); - - public static MetricsConsumer getVespaMetricsConsumer() { - return new MetricsConsumer(VESPA_CONSUMER_ID, vespaConsumerMetrics); - } - -} diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/builder/Metrics.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/builder/Metrics.java index 1f81f16a80b..6f9e9a08aa6 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/builder/Metrics.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/builder/Metrics.java @@ -17,7 +17,7 @@ public class Metrics { private final Map<String, MetricsConsumer> consumers = new LinkedHashMap<>(); public void addConsumer(MetricsConsumer consumer) { - consumers.put(consumer.getId(), consumer); + consumers.put(consumer.id(), consumer); } public Map<String, MetricsConsumer> getConsumers() { diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/builder/PredefinedMetricSets.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/builder/PredefinedMetricSets.java index 694108d4bb1..dd514f1e245 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/builder/PredefinedMetricSets.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/builder/PredefinedMetricSets.java @@ -7,7 +7,8 @@ import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; -import static com.yahoo.vespa.model.admin.monitoring.DefaultPublicMetrics.defaultPublicMetricSet; +import static com.yahoo.vespa.model.admin.monitoring.AutoscalingMetrics.autoscalingMetricSet; +import static com.yahoo.vespa.model.admin.monitoring.DefaultMetrics.defaultMetricSet; import static com.yahoo.vespa.model.admin.monitoring.NetworkMetrics.networkMetricSet; import static com.yahoo.vespa.model.admin.monitoring.SystemMetrics.systemMetricSet; import static com.yahoo.vespa.model.admin.monitoring.DefaultVespaMetrics.defaultVespaMetricSet; @@ -20,14 +21,17 @@ import static com.yahoo.vespa.model.admin.monitoring.VespaMetricSet.vespaMetricS */ public class PredefinedMetricSets { - public static final Map<String, MetricSet> predefinedMetricSets = toMapById( - defaultPublicMetricSet, + private static final Map<String, MetricSet> sets = toMapById( + defaultMetricSet, defaultVespaMetricSet, vespaMetricSet, systemMetricSet, - networkMetricSet + networkMetricSet, + autoscalingMetricSet ); + public static Map<String, MetricSet> get() { return sets; } + private static Map<String, MetricSet> toMapById(MetricSet... metricSets) { Map<String, MetricSet> availableMetricSets = new LinkedHashMap<>(); for (MetricSet metricSet : metricSets) { diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/builder/xml/MetricsBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/builder/xml/MetricsBuilder.java index b686288868f..919830d912f 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/builder/xml/MetricsBuilder.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/builder/xml/MetricsBuilder.java @@ -14,8 +14,6 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; -import static com.yahoo.vespa.model.admin.monitoring.DefaultPublicConsumer.DEFAULT_PUBLIC_CONSUMER_ID; -import static com.yahoo.vespa.model.admin.monitoring.VespaMetricsConsumer.VESPA_CONSUMER_ID; import static com.yahoo.vespa.model.admin.monitoring.DefaultVespaMetrics.defaultVespaMetricSet; import static com.yahoo.vespa.model.admin.monitoring.SystemMetrics.systemMetricSet; @@ -85,11 +83,11 @@ public class MetricsBuilder { } private void throwIfIllegalConsumerId(Metrics metrics, String consumerId) { - if (consumerId.equalsIgnoreCase(VESPA_CONSUMER_ID) && applicationType != ApplicationType.HOSTED_INFRASTRUCTURE) + if (consumerId.equalsIgnoreCase(MetricsConsumer.vespa.id()) && applicationType != ApplicationType.HOSTED_INFRASTRUCTURE) throw new IllegalArgumentException("'Vespa' is not allowed as metrics consumer id (case is ignored.)"); - if (consumerId.equalsIgnoreCase(DEFAULT_PUBLIC_CONSUMER_ID)) - throw new IllegalArgumentException("'" + DEFAULT_PUBLIC_CONSUMER_ID + "' is not allowed as metrics consumer id (case is ignored.)"); + if (consumerId.equalsIgnoreCase(MetricsConsumer.defaultConsumer.id())) + throw new IllegalArgumentException("'" + MetricsConsumer.defaultConsumer.id() + "' is not allowed as metrics consumer id (case is ignored.)"); if (metrics.hasConsumerIgnoreCase(consumerId)) throw new IllegalArgumentException("'" + consumerId + "' is used as id for two metrics consumers (case is ignored.)"); diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/CloudWatchValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/CloudWatchValidator.java index 462ac39fa84..025b7875677 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/CloudWatchValidator.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/CloudWatchValidator.java @@ -31,7 +31,7 @@ public class CloudWatchValidator extends Validator { } private List<String> consumerIds(List<MetricsConsumer> offendingConsumers) { - return offendingConsumers.stream().map(MetricsConsumer::getId).collect(toList()); + return offendingConsumers.stream().map(MetricsConsumer::id).collect(toList()); } } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomAdminBuilderBase.java b/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomAdminBuilderBase.java index d2f06da992c..b643f771d73 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomAdminBuilderBase.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomAdminBuilderBase.java @@ -18,6 +18,7 @@ import com.yahoo.vespa.model.admin.ModelConfigProvider; import com.yahoo.vespa.model.admin.monitoring.DefaultMonitoring; import com.yahoo.vespa.model.admin.monitoring.Monitoring; import com.yahoo.vespa.model.admin.monitoring.builder.Metrics; +import com.yahoo.vespa.model.admin.monitoring.builder.PredefinedMetricSets; import com.yahoo.vespa.model.admin.monitoring.builder.xml.MetricsBuilder; import com.yahoo.vespa.model.filedistribution.FileDistributionConfigProducer; import org.w3c.dom.Element; @@ -25,8 +26,6 @@ import org.w3c.dom.Element; import java.util.ArrayList; import java.util.List; -import static com.yahoo.vespa.model.admin.monitoring.builder.PredefinedMetricSets.predefinedMetricSets; - /** * A base class for admin model builders, to support common functionality across versions. * @@ -69,8 +68,8 @@ public abstract class DomAdminBuilderBase extends VespaDomBuilder.DomConfigProdu @Override protected Admin doBuild(DeployState deployState, AbstractConfigProducer parent, Element adminElement) { Monitoring monitoring = getMonitoring(XML.getChild(adminElement,"monitoring"), deployState.isHosted()); - Metrics metrics = new MetricsBuilder(applicationType, predefinedMetricSets) - .buildMetrics(XML.getChild(adminElement, "metrics")); + Metrics metrics = new MetricsBuilder(applicationType, PredefinedMetricSets.get()) + .buildMetrics(XML.getChild(adminElement, "metrics")); FileDistributionConfigProducer fileDistributionConfigProducer = getFileDistributionConfigProducer(parent, deployState.isHosted()); Admin admin = new Admin(parent, monitoring, metrics, multitenant, fileDistributionConfigProducer, deployState.isHosted()); 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 9012cc2aba0..feaa6eb5940 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 @@ -3,17 +3,16 @@ package com.yahoo.vespa.model.clients; import com.yahoo.config.model.producer.AbstractConfigProducer; import com.yahoo.container.bundle.BundleInstantiationSpecification; +import com.yahoo.container.handler.threadpool.ContainerThreadpoolConfig; import com.yahoo.osgi.provider.model.ComponentModel; import com.yahoo.vespa.model.container.ContainerCluster; -import com.yahoo.vespa.model.container.ThreadPoolExecutorComponent; +import com.yahoo.vespa.model.container.ContainerThreadpool; import com.yahoo.vespa.model.container.component.Handler; import com.yahoo.vespa.model.container.component.SystemBindingPattern; import com.yahoo.vespa.model.container.component.UserBindingPattern; import java.util.Collection; import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; /** * @author Einar M R Rosenvinge @@ -24,51 +23,31 @@ 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) { - this.cluster = cluster; - this.options = options; - this.restApiHandler = addRestApiHandler(cluster, options); - this.feedHandler = addFeedHandler(cluster, options); - } - - - public void addNodesDependentThreadpoolConfiguration() { - if (cluster.getContainers().isEmpty()) throw new IllegalStateException("Cluster is empty"); - ThreadPoolExecutorComponent feedHandlerExecutor = newExecutorComponent("feedapi-handler", cluster, options); - feedHandler.inject(feedHandlerExecutor); - feedHandler.addComponent(feedHandlerExecutor); - ThreadPoolExecutorComponent restApiHandlerExecutor = newExecutorComponent("restapi-handler", cluster, options); - restApiHandler.inject(restApiHandlerExecutor); - restApiHandler.addComponent(restApiHandlerExecutor); + addRestApiHandler(cluster, options); + addFeedHandler(cluster, options); } - private static Handler<AbstractConfigProducer<?>> addFeedHandler(ContainerCluster<?> cluster, Options options) { + private static void addFeedHandler(ContainerCluster<?> cluster, Options options) { String bindingSuffix = ContainerCluster.RESERVED_URI_PREFIX + "/feedapi"; var handler = newVespaClientHandler( "com.yahoo.vespa.http.server.FeedHandler", bindingSuffix, options); cluster.addComponent(handler); - return handler; + var executor = new Threadpool( + "feedapi-handler", cluster, options.feedApiThreadpoolOptions, options.feedThreadPoolSizeFactor); + handler.inject(executor); + handler.addComponent(executor); } - private static Handler<AbstractConfigProducer<?>> addRestApiHandler(ContainerCluster<?> cluster, Options options) { + private static void addRestApiHandler(ContainerCluster<?> cluster, Options options) { var handler = newVespaClientHandler( "com.yahoo.document.restapi.resource.RestApi", "/document/v1/*", options); cluster.addComponent(handler); - return handler; - } - - private static ThreadPoolExecutorComponent newExecutorComponent(String name, ContainerCluster<?> cluster, Options options) { - return new ThreadPoolExecutorComponent.Builder(name) - .maxPoolSize(maxPoolSize(cluster, options)) - .corePoolSize(corePoolSize(cluster, options)) - .queueSize(500) - .build(); + var executor = new Threadpool( + "restapi-handler", cluster, options.restApiThreadpoolOptions, options.feedThreadPoolSizeFactor); + handler.inject(executor); + handler.addComponent(executor); } private static Handler<AbstractConfigProducer<?>> newVespaClientHandler( @@ -92,37 +71,60 @@ public class ContainerDocumentApi { return handler; } - private static int maxPoolSize(ContainerCluster<?> cluster, Options options) { - double vcpu = vcpu(cluster); - if (vcpu == 0) return FALLBACK_MAX_POOL_SIZE; - return Math.max(2, (int)Math.ceil(vcpu * options.feedThreadPoolSizeFactor)); - } + public static final class Options { + private final Collection<String> bindings; + private final ContainerThreadpool.UserOptions restApiThreadpoolOptions; + private final ContainerThreadpool.UserOptions feedApiThreadpoolOptions; + private final double feedThreadPoolSizeFactor; - private static int corePoolSize(ContainerCluster<?> cluster, Options options) { - double vcpu = vcpu(cluster); - if (vcpu == 0) return FALLBACK_CORE_POOL_SIZE; - return Math.max(1, (int)Math.ceil(vcpu * options.feedThreadPoolSizeFactor * 0.5)); + public Options(Collection<String> bindings, + ContainerThreadpool.UserOptions restApiThreadpoolOptions, + ContainerThreadpool.UserOptions feedApiThreadpoolOptions, + double feedThreadPoolSizeFactor) { + this.bindings = Collections.unmodifiableCollection(bindings); + this.restApiThreadpoolOptions = restApiThreadpoolOptions; + this.feedApiThreadpoolOptions = feedApiThreadpoolOptions; + this.feedThreadPoolSizeFactor = feedThreadPoolSizeFactor; + } } - private static double vcpu(ContainerCluster<?> cluster) { - List<Double> vcpus = cluster.getContainers().stream() - .filter(c -> c.getHostResource() != null && c.getHostResource().realResources() != null) - .map(c -> c.getHostResource().realResources().vcpu()) - .distinct() - .collect(Collectors.toList()); - // We can only use host resource for calculation if all container nodes in the cluster are homogeneous (in terms of vcpu) - if (vcpus.size() != 1 || vcpus.get(0) == 0) return 0; - return vcpus.get(0); - } + private static class Threadpool extends ContainerThreadpool { - public static final class Options { - private final Collection<String> bindings; + private final ContainerCluster<?> cluster; private final double feedThreadPoolSizeFactor; - public Options(Collection<String> bindings, double feedThreadPoolSizeFactor) { - this.bindings = Collections.unmodifiableCollection(bindings); + Threadpool(String name, + ContainerCluster<?> cluster, + ContainerThreadpool.UserOptions threadpoolOptions, + double feedThreadPoolSizeFactor ) { + super(name, threadpoolOptions); + this.cluster = cluster; this.feedThreadPoolSizeFactor = feedThreadPoolSizeFactor; } + + @Override + public void getConfig(ContainerThreadpoolConfig.Builder builder) { + super.getConfig(builder); + + // User options overrides below configuration + if (hasUserOptions()) return; + + builder.maxThreads(maxPoolSize()); + builder.minThreads(minPoolSize()); + builder.queueSize(500); + } + + private int maxPoolSize() { + double vcpu = vcpu(cluster); + if (vcpu == 0) return FALLBACK_MAX_POOL_SIZE; + return Math.max(2, (int)Math.ceil(vcpu * feedThreadPoolSizeFactor)); + } + + private int minPoolSize() { + double vcpu = vcpu(cluster); + if (vcpu == 0) return FALLBACK_CORE_POOL_SIZE; + return Math.max(1, (int)Math.ceil(vcpu * feedThreadPoolSizeFactor * 0.5)); + } } } 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 5207a0163cb..232552ea4ce 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 @@ -3,8 +3,8 @@ package com.yahoo.vespa.model.container; import com.yahoo.config.model.api.container.ContainerServiceType; import com.yahoo.config.model.producer.AbstractConfigProducer; +import com.yahoo.config.provision.NodeResources; 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,10 +15,7 @@ import com.yahoo.vespa.model.container.component.Component; * * @author gjoranv */ -public final class ApplicationContainer extends Container implements - QrStartConfig.Producer, - ThreadpoolConfig.Producer -{ +public final class ApplicationContainer extends Container implements QrStartConfig.Producer { private static final String defaultHostedJVMArgs = "-XX:+UseOSErrorReporting -XX:+SuppressFatalErrorMessage"; @@ -44,9 +41,9 @@ public final class ApplicationContainer extends Container implements @Override public void getConfig(QrStartConfig.Builder builder) { if (getHostResource() != null) { - if ( ! getHostResource().realResources().isUnspecified()) { - NodeResourcesTuning flavorTuning = new NodeResourcesTuning(getHostResource().realResources()); - flavorTuning.getConfig(builder); + NodeResources nodeResources = getHostResource().realResources(); + if ( ! nodeResources.isUnspecified()) { + builder.jvm.availableProcessors(Math.max(2, (int)Math.ceil(nodeResources.vcpu()))); } } } @@ -75,17 +72,4 @@ public final class ApplicationContainer extends Container implements private boolean hasDocproc() { return (parent instanceof ContainerCluster) && (((ContainerCluster)parent).getDocproc() != null); } - - @Override - public void getConfig(ThreadpoolConfig.Builder builder) { - if (! (parent instanceof ContainerCluster)) return; - if ((getHostResource() == null) || getHostResource().realResources().isUnspecified()) return; - ContainerCluster containerCluster = (ContainerCluster) parent; - if (containerCluster.getThreadPoolSizeFactor() <= 0.0) return; - - NodeResourcesTuning resourcesTuning = new NodeResourcesTuning(getHostResource().realResources()) - .setThreadPoolSizeFactor(containerCluster.getThreadPoolSizeFactor()) - .setQueueSizeFactor(containerCluster.getQueueSizeFactor()); - resourcesTuning.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 6d8f3056cef..87e8f16f88c 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,17 +160,11 @@ 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"); @@ -192,14 +186,6 @@ 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/ContainerThreadpool.java b/config-model/src/main/java/com/yahoo/vespa/model/container/ContainerThreadpool.java new file mode 100644 index 00000000000..c4d252ccbfe --- /dev/null +++ b/config-model/src/main/java/com/yahoo/vespa/model/container/ContainerThreadpool.java @@ -0,0 +1,86 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.model.container; + +import com.yahoo.container.bundle.BundleInstantiationSpecification; +import com.yahoo.container.handler.threadpool.ContainerThreadPool; +import com.yahoo.container.handler.threadpool.ContainerThreadpoolConfig; +import com.yahoo.osgi.provider.model.ComponentModel; +import com.yahoo.text.XML; +import com.yahoo.vespa.model.container.component.SimpleComponent; +import org.w3c.dom.Element; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * Component definition for a {@link java.util.concurrent.Executor} using {@link ContainerThreadPool}. + * + * @author bjorncs + */ +public class ContainerThreadpool extends SimpleComponent implements ContainerThreadpoolConfig.Producer { + + private final String name; + private final UserOptions userOptions; + + public ContainerThreadpool(String name) { this(name, null); } + + public ContainerThreadpool(String name, UserOptions userOptions) { + super(new ComponentModel( + BundleInstantiationSpecification.getFromStrings( + "threadpool@" + name, + ContainerThreadPool.class.getName(), + null))); + this.name = name; + this.userOptions = userOptions; + } + + @Override + public void getConfig(ContainerThreadpoolConfig.Builder builder) { + builder.name(this.name); + if (userOptions != null) { + builder.maxThreads(userOptions.maxThreads); + builder.minThreads(userOptions.minThreads); + builder.queueSize(userOptions.queueSize); + } + } + + protected Optional<UserOptions> userOptions() { return Optional.ofNullable(userOptions); } + protected boolean hasUserOptions() { return userOptions().isPresent(); } + + protected static double vcpu(ContainerCluster<?> cluster) { + List<Double> vcpus = cluster.getContainers().stream() + .filter(c -> c.getHostResource() != null && c.getHostResource().realResources() != null) + .map(c -> c.getHostResource().realResources().vcpu()) + .distinct() + .collect(Collectors.toList()); + // We can only use host resource for calculation if all container nodes in the cluster are homogeneous (in terms of vcpu) + if (vcpus.size() != 1 || vcpus.get(0) == 0) return 0; + return vcpus.get(0); + } + + public static class UserOptions { + private final int maxThreads; + private final int minThreads; + private final int queueSize; + + private UserOptions(int maxThreads, int minThreads, int queueSize) { + this.maxThreads = maxThreads; + this.minThreads = minThreads; + this.queueSize = queueSize; + } + + public static Optional<UserOptions> fromXml(Element xml) { + Element element = XML.getChild(xml, "threadpool"); + if (element == null) return Optional.empty(); + return Optional.of(new UserOptions( + intOption(element, "max-threads"), + intOption(element, "min-threads"), + intOption(element, "queue-size"))); + } + + private static int intOption(Element element, String name) { + return Integer.parseInt(XML.getChild(element, name).getTextContent()); + } + } +} diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/NodeResourcesTuning.java b/config-model/src/main/java/com/yahoo/vespa/model/container/NodeResourcesTuning.java deleted file mode 100644 index 7eb7a1fb518..00000000000 --- a/config-model/src/main/java/com/yahoo/vespa/model/container/NodeResourcesTuning.java +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.model.container; - -import com.yahoo.config.provision.NodeResources; -import com.yahoo.container.handler.ThreadpoolConfig; -import com.yahoo.search.config.QrStartConfig; - -/** - * Tuning of qr-start config for a container service based on node resources. - * - * @author balder - */ -public class NodeResourcesTuning implements QrStartConfig.Producer, ThreadpoolConfig.Producer { - - private final NodeResources resources; - - public NodeResourcesTuning setThreadPoolSizeFactor(double threadPoolSizeFactor) { - this.threadPoolSizeFactor = threadPoolSizeFactor; - return this; - } - - public NodeResourcesTuning setQueueSizeFactor(double queueSizeFactor) { - this.queueSizeFactor = queueSizeFactor; - return this; - } - - private double threadPoolSizeFactor = 8.0; - private double queueSizeFactor = 8.0; - - NodeResourcesTuning(NodeResources resources) { - this.resources = resources; - } - - @Override - public void getConfig(QrStartConfig.Builder builder) { - builder.jvm.availableProcessors(Math.max(2, (int)Math.ceil(resources.vcpu()))); - } - - @Override - public void getConfig(ThreadpoolConfig.Builder builder) { - // Controls max number of concurrent requests per container - int workerThreads = Math.max(2, (int)Math.ceil(resources.vcpu() * 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/main/java/com/yahoo/vespa/model/container/ThreadPoolExecutorComponent.java b/config-model/src/main/java/com/yahoo/vespa/model/container/ThreadPoolExecutorComponent.java deleted file mode 100644 index 9d59941f603..00000000000 --- a/config-model/src/main/java/com/yahoo/vespa/model/container/ThreadPoolExecutorComponent.java +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.model.container; - -import com.yahoo.container.bundle.BundleInstantiationSpecification; -import com.yahoo.container.handler.threadpool.ContainerThreadPool; -import com.yahoo.container.handler.threadpool.ContainerThreadpoolConfig; -import com.yahoo.osgi.provider.model.ComponentModel; -import com.yahoo.vespa.model.container.component.SimpleComponent; - -import java.time.Duration; - -/** - * Component definition for a {@link java.util.concurrent.Executor} using {@link ContainerThreadPool}. - * - * @author bjorncs - */ -public class ThreadPoolExecutorComponent extends SimpleComponent implements ContainerThreadpoolConfig.Producer { - - private final String name; - private final Integer maxPoolSize; - private final Integer corePoolSize; - private final Duration keepAliveTime; - private final Integer queueSize; - private final Duration maxThreadExecutionTime; - - private ThreadPoolExecutorComponent(Builder builder) { - super(new ComponentModel( - BundleInstantiationSpecification.getFromStrings( - "threadpool@" + builder.name, - ContainerThreadPool.class.getName(), - null))); - this.name = builder.name; - this.maxPoolSize = builder.maxPoolSize; - this.corePoolSize = builder.corePoolSize; - this.keepAliveTime = builder.keepAliveTime; - this.queueSize = builder.queueSize; - this.maxThreadExecutionTime = builder.maxThreadExecutionTime; - } - - @Override - public void getConfig(ContainerThreadpoolConfig.Builder builder) { - builder.name(this.name); - if (maxPoolSize != null) builder.maxThreads(maxPoolSize); - if (corePoolSize != null) builder.minThreads(corePoolSize); - if (keepAliveTime != null) builder.keepAliveTime(keepAliveTime.toMillis() / 1000D); - if (queueSize != null) builder.queueSize(queueSize); - if (maxThreadExecutionTime != null) builder.maxThreadExecutionTimeSeconds((int)maxThreadExecutionTime.toMillis() / 1000); - } - - public static class Builder { - - private final String name; - private Integer maxPoolSize; - private Integer corePoolSize; - private Duration keepAliveTime; - private Integer queueSize; - private Duration maxThreadExecutionTime; - - public Builder(String name) { this.name = name; } - - public Builder maxPoolSize(int size) { this.maxPoolSize = size; return this; } - public Builder corePoolSize(int size) { this.corePoolSize = size; return this; } - public Builder keepAliveTime(Duration time) { this.keepAliveTime = time; return this; } - public Builder queueSize(int size) { this.queueSize = size; return this; } - public Builder maxThreadExecutionTime(Duration time) { this.maxThreadExecutionTime = time; return this; } - - public ThreadPoolExecutorComponent build() { return new ThreadPoolExecutorComponent(this); } - - } -} diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/BundleInstantiationSpecificationBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/BundleInstantiationSpecificationBuilder.java index 4e0bff1c1fc..12d74418f9f 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/BundleInstantiationSpecificationBuilder.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/BundleInstantiationSpecificationBuilder.java @@ -9,8 +9,6 @@ import org.w3c.dom.Element; import java.util.Arrays; import java.util.List; -import static com.yahoo.vespa.model.container.xml.ContainerModelBuilder.SEARCH_HANDLER_CLASS; - /** * This object builds a bundle instantiation spec from an XML element. * @@ -39,7 +37,7 @@ public class BundleInstantiationSpecificationBuilder { private static void validate(BundleInstantiationSpecification instSpec) { List<String> forbiddenClasses = Arrays.asList( - SEARCH_HANDLER_CLASS, + SearchHandler.HANDLER_CLASS, "com.yahoo.processing.handler.ProcessingHandler"); for (String forbiddenClass: forbiddenClasses) { 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 0e77c6387ae..638c02caf55 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 @@ -54,6 +54,7 @@ import com.yahoo.vespa.model.container.Container; import com.yahoo.vespa.model.container.ContainerCluster; import com.yahoo.vespa.model.container.ContainerModel; import com.yahoo.vespa.model.container.ContainerModelEvaluation; +import com.yahoo.vespa.model.container.ContainerThreadpool; import com.yahoo.vespa.model.container.IdentityProvider; import com.yahoo.vespa.model.container.SecretStore; import com.yahoo.vespa.model.container.component.BindingPattern; @@ -111,9 +112,6 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> { private static final String DEPRECATED_CONTAINER_TAG = "jdisc"; private static final String ENVIRONMENT_VARIABLES_ELEMENT = "environment-variables"; - static final String SEARCH_HANDLER_CLASS = com.yahoo.search.handler.SearchHandler.class.getName(); - static final BindingPattern SEARCH_HANDLER_BINDING = SystemBindingPattern.fromHttpPath("/search/*"); - public enum Networking { disable, enable } private ApplicationPackage app; @@ -197,7 +195,6 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> { addClientProviders(deployState, spec, cluster); addServerProviders(deployState, spec, cluster); - addHandlerSpecificThreadpools(cluster); addAthensCopperArgos(cluster, context); // Must be added after nodes. } @@ -212,13 +209,6 @@ 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) @@ -427,7 +417,7 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> { addIncludes(searchElement); cluster.setSearch(buildSearch(deployState, cluster, searchElement)); - addSearchHandler(cluster, searchElement); + addSearchHandler(cluster, searchElement, deployState); addGUIHandler(cluster); validateAndAddConfiguredComponents(deployState, cluster, searchElement, "renderer", ContainerModelBuilder::validateRendererElement); } @@ -447,7 +437,7 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> { addIncludes(processingElement); cluster.setProcessingChains(new DomProcessingBuilder(null).build(deployState, cluster, processingElement), - serverBindings(processingElement, ProcessingChains.defaultBindings)); + serverBindings(processingElement, ProcessingChains.defaultBindings).toArray(BindingPattern[]::new)); validateAndAddConfiguredComponents(deployState, cluster, processingElement, "renderer", ContainerModelBuilder::validateRendererElement); } @@ -791,19 +781,17 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> { container.setPreLoad(nodesElement.getAttribute(VespaDomBuilder.PRELOAD_ATTRIB_NAME)); } - private void addSearchHandler(ApplicationContainerCluster cluster, Element searchElement) { + private void addSearchHandler(ApplicationContainerCluster cluster, Element searchElement, DeployState deployState) { // Magic spell is needed to receive the chains config :-| cluster.addComponent(new ProcessingHandler<>(cluster.getSearch().getChains(), "com.yahoo.search.searchchain.ExecutionFactory")); - ProcessingHandler<SearchChains> searchHandler = new ProcessingHandler<>(cluster.getSearch().getChains(), - "com.yahoo.search.handler.SearchHandler"); - BindingPattern[] defaultBindings = {SEARCH_HANDLER_BINDING}; - for (BindingPattern binding: serverBindings(searchElement, defaultBindings)) { - searchHandler.addServerBindings(binding); - } - - cluster.addComponent(searchHandler); + cluster.addComponent( + new SearchHandler( + cluster, + serverBindings(searchElement, SearchHandler.DEFAULT_BINDING), + ContainerThreadpool.UserOptions.fromXml(searchElement).orElse(null), + deployState)); } private void addGUIHandler(ApplicationContainerCluster cluster) { @@ -813,15 +801,15 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> { } - private BindingPattern[] serverBindings(Element searchElement, BindingPattern... defaultBindings) { + private List<BindingPattern> serverBindings(Element searchElement, BindingPattern... defaultBindings) { List<Element> bindings = XML.getChildren(searchElement, "binding"); if (bindings.isEmpty()) - return defaultBindings; + return List.of(defaultBindings); return toBindingList(bindings); } - private BindingPattern[] toBindingList(List<Element> bindingElements) { + private List<BindingPattern> toBindingList(List<Element> bindingElements) { List<BindingPattern> result = new ArrayList<>(); for (Element element: bindingElements) { @@ -830,7 +818,7 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> { result.add(UserBindingPattern.fromPattern(text)); } - return result.toArray(BindingPattern[]::new); + return result; } private ContainerDocumentApi buildDocumentApi(DeployState deployState, ApplicationContainerCluster cluster, Element spec) { diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/DocumentApiOptionsBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/DocumentApiOptionsBuilder.java index 34de21de404..99ae6184f5c 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/DocumentApiOptionsBuilder.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/DocumentApiOptionsBuilder.java @@ -4,6 +4,7 @@ package com.yahoo.vespa.model.container.xml; import com.yahoo.config.model.deploy.DeployState; import com.yahoo.text.XML; import com.yahoo.vespa.model.clients.ContainerDocumentApi; +import com.yahoo.vespa.model.container.ContainerThreadpool; import org.w3c.dom.Element; import java.util.ArrayList; @@ -20,7 +21,17 @@ public class DocumentApiOptionsBuilder { public static ContainerDocumentApi.Options build(DeployState deployState, Element spec) { - return new ContainerDocumentApi.Options(getBindings(spec), deployState.getProperties().feedCoreThreadPoolSizeFactor()); + return new ContainerDocumentApi.Options( + getBindings(spec), + threadpoolOptions(spec, "rest-api"), + threadpoolOptions(spec, "http-client-api"), + deployState.getProperties().feedCoreThreadPoolSizeFactor()); + } + + private static ContainerThreadpool.UserOptions threadpoolOptions(Element spec, String elementName) { + Element element = XML.getChild(spec, elementName); + if (element == null) return null; + return ContainerThreadpool.UserOptions.fromXml(element).orElse(null); } private static List<String> getBindings(Element spec) { diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/SearchHandler.java b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/SearchHandler.java new file mode 100644 index 00000000000..81ab2cc1503 --- /dev/null +++ b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/SearchHandler.java @@ -0,0 +1,80 @@ +// Copyright Verizon Media. 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.deploy.DeployState; +import com.yahoo.container.handler.threadpool.ContainerThreadpoolConfig; +import com.yahoo.vespa.model.container.ApplicationContainerCluster; +import com.yahoo.vespa.model.container.ContainerThreadpool; +import com.yahoo.vespa.model.container.component.BindingPattern; +import com.yahoo.vespa.model.container.component.SystemBindingPattern; +import com.yahoo.vespa.model.container.component.chain.ProcessingHandler; +import com.yahoo.vespa.model.container.search.searchchain.SearchChains; + +import java.util.List; + +/** + * Component definition for {@link com.yahoo.search.handler.SearchHandler} + * + * @author bjorncs + */ +class SearchHandler extends ProcessingHandler<SearchChains> { + + static final String HANDLER_CLASS = com.yahoo.search.handler.SearchHandler.class.getName(); + static final BindingPattern DEFAULT_BINDING = SystemBindingPattern.fromHttpPath("/search/*"); + + private final ApplicationContainerCluster cluster; + + SearchHandler(ApplicationContainerCluster cluster, + List<BindingPattern> bindings, + ContainerThreadpool.UserOptions threadpoolOptions, + DeployState deployState) { + super(cluster.getSearchChains(), HANDLER_CLASS); + this.cluster = cluster; + bindings.forEach(this::addServerBindings); + Threadpool threadpool = new Threadpool(cluster, threadpoolOptions, deployState); + inject(threadpool); + addComponent(threadpool); + } + + private static class Threadpool extends ContainerThreadpool { + private final ApplicationContainerCluster cluster; + private final DeployState deployState; + + Threadpool(ApplicationContainerCluster cluster, UserOptions options, DeployState deployState) { + super("search-handler", options); + this.cluster = cluster; + this.deployState = deployState; + } + + @Override + public void getConfig(ContainerThreadpoolConfig.Builder builder) { + super.getConfig(builder); + + builder.maxThreadExecutionTimeSeconds(190); + builder.keepAliveTime(5.0); + + // User options overrides below configuration + if (hasUserOptions()) return; + + double threadPoolSizeFactor = deployState.getProperties().threadPoolSizeFactor(); + double vcpu = vcpu(cluster); + if (threadPoolSizeFactor <= 0 || vcpu == 0) { + builder.maxThreads(500); + builder.minThreads(500); + builder.queueSize(0); + } else { + // Controls max number of concurrent requests per container + int workerThreads = Math.max(2, (int)Math.ceil(vcpu * threadPoolSizeFactor)); + builder.maxThreads(workerThreads); + builder.minThreads(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 * deployState.getProperties().queueSizeFactor())); + } + } + + + } +} diff --git a/config-model/src/main/java/com/yahoo/vespa/model/content/ContentNode.java b/config-model/src/main/java/com/yahoo/vespa/model/content/ContentNode.java index f2e90ae2859..34b6dd017cf 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/content/ContentNode.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/content/ContentNode.java @@ -27,6 +27,7 @@ public abstract class ContentNode extends AbstractService private final boolean skipCommunicationManagerThread; private final boolean skipMbusRequestThread; private final boolean skipMbusReplyThread; + private final boolean useDirectStorageApiRpc; public ContentNode(ModelContext.Properties properties, AbstractConfigProducer parent, String clusterName, String rootDirectory, int distributionKey) { super(parent, "" + distributionKey); @@ -35,6 +36,7 @@ public abstract class ContentNode extends AbstractService this.skipMbusRequestThread = properties.skipMbusRequestThread(); this.skipMbusReplyThread = properties.skipMbusReplyThread(); this.rootDirectory = rootDirectory; + this.useDirectStorageApiRpc = properties.useDirectStorageApiRpc(); initialize(); setProp("clustertype", "content"); @@ -81,6 +83,7 @@ public abstract class ContentNode extends AbstractService builder.skip_thread(skipCommunicationManagerThread); builder.mbus.skip_request_thread(skipMbusRequestThread); builder.mbus.skip_reply_thread(skipMbusReplyThread); + builder.use_direct_storageapi_rpc(useDirectStorageApiRpc); } @Override diff --git a/config-model/src/main/resources/schema/containercluster.rnc b/config-model/src/main/resources/schema/containercluster.rnc index 3c8b60fb84b..98ea696ceef 100644 --- a/config-model/src/main/resources/schema/containercluster.rnc +++ b/config-model/src/main/resources/schema/containercluster.rnc @@ -105,6 +105,12 @@ SslProvider = element ssl-provider { BundleSpec } +Threadpool = element threadpool { + element max-threads { xsd:nonNegativeInteger } & + element min-threads { xsd:nonNegativeInteger } & + element queue-size { xsd:nonNegativeInteger } +} + # REST-API: RestApi = element rest-api { @@ -142,7 +148,8 @@ SearchInContainer = element search { SearchChain* & Provider* & Renderer* & - GenericConfig* + GenericConfig* & + Threadpool? } SearchChain = element chain { @@ -207,10 +214,18 @@ DocumentApi = element document-api { element retrydelay { xsd:double { minInclusive = "0.0" } }? & element timeout { xsd:double { minInclusive = "0.0" } }? & element tracelevel { xsd:positiveInteger }? & - element mbusport { xsd:positiveInteger }? + element mbusport { xsd:positiveInteger }? & + DocumentRestApi? & + HttpClientApi? } +DocumentRestApi = element rest-api { + Threadpool? +} +HttpClientApi = element http-client-api { + Threadpool? +} # NODES: diff --git a/config-model/src/main/resources/schema/federation.rnc b/config-model/src/main/resources/schema/federation.rnc index 6dbeb32fbb2..227bebc16ba 100644 --- a/config-model/src/main/resources/schema/federation.rnc +++ b/config-model/src/main/resources/schema/federation.rnc @@ -16,6 +16,8 @@ Provider = attribute cachesize { xsd:string { pattern = "\d+(\.\d*)?\s*[kmgKMG]?" } }? & attribute type { xsd:string }? & attribute cluster { xsd:string }? & + + # TODO Vespa 8 Remove yca concepts from services.xml syntax attribute yca-application-id { xsd:string }? & attribute yca-cache-ttl { xsd:string { pattern = "\d+(\.\d*)?\s*m?s" } }? & attribute yca-cache-retry-wait { xsd:string { pattern = "\d+(\.\d*)?\s*m?s" } }? & diff --git a/config-model/src/test/java/com/yahoo/vespa/model/admin/DedicatedAdminV4Test.java b/config-model/src/test/java/com/yahoo/vespa/model/admin/DedicatedAdminV4Test.java index be7fc19a429..71dc1564277 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/admin/DedicatedAdminV4Test.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/admin/DedicatedAdminV4Test.java @@ -87,7 +87,7 @@ public class DedicatedAdminV4Test { MetricsConsumer consumer = model.getAdmin().getUserMetrics().getConsumers().get("slingstone"); assertNotNull(consumer); - Metric metric = consumer.getMetrics().get("foobar.count"); + Metric metric = consumer.metrics().get("foobar.count"); assertNotNull(metric); assertEquals("foobar", metric.outputName); } diff --git a/config-model/src/test/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsConsumersTest.java b/config-model/src/test/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsConsumersTest.java index 12a10a7e354..36eb30073b3 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsConsumersTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsConsumersTest.java @@ -4,6 +4,7 @@ import ai.vespa.metricsproxy.core.ConsumersConfig; import com.yahoo.vespa.model.VespaModel; import com.yahoo.vespa.model.admin.monitoring.Metric; import com.yahoo.vespa.model.admin.monitoring.MetricSet; +import com.yahoo.vespa.model.admin.monitoring.MetricsConsumer; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -16,13 +17,11 @@ import static com.yahoo.vespa.model.admin.metricsproxy.MetricsProxyModelTester.c import static com.yahoo.vespa.model.admin.metricsproxy.MetricsProxyModelTester.getCustomConsumer; import static com.yahoo.vespa.model.admin.metricsproxy.MetricsProxyModelTester.getModel; import static com.yahoo.vespa.model.admin.metricsproxy.MetricsProxyModelTester.servicesWithAdminOnly; -import static com.yahoo.vespa.model.admin.monitoring.DefaultPublicConsumer.DEFAULT_PUBLIC_CONSUMER_ID; -import static com.yahoo.vespa.model.admin.monitoring.DefaultPublicMetrics.defaultPublicMetricSet; +import static com.yahoo.vespa.model.admin.monitoring.DefaultMetrics.defaultMetricSet; import static com.yahoo.vespa.model.admin.monitoring.DefaultVespaMetrics.defaultVespaMetricSet; import static com.yahoo.vespa.model.admin.monitoring.NetworkMetrics.networkMetricSet; import static com.yahoo.vespa.model.admin.monitoring.SystemMetrics.systemMetricSet; import static com.yahoo.vespa.model.admin.monitoring.VespaMetricSet.vespaMetricSet; -import static com.yahoo.vespa.model.admin.monitoring.VespaMetricsConsumer.VESPA_CONSUMER_ID; import static java.util.Collections.singleton; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -34,7 +33,7 @@ import static org.junit.Assert.assertTrue; */ public class MetricsConsumersTest { - private static int numPublicDefaultMetrics = defaultPublicMetricSet.getMetrics().size(); + private static int numPublicDefaultMetrics = defaultMetricSet.getMetrics().size(); private static int numDefaultVespaMetrics = defaultVespaMetricSet.getMetrics().size(); private static int numVespaMetrics = vespaMetricSet.getMetrics().size(); private static int numSystemMetrics = systemMetricSet.getMetrics().size(); @@ -48,9 +47,9 @@ public class MetricsConsumersTest { public void default_public_consumer_is_set_up_for_self_hosted() { ConsumersConfig config = consumersConfigFromXml(servicesWithAdminOnly(), self_hosted); assertEquals(2, config.consumer().size()); - assertEquals(config.consumer(1).name(), DEFAULT_PUBLIC_CONSUMER_ID); + assertEquals(MetricsConsumer.defaultConsumer.id(), config.consumer(1).name()); - int numMetricsForPublicDefaultConsumer = defaultPublicMetricSet.getMetrics().size() + numSystemMetrics; + int numMetricsForPublicDefaultConsumer = defaultMetricSet.getMetrics().size() + numSystemMetrics; assertEquals(numMetricsForPublicDefaultConsumer, config.consumer(1).metric().size()); } @@ -58,14 +57,14 @@ public class MetricsConsumersTest { public void vespa_consumer_and_default_public_consumer_is_set_up_for_hosted() { ConsumersConfig config = consumersConfigFromXml(servicesWithAdminOnly(), hosted); assertEquals(2, config.consumer().size()); - assertEquals(config.consumer(0).name(), VESPA_CONSUMER_ID); - assertEquals(config.consumer(1).name(), DEFAULT_PUBLIC_CONSUMER_ID); + assertEquals(MetricsConsumer.vespa.id(), config.consumer(0).name()); + assertEquals(MetricsConsumer.defaultConsumer.id(), config.consumer(1).name()); } @Test public void vespa_consumer_is_always_present_and_has_all_vespa_metrics_and_all_system_metrics() { ConsumersConfig config = consumersConfigFromXml(servicesWithAdminOnly(), self_hosted); - assertEquals(config.consumer(0).name(), VESPA_CONSUMER_ID); + assertEquals(MetricsConsumer.vespa.id(), config.consumer(0).name()); assertEquals(numMetricsForVespaConsumer, config.consumer(0).metric().size()); } diff --git a/config-model/src/test/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsProxyModelTester.java b/config-model/src/test/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsProxyModelTester.java index 8ecb13d7ae5..b6037d2614e 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsProxyModelTester.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/admin/metricsproxy/MetricsProxyModelTester.java @@ -14,12 +14,11 @@ import ai.vespa.metricsproxy.service.VespaServicesConfig; import com.yahoo.search.config.QrStartConfig; import com.yahoo.vespa.model.VespaModel; import com.yahoo.vespa.model.admin.monitoring.Metric; +import com.yahoo.vespa.model.admin.monitoring.MetricsConsumer; import com.yahoo.vespa.model.test.VespaModelTester; import static com.yahoo.vespa.model.admin.metricsproxy.MetricsProxyModelTester.TestMode.hosted; import static com.yahoo.vespa.model.admin.metricsproxy.MetricsProxyModelTester.TestMode.self_hosted; -import static com.yahoo.vespa.model.admin.monitoring.DefaultPublicConsumer.DEFAULT_PUBLIC_CONSUMER_ID; -import static com.yahoo.vespa.model.admin.monitoring.VespaMetricsConsumer.VESPA_CONSUMER_ID; /** * @author gjoranv @@ -76,7 +75,8 @@ class MetricsProxyModelTester { static ConsumersConfig.Consumer getCustomConsumer(String servicesXml) { ConsumersConfig config = consumersConfigFromXml(servicesXml, self_hosted); for (ConsumersConfig.Consumer consumer : config.consumer()) { - if (! consumer.name().equals(VESPA_CONSUMER_ID) && ! consumer.name().equals(DEFAULT_PUBLIC_CONSUMER_ID)) + if (! consumer.name().equals(MetricsConsumer.vespa.id()) && + ! consumer.name().equals(MetricsConsumer.defaultConsumer.id())) return consumer; } throw new RuntimeException("Custom consumer not found!"); 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 97359b392a5..d493afd9c1f 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 @@ -10,11 +10,9 @@ import com.yahoo.config.model.deploy.TestProperties; import com.yahoo.config.model.test.MockRoot; import com.yahoo.config.provision.ApplicationId; 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.di.config.PlatformBundlesConfig; import com.yahoo.container.handler.ThreadpoolConfig; import com.yahoo.search.config.QrStartConfig; @@ -230,20 +228,6 @@ public class ContainerClusterTest { } @Test - public void requireThatPoolAndQueueCanBeControlledByPropertiesAndFlavor() { - FlavorsConfig.Flavor.Builder flavorBuilder = new FlavorsConfig.Flavor.Builder().name("my_flavor").minCpuCores(3); - NodeResourcesTuning nodeResourcesTuning = new NodeResourcesTuning(new Flavor(new FlavorsConfig.Flavor(flavorBuilder)).resources()) - .setThreadPoolSizeFactor(13.3) - .setQueueSizeFactor(17.5); - - ThreadpoolConfig.Builder tpBuilder = new ThreadpoolConfig.Builder(); - nodeResourcesTuning.getConfig(tpBuilder); - ThreadpoolConfig threadpoolConfig = new ThreadpoolConfig(tpBuilder); - assertEquals(40, threadpoolConfig.maxthreads()); - assertEquals(700, threadpoolConfig.queueSize()); - } - - @Test public void requireThatDefaultThreadPoolConfigIsSane() { MockRoot root = new MockRoot("foo"); ApplicationContainerCluster cluster = createContainerCluster(root, false); 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 93117821c5a..def5da3a9c2 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 @@ -121,6 +121,43 @@ public class ContainerDocumentApiBuilderTest extends ContainerModelBuilderTestBa assertEquals(8, config.minThreads()); } + @Test + public void threadpools_configuration_can_be_overridden() { + Element elem = DomBuilderTest.parse( + "<container id='cluster1' version='1.0'>", + " <document-api>", + " <rest-api>", + " <threadpool>", + " <max-threads>20</max-threads>", + " <min-threads>10</min-threads>", + " <queue-size>0</queue-size>", + " </threadpool>", + " </rest-api>", + " <http-client-api>", + " <threadpool>", + " <max-threads>50</max-threads>", + " <min-threads>25</min-threads>", + " <queue-size>1000</queue-size>", + " </threadpool>", + " </http-client-api>", + " </document-api>", + nodesXml, + "</container>"); + createModel(root, elem); + + ContainerThreadpoolConfig restApiThreadpoolConfig = root.getConfig( + ContainerThreadpoolConfig.class, "cluster1/component/com.yahoo.document.restapi.resource.RestApi/threadpool@restapi-handler"); + assertEquals(20, restApiThreadpoolConfig.maxThreads()); + assertEquals(10, restApiThreadpoolConfig.minThreads()); + assertEquals(0, restApiThreadpoolConfig.queueSize()); + + ContainerThreadpoolConfig feedThreadpoolConfig = root.getConfig( + ContainerThreadpoolConfig.class, "cluster1/component/com.yahoo.vespa.http.server.FeedHandler/threadpool@feedapi-handler"); + assertEquals(50, feedThreadpoolConfig.maxThreads()); + assertEquals(25, feedThreadpoolConfig.minThreads()); + assertEquals(1000, feedThreadpoolConfig.queueSize()); + } + private static class HostProvisionerWithCustomRealResource implements HostProvisioner { @Override diff --git a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/SearchBuilderTest.java b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/SearchBuilderTest.java index c8564c5a273..4c1fda44038 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/SearchBuilderTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/SearchBuilderTest.java @@ -4,10 +4,11 @@ package com.yahoo.vespa.model.container.xml; import com.yahoo.component.ComponentId; import com.yahoo.config.model.builder.xml.test.DomBuilderTest; import com.yahoo.container.core.ChainsConfig; +import com.yahoo.container.handler.threadpool.ContainerThreadpoolConfig; import com.yahoo.container.jdisc.JdiscBindingsConfig; import com.yahoo.vespa.model.VespaModel; -import com.yahoo.vespa.model.container.ContainerCluster; import com.yahoo.vespa.model.container.ApplicationContainerCluster; +import com.yahoo.vespa.model.container.ContainerCluster; import com.yahoo.vespa.model.container.component.Handler; import com.yahoo.vespa.model.container.search.GUIHandler; import com.yahoo.vespa.model.test.utils.ApplicationPackageUtils; @@ -18,9 +19,8 @@ import org.w3c.dom.Element; import static com.yahoo.config.model.api.container.ContainerServiceType.QRSERVER; import static com.yahoo.test.Matchers.hasItemWithMethod; import static com.yahoo.vespa.model.container.search.ContainerSearch.QUERY_PROFILE_REGISTRY_CLASS; -import static com.yahoo.vespa.model.container.xml.ContainerModelBuilder.SEARCH_HANDLER_BINDING; -import static com.yahoo.vespa.model.container.xml.ContainerModelBuilder.SEARCH_HANDLER_CLASS; import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.not; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -105,7 +105,7 @@ public class SearchBuilderTest extends ContainerModelBuilderTestBase { "<container id='default' version='1.0'>", " <search />", " <handler id='" + myHandler + "'>", - " <binding>" + SEARCH_HANDLER_BINDING.patternString() + "</binding>", + " <binding>" + SearchHandler.DEFAULT_BINDING.patternString() + "</binding>", " </handler>", nodesXml, "</container>"); @@ -113,8 +113,8 @@ public class SearchBuilderTest extends ContainerModelBuilderTestBase { createModel(root, clusterElem); var discBindingsConfig = root.getConfig(JdiscBindingsConfig.class, "default"); - assertEquals(SEARCH_HANDLER_BINDING.patternString(), discBindingsConfig.handlers(myHandler).serverBindings(0)); - assertNull(discBindingsConfig.handlers(SEARCH_HANDLER_CLASS)); + assertEquals(SearchHandler.DEFAULT_BINDING.patternString(), discBindingsConfig.handlers(myHandler).serverBindings(0)); + assertNull(discBindingsConfig.handlers(SearchHandler.HANDLER_CLASS)); } // TODO: remove test when all containers are named 'container' @@ -222,6 +222,51 @@ public class SearchBuilderTest extends ContainerModelBuilderTestBase { assertFalse(cluster.getSearchChains().localProviders().isEmpty()); } + @Test + public void search_handler_has_dedicated_threadpool() { + Element clusterElem = DomBuilderTest.parse( + "<container id='default' version='1.0'>", + " <search />", + nodesXml, + "</container>"); + + createModel(root, clusterElem); + + ApplicationContainerCluster cluster = (ApplicationContainerCluster)root.getChildren().get("default"); + Handler<?> searchHandler = cluster.getHandlers().stream() + .filter(h -> h.getComponentId().toString().equals(SearchHandler.HANDLER_CLASS)) + .findAny() + .get(); + + assertThat(searchHandler.getInjectedComponentIds(), hasItem("threadpool@search-handler")); + + ContainerThreadpoolConfig config = root.getConfig( + ContainerThreadpoolConfig.class, "default/component/" + SearchHandler.HANDLER_CLASS + "/threadpool@search-handler"); + assertEquals(500, config.maxThreads()); + assertEquals(500, config.minThreads()); + assertEquals(0, config.queueSize()); + } + + @Test + public void threadpool_configuration_can_be_overridden() { + Element clusterElem = DomBuilderTest.parse( + "<container id='default' version='1.0'>", + " <search>", + " <threadpool>", + " <max-threads>100</max-threads>", + " <min-threads>80</min-threads>", + " <queue-size>10</queue-size>", + " </threadpool>", + " </search>", + nodesXml, + "</container>"); + createModel(root, clusterElem); + ContainerThreadpoolConfig config = root.getConfig( + ContainerThreadpoolConfig.class, "default/component/" + SearchHandler.HANDLER_CLASS + "/threadpool@search-handler"); + assertEquals(100, config.maxThreads()); + assertEquals(80, config.minThreads()); + assertEquals(10, config.queueSize()); + } private VespaModel getVespaModelWithMusic(String hosts, String services) { return new VespaModelCreatorWithMockPkg(hosts, services, ApplicationPackageUtils.generateSchemas("music")).create(); diff --git a/config-model/src/test/java/com/yahoo/vespa/model/content/ContentClusterTest.java b/config-model/src/test/java/com/yahoo/vespa/model/content/ContentClusterTest.java index 27c88ad2d1f..61f5ec56bb4 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/content/ContentClusterTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/content/ContentClusterTest.java @@ -16,6 +16,7 @@ import com.yahoo.vespa.config.content.AllClustersBucketSpacesConfig; import com.yahoo.vespa.config.content.FleetcontrollerConfig; import com.yahoo.vespa.config.content.StorDistributionConfig; import com.yahoo.vespa.config.content.StorFilestorConfig; +import com.yahoo.vespa.config.content.core.StorCommunicationmanagerConfig; import com.yahoo.vespa.config.content.core.StorDistributormanagerConfig; import com.yahoo.vespa.config.content.core.StorServerConfig; import com.yahoo.vespa.config.search.DispatchConfig; @@ -980,4 +981,31 @@ public class ContentClusterTest extends ContentBaseTest { assertTrue(resolveThreePhaseUpdateConfigWithFeatureFlag(true)); } + void assertDirectStorageApiRpcConfig(boolean expUseDirectStorageApiRpc, ContentNode node) { + var builder = new StorCommunicationmanagerConfig.Builder(); + node.getConfig(builder); + var config = new StorCommunicationmanagerConfig(builder); + assertEquals(expUseDirectStorageApiRpc, config.use_direct_storageapi_rpc()); + } + + void assertDirectStorageApiRpcFlagIsPropagatedToConfig(boolean useDirectStorageApiRpc) { + VespaModel model = createEnd2EndOneNode(new TestProperties().setUseDirectStorageApiRpc(useDirectStorageApiRpc)); + + ContentCluster cc = model.getContentClusters().get("storage"); + assertFalse(cc.getDistributorNodes().getChildren().isEmpty()); + for (Distributor d : cc.getDistributorNodes().getChildren().values()) { + assertDirectStorageApiRpcConfig(useDirectStorageApiRpc, d); + } + assertFalse(cc.getStorageNodes().getChildren().isEmpty()); + for (StorageNode node : cc.getStorageNodes().getChildren().values()) { + assertDirectStorageApiRpcConfig(useDirectStorageApiRpc, node); + } + } + + @Test + public void use_direct_storage_api_rpc_config_is_controlled_by_properties() { + assertDirectStorageApiRpcFlagIsPropagatedToConfig(false); + assertDirectStorageApiRpcFlagIsPropagatedToConfig(true); + } + } diff --git a/config-model/src/test/schema-test-files/services.xml b/config-model/src/test/schema-test-files/services.xml index e7ea2683e3f..683e2dc0b0d 100644 --- a/config-model/src/test/schema-test-files/services.xml +++ b/config-model/src/test/schema-test-files/services.xml @@ -158,6 +158,20 @@ <timeout>5.55</timeout> <route>default</route> <maxpendingdocs>100</maxpendingdocs> + <rest-api> + <threadpool> + <max-threads>50</max-threads> + <min-threads>10</min-threads> + <queue-size>1000</queue-size> + </threadpool> + </rest-api> + <http-client-api> + <threadpool> + <max-threads>50</max-threads> + <min-threads>10</min-threads> + <queue-size>1000</queue-size> + </threadpool> + </http-client-api> </document-api> <search> @@ -184,6 +198,12 @@ </chain> <chain id="achain" searchers="asearcher anothersearcher" inherits="wonkaparentchain" excludes="notneededsearcher"/> + + <threadpool> + <max-threads>500</max-threads> + <min-threads>500</min-threads> + <queue-size>0</queue-size> + </threadpool> </search> <processing> |