summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java1
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/admin/Slobrok.java7
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/VespaMetricSet.java2
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/clients/ContainerDocumentApi.java20
-rwxr-xr-xconfig-model/src/main/java/com/yahoo/vespa/model/container/ContainerCluster.java9
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/DefaultThreadpoolProvider.java10
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/component/AccessLogComponent.java21
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/component/ConnectionLogComponent.java19
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/http/JettyHttpServer.java9
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/http/ssl/HostedSslConnectorFactory.java20
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/xml/AccessLogBuilder.java1
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/xml/ConfigServerContainerModelBuilder.java3
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java8
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/xml/SearchHandler.java18
-rwxr-xr-xconfig-model/src/test/java/com/yahoo/vespa/model/container/ContainerClusterTest.java28
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/container/xml/AccessLogTest.java2
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerDocumentApiBuilderTest.java7
-rw-r--r--config-proxy/src/main/java/com/yahoo/vespa/config/proxy/filedistribution/FileDistributionAndUrlDownload.java2
-rw-r--r--config/src/main/java/com/yahoo/config/subscription/impl/JRTConfigSubscription.java11
-rw-r--r--config/src/main/java/com/yahoo/vespa/config/JRTConnectionPool.java6
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java3
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/FileDistributionUtil.java2
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java8
-rw-r--r--container-core/src/main/java/com/yahoo/container/handler/threadpool/DefaultContainerThreadpool.java60
-rw-r--r--container-core/src/main/java/com/yahoo/container/logging/AccessLogHandler.java8
-rw-r--r--container-core/src/main/java/com/yahoo/container/logging/FileConnectionLog.java8
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java15
-rw-r--r--container-core/src/main/resources/configdefinitions/container.handler.threadpool.container-threadpool.def3
-rw-r--r--container-core/src/main/resources/configdefinitions/container.handler.threadpool.def7
-rw-r--r--container-core/src/test/java/com/yahoo/container/handler/threadpool/DefaultContainerThreadPoolTest.java29
-rw-r--r--container-disc/src/main/java/com/yahoo/container/jdisc/ConfiguredApplication.java9
-rw-r--r--container-disc/src/test/java/com/yahoo/container/jdisc/ConfiguredApplicationTest.java14
-rw-r--r--container-search/src/main/java/com/yahoo/search/dispatch/Dispatcher.java6
-rw-r--r--container-search/src/main/java/com/yahoo/search/dispatch/searchcluster/SearchCluster.java22
-rw-r--r--container-search/src/test/java/com/yahoo/prelude/cluster/ClusterSearcherTestCase.java9
-rw-r--r--container-search/src/test/java/com/yahoo/search/dispatch/searchcluster/SearchClusterTest.java2
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/systemflags/v1/SystemFlagsDataArchive.java5
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java9
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobProfile.java4
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/Run.java4
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/systemflags/SystemFlagsDeployResult.java10
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/systemflags/SystemFlagsDeployer.java16
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/RunSerializerTest.java2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/systemflags/SystemFlagsDeployerTest.java4
-rw-r--r--eval/CMakeLists.txt1
-rw-r--r--eval/src/tests/eval/tensor_function/tensor_function_test.cpp14
-rw-r--r--eval/src/tests/instruction/best_similarity_function/CMakeLists.txt9
-rw-r--r--eval/src/tests/instruction/best_similarity_function/best_similarity_function_test.cpp155
-rw-r--r--eval/src/tests/instruction/sum_max_dot_product_function/sum_max_dot_product_function_test.cpp2
-rw-r--r--eval/src/vespa/eval/eval/optimize_tensor_function.cpp98
-rw-r--r--eval/src/vespa/eval/eval/tensor_function.cpp6
-rw-r--r--eval/src/vespa/eval/eval/value.cpp19
-rw-r--r--eval/src/vespa/eval/eval/value.h13
-rw-r--r--eval/src/vespa/eval/instruction/CMakeLists.txt1
-rw-r--r--eval/src/vespa/eval/instruction/best_similarity_function.cpp224
-rw-r--r--eval/src/vespa/eval/instruction/best_similarity_function.h38
-rw-r--r--flags/src/main/java/com/yahoo/vespa/flags/Flags.java16
-rw-r--r--hosted-api/src/main/java/ai/vespa/hosted/api/ControllerHttpClient.java55
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodesAndHosts.java5
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainer.java9
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/GroupPreparer.java62
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java15
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodePrioritizer.java28
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/Preparer.java19
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesResponse.java2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-container1.json1
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-os-upgrade-complete.json1
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports-2.json1
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports-3.json1
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports-4.json1
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports.json1
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1.json1
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node2.json1
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node3.json1
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node4.json1
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node5.json1
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/dockerhost1-with-firmware-data.json1
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node1.json1
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node10.json1
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node13.json1
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node14.json1
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node2.json1
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node4-after-changes.json1
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node4-with-hostnames.json1
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node4.json1
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node6.json1
-rw-r--r--pom.xml5
87 files changed, 902 insertions, 378 deletions
diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java
index 05c736e050b..fc1572f6593 100644
--- a/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java
+++ b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java
@@ -96,6 +96,7 @@ public interface ModelContext {
@ModelFeatureFlag(owners = {"hmusum"}) default double resourceLimitMemory() { return 0.8; }
@ModelFeatureFlag(owners = {"geirst", "vekterli"}) default double minNodeRatioPerGroup() { return 0.0; }
@ModelFeatureFlag(owners = {"arnej"}) default boolean newLocationBrokerLogic() { return true; }
+ @ModelFeatureFlag(owners = {"bjorncs"}) default int maxConnectionLifeInHosted() { return 45; }
}
/** Warning: As elsewhere in this package, do not make backwards incompatible changes that will break old config models! */
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/Slobrok.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/Slobrok.java
index 07b1de3fdad..2b9551c2858 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/admin/Slobrok.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/Slobrok.java
@@ -17,7 +17,6 @@ public class Slobrok extends AbstractService implements StateserverConfig.Produc
private static final long serialVersionUID = 1L;
public final static int BASEPORT = 19099;
- public final boolean useNewLogic;
@Override
public void getConfig(StateserverConfig.Builder builder) {
@@ -32,7 +31,6 @@ public class Slobrok extends AbstractService implements StateserverConfig.Produc
ModelContext.FeatureFlags featureFlags)
{
super(parent, "slobrok." + index);
- this.useNewLogic = featureFlags.newLocationBrokerLogic();
portsMeta.on(0).tag("rpc").tag("admin").tag("status");
portsMeta.on(1).tag("http").tag("state");
setProp("index", index);
@@ -50,10 +48,7 @@ public class Slobrok extends AbstractService implements StateserverConfig.Produc
}
public String getStartupCommand() {
- if (useNewLogic) {
- return "exec $ROOT/sbin/vespa-slobrok -N -p " + getRpcPort() + " -c " + getConfigId();
- }
- return "exec $ROOT/sbin/vespa-slobrok -p " + getRpcPort() + " -c " + getConfigId();
+ return "exec $ROOT/sbin/vespa-slobrok -N -p " + getRpcPort() + " -c " + getConfigId();
}
@Override
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/VespaMetricSet.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/VespaMetricSet.java
index c91c4e92486..0638679b817 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/VespaMetricSet.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/VespaMetricSet.java
@@ -181,6 +181,8 @@ public class VespaMetricSet {
metrics.add(new Metric("jdisc.deactivated_containers.with_retained_refs.last"));
metrics.add(new Metric("athenz-tenant-cert.expiry.seconds.last"));
+ metrics.add(new Metric("node-certificate.expiry.seconds.last"));
+ metrics.add(new Metric("container-iam-role.expiry.seconds.last"));
metrics.add(new Metric("jdisc.http.request.prematurely_closed.rate"));
addMetric(metrics, "jdisc.http.request.requests_per_connection", List.of("sum", "count", "min", "max", "average"));
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 9e1407ec93e..1c2da13738f 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,9 +22,6 @@ public class ContainerDocumentApi {
public static final String DOCUMENT_V1_PREFIX = "/document/v1";
- 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
-
public ContainerDocumentApi(ContainerCluster<?> cluster, Options options) {
addRestApiHandler(cluster, options);
addFeedHandler(cluster, options);
@@ -102,22 +99,7 @@ public class ContainerDocumentApi {
// User options overrides below configuration
if (hasUserOptions()) return;
-
- builder.maxThreads(maxPoolSize());
- builder.minThreads(minPoolSize());
- builder.queueSize(500);
- }
-
- private int maxPoolSize() {
- double vcpu = cluster.vcpu().orElse(0);
- if (vcpu == 0) return FALLBACK_MAX_POOL_SIZE;
- return Math.max(2, (int)Math.ceil(vcpu * 4.0));
- }
-
- private int minPoolSize() {
- double vcpu = cluster.vcpu().orElse(0);
- if (vcpu == 0) return FALLBACK_CORE_POOL_SIZE;
- return Math.max(1, (int)Math.ceil(vcpu * 2.0));
+ builder.maxThreads(-4).minThreads(-4).queueSize(500);
}
}
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 f5b168958c0..d05650b10b5 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
@@ -70,7 +70,6 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
-import java.util.OptionalDouble;
import java.util.Set;
/**
@@ -652,12 +651,4 @@ public abstract class ContainerCluster<CONTAINER extends Container>
public boolean getDeferChangesUntilRestart() { return deferChangesUntilRestart; }
- /** Effective vcpu for the containers in cluster. Use this value as scale factor for performance/resource tuning. **/
- public OptionalDouble vcpu() {
- return getContainers().stream()
- .filter(c -> c.getHostResource() != null && c.getHostResource().realResources() != null)
- .mapToDouble(c -> c.getHostResource().realResources().vcpu())
- .max(); // Use highest vcpu as scale factor
- }
-
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/DefaultThreadpoolProvider.java b/config-model/src/main/java/com/yahoo/vespa/model/container/DefaultThreadpoolProvider.java
index 4d665b0bb58..e74eac09558 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/DefaultThreadpoolProvider.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/DefaultThreadpoolProvider.java
@@ -46,13 +46,7 @@ class DefaultThreadpoolProvider extends SimpleComponent implements ThreadpoolCon
return;
}
- double vcpu = cluster.vcpu().orElse(0);
- if (vcpu == 0) return;
-
- // Configuration is currently identical to the search handler's threadpool
- int workerThreads = Math.max(8, (int)Math.ceil(vcpu * 2.0));
- builder.maxthreads(workerThreads);
- builder.corePoolSize(workerThreads);
- builder.queueSize((int)(workerThreads * 40.0));
+ if (!cluster.isHostedVespa()) return;
+ builder.corePoolSize(-2).maxthreads(-2).queueSize(-40);
}
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/component/AccessLogComponent.java b/config-model/src/main/java/com/yahoo/vespa/model/container/component/AccessLogComponent.java
index fc41da43479..33e712feeb1 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/component/AccessLogComponent.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/component/AccessLogComponent.java
@@ -9,8 +9,6 @@ import com.yahoo.osgi.provider.model.ComponentModel;
import com.yahoo.vespa.model.container.ApplicationContainerCluster;
import com.yahoo.vespa.model.container.ContainerCluster;
-import java.util.OptionalInt;
-
/**
* @author Tony Vaagenes
* @author gjoranv
@@ -32,11 +30,10 @@ public final class AccessLogComponent extends SimpleComponent implements AccessL
public AccessLogComponent(ContainerCluster<?> cluster, AccessLogType logType, CompressionType compressionType, String clusterName, boolean isHostedVespa)
{
- this(cluster, logType, compressionType,
+ this(logType, compressionType,
String.format("logs/vespa/qrs/%s.%s.%s", capitalize(logType.name()), clusterName, "%Y%m%d%H%M%S"),
null, null, isHostedVespa,
- capitalize(logType.name()) + "." + clusterName,
- queueSize(cluster).orElse(-1),
+ capitalize(logType.name()) + "." + clusterName, -1,
((cluster instanceof ApplicationContainerCluster) ? 4*1024*1024 : null));
}
@@ -44,8 +41,7 @@ public final class AccessLogComponent extends SimpleComponent implements AccessL
return name.substring(0, 1).toUpperCase() + name.substring(1);
}
- public AccessLogComponent(ContainerCluster<?> cluster,
- AccessLogType logType,
+ public AccessLogComponent(AccessLogType logType,
CompressionType compressionType,
String fileNamePattern,
String rotationInterval,
@@ -69,13 +65,6 @@ public final class AccessLogComponent extends SimpleComponent implements AccessL
throw new RuntimeException("File name pattern required when configuring access log.");
}
- private static OptionalInt queueSize(ContainerCluster<?> cluster) {
- if (cluster == null) return OptionalInt.empty();
- double vcpu = cluster.vcpu().orElse(0);
- if (vcpu <= 0) return OptionalInt.empty();
- return OptionalInt.of((int) Math.max(4096, Math.ceil(vcpu * 256.0)));
- }
-
private static String accessLogClass(AccessLogType logType) {
switch (logType) {
case queryAccessLog:
@@ -105,9 +94,7 @@ public final class AccessLogComponent extends SimpleComponent implements AccessL
} else if (isHostedVespa) {
builder.compressOnRotation(true);
}
- if (queueSize >= 0) {
- builder.queueSize(queueSize);
- }
+ builder.queueSize(queueSize);
if (bufferSize != null) {
builder.bufferSize(bufferSize);
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/component/ConnectionLogComponent.java b/config-model/src/main/java/com/yahoo/vespa/model/container/component/ConnectionLogComponent.java
index 0b51cd163a2..4afac252085 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/component/ConnectionLogComponent.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/component/ConnectionLogComponent.java
@@ -6,38 +6,25 @@ import com.yahoo.container.logging.ConnectionLog;
import com.yahoo.container.logging.ConnectionLogConfig;
import com.yahoo.vespa.model.container.ContainerCluster;
-import java.util.OptionalInt;
-
public class ConnectionLogComponent extends SimpleComponent implements ConnectionLogConfig.Producer {
private final String logDirectoryName;
private final String clusterName;
- private final int queueSize;
public ConnectionLogComponent(ContainerCluster<?> cluster, Class<? extends ConnectionLog> cls, String logDirectoryName) {
- this(cluster, cls, logDirectoryName, cluster.getName());
+ this(cls, logDirectoryName, cluster.getName());
}
- public ConnectionLogComponent(ContainerCluster<?> cluster, Class<? extends ConnectionLog> cls, String logDirectoryName, String clusterName) {
+ public ConnectionLogComponent(Class<? extends ConnectionLog> cls, String logDirectoryName, String clusterName) {
super(cls.getName());
this.logDirectoryName = logDirectoryName;
this.clusterName = clusterName;
- this.queueSize = queueSize(cluster).orElse(-1);
- }
-
- private static OptionalInt queueSize(ContainerCluster<?> cluster) {
- if (cluster == null) return OptionalInt.empty();
- double vcpu = cluster.vcpu().orElse(0);
- if (vcpu <= 0) return OptionalInt.empty();
- return OptionalInt.of((int) Math.max(4096, Math.ceil(vcpu * 512.0)));
}
@Override
public void getConfig(ConnectionLogConfig.Builder builder) {
builder.cluster(clusterName);
builder.logDirectoryName(logDirectoryName);
- if (queueSize >= 0) {
- builder.queueSize(queueSize);
- }
+ builder.queueSize(-1);
}
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/http/JettyHttpServer.java b/config-model/src/main/java/com/yahoo/vespa/model/container/http/JettyHttpServer.java
index d13709114bf..a2181f317a6 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/http/JettyHttpServer.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/http/JettyHttpServer.java
@@ -70,18 +70,11 @@ public class JettyHttpServer extends SimpleComponent implements ServerConfig.Pro
private void configureJettyThreadpool(ServerConfig.Builder builder) {
if (cluster == null) return;
if (cluster instanceof ApplicationContainerCluster) {
- configureApplicationClusterJettyThreadPool(builder);
+ if (isHostedVespa) builder.minWorkerThreads(-1).maxWorkerThreads(-1);
} else {
builder.minWorkerThreads(4).maxWorkerThreads(4);
}
}
- private void configureApplicationClusterJettyThreadPool(ServerConfig.Builder builder) {
- double vcpu = cluster.vcpu().orElse(0);
- if (vcpu > 0) {
- int threads = 16 + (int) Math.ceil(vcpu);
- builder.minWorkerThreads(threads).maxWorkerThreads(threads);
- }
- }
static ComponentModel providerComponentModel(String parentId, String className) {
final ComponentSpecification classNameSpec = new ComponentSpecification(
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/http/ssl/HostedSslConnectorFactory.java b/config-model/src/main/java/com/yahoo/vespa/model/container/http/ssl/HostedSslConnectorFactory.java
index b25463b8547..aab417db1e2 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/http/ssl/HostedSslConnectorFactory.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/http/ssl/HostedSslConnectorFactory.java
@@ -25,16 +25,17 @@ public class HostedSslConnectorFactory extends ConnectorFactory {
private final boolean enforceClientAuth;
private final boolean enforceHandshakeClientAuth;
private final Collection<String> tlsCiphersOverride;
+ private final Duration maxConnectionLife;
/**
* Create connector factory that uses a certificate provided by the config-model / configserver and default hosted Vespa truststore.
*/
public static HostedSslConnectorFactory withProvidedCertificate(
String serverName, EndpointCertificateSecrets endpointCertificateSecrets, boolean enforceHandshakeClientAuth,
- Collection<String> tlsCiphersOverride) {
+ Collection<String> tlsCiphersOverride, Duration maxConnectionLife) {
ConfiguredDirectSslProvider sslProvider = createConfiguredDirectSslProvider(
serverName, endpointCertificateSecrets, DEFAULT_HOSTED_TRUSTSTORE, /*tlsCaCertificates*/null, enforceHandshakeClientAuth);
- return new HostedSslConnectorFactory(sslProvider, false, enforceHandshakeClientAuth, tlsCiphersOverride);
+ return new HostedSslConnectorFactory(sslProvider, false, enforceHandshakeClientAuth, tlsCiphersOverride, maxConnectionLife);
}
/**
@@ -42,25 +43,28 @@ public class HostedSslConnectorFactory extends ConnectorFactory {
*/
public static HostedSslConnectorFactory withProvidedCertificateAndTruststore(
String serverName, EndpointCertificateSecrets endpointCertificateSecrets, String tlsCaCertificates,
- Collection<String> tlsCiphersOverride) {
+ Collection<String> tlsCiphersOverride, Duration maxConnectionLife) {
ConfiguredDirectSslProvider sslProvider = createConfiguredDirectSslProvider(
serverName, endpointCertificateSecrets, /*tlsCaCertificatesPath*/null, tlsCaCertificates, false);
- return new HostedSslConnectorFactory(sslProvider, true, false, tlsCiphersOverride);
+ return new HostedSslConnectorFactory(sslProvider, true, false, tlsCiphersOverride, maxConnectionLife);
}
/**
* Create connector factory that uses the default certificate and truststore provided by Vespa (through Vespa-global TLS configuration).
*/
- public static HostedSslConnectorFactory withDefaultCertificateAndTruststore(String serverName, Collection<String> tlsCiphersOverride) {
- return new HostedSslConnectorFactory(new DefaultSslProvider(serverName), true, false, tlsCiphersOverride);
+ public static HostedSslConnectorFactory withDefaultCertificateAndTruststore(
+ String serverName, Collection<String> tlsCiphersOverride, Duration maxConnectionLife) {
+ return new HostedSslConnectorFactory(new DefaultSslProvider(serverName), true, false, tlsCiphersOverride, maxConnectionLife);
}
private HostedSslConnectorFactory(SslProvider sslProvider, boolean enforceClientAuth,
- boolean enforceHandshakeClientAuth, Collection<String> tlsCiphersOverride) {
+ boolean enforceHandshakeClientAuth, Collection<String> tlsCiphersOverride,
+ Duration maxConnectionLife) {
super(new Builder("tls4443", 4443).sslProvider(sslProvider));
this.enforceClientAuth = enforceClientAuth;
this.enforceHandshakeClientAuth = enforceHandshakeClientAuth;
this.tlsCiphersOverride = tlsCiphersOverride;
+ this.maxConnectionLife = maxConnectionLife;
}
private static ConfiguredDirectSslProvider createConfiguredDirectSslProvider(
@@ -96,6 +100,6 @@ public class HostedSslConnectorFactory extends ConnectorFactory {
connectorBuilder
.proxyProtocol(new ConnectorConfig.ProxyProtocol.Builder().enabled(true).mixedMode(true))
.idleTimeout(Duration.ofSeconds(30).toSeconds())
- .maxConnectionLife(Duration.ofMinutes(10).toSeconds());
+ .maxConnectionLife(maxConnectionLife.toSeconds());
}
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/AccessLogBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/AccessLogBuilder.java
index d7812e9b4ff..62f04edf0ae 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/AccessLogBuilder.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/AccessLogBuilder.java
@@ -55,7 +55,6 @@ public class AccessLogBuilder {
@Override
protected AccessLogComponent doBuild(DeployState deployState, AbstractConfigProducer<?> ancestor, Element spec) {
return new AccessLogComponent(
- (ContainerCluster<?>) ancestor,
accessLogType,
compressionType(spec, isHostedVespa),
fileNamePattern(spec),
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ConfigServerContainerModelBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ConfigServerContainerModelBuilder.java
index a1f52cca9fd..75f11020c15 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ConfigServerContainerModelBuilder.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ConfigServerContainerModelBuilder.java
@@ -6,7 +6,6 @@ import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.container.logging.FileConnectionLog;
import com.yahoo.vespa.model.container.ApplicationContainerCluster;
import com.yahoo.vespa.model.container.ContainerModel;
-import com.yahoo.vespa.model.container.ContainerModelEvaluation;
import com.yahoo.vespa.model.container.component.AccessLogComponent;
import com.yahoo.vespa.model.container.component.ConnectionLogComponent;
import com.yahoo.vespa.model.container.configserver.ConfigserverCluster;
@@ -48,7 +47,7 @@ public class ConfigServerContainerModelBuilder extends ContainerModelBuilder {
if (isHosted()){
cluster.addComponent(
new AccessLogComponent(
- cluster, AccessLogComponent.AccessLogType.jsonAccessLog, AccessLogComponent.CompressionType.ZSTD,
+ AccessLogComponent.AccessLogType.jsonAccessLog, AccessLogComponent.CompressionType.ZSTD,
"logs/vespa/configserver/access-json.log.%Y%m%d%H%M%S", null, true, true, "access-json.log", 1024,256*1024));
cluster.addComponent(new ConnectionLogComponent(cluster, FileConnectionLog.class, "configserver"));
} else {
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 c62dee68b2d..2622a9e50b7 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
@@ -92,6 +92,7 @@ import org.w3c.dom.Node;
import java.net.URI;
import java.security.cert.X509Certificate;
+import java.time.Duration;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -436,6 +437,7 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
// If the deployment contains certificate/private key reference, setup TLS port
HostedSslConnectorFactory connectorFactory;
Collection<String> tlsCiphersOverride = deployState.getProperties().tlsCiphersOverride();
+ Duration maxConnectionLife = Duration.ofSeconds(deployState.featureFlags().maxConnectionLifeInHosted());
if (deployState.endpointCertificateSecrets().isPresent()) {
boolean authorizeClient = deployState.zone().system().isPublic();
if (authorizeClient && deployState.tlsClientAuthority().isEmpty()) {
@@ -450,11 +452,11 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
connectorFactory = authorizeClient
? HostedSslConnectorFactory.withProvidedCertificateAndTruststore(
- serverName, endpointCertificateSecrets, getTlsClientAuthorities(deployState), tlsCiphersOverride)
+ serverName, endpointCertificateSecrets, getTlsClientAuthorities(deployState), tlsCiphersOverride, maxConnectionLife)
: HostedSslConnectorFactory.withProvidedCertificate(
- serverName, endpointCertificateSecrets, enforceHandshakeClientAuth, tlsCiphersOverride);
+ serverName, endpointCertificateSecrets, enforceHandshakeClientAuth, tlsCiphersOverride, maxConnectionLife);
} else {
- connectorFactory = HostedSslConnectorFactory.withDefaultCertificateAndTruststore(serverName, tlsCiphersOverride);
+ connectorFactory = HostedSslConnectorFactory.withDefaultCertificateAndTruststore(serverName, tlsCiphersOverride, maxConnectionLife);
}
cluster.getHttp().getAccessControl().ifPresent(accessControl -> accessControl.configureHostedConnector(connectorFactory));
server.addConnector(connectorFactory);
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
index 95b333f4e52..d3001bd9100 100644
--- 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
@@ -48,22 +48,10 @@ class SearchHandler extends ProcessingHandler<SearchChains> {
// User options overrides below configuration
if (hasUserOptions()) return;
-
- double vcpu = cluster.vcpu().orElse(0);
- if (vcpu == 0) {
- builder.maxThreads(500);
- builder.minThreads(500);
- builder.queueSize(0);
+ if (cluster.isHostedVespa()) {
+ builder.maxThreads(-2).minThreads(-2).queueSize(-40);
} else {
- // Controls max number of concurrent requests per container
- int workerThreads = Math.max(8, (int)Math.ceil(vcpu * 2.0));
- 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 * 40.0));
+ builder.maxThreads(500).minThreads(500).queueSize(0);
}
}
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 a66ea736a5b..a2887ae76c1 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
@@ -277,45 +277,37 @@ public class ContainerClusterTest {
}
@Test
- public void config_for_default_threadpool_provider_scales_with_node_resources() {
- HostProvisionerWithCustomRealResource hostProvisioner = new HostProvisionerWithCustomRealResource();
+ public void config_for_default_threadpool_provider_scales_with_node_resources_in_hosted() {
MockRoot root = new MockRoot(
"foo",
new DeployState.Builder()
+ .properties(new TestProperties().setHostedVespa(true))
.applicationPackage(new MockApplicationPackage.Builder().build())
- .modelHostProvisioner(hostProvisioner)
.build());
ApplicationContainerCluster cluster = createContainerCluster(root, false);
- HostResource hostResource = new HostResource(
- new Host(null, "host-c1"),
- hostProvisioner.allocateHost("host-c1"));
- addContainerWithHostResource(root, cluster, "c1", hostResource);
+ addContainer(root, cluster, "c1", "host-c1");
root.freezeModelTopology();
ThreadpoolConfig threadpoolConfig = root.getConfig(ThreadpoolConfig.class, "container0/component/default-threadpool");
- assertEquals(8, threadpoolConfig.maxthreads());
- assertEquals(320, threadpoolConfig.queueSize());
+ assertEquals(-2, threadpoolConfig.maxthreads());
+ assertEquals(-40, threadpoolConfig.queueSize());
}
@Test
- public void jetty_threadpool_scales_with_node_resources() {
- HostProvisionerWithCustomRealResource hostProvisioner = new HostProvisionerWithCustomRealResource(12);
+ public void jetty_threadpool_scales_with_node_resources_in_hosted() {
MockRoot root = new MockRoot(
"foo",
new DeployState.Builder()
+ .properties(new TestProperties().setHostedVespa(true))
.applicationPackage(new MockApplicationPackage.Builder().build())
- .modelHostProvisioner(hostProvisioner)
.build());
ApplicationContainerCluster cluster = createContainerCluster(root, false);
- HostResource hostResource = new HostResource(
- new Host(null, "host-c1"),
- hostProvisioner.allocateHost("host-c1"));
- addContainerWithHostResource(root, cluster, "c1", hostResource);
+ addContainer(root, cluster, "c1", "host-c1");
root.freezeModelTopology();
ServerConfig cfg = root.getConfig(ServerConfig.class, "container0/c1/DefaultHttpServer");
- assertEquals(28, cfg.maxWorkerThreads());
- assertEquals(28, cfg.minWorkerThreads());
+ assertEquals(-1, cfg.maxWorkerThreads()); // Scale with cpu count observed by JVM
+ assertEquals(-1, cfg.minWorkerThreads()); // Scale with cpu count observed by JVM
}
@Test
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/AccessLogTest.java b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/AccessLogTest.java
index 80aafdd4ec7..06281c7b57e 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/AccessLogTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/AccessLogTest.java
@@ -117,7 +117,7 @@ public class AccessLogTest extends ContainerModelBuilderTestBase {
assertNotNull(connectionLogComponent);
ConnectionLogConfig config = root.getConfig(ConnectionLogConfig.class, "default/component/com.yahoo.container.logging.FileConnectionLog");
assertEquals("default", config.cluster());
- assertEquals(10000, config.queueSize());
+ assertEquals(-1, config.queueSize());
assertEquals(256*1024, config.bufferSize());
}
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 3c733d5109d..0176d5f6ffc 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
@@ -6,7 +6,6 @@ import com.yahoo.config.model.test.MockApplicationPackage;
import com.yahoo.config.model.test.MockRoot;
import com.yahoo.container.handler.threadpool.ContainerThreadpoolConfig;
import com.yahoo.vespa.model.container.ContainerCluster;
-import com.yahoo.vespa.model.container.HostProvisionerWithCustomRealResource;
import com.yahoo.vespa.model.container.component.Handler;
import com.yahoo.vespa.model.container.component.SystemBindingPattern;
import com.yahoo.vespa.model.container.component.UserBindingPattern;
@@ -98,7 +97,7 @@ public class ContainerDocumentApiBuilderTest extends ContainerModelBuilderTestBa
" <document-api />",
nodesXml,
"</container>");
- root = new MockRoot("root", new MockApplicationPackage.Builder().build(), new HostProvisionerWithCustomRealResource());
+ root = new MockRoot("root", new MockApplicationPackage.Builder().build());
createModel(root, elem);
Map<String, Handler<?>> handlers = getHandlers("cluster1");
Handler<?> feedApiHandler = handlers.get("com.yahoo.vespa.http.server.FeedHandler");
@@ -107,8 +106,8 @@ public class ContainerDocumentApiBuilderTest extends ContainerModelBuilderTestBa
ContainerThreadpoolConfig config = root.getConfig(
ContainerThreadpoolConfig.class, "cluster1/component/com.yahoo.vespa.http.server.FeedHandler/threadpool@feedapi-handler");
- assertEquals(16, config.maxThreads());
- assertEquals(8, config.minThreads());
+ assertEquals(-4, config.maxThreads());
+ assertEquals(-4, config.minThreads());
}
@Test
diff --git a/config-proxy/src/main/java/com/yahoo/vespa/config/proxy/filedistribution/FileDistributionAndUrlDownload.java b/config-proxy/src/main/java/com/yahoo/vespa/config/proxy/filedistribution/FileDistributionAndUrlDownload.java
index 1dba56805a5..d32a866cfbd 100644
--- a/config-proxy/src/main/java/com/yahoo/vespa/config/proxy/filedistribution/FileDistributionAndUrlDownload.java
+++ b/config-proxy/src/main/java/com/yahoo/vespa/config/proxy/filedistribution/FileDistributionAndUrlDownload.java
@@ -28,7 +28,7 @@ public class FileDistributionAndUrlDownload {
public FileDistributionAndUrlDownload(Supervisor supervisor, ConfigSourceSet source) {
fileDistributionRpcServer =
new FileDistributionRpcServer(supervisor,
- new FileDownloader(new JRTConnectionPool(source, "filedistribution-jrt-pool-")));
+ new FileDownloader(new JRTConnectionPool(source, "filedistribution-jrt-pool")));
urlDownloadRpcServer = new UrlDownloadRpcServer(supervisor);
cleanupExecutor.scheduleAtFixedRate(new CachedFilesMaintainer(), delay.toSeconds(), delay.toSeconds(), TimeUnit.SECONDS);
}
diff --git a/config/src/main/java/com/yahoo/config/subscription/impl/JRTConfigSubscription.java b/config/src/main/java/com/yahoo/config/subscription/impl/JRTConfigSubscription.java
index e83fc7aefc5..f50ed694115 100644
--- a/config/src/main/java/com/yahoo/config/subscription/impl/JRTConfigSubscription.java
+++ b/config/src/main/java/com/yahoo/config/subscription/impl/JRTConfigSubscription.java
@@ -105,16 +105,11 @@ public class JRTConfigSubscription<T extends ConfigInstance> extends ConfigSubsc
}
protected void setNewConfig(JRTClientConfigRequest jrtReq) {
- Exception badConfigE = null;
- T configInstance = null;
try {
- configInstance = toConfigInstance(jrtReq);
+ T configInstance = toConfigInstance(jrtReq);
+ setConfig(jrtReq.getNewGeneration(), jrtReq.responseIsApplyOnRestart(), configInstance, jrtReq.getNewChecksums());
} catch (IllegalArgumentException e) {
- badConfigE = e;
- }
- setConfig(jrtReq.getNewGeneration(), jrtReq.responseIsApplyOnRestart(), configInstance, jrtReq.getNewChecksums());
- if (badConfigE != null) {
- throw new IllegalArgumentException("Bad config from jrt", badConfigE);
+ throw new IllegalArgumentException("Bad config in response", e);
}
}
diff --git a/config/src/main/java/com/yahoo/vespa/config/JRTConnectionPool.java b/config/src/main/java/com/yahoo/vespa/config/JRTConnectionPool.java
index b5147075972..78580328bf9 100644
--- a/config/src/main/java/com/yahoo/vespa/config/JRTConnectionPool.java
+++ b/config/src/main/java/com/yahoo/vespa/config/JRTConnectionPool.java
@@ -38,12 +38,12 @@ public class JRTConnectionPool implements ConnectionPool {
private volatile JRTConnection currentConnection;
public JRTConnectionPool(ConfigSourceSet sourceSet) {
- this(sourceSet, "config-jrt-pool-" + sourceSet.hashCode());
+ this(sourceSet, "config-jrt-pool" + sourceSet.hashCode());
}
public JRTConnectionPool(ConfigSourceSet sourceSet, String poolName) {
this.poolName = poolName;
- supervisor = new Supervisor(new Transport(poolName)).setDropEmptyBuffers(true);
+ supervisor = new Supervisor(new Transport(poolName + "-")).setDropEmptyBuffers(true);
addSources(sourceSet);
}
@@ -91,7 +91,7 @@ public class JRTConnectionPool implements ConnectionPool {
List<JRTConnection> sourceCandidates = getSources();
sourceCandidates.remove(currentConnection);
JRTConnection newConnection = pickNewConnectionRandomly(sourceCandidates);
- log.log(Level.INFO, () -> "Switching from " + currentConnection + " to " + newConnection);
+ log.log(Level.INFO, () -> poolName + ": Switching from " + currentConnection + " to " + newConnection);
return currentConnection = newConnection;
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java
index 8a952f9523d..b583e0ea263 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java
@@ -190,6 +190,7 @@ public class ModelContextImpl implements ModelContext {
private final boolean newLocationBrokerLogic;
private final boolean containerDumpHeapOnShutdownTimeout;
private final double containerShutdownTimeout;
+ private final int maxConnectionLifeInHosted;
public FeatureFlags(FlagSource source, ApplicationId appId) {
this.defaultTermwiseLimit = flagValue(source, appId, Flags.DEFAULT_TERM_WISE_LIMIT);
@@ -218,6 +219,7 @@ public class ModelContextImpl implements ModelContext {
this.newLocationBrokerLogic = flagValue(source, appId, Flags.NEW_LOCATION_BROKER_LOGIC);
this.containerDumpHeapOnShutdownTimeout = flagValue(source, appId, Flags.CONTAINER_DUMP_HEAP_ON_SHUTDOWN_TIMEOUT);
this.containerShutdownTimeout = flagValue(source, appId,Flags.CONTAINER_SHUTDOWN_TIMEOUT);
+ this.maxConnectionLifeInHosted = flagValue(source, appId, Flags.MAX_CONNECTION_LIFE_IN_HOSTED);
}
@Override public double defaultTermwiseLimit() { return defaultTermwiseLimit; }
@@ -248,6 +250,7 @@ public class ModelContextImpl implements ModelContext {
@Override public boolean newLocationBrokerLogic() { return newLocationBrokerLogic; }
@Override public double containerShutdownTimeout() { return containerShutdownTimeout; }
@Override public boolean containerDumpHeapOnShutdownTimeout() { return containerDumpHeapOnShutdownTimeout; }
+ @Override public int maxConnectionLifeInHosted() { return maxConnectionLifeInHosted; }
private static <V> V flagValue(FlagSource source, ApplicationId appId, UnboundFlag<? extends V, ?, ?> flag) {
return flag.bindTo(source)
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/FileDistributionUtil.java b/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/FileDistributionUtil.java
index cfe7349a1c6..1985fd534fb 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/FileDistributionUtil.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/filedistribution/FileDistributionUtil.java
@@ -50,7 +50,7 @@ public class FileDistributionUtil {
.collect(Collectors.toList());
return configServers.size() > 0
- ? new JRTConnectionPool(new ConfigSourceSet(configServers), "filedistribution-jrt-pool-")
+ ? new JRTConnectionPool(new ConfigSourceSet(configServers), "filedistribution-jrt-pool")
: emptyConnectionPool();
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java
index 43a684c1fba..083cb535bfa 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java
@@ -1,4 +1,4 @@
-// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.config.server.session;
import com.google.common.collect.HashMultiset;
@@ -236,14 +236,16 @@ public class SessionRepository {
logger.log(Level.FINE, "Created application " + params.getApplicationId());
long sessionId = session.getSessionId();
SessionZooKeeperClient sessionZooKeeperClient = createSessionZooKeeperClient(sessionId);
- CompletionWaiter waiter = sessionZooKeeperClient.createPrepareWaiter();
+ Optional<CompletionWaiter> waiter = params.isDryRun()
+ ? Optional.empty()
+ : Optional.of(sessionZooKeeperClient.createPrepareWaiter());
Optional<ApplicationSet> activeApplicationSet = getActiveApplicationSet(params.getApplicationId());
ConfigChangeActions actions = sessionPreparer.prepare(applicationRepo.getHostValidator(), logger, params,
activeApplicationSet, now, getSessionAppDir(sessionId),
session.getApplicationPackage(), sessionZooKeeperClient)
.getConfigChangeActions();
setPrepared(session);
- waiter.awaitCompletion(params.getTimeoutBudget().timeLeft());
+ waiter.ifPresent(w -> w.awaitCompletion(params.getTimeoutBudget().timeLeft()));
return actions;
}
diff --git a/container-core/src/main/java/com/yahoo/container/handler/threadpool/DefaultContainerThreadpool.java b/container-core/src/main/java/com/yahoo/container/handler/threadpool/DefaultContainerThreadpool.java
index 6bed4a6f442..7f4d1462102 100644
--- a/container-core/src/main/java/com/yahoo/container/handler/threadpool/DefaultContainerThreadpool.java
+++ b/container-core/src/main/java/com/yahoo/container/handler/threadpool/DefaultContainerThreadpool.java
@@ -12,9 +12,10 @@ import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
+import java.util.logging.Logger;
/**
- * Default implementation of {@link DefaultContainerThreadpool}.
+ * Default implementation of {@link ContainerThreadPool}.
*
* @author Steinar Knutsen
* @author baldersheim
@@ -23,6 +24,10 @@ import java.util.concurrent.TimeUnit;
*/
public class DefaultContainerThreadpool extends AbstractComponent implements AutoCloseable, ContainerThreadPool {
+ private static final Logger log = Logger.getLogger(DefaultContainerThreadpool.class.getName());
+ private static final int MIN_QUEUE_SIZE = 650;
+ private static final int MIN_THREADS_WHEN_SCALE_FACTOR = 8;
+
private final ExecutorServiceWrapper threadpool;
@Inject
@@ -31,14 +36,23 @@ public class DefaultContainerThreadpool extends AbstractComponent implements Aut
}
public DefaultContainerThreadpool(ContainerThreadpoolConfig config, Metric metric, ProcessTerminator processTerminator) {
- ThreadPoolMetric threadPoolMetric = new ThreadPoolMetric(metric, config.name());
- int maxNumThreads = computeMaximumThreadPoolSize(config.maxThreads());
- int coreNumThreads = computeCoreThreadPoolSize(config.minThreads(), maxNumThreads);
+ this(config, metric, processTerminator, Runtime.getRuntime().availableProcessors());
+ }
+
+ DefaultContainerThreadpool(ContainerThreadpoolConfig config, Metric metric, ProcessTerminator processTerminator,
+ int cpus) {
+ String name = config.name();
+ int maxThreads = maxThreads(config, cpus);
+ int minThreads = minThreads(config, maxThreads, cpus);
+ int queueSize = queueSize(config, maxThreads);
+ log.info(String.format("Threadpool '%s': min=%d, max=%d, queue=%d", name, minThreads, maxThreads, queueSize));
+
+ ThreadPoolMetric threadPoolMetric = new ThreadPoolMetric(metric, name);
WorkerCompletionTimingThreadPoolExecutor executor =
- new WorkerCompletionTimingThreadPoolExecutor(coreNumThreads, maxNumThreads,
+ new WorkerCompletionTimingThreadPoolExecutor(minThreads, maxThreads,
(int)config.keepAliveTime() * 1000, TimeUnit.MILLISECONDS,
- createQ(config.queueSize(), maxNumThreads),
- ThreadFactoryFactory.getThreadFactory(config.name()),
+ createQueue(queueSize),
+ ThreadFactoryFactory.getThreadFactory(name),
threadPoolMetric);
// Prestart needed, if not all threads will be created by the fist N tasks and hence they might also
// get the dreaded thread locals initialized even if they will never run.
@@ -46,7 +60,7 @@ public class DefaultContainerThreadpool extends AbstractComponent implements Aut
executor.prestartAllCoreThreads();
threadpool = new ExecutorServiceWrapper(
executor, threadPoolMetric, processTerminator, config.maxThreadExecutionTimeSeconds() * 1000L,
- config.name(), config.queueSize());
+ name, queueSize);
}
@Override public Executor executor() { return threadpool; }
@@ -74,24 +88,26 @@ public class DefaultContainerThreadpool extends AbstractComponent implements Aut
}
}
- private static BlockingQueue<Runnable> createQ(int queueSize, int maxThreads) {
- return (queueSize == 0)
- ? new SynchronousQueue<>(false)
- : (queueSize < 0)
- ? new ArrayBlockingQueue<>(maxThreads*4)
- : new ArrayBlockingQueue<>(queueSize);
+ private static BlockingQueue<Runnable> createQueue(int size) {
+ return size == 0 ? new SynchronousQueue<>(false) : new ArrayBlockingQueue<>(size);
+ }
+
+ private static int maxThreads(ContainerThreadpoolConfig config, int cpus) {
+ if (config.maxThreads() > 0) return config.maxThreads();
+ else if (config.maxThreads() == 0) return 4 * cpus;
+ else return Math.max(MIN_THREADS_WHEN_SCALE_FACTOR, Math.abs(config.maxThreads()) * cpus);
}
- private static int computeMaximumThreadPoolSize(int maxNumThreads) {
- return (maxNumThreads <= 0)
- ? Runtime.getRuntime().availableProcessors() * 4
- : maxNumThreads;
+ private static int minThreads(ContainerThreadpoolConfig config, int max, int cpus) {
+ int threads;
+ if (config.minThreads() > 0) threads = config.minThreads();
+ else if (config.minThreads() == 0) threads = 4 * cpus;
+ else threads = Math.max(MIN_THREADS_WHEN_SCALE_FACTOR, Math.abs(config.minThreads()) * cpus);
+ return Math.min(threads, max);
}
- private static int computeCoreThreadPoolSize(int corePoolSize, int maxNumThreads) {
- return Math.min(
- corePoolSize <= 0 ? Runtime.getRuntime().availableProcessors() * 2 : corePoolSize,
- maxNumThreads);
+ private int queueSize(ContainerThreadpoolConfig config, int maxThreads) {
+ return config.queueSize() >= 0 ? config.queueSize() : Math.max(MIN_QUEUE_SIZE, Math.abs(config.queueSize()) * maxThreads);
}
}
diff --git a/container-core/src/main/java/com/yahoo/container/logging/AccessLogHandler.java b/container-core/src/main/java/com/yahoo/container/logging/AccessLogHandler.java
index f14479899f5..55c3ad2ca8e 100644
--- a/container-core/src/main/java/com/yahoo/container/logging/AccessLogHandler.java
+++ b/container-core/src/main/java/com/yahoo/container/logging/AccessLogHandler.java
@@ -13,13 +13,19 @@ class AccessLogHandler {
AccessLogHandler(AccessLogConfig.FileHandler config, LogWriter<RequestLogEntry> logWriter) {
logFileHandler = new LogFileHandler<>(
toCompression(config), config.bufferSize(), config.pattern(), config.rotation(),
- config.symlink(), config.queueSize(), "request-logger", logWriter);
+ config.symlink(), queueSize(config), "request-logger", logWriter);
+ }
+
+ private static int queueSize(AccessLogConfig.FileHandler config) {
+ if (config.queueSize() != -1) return config.queueSize();
+ return Math.max(4096, Runtime.getRuntime().availableProcessors() * 256);
}
public void log(RequestLogEntry entry) {
logFileHandler.publish(entry);
}
+
private LogFileHandler.Compression toCompression(AccessLogConfig.FileHandler config) {
if (!config.compressOnRotation()) return LogFileHandler.Compression.NONE;
switch (config.compressionFormat()) {
diff --git a/container-core/src/main/java/com/yahoo/container/logging/FileConnectionLog.java b/container-core/src/main/java/com/yahoo/container/logging/FileConnectionLog.java
index 749426d3da9..273d562d048 100644
--- a/container-core/src/main/java/com/yahoo/container/logging/FileConnectionLog.java
+++ b/container-core/src/main/java/com/yahoo/container/logging/FileConnectionLog.java
@@ -14,7 +14,13 @@ public class FileConnectionLog extends AbstractComponent implements ConnectionLo
@Inject
public FileConnectionLog(ConnectionLogConfig config) {
- logHandler = new ConnectionLogHandler(config.logDirectoryName(), config.bufferSize(), config.cluster(), config.queueSize(), new JsonConnectionLogWriter());
+ logHandler = new ConnectionLogHandler(config.logDirectoryName(), config.bufferSize(), config.cluster(),
+ queueSize(config), new JsonConnectionLogWriter());
+ }
+
+ private static int queueSize(ConnectionLogConfig config) {
+ if (config.queueSize() != -1) return config.queueSize();
+ return Math.max(4096, Runtime.getRuntime().availableProcessors() * 512);
}
@Override
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java
index 70f173b74e5..b44a32c4db1 100644
--- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java
@@ -132,9 +132,13 @@ public class JettyHttpServer extends AbstractServerProvider {
}
private static void configureJettyThreadpool(Server server, ServerConfig config) {
+ int cpus = Runtime.getRuntime().availableProcessors();
QueuedThreadPool pool = (QueuedThreadPool) server.getThreadPool();
- pool.setMaxThreads(config.maxWorkerThreads());
- pool.setMinThreads(config.minWorkerThreads());
+ int maxThreads = config.maxWorkerThreads() > 0 ? config.maxWorkerThreads() : 16 + cpus;
+ pool.setMaxThreads(maxThreads);
+ int minThreads = config.minWorkerThreads() >= 0 ? config.minWorkerThreads() : 16 + cpus;
+ pool.setMinThreads(minThreads);
+ log.info(String.format("Threadpool size: min=%d, max=%d", minThreads, maxThreads));
}
private static JMXServiceURL createJmxLoopbackOnlyServiceUrl(int port) {
@@ -224,10 +228,9 @@ public class JettyHttpServer extends AbstractServerProvider {
var sslConnectionFactory = serverConnector.getConnectionFactory(SslConnectionFactory.class);
if (sslConnectionFactory != null) {
var sslContextFactory = sslConnectionFactory.getSslContextFactory();
- log.info(String.format("Enabled SSL cipher suites for port '%d': %s",
- localPort, Arrays.toString(sslContextFactory.getSelectedCipherSuites())));
- log.info(String.format("Enabled SSL protocols for port '%d': %s",
- localPort, Arrays.toString(sslContextFactory.getSelectedProtocols())));
+ String protocols = Arrays.toString(sslContextFactory.getSelectedProtocols());
+ String cipherSuites = Arrays.toString(sslContextFactory.getSelectedCipherSuites());
+ log.info(String.format("TLS for port '%d': %s with %s", localPort, protocols, cipherSuites));
}
}
}
diff --git a/container-core/src/main/resources/configdefinitions/container.handler.threadpool.container-threadpool.def b/container-core/src/main/resources/configdefinitions/container.handler.threadpool.container-threadpool.def
index 9248bf2e2bf..4ba14c2da89 100644
--- a/container-core/src/main/resources/configdefinitions/container.handler.threadpool.container-threadpool.def
+++ b/container-core/src/main/resources/configdefinitions/container.handler.threadpool.container-threadpool.def
@@ -4,16 +4,19 @@ namespace=container.handler.threadpool
## Maximum number of thread in the thread pool
## 0 is translated to vcpu*4
+## Negative value is interpreted as scale factor ( vcpu*abs(maxThreads) )
maxThreads int default=0
## Minimum number of thread in the thread pool
## 0 is translated to vcpu*2
+## Negative value is interpreted as scale factor ( vcpu*abs(minThreads) )
minThreads int default=0
## The number of seconds that excess idle threads will wait for new tasks before terminating
keepAliveTime double default=5.0
## Max queue size
+## Negative value is interpreted as scale factor ( effectiveMaxThreads*abs(queueSize) )
queueSize int default=0
## The max time the container tolerates having no threads available before it shuts down to
diff --git a/container-core/src/main/resources/configdefinitions/container.handler.threadpool.def b/container-core/src/main/resources/configdefinitions/container.handler.threadpool.def
index d966738ea9f..e73ee2254fc 100644
--- a/container-core/src/main/resources/configdefinitions/container.handler.threadpool.def
+++ b/container-core/src/main/resources/configdefinitions/container.handler.threadpool.def
@@ -3,10 +3,13 @@
namespace=container.handler
## Maximum number of thread in the thread pool
-## Setting it to 0 or negative number will cause it to be set to #cores * 4
+## 0 is translated to vcpu*4
+## Negative value is interpreted as scale factor ( vcpu*abs(maxThreads) )
maxthreads int default=500
-# The number of threads to keep in the pool, even if they are idle
+## The number of threads to keep in the pool, even if they are idle
+## 0 is translated to vcpu*4
+## Negative value is interpreted as scale factor ( vcpu*abs(corePoolSize) )
corePoolSize int default=500
# The number of seconds that excess idle threads will wait for new tasks before terminating
diff --git a/container-core/src/test/java/com/yahoo/container/handler/threadpool/DefaultContainerThreadPoolTest.java b/container-core/src/test/java/com/yahoo/container/handler/threadpool/DefaultContainerThreadPoolTest.java
index 8b1ed12c796..1d9c4b367bd 100644
--- a/container-core/src/test/java/com/yahoo/container/handler/threadpool/DefaultContainerThreadPoolTest.java
+++ b/container-core/src/test/java/com/yahoo/container/handler/threadpool/DefaultContainerThreadPoolTest.java
@@ -21,6 +21,9 @@ import static org.junit.Assert.fail;
* @author bjorncs
*/
public class DefaultContainerThreadPoolTest {
+
+ private static final int CPUS = 16;
+
@Test
public final void testThreadPool() throws InterruptedException {
ContainerThreadpoolConfig config = new ContainerThreadpoolConfig(new ContainerThreadpoolConfig.Builder().maxThreads(1));
@@ -55,8 +58,12 @@ public class DefaultContainerThreadPoolTest {
}
private ThreadPoolExecutor createPool(int maxThreads, int queueSize) {
- ContainerThreadpoolConfig config = new ContainerThreadpoolConfig(new ContainerThreadpoolConfig.Builder().maxThreads(maxThreads).queueSize(queueSize));
- ContainerThreadPool threadPool = new DefaultContainerThreadpool(config, Mockito.mock(Metric.class));
+ ContainerThreadpoolConfig config = new ContainerThreadpoolConfig(new ContainerThreadpoolConfig.Builder()
+ .maxThreads(maxThreads)
+ .minThreads(maxThreads)
+ .queueSize(queueSize));
+ ContainerThreadPool threadPool = new DefaultContainerThreadpool(
+ config, Mockito.mock(Metric.class), new MockProcessTerminator(), CPUS);
ExecutorServiceWrapper wrapper = (ExecutorServiceWrapper) threadPool.executor();
WorkerCompletionTimingThreadPoolExecutor executor = (WorkerCompletionTimingThreadPoolExecutor)wrapper.delegate();
return executor;
@@ -64,27 +71,27 @@ public class DefaultContainerThreadPoolTest {
@Test
public void testThatThreadPoolSizeFollowsConfig() {
- ThreadPoolExecutor executor = createPool(3, 9);
+ ThreadPoolExecutor executor = createPool(3, 1200);
assertEquals(3, executor.getMaximumPoolSize());
- assertEquals(9, executor.getQueue().remainingCapacity());
+ assertEquals(1200, executor.getQueue().remainingCapacity());
}
@Test
public void testThatThreadPoolSizeAutoDetected() {
ThreadPoolExecutor executor = createPool(0, 0);
- assertEquals(Runtime.getRuntime().availableProcessors()*4, executor.getMaximumPoolSize());
+ assertEquals(CPUS*4, executor.getMaximumPoolSize());
assertEquals(0, executor.getQueue().remainingCapacity());
}
@Test
public void testThatQueueSizeAutoDetected() {
- ThreadPoolExecutor executor = createPool(3, -1);
- assertEquals(3, executor.getMaximumPoolSize());
- assertEquals(executor.getMaximumPoolSize()*4, executor.getQueue().remainingCapacity());
+ ThreadPoolExecutor executor = createPool(24, -50);
+ assertEquals(24, executor.getMaximumPoolSize());
+ assertEquals(24*50, executor.getQueue().remainingCapacity());
}
@Test
public void testThatThreadPoolSizeAndQueueSizeAutoDetected() {
- ThreadPoolExecutor executor = createPool(0, -1);
- assertEquals(Runtime.getRuntime().availableProcessors()*4, executor.getMaximumPoolSize());
- assertEquals(executor.getMaximumPoolSize()*4, executor.getQueue().remainingCapacity());
+ ThreadPoolExecutor executor = createPool(0, -100);
+ assertEquals(CPUS*4, executor.getMaximumPoolSize());
+ assertEquals(CPUS*4*100, executor.getQueue().remainingCapacity());
}
private class FlipIt implements Runnable {
diff --git a/container-disc/src/main/java/com/yahoo/container/jdisc/ConfiguredApplication.java b/container-disc/src/main/java/com/yahoo/container/jdisc/ConfiguredApplication.java
index a84d2521b8b..de595da07b6 100644
--- a/container-disc/src/main/java/com/yahoo/container/jdisc/ConfiguredApplication.java
+++ b/container-disc/src/main/java/com/yahoo/container/jdisc/ConfiguredApplication.java
@@ -68,6 +68,7 @@ public final class ConfiguredApplication implements Application {
private static final Logger log = Logger.getLogger(ConfiguredApplication.class.getName());
private static final Set<ClientProvider> startedClients = Collections.newSetFromMap(new WeakHashMap<>());
+ static final String SANITIZE_FILENAME = "[/,;]";
private static final Set<ServerProvider> startedServers = Collections.newSetFromMap(new IdentityHashMap<>());
private final SubscriberFactory subscriberFactory;
@@ -407,6 +408,12 @@ public final class ConfiguredApplication implements Application {
}
}
+ static String santizeFileName(String s) {
+ return s.trim()
+ .replace('\\', '.')
+ .replaceAll(SANITIZE_FILENAME, ".");
+ }
+
// Workaround for ApplicationLoader.stop not being able to shutdown
private void startShutdownDeadlineExecutor() {
shutdownDeadlineExecutor = new ScheduledThreadPoolExecutor(1, new DaemonThreadFactory("Shutdown deadline timer"));
@@ -414,7 +421,7 @@ public final class ConfiguredApplication implements Application {
long delayMillis = (long)(shudownTimeoutS.get() * 1000.0);
shutdownDeadlineExecutor.schedule(() -> {
if (dumpHeapOnShutdownTimeout.get()) {
- String heapDumpName = Defaults.getDefaults().underVespaHome("var/crash/java_pid.") + ProcessHandle.current().pid() + ".hprof";
+ String heapDumpName = Defaults.getDefaults().underVespaHome("var/crash/java_pid.") + santizeFileName(configId) + "." + ProcessHandle.current().pid() + ".hprof";
com.yahoo.protect.Process.dumpHeap(heapDumpName, true);
}
com.yahoo.protect.Process.logAndDie(
diff --git a/container-disc/src/test/java/com/yahoo/container/jdisc/ConfiguredApplicationTest.java b/container-disc/src/test/java/com/yahoo/container/jdisc/ConfiguredApplicationTest.java
new file mode 100644
index 00000000000..c8cf5c0ce63
--- /dev/null
+++ b/container-disc/src/test/java/com/yahoo/container/jdisc/ConfiguredApplicationTest.java
@@ -0,0 +1,14 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.container.jdisc;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class ConfiguredApplicationTest {
+ @Test
+ public void testConfigId2FileName() {
+ assertEquals("admin.metrics.2088223-v6-1.ostk.bm2.prod.ne1.yahoo.com", ConfiguredApplication.santizeFileName("admin/metrics/2088223-v6-1.ostk.bm2.prod.ne1.yahoo.com"));
+ assertEquals("admin.standalone.cluster-controllers.1", ConfiguredApplication.santizeFileName("admin/standalone/cluster-controllers/1 "));
+ }
+}
diff --git a/container-search/src/main/java/com/yahoo/search/dispatch/Dispatcher.java b/container-search/src/main/java/com/yahoo/search/dispatch/Dispatcher.java
index af731e3ade0..fc5bedf07c7 100644
--- a/container-search/src/main/java/com/yahoo/search/dispatch/Dispatcher.java
+++ b/container-search/src/main/java/com/yahoo/search/dispatch/Dispatcher.java
@@ -2,7 +2,6 @@
package com.yahoo.search.dispatch;
import com.google.inject.Inject;
-import com.yahoo.cloud.config.ClusterInfoConfig;
import com.yahoo.component.AbstractComponent;
import com.yahoo.component.ComponentId;
import com.yahoo.compress.Compressor;
@@ -26,11 +25,9 @@ import com.yahoo.search.query.profile.types.QueryProfileType;
import com.yahoo.search.result.ErrorMessage;
import com.yahoo.vespa.config.search.DispatchConfig;
-import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
-import java.util.OptionalInt;
import java.util.Set;
import java.util.stream.Collectors;
@@ -94,10 +91,9 @@ public class Dispatcher extends AbstractComponent {
public Dispatcher(RpcResourcePool resourcePool,
ComponentId clusterId,
DispatchConfig dispatchConfig,
- ClusterInfoConfig clusterInfoConfig,
VipStatus vipStatus,
Metric metric) {
- this(resourcePool, new SearchCluster(clusterId.stringValue(), dispatchConfig,clusterInfoConfig.nodeCount(),
+ this(resourcePool, new SearchCluster(clusterId.stringValue(), dispatchConfig,
vipStatus, new RpcPingFactory(resourcePool)),
dispatchConfig, metric);
diff --git a/container-search/src/main/java/com/yahoo/search/dispatch/searchcluster/SearchCluster.java b/container-search/src/main/java/com/yahoo/search/dispatch/searchcluster/SearchCluster.java
index 54d5dfc91af..b5fbede4701 100644
--- a/container-search/src/main/java/com/yahoo/search/dispatch/searchcluster/SearchCluster.java
+++ b/container-search/src/main/java/com/yahoo/search/dispatch/searchcluster/SearchCluster.java
@@ -53,7 +53,7 @@ public class SearchCluster implements NodeManager<Node> {
*/
private final Optional<Node> localCorpusDispatchTarget;
- public SearchCluster(String clusterId, DispatchConfig dispatchConfig, int containerClusterSize,
+ public SearchCluster(String clusterId, DispatchConfig dispatchConfig,
VipStatus vipStatus, PingFactory pingFactory) {
this.clusterId = clusterId;
this.dispatchConfig = dispatchConfig;
@@ -81,17 +81,7 @@ public class SearchCluster implements NodeManager<Node> {
this.nodesByHost = nodesByHostBuilder.build();
hitEstimator = new TopKEstimator(30.0, dispatchConfig.topKProbability(), SKEW_FACTOR);
- this.localCorpusDispatchTarget = findLocalCorpusDispatchTarget(HostName.getLocalhost(),
- size,
- containerClusterSize,
- nodesByHost,
- groups);
- }
-
- /* Testing only */
- public SearchCluster(String clusterId, DispatchConfig dispatchConfig,
- VipStatus vipStatus, PingFactory pingFactory) {
- this(clusterId, dispatchConfig, 1, vipStatus, pingFactory);
+ this.localCorpusDispatchTarget = findLocalCorpusDispatchTarget(HostName.getLocalhost(), nodesByHost, groups);
}
public void addMonitoring(ClusterMonitor<Node> clusterMonitor) {
@@ -102,8 +92,6 @@ public class SearchCluster implements NodeManager<Node> {
}
private static Optional<Node> findLocalCorpusDispatchTarget(String selfHostname,
- int searchClusterSize,
- int containerClusterSize,
ImmutableMultimap<String, Node> nodesByHost,
ImmutableMap<Integer, Group> groups) {
// A search node in the search cluster in question is configured on the same host as the currently running container.
@@ -120,12 +108,6 @@ public class SearchCluster implements NodeManager<Node> {
// Only use direct dispatch if the local search node has the entire corpus
if (localSearchGroup.nodes().size() != 1) return Optional.empty();
- // Only use direct dispatch if this container cluster has at least as many nodes as the search cluster
- // to avoid load skew/preserve fanout in the case where a subset of the search nodes are also containers.
- // This disregards the case where the search and container clusters are partially overlapping.
- // Such configurations produce skewed load in any case.
- if (containerClusterSize < searchClusterSize) return Optional.empty();
-
return Optional.of(localSearchNode);
}
diff --git a/container-search/src/test/java/com/yahoo/prelude/cluster/ClusterSearcherTestCase.java b/container-search/src/test/java/com/yahoo/prelude/cluster/ClusterSearcherTestCase.java
index ca98b6a1a77..38c231cb1bb 100644
--- a/container-search/src/test/java/com/yahoo/prelude/cluster/ClusterSearcherTestCase.java
+++ b/container-search/src/test/java/com/yahoo/prelude/cluster/ClusterSearcherTestCase.java
@@ -2,7 +2,6 @@
package com.yahoo.prelude.cluster;
import com.google.common.collect.ImmutableList;
-import com.yahoo.cloud.config.ClusterInfoConfig;
import com.yahoo.component.ComponentId;
import com.yahoo.component.provider.ComponentRegistry;
import com.yahoo.container.QrConfig;
@@ -518,7 +517,6 @@ public class ClusterSearcherTestCase {
Dispatcher dispatcher = new Dispatcher(new RpcResourcePool(dispatchConfig),
ComponentId.createAnonymousComponentId("test-id"),
dispatchConfig,
- createClusterInfoConfig(),
vipStatus,
new MockMetric());
ComponentRegistry<Dispatcher> dispatchers = new ComponentRegistry<>();
@@ -534,13 +532,6 @@ public class ClusterSearcherTestCase {
null);
}
- private static ClusterInfoConfig createClusterInfoConfig() {
- ClusterInfoConfig.Builder clusterInfoConfigBuilder = new ClusterInfoConfig.Builder();
- clusterInfoConfigBuilder.clusterId("containerCluster1");
- clusterInfoConfigBuilder.nodeCount(1);
- return new ClusterInfoConfig(clusterInfoConfigBuilder);
- }
-
private static class QueryTimeoutFixture {
ClusterSearcher searcher;
Execution exec;
diff --git a/container-search/src/test/java/com/yahoo/search/dispatch/searchcluster/SearchClusterTest.java b/container-search/src/test/java/com/yahoo/search/dispatch/searchcluster/SearchClusterTest.java
index f46717ce180..22cc783967d 100644
--- a/container-search/src/test/java/com/yahoo/search/dispatch/searchcluster/SearchClusterTest.java
+++ b/container-search/src/test/java/com/yahoo/search/dispatch/searchcluster/SearchClusterTest.java
@@ -58,7 +58,7 @@ public class SearchClusterTest {
numDocsPerNode.add(new AtomicInteger(1));
pingCounts.add(new AtomicInteger(0));
}
- searchCluster = new SearchCluster(clusterId, MockSearchCluster.createDispatchConfig(nodes), nodes.size() / nodesPerGroup,
+ searchCluster = new SearchCluster(clusterId, MockSearchCluster.createDispatchConfig(nodes),
vipStatus, new Factory(nodesPerGroup, numDocsPerNode, pingCounts));
clusterMonitor = new ClusterMonitor(searchCluster, false);
searchCluster.addMonitoring(clusterMonitor);
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/systemflags/v1/SystemFlagsDataArchive.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/systemflags/v1/SystemFlagsDataArchive.java
index 850e14b25e8..367b258e7b6 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/systemflags/v1/SystemFlagsDataArchive.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/systemflags/v1/SystemFlagsDataArchive.java
@@ -23,6 +23,7 @@ import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
@@ -125,9 +126,9 @@ public class SystemFlagsDataArchive {
uncheck(zipOut::flush);
}
- public Set<FlagData> flagData(FlagsTarget target) {
+ public List<FlagData> flagData(FlagsTarget target) {
List<String> filenames = target.flagDataFilesPrioritized();
- Set<FlagData> targetData = new HashSet<>();
+ List<FlagData> targetData = new ArrayList<>();
files.forEach((flagId, fileMap) -> {
for (String filename : filenames) {
FlagData data = fileMap.get(filename);
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java
index 4076013b2c5..d3615c942b9 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java
@@ -475,18 +475,18 @@ public class JobController {
/** Orders a run of the given type, or throws an IllegalStateException if that job type is already running. */
public void start(ApplicationId id, JobType type, Versions versions, boolean isRedeployment) {
- start(id, type, versions, isRedeployment, JobProfile.of(type), false);
+ start(id, type, versions, isRedeployment, JobProfile.of(type));
}
/** Orders a run of the given type, or throws an IllegalStateException if that job type is already running. */
- public void start(ApplicationId id, JobType type, Versions versions, boolean isRedeployment, JobProfile profile, boolean dryRun) {
+ public void start(ApplicationId id, JobType type, Versions versions, boolean isRedeployment, JobProfile profile) {
locked(id, type, __ -> {
Optional<Run> last = last(id, type);
if (last.flatMap(run -> active(run.id())).isPresent())
throw new IllegalStateException("Can not start " + type + " for " + id + "; it is already running!");
RunId newId = new RunId(id, type, last.map(run -> run.id().number()).orElse(0L) + 1);
- curator.writeLastRun(Run.initial(newId, versions, isRedeployment, controller.clock().instant(), profile, dryRun));
+ curator.writeLastRun(Run.initial(newId, versions, isRedeployment, controller.clock().instant(), profile));
metric.jobStarted(newId.job());
});
}
@@ -531,8 +531,7 @@ public class JobController {
lastRun.map(run -> run.versions().targetPlatform()),
lastRun.map(run -> run.versions().targetApplication())),
false,
- JobProfile.development,
- dryRun);
+ dryRun ? JobProfile.developmentDryRun : JobProfile.development);
});
locked(id, type, __ -> {
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobProfile.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobProfile.java
index 1c1d60a2cf0..75dae8d77df 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobProfile.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobProfile.java
@@ -68,7 +68,9 @@ public enum JobProfile {
development(EnumSet.of(deployReal,
installReal,
- copyVespaLogs));
+ copyVespaLogs)),
+
+ developmentDryRun(EnumSet.of(deployReal));
private final Set<Step> steps;
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/Run.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/Run.java
index b3768178b1e..98a8a49ec06 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/Run.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/Run.java
@@ -60,11 +60,11 @@ public class Run {
this.dryRun = dryRun;
}
- public static Run initial(RunId id, Versions versions, boolean isRedeployment, Instant now, JobProfile profile, boolean dryRun) {
+ public static Run initial(RunId id, Versions versions, boolean isRedeployment, Instant now, JobProfile profile) {
EnumMap<Step, StepInfo> steps = new EnumMap<>(Step.class);
profile.steps().forEach(step -> steps.put(step, StepInfo.initial(step)));
return new Run(id, steps, requireNonNull(versions), isRedeployment, requireNonNull(now), Optional.empty(), running,
- -1, Instant.EPOCH, Optional.empty(), Optional.empty(), Optional.empty(), dryRun);
+ -1, Instant.EPOCH, Optional.empty(), Optional.empty(), Optional.empty(), profile == JobProfile.developmentDryRun);
}
/** Returns a new Run with the status of the given completed step set accordingly. */
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/systemflags/SystemFlagsDeployResult.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/systemflags/SystemFlagsDeployResult.java
index d169cd97df7..529e892ced9 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/systemflags/SystemFlagsDeployResult.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/systemflags/SystemFlagsDeployResult.java
@@ -251,6 +251,13 @@ class SystemFlagsDeployResult {
return new OperationError(message, Set.of(), OperationType.VALIDATE_ARCHIVE, null, null);
}
+ static OperationError dataForUndefinedFlag(FlagsTarget target, FlagId id) {
+ return new OperationError("Flag data present for undefined flag. Remove flag data files if flag's definition " +
+ "is already removed from Flags / PermanentFlags. Consult ModelContext.FeatureFlags " +
+ "for safe removal of flag used by config-model.",
+ Set.of(), OperationType.DATA_FOR_UNDEFINED_FLAG, id, null);
+ }
+
String message() { return message; }
Set<FlagsTarget> targets() { return targets; }
OperationType operation() { return operation; }
@@ -284,7 +291,8 @@ class SystemFlagsDeployResult {
}
enum OperationType {
- CREATE("create"), DELETE("delete"), UPDATE("update"), LIST("list"), VALIDATE_ARCHIVE("validate-archive");
+ CREATE("create"), DELETE("delete"), UPDATE("update"), LIST("list"), VALIDATE_ARCHIVE("validate-archive"),
+ DATA_FOR_UNDEFINED_FLAG("data-for-undefined-flag");
private final String stringValue;
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/systemflags/SystemFlagsDeployer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/systemflags/SystemFlagsDeployer.java
index 21a429b59ad..e0b65b0834d 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/systemflags/SystemFlagsDeployer.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/systemflags/SystemFlagsDeployer.java
@@ -78,7 +78,7 @@ class SystemFlagsDeployer {
return SystemFlagsDeployResult.merge(results);
}
- private SystemFlagsDeployResult deployFlags(FlagsTarget target, Set<FlagData> flagData, boolean dryRun) {
+ private SystemFlagsDeployResult deployFlags(FlagsTarget target, List<FlagData> flagData, boolean dryRun) {
Map<FlagId, FlagData> wantedFlagData = lookupTable(flagData);
Map<FlagId, FlagData> currentFlagData;
List<FlagId> definedFlags;
@@ -98,7 +98,7 @@ class SystemFlagsDeployer {
updateExistingFlagData(target, dryRun, wantedFlagData, currentFlagData, results, errors);
removeOldFlagData(target, dryRun, wantedFlagData, currentFlagData, results, errors);
failOnNewFlagDataForUndefinedFlags(target, wantedFlagData, currentFlagData, definedFlags, errors);
- warnOnExistingFlagDataForUndefinedFlags(target, wantedFlagData, currentFlagData, definedFlags, warnings);
+ failOnFlagDataForUndefinedFlags(target, wantedFlagData, currentFlagData, definedFlags, errors);
return new SystemFlagsDeployResult(results, errors, warnings);
}
@@ -191,14 +191,14 @@ class SystemFlagsDeployer {
}
}
- private static void warnOnExistingFlagDataForUndefinedFlags(FlagsTarget target,
- Map<FlagId, FlagData> wantedFlagData,
- Map<FlagId, FlagData> currentFlagData,
- List<FlagId> definedFlags,
- List<Warning> warnings) {
+ private static void failOnFlagDataForUndefinedFlags(FlagsTarget target,
+ Map<FlagId, FlagData> wantedFlagData,
+ Map<FlagId, FlagData> currentFlagData,
+ List<FlagId> definedFlags,
+ List<OperationError> errors) {
for (FlagId flagId : currentFlagData.keySet()) {
if (wantedFlagData.containsKey(flagId) && !definedFlags.contains(flagId)) {
- warnings.add(Warning.dataForUndefinedFlag(target, flagId));
+ errors.add(OperationError.dataForUndefinedFlag(target, flagId));
}
}
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/RunSerializerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/RunSerializerTest.java
index 8bd22b5217f..eca2b17a5f1 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/RunSerializerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/RunSerializerTest.java
@@ -153,7 +153,7 @@ public class RunSerializerTest {
assertEquals(run.steps(), phoenix.steps());
assertEquals(run.isDryRun(), phoenix.isDryRun());
- Run initial = Run.initial(id, run.versions(), run.isRedeployment(), run.start(), JobProfile.production, true);
+ Run initial = Run.initial(id, run.versions(), run.isRedeployment(), run.start(), JobProfile.production);
assertEquals(initial, serializer.runFromSlime(serializer.toSlime(initial)));
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/systemflags/SystemFlagsDeployerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/systemflags/SystemFlagsDeployerTest.java
index 35a13cdeeec..549dd1ed253 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/systemflags/SystemFlagsDeployerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/systemflags/SystemFlagsDeployerTest.java
@@ -166,8 +166,8 @@ public class SystemFlagsDeployerTest {
.build();
SystemFlagsDeployer deployer = new SystemFlagsDeployer(flagsClient, SYSTEM, Set.of(prodUsEast3Target));
SystemFlagsDeployResult result = deployer.deployFlags(archive, true);
- assertThat(result.warnings())
- .containsOnly(SystemFlagsDeployResult.Warning.dataForUndefinedFlag(prodUsEast3Target, new FlagId("my-flag")));
+ assertThat(result.errors())
+ .containsOnly(OperationError.dataForUndefinedFlag(prodUsEast3Target, new FlagId("my-flag")));
}
private static FlagData flagData(String filename) throws IOException {
diff --git a/eval/CMakeLists.txt b/eval/CMakeLists.txt
index 8a7cd4f66bd..59ad1a530e1 100644
--- a/eval/CMakeLists.txt
+++ b/eval/CMakeLists.txt
@@ -45,6 +45,7 @@ vespa_define_module(
src/tests/eval/value_type
src/tests/gp/ponder_nov2017
src/tests/instruction/add_trivial_dimension_optimizer
+ src/tests/instruction/best_similarity_function
src/tests/instruction/dense_dot_product_function
src/tests/instruction/dense_hamming_distance
src/tests/instruction/dense_inplace_join_function
diff --git a/eval/src/tests/eval/tensor_function/tensor_function_test.cpp b/eval/src/tests/eval/tensor_function/tensor_function_test.cpp
index c457f68a614..3d4e2d41cb5 100644
--- a/eval/src/tests/eval/tensor_function/tensor_function_test.cpp
+++ b/eval/src/tests/eval/tensor_function/tensor_function_test.cpp
@@ -510,4 +510,18 @@ TEST("require that tensor function can be dumped for debugging") {
fprintf(stderr, "function dump -->[[%s]]<-- function dump\n", root.as_string().c_str());
}
+TEST("require that full tensor reduce expands dimension list") {
+ Stash stash;
+ const auto &num = inject(ValueType::from_spec("double"), 0, stash);
+ const auto &mat = inject(ValueType::from_spec("tensor(x[5],y[5])"), 1, stash);
+ const auto *reduce_num = as<Reduce>(reduce(num, Aggr::SUM, {}, stash));
+ const auto *reduce_mat = as<Reduce>(reduce(mat, Aggr::SUM, {}, stash));
+ ASSERT_TRUE(reduce_num);
+ ASSERT_TRUE(reduce_mat);
+ EXPECT_EQUAL(reduce_num->dimensions().size(), 0u);
+ ASSERT_EQUAL(reduce_mat->dimensions().size(), 2u);
+ EXPECT_EQUAL(reduce_mat->dimensions()[0], "x");
+ EXPECT_EQUAL(reduce_mat->dimensions()[1], "y");
+}
+
TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/eval/src/tests/instruction/best_similarity_function/CMakeLists.txt b/eval/src/tests/instruction/best_similarity_function/CMakeLists.txt
new file mode 100644
index 00000000000..dd83f4c72a8
--- /dev/null
+++ b/eval/src/tests/instruction/best_similarity_function/CMakeLists.txt
@@ -0,0 +1,9 @@
+# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_executable(eval_best_similarity_function_test_app TEST
+ SOURCES
+ best_similarity_function_test.cpp
+ DEPENDS
+ vespaeval
+ GTest::GTest
+)
+vespa_add_test(NAME eval_best_similarity_function_test_app COMMAND eval_best_similarity_function_test_app)
diff --git a/eval/src/tests/instruction/best_similarity_function/best_similarity_function_test.cpp b/eval/src/tests/instruction/best_similarity_function/best_similarity_function_test.cpp
new file mode 100644
index 00000000000..b461dc756d7
--- /dev/null
+++ b/eval/src/tests/instruction/best_similarity_function/best_similarity_function_test.cpp
@@ -0,0 +1,155 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/eval/eval/fast_value.h>
+#include <vespa/eval/eval/tensor_function.h>
+#include <vespa/eval/eval/test/eval_fixture.h>
+#include <vespa/eval/eval/test/gen_spec.h>
+#include <vespa/eval/instruction/best_similarity_function.h>
+#include <vespa/vespalib/gtest/gtest.h>
+
+using namespace vespalib;
+using namespace vespalib::eval;
+using namespace vespalib::eval::test;
+
+const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get();
+
+//-----------------------------------------------------------------------------
+
+void verify_impl(const TensorSpec &a, const TensorSpec &b, const vespalib::string &expr, bool optimized) {
+ EvalFixture::ParamRepo param_repo;
+ param_repo.add("a", a).add("b", b);
+ EvalFixture fast_fixture(prod_factory, expr, param_repo, true);
+ EXPECT_EQ(fast_fixture.result(), EvalFixture::ref(expr, param_repo));
+ EXPECT_EQ(fast_fixture.find_all<BestSimilarityFunction>().size(), optimized ? 1 : 0);
+}
+
+void verify(const TensorSpec &a, const TensorSpec &b, const vespalib::string &expr, bool optimized = true) {
+ verify_impl(a, b, expr, optimized);
+ verify_impl(b, a, expr, optimized);
+}
+
+//-----------------------------------------------------------------------------
+
+GenSpec gen_double(const vespalib::string &desc, int bias) {
+ return GenSpec::from_desc(desc).cells(CellType::DOUBLE).seq(N(bias));
+}
+
+GenSpec gen_float(const vespalib::string &desc, int bias) {
+ return GenSpec::from_desc(desc).cells(CellType::FLOAT).seq(N(bias));
+}
+
+GenSpec gen_int8(const vespalib::string &desc, int bias) {
+ return GenSpec::from_desc(desc).cells(CellType::INT8).seq(N(bias));
+}
+
+vespalib::string max_sim = "reduce(reduce(a*b,sum,d),max,b)";
+vespalib::string min_hamming = "reduce(reduce(hamming(a,b),sum,d),min,b)";
+
+//-----------------------------------------------------------------------------
+
+TEST(BestSimilarityFunctionTest, result_is_mutable) {
+ tensor_function::Inject child(ValueType::double_type(), 0);
+ BestSimilarityFunction node(ValueType::double_type(), child, child, nullptr, 1);
+ EXPECT_TRUE(node.result_is_mutable());
+}
+
+TEST(BestSimilarityFunctionTest, max_sim_can_be_optimized) {
+ verify(gen_float("A3_2B3d8", 3), gen_float("b5d8", 7), max_sim);
+ verify(gen_float("A3_2B3d8", 3), gen_float("b5_2d8", 7), max_sim);
+}
+
+TEST(BestSimilarityFunctionTest, min_hamming_can_be_optimized) {
+ verify(gen_int8("A3_2B3d8", 3), gen_int8("b5d8", 7), min_hamming);
+ verify(gen_int8("A3_2B3d8", 3), gen_int8("b5_2d8", 7), min_hamming);
+}
+
+TEST(BestSimilarityFunctionTest, result_can_be_sparse) {
+ verify(gen_float("A3_2d8", 3), gen_float("b5d8", 7), max_sim);
+ verify(gen_int8("A3_2d8", 3), gen_int8("b5_2d8", 7), min_hamming);
+}
+
+TEST(BestSimilarityFunctionTest, result_can_be_dense) {
+ verify(gen_float("B3d8", 3), gen_float("b5d8", 7), max_sim);
+ verify(gen_int8("B3d8", 3), gen_int8("b5_2d8", 7), min_hamming);
+}
+
+TEST(BestSimilarityFunctionTest, result_can_be_double) {
+ verify(gen_float("d8", 3), gen_float("b5d8", 7), max_sim);
+ verify(gen_int8("d8", 3), gen_int8("b5_2d8", 7), min_hamming);
+}
+
+TEST(BestSimilarityFunctionTest, primary_dimensions_can_be_trivial) {
+ verify(gen_float("d1", 3), gen_float("b1d1", 7), max_sim);
+ verify(gen_int8("d1", 3), gen_int8("b1d1", 7), min_hamming);
+}
+
+TEST(BestSimilarityFunctionTest, extra_trivial_dimensions_are_allowed) {
+ verify(gen_float("A1a1d8x1z1", 3), gen_float("a1b5c1d8x1y1", 7), max_sim);
+}
+
+TEST(BestSimilarityFunctionTest, allow_full_reduce_for_outer_dimension) {
+ vespalib::string my_max_sim = "reduce(reduce(a*b,sum,d),max)";
+ vespalib::string my_min_hamming = "reduce(reduce(hamming(a,b),sum,d),min)";
+ verify(gen_float("d8", 3), gen_float("b5d8", 7), my_max_sim);
+ verify(gen_int8("d8", 3), gen_int8("b5_2d8", 7), my_min_hamming);
+}
+
+vespalib::string inv_max_sim = "reduce(reduce(a*b,sum,b),max,d)";
+
+TEST(BestSimilarityFunctionTest, dimensions_can_be_inverted_if_best_dimension_is_sparse) {
+ verify(gen_float("b8", 3), gen_float("b8d5_2", 7), inv_max_sim);
+}
+
+//-----------------------------------------------------------------------------
+
+TEST(BestSimilarityFunctionTest, cell_type_must_match_operation) {
+ verify(gen_double("d8", 3), gen_double("b5d8", 7), max_sim, false);
+ verify(gen_float("d8", 3), gen_float("b5_2d8", 7), min_hamming, false);
+}
+
+TEST(BestSimilarityFunctionTest, similarity_must_use_1d_vector) {
+ vespalib::string max_sim_2d_dist = "reduce(reduce(a*b,sum,d,e),max,b)";
+ verify(gen_float("d8_1", 3), gen_float("b5d8_1", 7), max_sim, false);
+ verify(gen_float("d8e1", 3), gen_float("b5d8e1", 7), max_sim_2d_dist, false);
+}
+
+TEST(BestSimilarityFunctionTest, similarity_dimension_must_be_inner) {
+ verify(gen_float("d8e3", 3), gen_float("b5d8", 7), max_sim, false);
+ verify(gen_float("b8", 3), gen_float("b8d5", 7), inv_max_sim, false);
+}
+
+TEST(BestSimilarityFunctionTest, alternatives_must_use_a_single_dimension) {
+ vespalib::string max_sim_2d_best = "reduce(reduce(a*b,sum,d),max,a,b)";
+ verify(gen_float("d8", 3), gen_float("a1b5d8", 7), max_sim_2d_best, false);
+}
+
+TEST(BestSimilarityFunctionTest, alternatives_dimension_can_not_be_common) {
+ verify(gen_float("b5d8", 3), gen_float("b5d8", 7), max_sim, false);
+}
+
+TEST(BestSimilarityFunctionTest, extra_common_nontrivial_dimensions_not_allowed) {
+ verify(gen_float("a3d8", 3), gen_float("a3b5d8", 7), max_sim, false);
+ verify(gen_float("a3_2d8", 3), gen_float("a3_2b5d8", 7), max_sim, false);
+}
+
+TEST(BestSimilarityFunctionTest, secondary_tensor_must_not_contain_extra_nontrivial_dimensions) {
+ verify(gen_float("d8", 3), gen_float("a2b5d8", 7), max_sim, false);
+ verify(gen_float("d8", 3), gen_float("a2_1b5d8", 7), max_sim, false);
+}
+
+//-----------------------------------------------------------------------------
+
+TEST(BestSimilarityFunctionTest, similar_expressions_are_not_optimized) {
+ vespalib::string other_join = "reduce(reduce(a+b,sum,d),max,b)";
+ vespalib::string other_reduce = "reduce(reduce(a*b,min,d),max,b)";
+ vespalib::string mismatch_best_sim = "reduce(reduce(a*b,sum,d),min,b)";
+ vespalib::string mismatch_best_hamming = "reduce(reduce(hamming(a,b),sum,d),max,b)";
+ verify(gen_float("d8", 3), gen_float("b5d8", 7), other_join, false);
+ verify(gen_float("d8", 3), gen_float("b5d8", 7), other_reduce, false);
+ verify(gen_float("d8", 3), gen_float("b5d8", 7), mismatch_best_sim, false);
+ verify(gen_int8("d8", 3), gen_int8("b5d8", 7), mismatch_best_hamming, false);
+}
+
+//-----------------------------------------------------------------------------
+
+GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/eval/src/tests/instruction/sum_max_dot_product_function/sum_max_dot_product_function_test.cpp b/eval/src/tests/instruction/sum_max_dot_product_function/sum_max_dot_product_function_test.cpp
index f68c089e784..4998885c6a6 100644
--- a/eval/src/tests/instruction/sum_max_dot_product_function/sum_max_dot_product_function_test.cpp
+++ b/eval/src/tests/instruction/sum_max_dot_product_function/sum_max_dot_product_function_test.cpp
@@ -115,11 +115,9 @@ TEST(SumMaxDotProduct, similar_expressions_are_not_optimized) {
vespalib::string max_sum_expr = "reduce(reduce(reduce(a*b,sum,z),sum,y),max,x)";
vespalib::string not_dp_expr1 = "reduce(reduce(reduce(a+b,sum,z),max,y),sum,x)";
vespalib::string not_dp_expr2 = "reduce(reduce(reduce(a*b,min,z),max,y),sum,x)";
- vespalib::string sum_all_expr = "reduce(reduce(reduce(a*b,sum,z),max,y),sum)";
assert_not_optimized(query, document, max_sum_expr);
assert_not_optimized(query, document, not_dp_expr1);
assert_not_optimized(query, document, not_dp_expr2);
- assert_not_optimized(query, document, sum_all_expr);
}
//-----------------------------------------------------------------------------
diff --git a/eval/src/vespa/eval/eval/optimize_tensor_function.cpp b/eval/src/vespa/eval/eval/optimize_tensor_function.cpp
index c2e8d886fde..90849e55a71 100644
--- a/eval/src/vespa/eval/eval/optimize_tensor_function.cpp
+++ b/eval/src/vespa/eval/eval/optimize_tensor_function.cpp
@@ -11,6 +11,7 @@
#include <vespa/eval/instruction/sparse_full_overlap_join_function.h>
#include <vespa/eval/instruction/mixed_inner_product_function.h>
#include <vespa/eval/instruction/sum_max_dot_product_function.h>
+#include <vespa/eval/instruction/best_similarity_function.h>
#include <vespa/eval/instruction/dense_xw_product_function.h>
#include <vespa/eval/instruction/dense_matmul_function.h>
#include <vespa/eval/instruction/dense_multi_matmul_function.h>
@@ -37,54 +38,59 @@ namespace vespalib::eval {
namespace {
-const TensorFunction &optimize_for_factory(const ValueBuilderFactory &, const TensorFunction &expr, Stash &stash) {
- using Child = TensorFunction::Child;
- Child root(expr);
- {
- std::vector<Child::CREF> nodes({root});
- for (size_t i = 0; i < nodes.size(); ++i) {
- nodes[i].get().get().push_children(nodes);
- }
- while (!nodes.empty()) {
- const Child &child = nodes.back().get();
- child.set(SumMaxDotProductFunction::optimize(child.get(), stash));
- child.set(DenseDotProductFunction::optimize(child.get(), stash));
- child.set(SparseDotProductFunction::optimize(child.get(), stash));
- child.set(DenseXWProductFunction::optimize(child.get(), stash));
- child.set(DenseMatMulFunction::optimize(child.get(), stash));
- child.set(DenseMultiMatMulFunction::optimize(child.get(), stash));
- child.set(MixedInnerProductFunction::optimize(child.get(), stash));
- child.set(DenseHammingDistance::optimize(child.get(), stash));
- nodes.pop_back();
- }
+using Child = TensorFunction::Child;
+
+void run_optimize_pass(const Child &root, auto optimize_node) {
+ std::vector<Child::CREF> nodes({root});
+ for (size_t i = 0; i < nodes.size(); ++i) {
+ nodes[i].get().get().push_children(nodes);
}
- {
- std::vector<Child::CREF> nodes({root});
- for (size_t i = 0; i < nodes.size(); ++i) {
- nodes[i].get().get().push_children(nodes);
- }
- while (!nodes.empty()) {
- const Child &child = nodes.back().get();
- child.set(DenseSimpleExpandFunction::optimize(child.get(), stash));
- child.set(AddTrivialDimensionOptimizer::optimize(child.get(), stash));
- child.set(RemoveTrivialDimensionOptimizer::optimize(child.get(), stash));
- child.set(VectorFromDoublesFunction::optimize(child.get(), stash));
- child.set(DenseTensorCreateFunction::optimize(child.get(), stash));
- child.set(DenseTensorPeekFunction::optimize(child.get(), stash));
- child.set(DenseLambdaPeekOptimizer::optimize(child.get(), stash));
- child.set(UnpackBitsFunction::optimize(child.get(), stash));
- child.set(FastRenameOptimizer::optimize(child.get(), stash));
- child.set(PowAsMapOptimizer::optimize(child.get(), stash));
- child.set(InplaceMapFunction::optimize(child.get(), stash));
- child.set(MixedSimpleJoinFunction::optimize(child.get(), stash));
- child.set(JoinWithNumberFunction::optimize(child.get(), stash));
- child.set(DenseSingleReduceFunction::optimize(child.get(), stash));
- child.set(SparseMergeFunction::optimize(child.get(), stash));
- child.set(SparseNoOverlapJoinFunction::optimize(child.get(), stash));
- child.set(SparseFullOverlapJoinFunction::optimize(child.get(), stash));
- nodes.pop_back();
- }
+ while (!nodes.empty()) {
+ optimize_node(nodes.back().get());
+ nodes.pop_back();
}
+}
+
+const TensorFunction &optimize_for_factory(const ValueBuilderFactory &, const TensorFunction &expr, Stash &stash) {
+ Child root(expr);
+ run_optimize_pass(root, [&stash](const Child &child)
+ {
+ child.set(SumMaxDotProductFunction::optimize(child.get(), stash));
+ });
+ run_optimize_pass(root, [&stash](const Child &child)
+ {
+ child.set(BestSimilarityFunction::optimize(child.get(), stash));
+ });
+ run_optimize_pass(root, [&stash](const Child &child)
+ {
+ child.set(DenseDotProductFunction::optimize(child.get(), stash));
+ child.set(SparseDotProductFunction::optimize(child.get(), stash));
+ child.set(DenseXWProductFunction::optimize(child.get(), stash));
+ child.set(DenseMatMulFunction::optimize(child.get(), stash));
+ child.set(DenseMultiMatMulFunction::optimize(child.get(), stash));
+ child.set(MixedInnerProductFunction::optimize(child.get(), stash));
+ child.set(DenseHammingDistance::optimize(child.get(), stash));
+ });
+ run_optimize_pass(root, [&stash](const Child &child)
+ {
+ child.set(DenseSimpleExpandFunction::optimize(child.get(), stash));
+ child.set(AddTrivialDimensionOptimizer::optimize(child.get(), stash));
+ child.set(RemoveTrivialDimensionOptimizer::optimize(child.get(), stash));
+ child.set(VectorFromDoublesFunction::optimize(child.get(), stash));
+ child.set(DenseTensorCreateFunction::optimize(child.get(), stash));
+ child.set(DenseTensorPeekFunction::optimize(child.get(), stash));
+ child.set(DenseLambdaPeekOptimizer::optimize(child.get(), stash));
+ child.set(UnpackBitsFunction::optimize(child.get(), stash));
+ child.set(FastRenameOptimizer::optimize(child.get(), stash));
+ child.set(PowAsMapOptimizer::optimize(child.get(), stash));
+ child.set(InplaceMapFunction::optimize(child.get(), stash));
+ child.set(MixedSimpleJoinFunction::optimize(child.get(), stash));
+ child.set(JoinWithNumberFunction::optimize(child.get(), stash));
+ child.set(DenseSingleReduceFunction::optimize(child.get(), stash));
+ child.set(SparseMergeFunction::optimize(child.get(), stash));
+ child.set(SparseNoOverlapJoinFunction::optimize(child.get(), stash));
+ child.set(SparseFullOverlapJoinFunction::optimize(child.get(), stash));
+ });
return root.get();
}
diff --git a/eval/src/vespa/eval/eval/tensor_function.cpp b/eval/src/vespa/eval/eval/tensor_function.cpp
index c0cd7280212..70797250c5a 100644
--- a/eval/src/vespa/eval/eval/tensor_function.cpp
+++ b/eval/src/vespa/eval/eval/tensor_function.cpp
@@ -443,7 +443,11 @@ const TensorFunction &inject(const ValueType &type, size_t param_idx, Stash &sta
const TensorFunction &reduce(const TensorFunction &child, Aggr aggr, const std::vector<vespalib::string> &dimensions, Stash &stash) {
ValueType result_type = child.result_type().reduce(dimensions);
- return stash.create<Reduce>(result_type, child, aggr, dimensions);
+ if (dimensions.empty()) { // expand dimension list for full reduce
+ return stash.create<Reduce>(result_type, child, aggr, child.result_type().dimension_names());
+ } else {
+ return stash.create<Reduce>(result_type, child, aggr, dimensions);
+ }
}
const TensorFunction &map(const TensorFunction &child, map_fun_t function, Stash &stash) {
diff --git a/eval/src/vespa/eval/eval/value.cpp b/eval/src/vespa/eval/eval/value.cpp
index b799658cfae..e32e3152449 100644
--- a/eval/src/vespa/eval/eval/value.cpp
+++ b/eval/src/vespa/eval/eval/value.cpp
@@ -10,6 +10,11 @@ namespace eval {
namespace {
+struct EmptyView : Value::Index::View {
+ void lookup(ConstArrayRef<const string_id*> ) override {}
+ bool next_result(ConstArrayRef<string_id*> , size_t &) override { return false; }
+};
+
struct TrivialView : Value::Index::View {
bool first = false;
void lookup(ConstArrayRef<const string_id*> ) override { first = true; }
@@ -36,6 +41,20 @@ struct MySum {
} // <unnamed>
+EmptyIndex::EmptyIndex() = default;
+EmptyIndex EmptyIndex::_index;
+
+size_t
+EmptyIndex::size() const
+{
+ return 0;
+}
+
+std::unique_ptr<Value::Index::View>
+EmptyIndex::create_view(ConstArrayRef<size_t>) const
+{
+ return std::make_unique<EmptyView>();
+}
TrivialIndex::TrivialIndex() = default;
TrivialIndex TrivialIndex::_index;
diff --git a/eval/src/vespa/eval/eval/value.h b/eval/src/vespa/eval/eval/value.h
index fcdaa7131c7..433ee36cb6a 100644
--- a/eval/src/vespa/eval/eval/value.h
+++ b/eval/src/vespa/eval/eval/value.h
@@ -64,6 +64,19 @@ struct Value {
};
/**
+ * Common empty index
+ **/
+class EmptyIndex : public Value::Index {
+private:
+ EmptyIndex();
+ static EmptyIndex _index;
+public:
+ static const EmptyIndex &get() { return _index; }
+ size_t size() const override;
+ std::unique_ptr<View> create_view(ConstArrayRef<size_t> dims) const override;
+};
+
+/**
* Common index for values without any mapped dimensions.
**/
class TrivialIndex : public Value::Index {
diff --git a/eval/src/vespa/eval/instruction/CMakeLists.txt b/eval/src/vespa/eval/instruction/CMakeLists.txt
index 3ed969c0a18..90ab58827d1 100644
--- a/eval/src/vespa/eval/instruction/CMakeLists.txt
+++ b/eval/src/vespa/eval/instruction/CMakeLists.txt
@@ -3,6 +3,7 @@
vespa_add_library(eval_instruction OBJECT
SOURCES
add_trivial_dimension_optimizer.cpp
+ best_similarity_function.cpp
dense_cell_range_function.cpp
dense_dot_product_function.cpp
dense_hamming_distance.cpp
diff --git a/eval/src/vespa/eval/instruction/best_similarity_function.cpp b/eval/src/vespa/eval/instruction/best_similarity_function.cpp
new file mode 100644
index 00000000000..a8531d84cf0
--- /dev/null
+++ b/eval/src/vespa/eval/instruction/best_similarity_function.cpp
@@ -0,0 +1,224 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "best_similarity_function.h"
+#include <vespa/eval/eval/operation.h>
+#include <vespa/eval/eval/value.h>
+#include <vespa/vespalib/util/binary_hamming_distance.h>
+#include <cblas.h>
+
+namespace vespalib::eval {
+
+using namespace tensor_function;
+using namespace operation;
+
+namespace {
+
+struct BestSimParam {
+ ValueType res_type;
+ size_t inner_size;
+ BestSimParam(const ValueType &res_type_in, size_t inner_size_in)
+ : res_type(res_type_in), inner_size(inner_size_in) {}
+};
+
+struct UseDotProduct {
+ static float calc(const float *pri, const float *sec, size_t size) {
+ return cblas_sdot(size, pri, 1, sec, 1);
+ }
+};
+
+struct UseHammingDist {
+ static float calc(const Int8Float *pri, const Int8Float *sec, size_t size) {
+ return binary_hamming_distance(pri, sec, size);
+ }
+};
+
+template <typename CT, typename AGGR, typename DIST>
+float best_similarity(const CT *pri, ConstArrayRef<CT> sec_cells, size_t inner_size) {
+ AGGR aggr;
+ for (const CT *sec = sec_cells.begin(); sec < sec_cells.end(); sec += inner_size) {
+ aggr.sample(DIST::calc(pri, sec, inner_size));
+ }
+ return aggr.result();
+}
+
+template <bool is_double>
+const Value &create_empty_result(const ValueType &type, Stash &stash) {
+ if (is_double) {
+ return stash.create<DoubleValue>(0.0);
+ } else if (type.count_mapped_dimensions() == 0) {
+ auto zero_cells = stash.create_array<float>(type.dense_subspace_size());
+ return stash.create<ValueView>(type, TrivialIndex::get(), TypedCells(zero_cells));
+ } else {
+ return stash.create<ValueView>(type, EmptyIndex::get(), TypedCells(nullptr, CellType::FLOAT, 0));
+ }
+}
+
+template <bool is_double, typename CT, typename AGGR, typename DIST>
+void my_best_similarity_op(InterpretedFunction::State &state, uint64_t param) {
+ size_t inner_size = is_double ? param : unwrap_param<BestSimParam>(param).inner_size;
+ const ValueType &res_type = is_double ? DoubleValue::shared_type() : unwrap_param<BestSimParam>(param).res_type;
+ const Value &pri_value = state.peek(1);
+ auto pri_cells = pri_value.cells().typify<CT>();
+ auto sec_cells = state.peek(0).cells().typify<CT>();
+ if ((pri_cells.size() == 0) || (sec_cells.size() == 0)) {
+ return state.pop_pop_push(create_empty_result<is_double>(res_type, state.stash));
+ }
+ if (is_double) {
+ auto best_sim = best_similarity<CT, AGGR, DIST>(pri_cells.begin(), sec_cells, inner_size);
+ return state.pop_pop_push(state.stash.create<DoubleValue>(best_sim));
+ }
+ auto out_cells = state.stash.create_uninitialized_array<float>(pri_cells.size() / inner_size);
+ const CT *pri = pri_cells.begin();
+ for (auto &out: out_cells) {
+ out = best_similarity<CT, AGGR, DIST>(pri, sec_cells, inner_size);
+ pri += inner_size;
+ }
+ Value &result_ref = state.stash.create<ValueView>(res_type, pri_value.index(), TypedCells(out_cells));
+ state.pop_pop_push(result_ref);
+}
+
+//-----------------------------------------------------------------------------
+
+size_t stride(const ValueType &type, const vespalib::string &name) {
+ size_t stride = 0;
+ for (const auto &dim: type.dimensions()) {
+ if (dim.is_indexed()) {
+ if (dim.name == name) {
+ stride = 1;
+ } else {
+ stride *= dim.size;
+ }
+ }
+ }
+ return stride;
+}
+
+bool check_dims(const ValueType &pri, const ValueType &sec,
+ const vespalib::string &best, const vespalib::string &inner)
+{
+ if ((stride(pri, inner) != 1) || (stride(sec, inner) != 1)) {
+ return false;
+ }
+ if (pri.dimension_index(best) != ValueType::Dimension::npos) {
+ return false;
+ }
+ if (sec.dimension_index(best) == ValueType::Dimension::npos) {
+ return false;
+ }
+ for (auto &&type = sec.reduce({inner,best}); auto &&dim: type.dimensions()) {
+ if (!dim.is_trivial()) {
+ return false;
+ }
+ }
+ return true;
+}
+
+size_t get_dim_size(const ValueType &type, const vespalib::string &dim) {
+ size_t npos = ValueType::Dimension::npos;
+ size_t idx = type.dimension_index(dim);
+ assert(idx != npos);
+ assert(type.dimensions()[idx].is_indexed());
+ return type.dimensions()[idx].size;
+}
+
+const Reduce *check_reduce(const TensorFunction &expr, std::initializer_list<Aggr> allow) {
+ if (auto reduce = as<Reduce>(expr)) {
+ if (reduce->dimensions().size() == 1) {
+ if (std::find(allow.begin(), allow.end(), reduce->aggr()) != allow.end()) {
+ return reduce;
+ }
+ }
+ }
+ return nullptr;
+}
+
+const Join *check_join(const TensorFunction &expr, std::initializer_list<op2_t> allow) {
+ if (auto join = as<Join>(expr)) {
+ if (std::find(allow.begin(), allow.end(), join->function()) != allow.end()) {
+ return join;
+ }
+ }
+ return nullptr;
+}
+
+struct SelectFun {
+ const ValueType &res_type;
+ const ValueType &lhs_type;
+ const ValueType &rhs_type;
+ SelectFun(const auto &res, const auto &lhs, const auto &rhs)
+ : res_type(res.result_type()), lhs_type(lhs.result_type()), rhs_type(rhs.result_type()) {}
+ template <typename R1> static InterpretedFunction::op_function invoke(Aggr best_aggr, op2_t join_fun, CellType cell_types) {
+ if ((best_aggr == Aggr::MAX) && (join_fun == Mul::f) && (cell_types == CellType::FLOAT)) {
+ return my_best_similarity_op<R1::value, float, aggr::Max<float>, UseDotProduct>;
+ }
+ if ((best_aggr == Aggr::MIN) && (join_fun == Hamming::f) && (cell_types == CellType::INT8)) {
+ return my_best_similarity_op<R1::value, Int8Float, aggr::Min<float>, UseHammingDist>;
+ }
+ return nullptr;
+ }
+ InterpretedFunction::op_function operator()(Aggr best_aggr, op2_t join_fun) {
+ static_assert(std::is_same_v<float, CellValueType<CellType::FLOAT>>);
+ static_assert(std::is_same_v<Int8Float, CellValueType<CellType::INT8>>);
+ if (lhs_type.cell_type() != rhs_type.cell_type()) {
+ return nullptr;
+ }
+ return typify_invoke<1,TypifyBool,SelectFun>(res_type.is_double(), best_aggr, join_fun, lhs_type.cell_type());
+ }
+};
+
+} // namespace <unnamed>
+
+uint64_t
+BestSimilarityFunction::make_param(Stash &stash) const
+{
+ if (result_type().is_double()) {
+ return _inner_size;
+ }
+ return wrap_param<BestSimParam>(stash.create<BestSimParam>(result_type(), _inner_size));
+}
+
+BestSimilarityFunction::BestSimilarityFunction(const ValueType &res_type_in,
+ const TensorFunction &pri,
+ const TensorFunction &sec,
+ InterpretedFunction::op_function my_fun,
+ size_t inner_size)
+ : tensor_function::Op2(res_type_in, pri, sec),
+ _my_fun(my_fun),
+ _inner_size(inner_size)
+{
+}
+
+InterpretedFunction::Instruction
+BestSimilarityFunction::compile_self(const ValueBuilderFactory &, Stash &stash) const
+{
+ return InterpretedFunction::Instruction(_my_fun, make_param(stash));
+}
+
+const TensorFunction &
+BestSimilarityFunction::optimize(const TensorFunction &expr, Stash &stash)
+{
+ if (auto best_reduce = check_reduce(expr, {Aggr::MAX, Aggr::MIN})) {
+ if (auto sum_reduce = check_reduce(best_reduce->child(), {Aggr::SUM})) {
+ if (auto join = check_join(sum_reduce->child(), {Mul::f, Hamming::f})) {
+ SelectFun select_fun(expr, join->lhs(), join->rhs());
+ if (auto my_fun = select_fun(best_reduce->aggr(), join->function())) {
+ const auto &best_dim = best_reduce->dimensions()[0];
+ const auto &inner_dim = sum_reduce->dimensions()[0];
+ const TensorFunction &lhs = join->lhs();
+ const TensorFunction &rhs = join->rhs();
+ if (check_dims(lhs.result_type(), rhs.result_type(), best_dim, inner_dim)) {
+ size_t inner_size = get_dim_size(lhs.result_type(), inner_dim);
+ return stash.create<BestSimilarityFunction>(expr.result_type(), lhs, rhs, my_fun, inner_size);
+ }
+ if (check_dims(rhs.result_type(), lhs.result_type(), best_dim, inner_dim)) {
+ size_t inner_size = get_dim_size(rhs.result_type(), inner_dim);
+ return stash.create<BestSimilarityFunction>(expr.result_type(), rhs, lhs, my_fun, inner_size);
+ }
+ }
+ }
+ }
+ }
+ return expr;
+}
+
+} // namespace
diff --git a/eval/src/vespa/eval/instruction/best_similarity_function.h b/eval/src/vespa/eval/instruction/best_similarity_function.h
new file mode 100644
index 00000000000..5b61eaec085
--- /dev/null
+++ b/eval/src/vespa/eval/instruction/best_similarity_function.h
@@ -0,0 +1,38 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#pragma once
+
+#include <vespa/eval/eval/tensor_function.h>
+
+namespace vespalib::eval {
+
+/**
+ * Tensor function combining multiple vector-based similarity measures
+ * to find the best one. This function supports the following cases:
+ *
+ * - maximum dot product of vectors with float cell type (MaxSim)
+ * - minimum hamming distance of bitvectors with int8 cell type
+ *
+ * The vectors used to calculate the individual distance metrics must
+ * be the inner dense dimension of both inputs. The dimension reduced
+ * to find the best similarity measure must be the remaining dimension
+ * of one of the inputs.
+ **/
+class BestSimilarityFunction : public tensor_function::Op2
+{
+private:
+ InterpretedFunction::op_function _my_fun;
+ size_t _inner_size;
+ uint64_t make_param(Stash &stash) const;
+public:
+ BestSimilarityFunction(const ValueType &res_type_in,
+ const TensorFunction &pri,
+ const TensorFunction &sec,
+ InterpretedFunction::op_function my_fun,
+ size_t inner_size);
+ InterpretedFunction::Instruction compile_self(const ValueBuilderFactory &factory, Stash &stash) const override;
+ bool result_is_mutable() const override { return true; }
+ static const TensorFunction &optimize(const TensorFunction &expr, Stash &stash);
+};
+
+} // namespace
diff --git a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java
index de54b17da09..7e9681209f5 100644
--- a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java
+++ b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java
@@ -123,7 +123,7 @@ public class Flags {
ZONE_ID, APPLICATION_ID);
public static final UnboundIntFlag NUM_DEPLOY_HELPER_THREADS = defineIntFlag(
- "num-model-builder-threads", 0,
+ "num-model-builder-threads", -1,
List.of("balder"), "2021-09-09", "2021-10-01",
"Number of threads used for speeding up building of models.",
"Takes effect on first (re)start of config server");
@@ -283,6 +283,20 @@ public class Flags {
TENANT_ID
);
+ public static final UnboundIntFlag MAX_CONNECTION_LIFE_IN_HOSTED = defineIntFlag(
+ "max-connection-life-in-hosted", 45,
+ List.of("bjorncs"), "2021-09-30", "2021-12-31",
+ "Max connection life for connections to jdisc endpoints in hosted",
+ "Takes effect at redeployment",
+ APPLICATION_ID);
+
+ public static final UnboundBooleanFlag ENABLE_ROUTING_REUSE_PORT = defineFeatureFlag(
+ "enable-routing-reuse-port", false,
+ List.of("mortent"), "2021-09-29", "2021-12-31",
+ "Enable reuse port in routing configuration",
+ "Takes effect on container restart",
+ HOSTNAME
+ );
/** WARNING: public for testing: All flags should be defined in {@link Flags}. */
public static UnboundBooleanFlag defineFeatureFlag(String flagId, boolean defaultValue, List<String> owners,
diff --git a/hosted-api/src/main/java/ai/vespa/hosted/api/ControllerHttpClient.java b/hosted-api/src/main/java/ai/vespa/hosted/api/ControllerHttpClient.java
index 614f2fe6732..907d57fffe7 100644
--- a/hosted-api/src/main/java/ai/vespa/hosted/api/ControllerHttpClient.java
+++ b/hosted-api/src/main/java/ai/vespa/hosted/api/ControllerHttpClient.java
@@ -4,6 +4,7 @@ package ai.vespa.hosted.api;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.ApplicationName;
import com.yahoo.config.provision.Environment;
+import com.yahoo.config.provision.InstanceName;
import com.yahoo.config.provision.TenantName;
import com.yahoo.config.provision.zone.ZoneId;
import com.yahoo.security.KeyUtils;
@@ -36,9 +37,11 @@ import java.security.cert.X509Certificate;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.OptionalLong;
+import java.util.Set;
import java.util.concurrent.Callable;
import java.util.function.Consumer;
import java.util.function.Supplier;
@@ -175,6 +178,28 @@ public abstract class ControllerHttpClient {
GET));
}
+ /** Returns the tenants in this system. */
+ public Set<TenantName> tenants() {
+ return toTenants(send(request(HttpRequest.newBuilder(tenantsPath())
+ .timeout(Duration.ofSeconds(20)),
+ GET)));
+ }
+
+ /** Returns the applications for the given tenant. */
+ public Set<ApplicationName> applications(TenantName tenantName) {
+ return toApplications(send(request(HttpRequest.newBuilder(applicationsPath(tenantName))
+ .timeout(Duration.ofSeconds(20)),
+ GET)));
+ }
+
+ /** Returns the application instances for the given tenant. */
+ public Set<ApplicationId> applicationInstances(TenantName tenantName) {
+ return toApplicationInstances(send(request(HttpRequest.newBuilder(applicationsPath(tenantName))
+ .timeout(Duration.ofSeconds(20)),
+ GET)),
+ tenantName);
+ }
+
/** Follows the given deployment job until it is done, or this thread is interrupted, at which point the current status is returned. */
public DeploymentLog followDeploymentUntilDone(ApplicationId id, ZoneId zone, long run,
Consumer<DeploymentLog.Entry> out) {
@@ -227,10 +252,14 @@ public abstract class ControllerHttpClient {
return concatenated(endpoint, "application", "v4");
}
+ private URI tenantsPath() { return concatenated(applicationApiPath(), "tenant"); }
+
private URI tenantPath(TenantName tenant) {
return concatenated(applicationApiPath(), "tenant", tenant.value());
}
+ private URI applicationsPath(TenantName tenant) { return concatenated(tenantPath(tenant), "application"); }
+
private URI applicationPath(TenantName tenant, ApplicationName application) {
return concatenated(tenantPath(tenant), "application", application.value());
}
@@ -415,6 +444,32 @@ public abstract class ControllerHttpClient {
: OptionalLong.empty());
}
+ private static Set<TenantName> toTenants(HttpResponse<byte[]> response) {
+ Set<TenantName> tenants = new HashSet<>();
+ toInspector(response).traverse((ArrayTraverser) (___, entryObject) ->
+ tenants.add(TenantName.from(entryObject.field("tenant").asString())));
+ return tenants;
+ }
+
+ private static Set<ApplicationName> toApplications(HttpResponse<byte[]> response) {
+ Set<ApplicationName> applications = new HashSet<>();
+ toInspector(response).traverse((ArrayTraverser) (___, entryObject) ->
+ applications.add(ApplicationName.from(entryObject.field("application").asString())));
+ return applications;
+ }
+
+ private static Set<ApplicationId> toApplicationInstances(HttpResponse<byte[]> response, TenantName tenantName) {
+ Set<ApplicationId> applicationIds = new HashSet<>();
+ toInspector(response).traverse((ArrayTraverser) (___, entryObject) -> {
+ ApplicationName applicationName = ApplicationName.from(entryObject.field("application").asString());
+ entryObject.field("instances").traverse((ArrayTraverser) (____, instanceObject) ->
+ applicationIds.add(ApplicationId.from(tenantName,
+ applicationName,
+ InstanceName.from(instanceObject.field("instance").asString()))));
+ });
+ return applicationIds;
+ }
+
private static Slime toSlime(byte[] data) {
return SlimeUtils.jsonToSlime(data);
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodesAndHosts.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodesAndHosts.java
index cdf117c11ce..70e5cf14b54 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodesAndHosts.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodesAndHosts.java
@@ -44,7 +44,10 @@ public class NodesAndHosts<NL extends NodeList> {
public NL nodes() { return nodes; }
public NodeList childrenOf(Node host) {
- HostAndNodes hostAndNodes = host2Nodes.get(host.hostname());
+ return childrenOf(host.hostname());
+ }
+ public NodeList childrenOf(String hostname) {
+ HostAndNodes hostAndNodes = host2Nodes.get(hostname);
return hostAndNodes != null ? NodeList.copyOf(hostAndNodes.children) : NodeList.of();
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainer.java
index 78686d8aeed..9c5b556b309 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/DynamicProvisioningMaintainer.java
@@ -22,6 +22,7 @@ import com.yahoo.vespa.hosted.provision.LockedNodeList;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeList;
import com.yahoo.vespa.hosted.provision.NodeRepository;
+import com.yahoo.vespa.hosted.provision.NodesAndHosts;
import com.yahoo.vespa.hosted.provision.node.Agent;
import com.yahoo.vespa.hosted.provision.node.History;
import com.yahoo.vespa.hosted.provision.node.IP;
@@ -269,8 +270,8 @@ public class DynamicProvisioningMaintainer extends NodeRepositoryMaintainer {
ArrayList<Node> mutableNodes) {
for (int clusterIndex = 0; clusterIndex < preprovisionCapacity.size(); ++clusterIndex) {
ClusterCapacity clusterCapacity = preprovisionCapacity.get(clusterIndex);
- LockedNodeList nodeList = new LockedNodeList(mutableNodes, () -> {});
- List<Node> candidates = findCandidates(clusterCapacity, clusterIndex, nodeList);
+ NodesAndHosts<LockedNodeList> nodesAndHosts = NodesAndHosts.create(new LockedNodeList(mutableNodes, () -> {}));
+ List<Node> candidates = findCandidates(clusterCapacity, clusterIndex, nodesAndHosts);
int deficit = Math.max(0, clusterCapacity.count() - candidates.size());
if (deficit > 0) {
return Optional.of(clusterCapacity.withCount(deficit));
@@ -283,7 +284,7 @@ public class DynamicProvisioningMaintainer extends NodeRepositoryMaintainer {
return Optional.empty();
}
- private List<Node> findCandidates(ClusterCapacity clusterCapacity, int clusterIndex, LockedNodeList nodeList) {
+ private List<Node> findCandidates(ClusterCapacity clusterCapacity, int clusterIndex, NodesAndHosts<LockedNodeList> nodesAndHosts) {
NodeResources nodeResources = toNodeResources(clusterCapacity);
// We'll allocate each ClusterCapacity as a unique cluster in a dummy application
@@ -296,7 +297,7 @@ public class DynamicProvisioningMaintainer extends NodeRepositoryMaintainer {
NodeSpec nodeSpec = NodeSpec.from(clusterCapacity.count(), nodeResources, false, true);
int wantedGroups = 1;
- NodePrioritizer prioritizer = new NodePrioritizer(nodeList, applicationId, clusterSpec, nodeSpec, wantedGroups,
+ NodePrioritizer prioritizer = new NodePrioritizer(nodesAndHosts, applicationId, clusterSpec, nodeSpec, wantedGroups,
true, nodeRepository().nameResolver(), nodeRepository().resourcesCalculator(),
nodeRepository().spareCount());
List<NodeCandidate> nodeCandidates = prioritizer.collect(List.of());
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/GroupPreparer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/GroupPreparer.java
index aad32f64fa8..76ccac9c618 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/GroupPreparer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/GroupPreparer.java
@@ -10,6 +10,7 @@ import com.yahoo.transaction.Mutex;
import com.yahoo.vespa.hosted.provision.LockedNodeList;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeRepository;
+import com.yahoo.vespa.hosted.provision.NodesAndHosts;
import com.yahoo.vespa.hosted.provision.node.Agent;
import com.yahoo.vespa.hosted.provision.provisioning.HostProvisioner.HostSharing;
@@ -30,6 +31,18 @@ public class GroupPreparer {
private final NodeRepository nodeRepository;
private final Optional<HostProvisioner> hostProvisioner;
+ /**
+ * Contains list of prepared nodes and the NodesAndHost object to use for next prepare call.
+ */
+ public static class PrepareResult {
+ public final List<Node> prepared;
+ public final NodesAndHosts<LockedNodeList> allNodesAndHosts;
+ PrepareResult(List<Node> prepared, NodesAndHosts<LockedNodeList> allNodesAndHosts) {
+ this.prepared = prepared;
+ this.allNodesAndHosts = allNodesAndHosts;
+ }
+ }
+
public GroupPreparer(NodeRepository nodeRepository, Optional<HostProvisioner> hostProvisioner) {
this.nodeRepository = nodeRepository;
this.hostProvisioner = hostProvisioner;
@@ -45,33 +58,44 @@ public class GroupPreparer {
* This method will remove from this list if it finds it needs additional nodes
* @param indices the next available node indices for this cluster.
* This method will consume these when it allocates new nodes to the cluster.
- * @return the list of nodes this cluster group will have allocated if activated
+ * @param allNodesAndHosts list of all nodes and hosts. Use createNodesAndHostUnlocked to create param for
+ * first invocation. Then use previous PrepareResult.allNodesAndHosts for the following.
+ * @return the list of nodes this cluster group will have allocated if activated, and
*/
// Note: This operation may make persisted changes to the set of reserved and inactive nodes,
// but it may not change the set of active nodes, as the active nodes must stay in sync with the
// active config model which is changed on activate
- public List<Node> prepare(ApplicationId application, ClusterSpec cluster, NodeSpec requestedNodes,
- List<Node> surplusActiveNodes, NodeIndices indices, int wantedGroups) {
+ public PrepareResult prepare(ApplicationId application, ClusterSpec cluster, NodeSpec requestedNodes,
+ List<Node> surplusActiveNodes, NodeIndices indices, int wantedGroups,
+ NodesAndHosts<LockedNodeList> allNodesAndHosts) {
// Try preparing in memory without global unallocated lock. Most of the time there should be no changes and we
// can return nodes previously allocated.
- {
- NodeAllocation probeAllocation = prepareAllocation(application, cluster, requestedNodes, surplusActiveNodes,
- indices::probeNext, wantedGroups, PROBE_LOCK);
- if (probeAllocation.fulfilledAndNoChanges()) {
- List<Node> acceptedNodes = probeAllocation.finalNodes();
- surplusActiveNodes.removeAll(acceptedNodes);
- indices.commitProbe();
- return acceptedNodes;
- }
+ NodeAllocation probeAllocation = prepareAllocation(application, cluster, requestedNodes, surplusActiveNodes,
+ indices::probeNext, wantedGroups, allNodesAndHosts);
+ if (probeAllocation.fulfilledAndNoChanges()) {
+ List<Node> acceptedNodes = probeAllocation.finalNodes();
+ surplusActiveNodes.removeAll(acceptedNodes);
+ indices.commitProbe();
+ return new PrepareResult(acceptedNodes, allNodesAndHosts);
+ } else {
+ // There were some changes, so re-do the allocation with locks
indices.resetProbe();
+ List<Node> prepared = prepareWithLocks(application, cluster, requestedNodes, surplusActiveNodes, indices, wantedGroups);
+ return new PrepareResult(prepared, createNodesAndHostUnlocked());
}
+ }
+
+ // Use this to create allNodesAndHosts param to prepare method for first invocation of prepare
+ public NodesAndHosts<LockedNodeList> createNodesAndHostUnlocked() { return NodesAndHosts.create(nodeRepository.nodes().list(PROBE_LOCK)); }
- // There were some changes, so re-do the allocation with locks
+ /// Note that this will write to the node repo.
+ private List<Node> prepareWithLocks(ApplicationId application, ClusterSpec cluster, NodeSpec requestedNodes,
+ List<Node> surplusActiveNodes, NodeIndices indices, int wantedGroups) {
try (Mutex lock = nodeRepository.nodes().lock(application);
Mutex allocationLock = nodeRepository.nodes().lockUnallocated()) {
-
+ NodesAndHosts<LockedNodeList> allNodesAndHosts = NodesAndHosts.create(nodeRepository.nodes().list(allocationLock));
NodeAllocation allocation = prepareAllocation(application, cluster, requestedNodes, surplusActiveNodes,
- indices::next, wantedGroups, allocationLock);
+ indices::next, wantedGroups, allNodesAndHosts);
NodeType hostType = allocation.nodeType().hostType();
if (canProvisionDynamically(hostType)) {
HostSharing sharing = hostSharing(requestedNodes, hostType);
@@ -115,10 +139,10 @@ public class GroupPreparer {
private NodeAllocation prepareAllocation(ApplicationId application, ClusterSpec cluster, NodeSpec requestedNodes,
List<Node> surplusActiveNodes, Supplier<Integer> nextIndex, int wantedGroups,
- Mutex allocationLock) {
- LockedNodeList allNodes = nodeRepository.nodes().list(allocationLock);
- NodeAllocation allocation = new NodeAllocation(allNodes, application, cluster, requestedNodes, nextIndex, nodeRepository);
- NodePrioritizer prioritizer = new NodePrioritizer(allNodes,
+ NodesAndHosts<LockedNodeList> allNodesAndHosts) {
+
+ NodeAllocation allocation = new NodeAllocation(allNodesAndHosts, application, cluster, requestedNodes, nextIndex, nodeRepository);
+ NodePrioritizer prioritizer = new NodePrioritizer(allNodesAndHosts,
application,
cluster,
requestedNodes,
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java
index bdb7cb4b64d..d96613201c3 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java
@@ -11,6 +11,7 @@ import com.yahoo.config.provision.SystemName;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeList;
import com.yahoo.vespa.hosted.provision.NodeRepository;
+import com.yahoo.vespa.hosted.provision.NodesAndHosts;
import com.yahoo.vespa.hosted.provision.node.Agent;
import com.yahoo.vespa.hosted.provision.node.Allocation;
@@ -40,7 +41,7 @@ class NodeAllocation {
private static final Logger LOG = Logger.getLogger(NodeAllocation.class.getName());
/** List of all nodes in node-repository */
- private final NodeList allNodes;
+ private final NodesAndHosts<? extends NodeList> allNodesAndHosts;
/** The application this list is for */
private final ApplicationId application;
@@ -80,9 +81,9 @@ class NodeAllocation {
private final NodeRepository nodeRepository;
private final NodeResourceLimits nodeResourceLimits;
- NodeAllocation(NodeList allNodes, ApplicationId application, ClusterSpec cluster, NodeSpec requestedNodes,
+ NodeAllocation(NodesAndHosts<? extends NodeList> allNodesAndHosts, ApplicationId application, ClusterSpec cluster, NodeSpec requestedNodes,
Supplier<Integer> nextIndex, NodeRepository nodeRepository) {
- this.allNodes = allNodes;
+ this.allNodesAndHosts = allNodesAndHosts;
this.application = application;
this.cluster = cluster;
this.requestedNodes = requestedNodes;
@@ -199,7 +200,7 @@ class NodeAllocation {
// In non-dynamic provisioned zones we require that if either of the nodes on the host requires exclusivity,
// then all the nodes on the host must have the same owner
- for (Node nodeOnHost : allNodes.childrenOf(candidate.parentHostname().get())) {
+ for (Node nodeOnHost : allNodesAndHosts.childrenOf(candidate.parentHostname().get())) {
if (nodeOnHost.allocation().isEmpty()) continue;
if (requestedNodes.isExclusive() || nodeOnHost.allocation().get().membership().cluster().isExclusive()) {
if ( ! nodeOnHost.allocation().get().owner().equals(application)) return true;
@@ -273,7 +274,7 @@ class NodeAllocation {
}
private Node resize(Node node) {
- NodeResources hostResources = allNodes.parentOf(node).get().flavor().resources();
+ NodeResources hostResources = allNodesAndHosts.parentOf(node).get().flavor().resources();
return node.with(new Flavor(requestedNodes.resources().get()
.with(hostResources.diskSpeed())
.with(hostResources.storageType())),
@@ -324,7 +325,7 @@ class NodeAllocation {
if (hostType == NodeType.host) return nodeRepository.database().readProvisionIndices(count);
// Infrastructure hosts have fixed indices, starting at 1
- Set<Integer> currentIndices = allNodes.nodeType(hostType)
+ Set<Integer> currentIndices = allNodesAndHosts.nodes().nodeType(hostType)
.hostnames()
.stream()
// TODO(mpolden): Use cluster index instead of parsing hostname, once all
@@ -424,7 +425,7 @@ class NodeAllocation {
if (nodeType() == NodeType.tenant) return accepted;
// Infrastructure nodes are always allocated by type. Count all nodes as accepted so that we never exceed
// the wanted number of nodes for the type.
- return allNodes.nodeType(nodeType()).size();
+ return allNodesAndHosts.nodes().nodeType(nodeType()).size();
}
/** Prefer to retire nodes we want the least */
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodePrioritizer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodePrioritizer.java
index 1f618a18d24..c7a2d27ca00 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodePrioritizer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodePrioritizer.java
@@ -31,7 +31,7 @@ import java.util.stream.Collectors;
public class NodePrioritizer {
private final List<NodeCandidate> nodes = new ArrayList<>();
- private final NodesAndHosts<LockedNodeList> allNodes;
+ private final NodesAndHosts<LockedNodeList> allNodesAndHosts;
private final HostCapacity capacity;
private final NodeSpec requestedNodes;
private final ApplicationId application;
@@ -45,21 +45,21 @@ public class NodePrioritizer {
private final int currentClusterSize;
private final Set<Node> spareHosts;
- public NodePrioritizer(LockedNodeList allLockedNodes, ApplicationId application, ClusterSpec clusterSpec, NodeSpec nodeSpec,
+ public NodePrioritizer(NodesAndHosts<LockedNodeList> allNodesAndHosts, ApplicationId application, ClusterSpec clusterSpec, NodeSpec nodeSpec,
int wantedGroups, boolean dynamicProvisioning, NameResolver nameResolver,
HostResourcesCalculator hostResourcesCalculator, int spareCount) {
- this.allNodes = NodesAndHosts.create(allLockedNodes);
- this.capacity = new HostCapacity(allNodes, hostResourcesCalculator);
+ this.allNodesAndHosts = allNodesAndHosts;
+ this.capacity = new HostCapacity(this.allNodesAndHosts, hostResourcesCalculator);
this.requestedNodes = nodeSpec;
this.clusterSpec = clusterSpec;
this.application = application;
this.dynamicProvisioning = dynamicProvisioning;
this.spareHosts = dynamicProvisioning ?
- capacity.findSpareHostsInDynamicallyProvisionedZones(allNodes.nodes().asList()) :
- capacity.findSpareHosts(allNodes.nodes().asList(), spareCount);
+ capacity.findSpareHostsInDynamicallyProvisionedZones(this.allNodesAndHosts.nodes().asList()) :
+ capacity.findSpareHosts(this.allNodesAndHosts.nodes().asList(), spareCount);
this.nameResolver = nameResolver;
- NodeList nodesInCluster = allNodes.nodes().owner(application).type(clusterSpec.type()).cluster(clusterSpec.id());
+ NodeList nodesInCluster = this.allNodesAndHosts.nodes().owner(application).type(clusterSpec.type()).cluster(clusterSpec.id());
NodeList nonRetiredNodesInCluster = nodesInCluster.not().retired();
long currentGroups = nonRetiredNodesInCluster.state(Node.State.active).stream()
.flatMap(node -> node.allocation()
@@ -135,7 +135,7 @@ public class NodePrioritizer {
private void addCandidatesOnExistingHosts() {
if ( !canAllocateNew) return;
- for (Node host : allNodes.nodes()) {
+ for (Node host : allNodesAndHosts.nodes()) {
if ( ! Nodes.canAllocateTenantNodeTo(host, dynamicProvisioning)) continue;
if (host.reservedTo().isPresent() && !host.reservedTo().get().equals(application.tenant())) continue;
if (host.reservedTo().isPresent() && application.instance().isTester()) continue;
@@ -143,12 +143,12 @@ public class NodePrioritizer {
if ( ! host.exclusiveToClusterType().map(clusterSpec.type()::equals).orElse(true)) continue;
if (spareHosts.contains(host) && !canAllocateToSpareHosts) continue;
if ( ! capacity.hasCapacity(host, requestedNodes.resources().get())) continue;
- if ( ! allNodes.childrenOf(host).owner(application).cluster(clusterSpec.id()).isEmpty()) continue;
+ if ( ! allNodesAndHosts.childrenOf(host).owner(application).cluster(clusterSpec.id()).isEmpty()) continue;
nodes.add(NodeCandidate.createNewChild(requestedNodes.resources().get(),
capacity.availableCapacityOf(host),
host,
spareHosts.contains(host),
- allNodes.nodes(),
+ allNodesAndHosts.nodes(),
nameResolver));
}
}
@@ -156,7 +156,7 @@ public class NodePrioritizer {
/** Add existing nodes allocated to the application */
private void addApplicationNodes() {
EnumSet<Node.State> legalStates = EnumSet.of(Node.State.active, Node.State.inactive, Node.State.reserved);
- allNodes.nodes().stream()
+ allNodesAndHosts.nodes().stream()
.filter(node -> node.type() == requestedNodes.type())
.filter(node -> legalStates.contains(node.state()))
.filter(node -> node.allocation().isPresent())
@@ -169,7 +169,7 @@ public class NodePrioritizer {
/** Add nodes already provisioned, but not allocated to any application */
private void addReadyNodes() {
- allNodes.nodes().stream()
+ allNodesAndHosts.nodes().stream()
.filter(node -> node.type() == requestedNodes.type())
.filter(node -> node.state() == Node.State.ready)
.map(node -> candidateFrom(node, false))
@@ -179,7 +179,7 @@ public class NodePrioritizer {
/** Create a candidate from given pre-existing node */
private NodeCandidate candidateFrom(Node node, boolean isSurplus) {
- Optional<Node> optionalParent = allNodes.parentOf(node);
+ Optional<Node> optionalParent = allNodesAndHosts.parentOf(node);
if (optionalParent.isPresent()) {
Node parent = optionalParent.get();
return NodeCandidate.createChild(node,
@@ -217,7 +217,7 @@ public class NodePrioritizer {
*/
private boolean canStillAllocate(Node node) {
if (node.type() != NodeType.tenant || node.parentHostname().isEmpty()) return true;
- Optional<Node> parent = allNodes.parentOf(node);
+ Optional<Node> parent = allNodesAndHosts.parentOf(node);
return parent.isPresent() ? Nodes.canAllocateTenantNodeTo(parent.get(), dynamicProvisioning) : null;
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/Preparer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/Preparer.java
index d5b754117cb..a27cf252a3a 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/Preparer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/Preparer.java
@@ -5,9 +5,11 @@ import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.ClusterMembership;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.OutOfCapacityException;
+import com.yahoo.vespa.hosted.provision.LockedNodeList;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeList;
import com.yahoo.vespa.hosted.provision.NodeRepository;
+import com.yahoo.vespa.hosted.provision.NodesAndHosts;
import com.yahoo.vespa.hosted.provision.node.Nodes;
import java.util.ArrayList;
@@ -57,22 +59,23 @@ class Preparer {
// but it may not change the set of active nodes, as the active nodes must stay in sync with the
// active config model which is changed on activate
private List<Node> prepareNodes(ApplicationId application, ClusterSpec cluster, NodeSpec requestedNodes, int wantedGroups) {
- NodeList allNodes = nodeRepository.nodes().list();
- NodeList appNodes = allNodes.owner(application);
+ NodesAndHosts<LockedNodeList> allNodesAndHosts = groupPreparer.createNodesAndHostUnlocked();
+ NodeList appNodes = allNodesAndHosts.nodes().owner(application);
List<Node> surplusNodes = findNodesInRemovableGroups(appNodes, cluster, wantedGroups);
List<Integer> usedIndices = appNodes.cluster(cluster.id()).mapToList(node -> node.allocation().get().membership().index());
NodeIndices indices = new NodeIndices(usedIndices, ! cluster.type().isContent());
List<Node> acceptedNodes = new ArrayList<>();
+
for (int groupIndex = 0; groupIndex < wantedGroups; groupIndex++) {
ClusterSpec clusterGroup = cluster.with(Optional.of(ClusterSpec.Group.from(groupIndex)));
- List<Node> accepted = groupPreparer.prepare(application, clusterGroup,
- requestedNodes.fraction(wantedGroups), surplusNodes,
- indices, wantedGroups);
-
+ GroupPreparer.PrepareResult result = groupPreparer.prepare(
+ application, clusterGroup, requestedNodes.fraction(wantedGroups),
+ surplusNodes, indices, wantedGroups, allNodesAndHosts);
+ allNodesAndHosts = result.allNodesAndHosts; // Might have changed
+ List<Node> accepted = result.prepared;
if (requestedNodes.rejectNonActiveParent()) {
- Nodes nodes = nodeRepository.nodes();
- NodeList activeHosts = nodes.list(Node.State.active).parents().nodeType(requestedNodes.type().hostType());
+ NodeList activeHosts = allNodesAndHosts.nodes().state(Node.State.active).parents().nodeType(requestedNodes.type().hostType());
accepted = accepted.stream()
.filter(node -> node.parentHostname().isEmpty() || activeHosts.parentOf(node).isPresent())
.collect(Collectors.toList());
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesResponse.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesResponse.java
index 80100128379..d9637c412fd 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesResponse.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesResponse.java
@@ -153,8 +153,6 @@ class NodesResponse extends SlimeJsonResponse {
allocation.networkPorts().ifPresent(ports -> NetworkPortsSerializer.toSlime(ports, object.setArray("networkPorts")));
orchestrator.apply(new HostName(node.hostname()))
.ifPresent(info -> {
- object.setBool("allowedToBeDown", info.status().isSuspended());
- // TODO: Remove allowedToBeDown as a special-case of orchestratorStatus
if (info.status() != HostStatus.NO_REMARKS) {
object.setString("orchestratorStatus", info.status().asString());
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-container1.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-container1.json
index 6be127315e2..33b7a91fc61 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-container1.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-container1.json
@@ -27,7 +27,6 @@
"wantedDockerImage": "docker-registry.domain.tld:8080/dist/vespa:6.42.0",
"wantedVespaVersion": "6.42.0",
"requestedResources": { "vcpu":1.0, "memoryGb":4.0, "diskGb":100.0, "bandwidthGbps":1.0,"diskSpeed":"fast", "storageType":"any" },
- "allowedToBeDown": false,
"rebootGeneration": 0,
"currentRebootGeneration": 0,
"failCount": 0,
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-os-upgrade-complete.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-os-upgrade-complete.json
index cc9f8c7c58f..ec46755b5ac 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-os-upgrade-complete.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-os-upgrade-complete.json
@@ -27,7 +27,6 @@
"wantedDockerImage": "docker-registry.domain.tld:8080/dist/vespa:6.42.0",
"wantedVespaVersion": "6.42.0",
"requestedResources": { "vcpu":4.0, "memoryGb":32.0, "diskGb":1600.0, "bandwidthGbps":20.0, "diskSpeed": "fast", "storageType":"remote" },
- "allowedToBeDown": false,
"rebootGeneration": 0,
"currentRebootGeneration": 0,
"currentOsVersion": "7.5.2",
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports-2.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports-2.json
index f9dd810902c..c44b172633d 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports-2.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports-2.json
@@ -34,7 +34,6 @@
"diskSpeed": "fast",
"storageType": "remote"
},
- "allowedToBeDown": false,
"rebootGeneration": 0,
"currentRebootGeneration": 0,
"failCount": 0,
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports-3.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports-3.json
index 74d402de796..df745729288 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports-3.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports-3.json
@@ -34,7 +34,6 @@
"diskSpeed": "fast",
"storageType": "remote"
},
- "allowedToBeDown": false,
"rebootGeneration": 0,
"currentRebootGeneration": 0,
"failCount": 0,
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports-4.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports-4.json
index b1d8c5fba9a..f6ff292c830 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports-4.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports-4.json
@@ -34,7 +34,6 @@
"diskSpeed": "fast",
"storageType": "remote"
},
- "allowedToBeDown": false,
"rebootGeneration": 0,
"currentRebootGeneration": 0,
"failCount": 0,
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports.json
index 660e67796f9..335a95f47f5 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports.json
@@ -34,7 +34,6 @@
"diskSpeed": "fast",
"storageType": "remote"
},
- "allowedToBeDown": false,
"rebootGeneration": 0,
"currentRebootGeneration": 0,
"failCount": 0,
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1.json
index b8397cfb6af..4b7eecdfc26 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1.json
@@ -27,7 +27,6 @@
"wantedDockerImage": "docker-registry.domain.tld:8080/dist/vespa:6.42.0",
"wantedVespaVersion": "6.42.0",
"requestedResources": { "vcpu":4.0, "memoryGb":32.0, "diskGb":1600.0, "bandwidthGbps":20.0, "diskSpeed":"fast", "storageType":"remote" },
- "allowedToBeDown": false,
"rebootGeneration": 0,
"currentRebootGeneration": 0,
"failCount": 0,
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node2.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node2.json
index 60d194163b7..e0a7448c111 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node2.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node2.json
@@ -27,7 +27,6 @@
"wantedDockerImage": "docker-registry.domain.tld:8080/dist/vespa:6.42.0",
"wantedVespaVersion": "6.42.0",
"requestedResources": { "vcpu":4.0, "memoryGb":32.0, "diskGb":1600.0, "bandwidthGbps":20.0, "diskSpeed":"fast", "storageType":"remote" },
- "allowedToBeDown": false,
"rebootGeneration": 0,
"currentRebootGeneration": 0,
"failCount": 0,
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node3.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node3.json
index 58db8d47bcc..21f3a54311f 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node3.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node3.json
@@ -27,7 +27,6 @@
"wantedDockerImage": "docker-registry.domain.tld:8080/dist/vespa:6.42.0",
"wantedVespaVersion": "6.42.0",
"requestedResources": { "vcpu":4.0, "memoryGb":32.0, "diskGb":1600.0, "bandwidthGbps":20.0, "diskSpeed":"fast", "storageType":"remote" },
- "allowedToBeDown": false,
"rebootGeneration": 0,
"currentRebootGeneration": 0,
"failCount": 0,
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node4.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node4.json
index b5ddc4d99a8..789b0580357 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node4.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node4.json
@@ -27,7 +27,6 @@
"wantedDockerImage": "docker-registry.domain.tld:8080/dist/vespa:6.42.0",
"wantedVespaVersion": "6.42.0",
"requestedResources": { "vcpu":4.0, "memoryGb":32.0, "diskGb":1600.0, "bandwidthGbps":20.0, "diskSpeed":"fast", "storageType":"remote" },
- "allowedToBeDown": false,
"rebootGeneration": 0,
"currentRebootGeneration": 0,
"failCount": 0,
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node5.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node5.json
index 8f4c91282ca..35ec6fc0273 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node5.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node5.json
@@ -27,7 +27,6 @@
"wantedDockerImage": "docker-registry.domain.tld:8080/dist/vespa:6.42.0",
"wantedVespaVersion": "6.42.0",
"requestedResources": { "vcpu":4.0, "memoryGb":32.0, "diskGb":1600.0, "bandwidthGbps":20.0, "diskSpeed":"fast", "storageType":"remote" },
- "allowedToBeDown": false,
"rebootGeneration": 0,
"currentRebootGeneration": 0,
"failCount": 0,
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/dockerhost1-with-firmware-data.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/dockerhost1-with-firmware-data.json
index 866efefc1d3..498780a2eba 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/dockerhost1-with-firmware-data.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/dockerhost1-with-firmware-data.json
@@ -27,7 +27,6 @@
"wantedDockerImage": "docker-registry.domain.tld:8080/dist/vespa:6.42.0",
"wantedVespaVersion": "6.42.0",
"requestedResources": { "vcpu":4.0, "memoryGb":32.0, "diskGb":1600.0, "bandwidthGbps":20.0, "diskSpeed":"fast", "storageType":"remote" },
- "allowedToBeDown": false,
"rebootGeneration": 0,
"currentRebootGeneration": 0,
"currentFirmwareCheck": 100,
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node1.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node1.json
index 32ed54452de..a35e8aa638b 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node1.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node1.json
@@ -26,7 +26,6 @@
"wantedDockerImage": "docker-registry.domain.tld:8080/dist/vespa:6.42.0",
"wantedVespaVersion": "6.42.0",
"requestedResources": { "vcpu":2.0, "memoryGb":8.0, "diskGb":50.0, "bandwidthGbps":1.0, "diskSpeed":"fast", "storageType":"any" },
- "allowedToBeDown": false,
"rebootGeneration": 0,
"currentRebootGeneration": 0,
"failCount": 0,
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node10.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node10.json
index 624976414da..5d98c75f346 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node10.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node10.json
@@ -27,7 +27,6 @@
"wantedDockerImage": "docker-registry.domain.tld:8080/dist/vespa:6.42.0",
"wantedVespaVersion": "6.42.0",
"requestedResources": { "vcpu":2.0, "memoryGb":8.0, "diskGb":50.0, "bandwidthGbps":1.0, "diskSpeed":"fast", "storageType":"any" },
- "allowedToBeDown": false,
"rebootGeneration": 0,
"currentRebootGeneration": 0,
"vespaVersion": "5.104.142",
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node13.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node13.json
index f3feaea4d3a..477a87124e7 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node13.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node13.json
@@ -26,7 +26,6 @@
"wantedDockerImage": "docker-registry.domain.tld:8080/dist/vespa:6.42.0",
"wantedVespaVersion": "6.42.0",
"requestedResources": { "vcpu":10.0, "memoryGb":48.0, "diskGb":500.0, "bandwidthGbps":1.0, "diskSpeed":"fast", "storageType":"any" },
- "allowedToBeDown": false,
"rebootGeneration": 0,
"currentRebootGeneration": 0,
"failCount": 0,
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node14.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node14.json
index cd71055c3e2..fd533b6372c 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node14.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node14.json
@@ -26,7 +26,6 @@
"wantedDockerImage": "docker-registry.domain.tld:8080/dist/vespa:6.42.0",
"wantedVespaVersion": "6.42.0",
"requestedResources": { "vcpu":10.0, "memoryGb":48.0, "diskGb":500.0, "bandwidthGbps":1.0, "diskSpeed":"fast", "storageType":"any" },
- "allowedToBeDown": false,
"rebootGeneration": 0,
"currentRebootGeneration": 0,
"failCount": 0,
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node2.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node2.json
index f544436159c..e288aaccc28 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node2.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node2.json
@@ -26,7 +26,6 @@
"wantedDockerImage": "docker-registry.domain.tld:8080/dist/vespa:6.42.0",
"wantedVespaVersion": "6.42.0",
"requestedResources": { "vcpu":2.0, "memoryGb":8.0, "diskGb":50.0, "bandwidthGbps":1.0, "diskSpeed":"fast", "storageType":"any" },
- "allowedToBeDown": false,
"rebootGeneration": 0,
"currentRebootGeneration": 0,
"failCount": 0,
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node4-after-changes.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node4-after-changes.json
index 7298f4737fe..6f25254b420 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node4-after-changes.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node4-after-changes.json
@@ -28,7 +28,6 @@
"wantedDockerImage": "docker-registry.domain.tld:8080/my/image:6.42.0",
"wantedVespaVersion": "6.42.0",
"requestedResources": { "vcpu":1.0, "memoryGb":4.0, "diskGb":100.0, "bandwidthGbps":1.0, "diskSpeed":"fast", "storageType":"any" },
- "allowedToBeDown": true,
"orchestratorStatus": "ALLOWED_TO_BE_DOWN",
"suspendedSinceMillis": 0,
"rebootGeneration": 2,
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node4-with-hostnames.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node4-with-hostnames.json
index 603b7f22bb3..165e2480340 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node4-with-hostnames.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node4-with-hostnames.json
@@ -27,7 +27,6 @@
"wantedDockerImage": "docker-registry.domain.tld:8080/dist/vespa:6.42.0",
"wantedVespaVersion": "6.42.0",
"requestedResources": { "vcpu":1.0, "memoryGb":4.0, "diskGb":100.0, "bandwidthGbps":1.0, "diskSpeed":"fast", "storageType":"any" },
- "allowedToBeDown": false,
"rebootGeneration": 0,
"currentRebootGeneration": 0,
"vespaVersion": "6.41.0",
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node4.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node4.json
index ba9e58bdcba..ceb9d88763f 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node4.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node4.json
@@ -27,7 +27,6 @@
"wantedDockerImage": "docker-registry.domain.tld:8080/dist/vespa:6.42.0",
"wantedVespaVersion": "6.42.0",
"requestedResources": { "vcpu":1.0, "memoryGb":4.0, "diskGb":100.0, "bandwidthGbps":1.0, "diskSpeed":"fast", "storageType":"any" },
- "allowedToBeDown": false,
"rebootGeneration": 0,
"currentRebootGeneration": 0,
"vespaVersion": "6.41.0",
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node6.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node6.json
index f4dbf657926..1e64c8a8edd 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node6.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node6.json
@@ -26,7 +26,6 @@
"wantedDockerImage": "docker-registry.domain.tld:8080/dist/vespa:6.42.0",
"wantedVespaVersion": "6.42.0",
"requestedResources": { "vcpu":2.0, "memoryGb":8.0, "diskGb":50.0, "bandwidthGbps":1.0, "diskSpeed":"fast", "storageType":"any" },
- "allowedToBeDown": false,
"rebootGeneration": 0,
"currentRebootGeneration": 0,
"failCount": 0,
diff --git a/pom.xml b/pom.xml
index bf0d66514a4..25370012a6c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -150,4 +150,9 @@
<module>zookeeper-server</module>
</modules>
+ <properties>
+ <maven.deploy.skip>true</maven.deploy.skip>
+ <maven.javadoc.skip>true</maven.javadoc.skip>
+ </properties>
+
</project>