diff options
61 files changed, 595 insertions, 385 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 2911eae8d83..e465f97ae4c 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 @@ -79,10 +79,10 @@ public interface ModelContext { // TODO Revisit in May or June 2020 double queueSizeFactor(); - // TODO Revisit in May or June 2020 - double defaultSoftStartSeconds(); + // TODO Remove when 7.229 is last + default double defaultSoftStartSeconds() { return 0; } - // TODO Remove when 7.225 is last + // TODO Remove when 7.226 is last default double defaultTopKProbability() { return 0.9999; } diff --git a/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java b/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java index b06022ba714..16d1261b8d6 100644 --- a/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java +++ b/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java @@ -40,7 +40,6 @@ public class TestProperties implements ModelContext.Properties { private boolean useDistributorBtreeDb = false; private boolean useThreePhaseUpdates = false; private double defaultTermwiseLimit = 1.0; - private double softStartSeconds = 0.0; private double threadPoolSizeFactor = 0.0; private double queueSizeFactor = 0.0; private Optional<EndpointCertificateSecrets> endpointCertificateSecrets = Optional.empty(); @@ -73,11 +72,6 @@ public class TestProperties implements ModelContext.Properties { return queueSizeFactor; } - @Override - public double defaultSoftStartSeconds() { - return softStartSeconds; - } - @Override public boolean useDistributorBtreeDb() { return useDistributorBtreeDb; } @Override public boolean useThreePhaseUpdates() { return useThreePhaseUpdates; } @Override public Optional<AthenzDomain> athenzDomain() { return Optional.ofNullable(athenzDomain); } @@ -98,10 +92,6 @@ public class TestProperties implements ModelContext.Properties { return this; } - public TestProperties setSoftStartSeconds(double softStartSeconds) { - this.softStartSeconds = softStartSeconds; - return this; - } public TestProperties setThreadPoolSizeFactor(double threadPoolSizeFactor) { this.threadPoolSizeFactor = threadPoolSizeFactor; return this; diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/ApplicationContainer.java b/config-model/src/main/java/com/yahoo/vespa/model/container/ApplicationContainer.java index 207e130eaaa..5207a0163cb 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/container/ApplicationContainer.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/container/ApplicationContainer.java @@ -44,8 +44,8 @@ public final class ApplicationContainer extends Container implements @Override public void getConfig(QrStartConfig.Builder builder) { if (getHostResource() != null) { - if ( ! getHostResource().advertisedResources().isUnspecified()) { - NodeResourcesTuning flavorTuning = new NodeResourcesTuning(getHostResource().advertisedResources()); + if ( ! getHostResource().realResources().isUnspecified()) { + NodeResourcesTuning flavorTuning = new NodeResourcesTuning(getHostResource().realResources()); flavorTuning.getConfig(builder); } } @@ -79,13 +79,13 @@ public final class ApplicationContainer extends Container implements @Override public void getConfig(ThreadpoolConfig.Builder builder) { if (! (parent instanceof ContainerCluster)) return; - if ((getHostResource() == null) || getHostResource().advertisedResources().isUnspecified()) return; + if ((getHostResource() == null) || getHostResource().realResources().isUnspecified()) return; ContainerCluster containerCluster = (ContainerCluster) parent; if (containerCluster.getThreadPoolSizeFactor() <= 0.0) return; - NodeResourcesTuning flavorTuning = new NodeResourcesTuning(getHostResource().advertisedResources()) + NodeResourcesTuning resourcesTuning = new NodeResourcesTuning(getHostResource().realResources()) .setThreadPoolSizeFactor(containerCluster.getThreadPoolSizeFactor()) .setQueueSizeFactor(containerCluster.getQueueSizeFactor()); - flavorTuning.getConfig(builder); + resourcesTuning.getConfig(builder); } } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/ApplicationContainerCluster.java b/config-model/src/main/java/com/yahoo/vespa/model/container/ApplicationContainerCluster.java index 37548a15835..56e0bd579cb 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/container/ApplicationContainerCluster.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/container/ApplicationContainerCluster.java @@ -69,7 +69,6 @@ public final class ApplicationContainerCluster extends ContainerCluster<Applicat private MbusParams mbusParams; private boolean messageBusEnabled = true; - private final double softStartSeconds; private Integer memoryPercentage = null; @@ -87,7 +86,6 @@ public final class ApplicationContainerCluster extends ContainerCluster<Applicat addSimpleComponent("ai.vespa.cloud.SystemInfo"); addMetricsV2Handler(); addTestrunnerComponentsIfTester(deployState); - softStartSeconds = deployState.getProperties().defaultSoftStartSeconds(); } @Override @@ -254,7 +252,6 @@ public final class ApplicationContainerCluster extends ContainerCluster<Applicat @Override public void getConfig(ThreadpoolConfig.Builder builder) { - builder.softStartSeconds(softStartSeconds); } public static class MbusParams { diff --git a/config-model/src/main/java/com/yahoo/vespa/model/content/StorageNode.java b/config-model/src/main/java/com/yahoo/vespa/model/content/StorageNode.java index 028aee369c3..f41188eccde 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/content/StorageNode.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/content/StorageNode.java @@ -86,8 +86,8 @@ public class StorageNode extends ContentNode implements StorServerConfig.Produce @Override public void getConfig(StorFilestorConfig.Builder builder) { - if (getHostResource() != null && ! getHostResource().advertisedResources().isUnspecified()) { - builder.num_threads(Math.max(4, (int)getHostResource().advertisedResources().vcpu())); + if (getHostResource() != null && ! getHostResource().realResources().isUnspecified()) { + builder.num_threads(Math.max(4, (int)getHostResource().realResources().vcpu())); } cluster.getConfig(builder); } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/search/SearchNode.java b/config-model/src/main/java/com/yahoo/vespa/model/search/SearchNode.java index f908d091a72..c1498936280 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/search/SearchNode.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/search/SearchNode.java @@ -269,19 +269,14 @@ public class SearchNode extends AbstractService implements // to make sure the node failer has done its work builder.pruneremoveddocumentsage(4 * 24 * 3600 + 3600 + 60); } - if (getHostResource() != null && ! getHostResource().advertisedResources().isUnspecified()) { - NodeResourcesTuning nodeResourcesTuning = tuning.isPresent() - ? new NodeResourcesTuning(getHostResource().advertisedResources(), redundancy, searchableCopies, tuning.get().getNumThreadsPerSearch()) - : new NodeResourcesTuning(getHostResource().advertisedResources(), redundancy, searchableCopies); + if (getHostResource() != null && ! getHostResource().realResources().isUnspecified()) { + var nodeResourcesTuning = tuning.isPresent() + ? new NodeResourcesTuning(getHostResource().realResources(), redundancy, searchableCopies, tuning.get().getNumThreadsPerSearch()) + : new NodeResourcesTuning(getHostResource().realResources(), redundancy, searchableCopies); nodeResourcesTuning.getConfig(builder); - if (tuning.isPresent()) { - tuning.get().getConfig(builder); - } - - if (resourceLimits.isPresent()) { - resourceLimits.get().getConfig(builder); - } + tuning.ifPresent(t -> t.getConfig(builder)); + resourceLimits.ifPresent(l -> l.getConfig(builder)); } } 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 9a59907a230..739ae055ec7 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 @@ -167,7 +167,6 @@ public class ContainerClusterTest { ThreadpoolConfig threadpoolConfig = new ThreadpoolConfig(tpBuilder); assertEquals(10, threadpoolConfig.maxthreads()); assertEquals(0, threadpoolConfig.queueSize()); - assertEquals(0, threadpoolConfig.softStartSeconds(), 0); } @Test @@ -206,22 +205,6 @@ public class ContainerClusterTest { } @Test - public void requireThatSoftStartSecondsCanBeControlledByProperties() { - DeployState state = new DeployState.Builder().properties(new TestProperties().setSoftStartSeconds(300.0)) - .build(); - MockRoot root = new MockRoot("foo", state); - ApplicationContainerCluster cluster = createContainerCluster(root, false); - addContainer(root.deployLogger(), cluster, "c1", "host-c1"); - - ThreadpoolConfig.Builder tpBuilder = new ThreadpoolConfig.Builder(); - cluster.getConfig(tpBuilder); - ThreadpoolConfig threadpoolConfig = new ThreadpoolConfig(tpBuilder); - assertEquals(500, threadpoolConfig.maxthreads()); - assertEquals(0, threadpoolConfig.queueSize()); - assertEquals(300.0, threadpoolConfig.softStartSeconds(), 0.0); - } - - @Test public void requireThatPoolAndQueueCanNotBeControlledByPropertiesWhenNoFlavor() { DeployState state = new DeployState.Builder().properties(new TestProperties() .setThreadPoolSizeFactor(8.5) @@ -236,7 +219,6 @@ public class ContainerClusterTest { ThreadpoolConfig threadpoolConfig = new ThreadpoolConfig(tpBuilder); assertEquals(500, threadpoolConfig.maxthreads()); assertEquals(0, threadpoolConfig.queueSize()); - assertEquals(0.0, threadpoolConfig.softStartSeconds(), 0.0); } @Test @@ -251,7 +233,6 @@ public class ContainerClusterTest { ThreadpoolConfig threadpoolConfig = new ThreadpoolConfig(tpBuilder); assertEquals(40, threadpoolConfig.maxthreads()); assertEquals(700, threadpoolConfig.queueSize()); - assertEquals(0.0, threadpoolConfig.softStartSeconds(), 0.0); } @Test @@ -265,7 +246,6 @@ public class ContainerClusterTest { ThreadpoolConfig threadpoolConfig = new ThreadpoolConfig(tpBuilder); assertEquals(500, threadpoolConfig.maxthreads()); assertEquals(0, threadpoolConfig.queueSize()); - assertEquals(0.0, threadpoolConfig.softStartSeconds(), 0.0); } @Test diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java b/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java index 73c8521d963..3cadb78f15f 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java @@ -223,13 +223,6 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye } } - public PrepareResult prepareAndActivate(Tenant tenant, long sessionId, PrepareParams prepareParams, - boolean ignoreSessionStaleFailure, Instant now) { - PrepareResult result = prepare(tenant, sessionId, prepareParams, now); - activate(tenant, sessionId, prepareParams.getTimeoutBudget(), ignoreSessionStaleFailure); - return result; - } - public PrepareResult deploy(CompressedApplicationInputStream in, PrepareParams prepareParams) { return deploy(in, prepareParams, false, clock.instant()); } @@ -255,7 +248,9 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye ApplicationId applicationId = prepareParams.getApplicationId(); long sessionId = createSession(applicationId, prepareParams.getTimeoutBudget(), applicationPackage); Tenant tenant = tenantRepository.getTenant(applicationId.tenant()); - return prepareAndActivate(tenant, sessionId, prepareParams, ignoreSessionStaleFailure, now); + PrepareResult result = prepare(tenant, sessionId, prepareParams, now); + activate(tenant, sessionId, prepareParams.getTimeoutBudget(), ignoreSessionStaleFailure); + return result; } /** @@ -567,7 +562,6 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye return logRetriever.getLogs(logServerURI); } - // ---------------- Methods to do call against tester containers in hosted ------------------------------ public HttpResponse getTesterStatus(ApplicationId applicationId) { 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 6d57239fc4a..288df341f2a 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 @@ -151,7 +151,6 @@ public class ModelContextImpl implements ModelContext { private final boolean useThreePhaseUpdates; private final Optional<EndpointCertificateSecrets> endpointCertificateSecrets; private final double defaultTermwiseLimit; - private final double defaultSoftStartSeconds; private final double threadPoolSizeFactor; private final double queueSizefactor; private final Optional<AthenzDomain> athenzDomain; @@ -187,8 +186,6 @@ public class ModelContextImpl implements ModelContext { this.endpointCertificateSecrets = endpointCertificateSecrets; defaultTermwiseLimit = Flags.DEFAULT_TERM_WISE_LIMIT.bindTo(flagSource) .with(FetchVector.Dimension.APPLICATION_ID, applicationId.serializedForm()).value(); - defaultSoftStartSeconds = Flags.DEFAULT_SOFT_START_SECONDS.bindTo(flagSource) - .with(FetchVector.Dimension.APPLICATION_ID, applicationId.serializedForm()).value(); useDistributorBtreeDb = Flags.USE_DISTRIBUTOR_BTREE_DB.bindTo(flagSource) .with(FetchVector.Dimension.APPLICATION_ID, applicationId.serializedForm()).value(); useThreePhaseUpdates = Flags.USE_THREE_PHASE_UPDATES.bindTo(flagSource) @@ -256,10 +253,6 @@ public class ModelContextImpl implements ModelContext { return queueSizefactor; } - public double defaultSoftStartSeconds() { - return defaultSoftStartSeconds; - } - @Override public boolean useDistributorBtreeDb() { return useDistributorBtreeDb; diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationApiHandler.java b/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationApiHandler.java index ef510b7dc37..dedd96da6f3 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationApiHandler.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationApiHandler.java @@ -7,6 +7,7 @@ import com.yahoo.config.provision.TenantName; import com.yahoo.config.provision.Zone; import com.yahoo.container.jdisc.HttpRequest; import com.yahoo.container.jdisc.HttpResponse; +import com.yahoo.jdisc.application.BindingMatch; import com.yahoo.vespa.config.server.ApplicationRepository; import com.yahoo.vespa.config.server.application.CompressedApplicationInputStream; import com.yahoo.vespa.config.server.http.SessionHandler; @@ -18,6 +19,10 @@ import com.yahoo.vespa.config.server.tenant.TenantRepository; import java.time.Duration; import java.time.Instant; +import static com.yahoo.vespa.config.server.application.CompressedApplicationInputStream.createFromCompressedStream; +import static com.yahoo.vespa.config.server.http.Utils.checkThatTenantExists; +import static com.yahoo.vespa.config.server.http.v2.SessionCreateHandler.validateDataAndHeader; + /** * * The implementation of the /application/v2 API. * @@ -46,31 +51,16 @@ public class ApplicationApiHandler extends SessionHandler { } @Override - protected HttpResponse handlePUT(HttpRequest request) { - Tenant tenant = getExistingTenant(request); - TenantName tenantName = tenant.getName(); - long sessionId = getSessionIdV2(request); - PrepareParams prepareParams = PrepareParams.fromHttpRequest(request, tenantName, zookeeperBarrierTimeout); - - PrepareResult result = applicationRepository.prepareAndActivate(tenant, sessionId, prepareParams, - shouldIgnoreSessionStaleFailure(request), - Instant.now()); - return new SessionPrepareAndActivateResponse(result, tenantName, request, prepareParams.getApplicationId(), zone); - } - - @Override protected HttpResponse handlePOST(HttpRequest request) { - Tenant tenant = getExistingTenant(request); - TenantName tenantName = tenant.getName(); - PrepareParams prepareParams = PrepareParams.fromHttpRequest(request, tenantName, zookeeperBarrierTimeout); - SessionCreateHandler.validateDataAndHeader(request); - - PrepareResult result = - applicationRepository.deploy(CompressedApplicationInputStream.createFromCompressedStream(request.getData(), request.getHeader(contentTypeHeader)), - prepareParams, - shouldIgnoreSessionStaleFailure(request), - Instant.now()); - return new SessionPrepareAndActivateResponse(result, tenantName, request, prepareParams.getApplicationId(), zone); + validateDataAndHeader(request); + Tenant tenant = validateTenant(request); + PrepareParams prepareParams = PrepareParams.fromHttpRequest(request, tenant.getName(), zookeeperBarrierTimeout); + CompressedApplicationInputStream compressedStream = createFromCompressedStream(request.getData(), request.getHeader(contentTypeHeader)); + PrepareResult result = applicationRepository.deploy(compressedStream, + prepareParams, + shouldIgnoreSessionStaleFailure(request), + Instant.now()); + return new SessionPrepareAndActivateResponse(result, request, prepareParams.getApplicationId(), zone); } @Override @@ -78,10 +68,15 @@ public class ApplicationApiHandler extends SessionHandler { return zookeeperBarrierTimeout.plus(Duration.ofSeconds(10)); } - private Tenant getExistingTenant(HttpRequest request) { - TenantName tenantName = Utils.getTenantNameFromSessionRequest(request); - Utils.checkThatTenantExists(tenantRepository, tenantName); + private Tenant validateTenant(HttpRequest request) { + TenantName tenantName = getTenantNameFromRequest(request); + checkThatTenantExists(tenantRepository, tenantName); return tenantRepository.getTenant(tenantName); } + public static TenantName getTenantNameFromRequest(HttpRequest request) { + BindingMatch<?> bm = Utils.getBindingMatch(request, "http://*/application/v2/tenant/*/prepareandactivate*"); + return TenantName.from(bm.group(2)); + } + } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/SessionPrepareAndActivateResponse.java b/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/SessionPrepareAndActivateResponse.java index 4665a33c647..7d9a0b11c28 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/SessionPrepareAndActivateResponse.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/SessionPrepareAndActivateResponse.java @@ -5,8 +5,6 @@ import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.TenantName; import com.yahoo.config.provision.Zone; import com.yahoo.container.jdisc.HttpRequest; -import com.yahoo.slime.Slime; -import com.yahoo.vespa.config.server.configchange.ConfigChangeActions; import com.yahoo.vespa.config.server.configchange.ConfigChangeActionsSlimeConverter; import com.yahoo.vespa.config.server.http.SessionResponse; @@ -17,17 +15,10 @@ import com.yahoo.vespa.config.server.http.SessionResponse; */ class SessionPrepareAndActivateResponse extends SessionResponse { - SessionPrepareAndActivateResponse(PrepareResult result, TenantName tenantName, HttpRequest request, - ApplicationId applicationId, Zone zone) { - this(result.deployLog(), tenantName, request, result.sessionId(), result.configChangeActions(), - zone, applicationId); - } - - private SessionPrepareAndActivateResponse(Slime deployLog, TenantName tenantName, HttpRequest request, - long sessionId, ConfigChangeActions actions, Zone zone, - ApplicationId applicationId) { - super(deployLog, deployLog.get()); - String message = "Session " + sessionId + " for tenant '" + tenantName.value() + "' prepared and activated."; + SessionPrepareAndActivateResponse(PrepareResult result, HttpRequest request, ApplicationId applicationId, Zone zone) { + super(result.deployLog(), result.deployLog().get()); + TenantName tenantName = applicationId.tenant(); + String message = "Session " + result.sessionId() + " for tenant '" + tenantName.value() + "' prepared and activated."; this.root.setString("tenant", tenantName.value()); root.setString("url", "http://" + request.getHost() + ":" + request.getPort() + "/application/v2/tenant/" + tenantName + @@ -36,7 +27,7 @@ class SessionPrepareAndActivateResponse extends SessionResponse { "/region/" + zone.region().value() + "/instance/" + applicationId.instance().value()); root.setString("message", message); - new ConfigChangeActionsSlimeConverter(actions).toSlime(root); + new ConfigChangeActionsSlimeConverter(result.configChangeActions()).toSlime(root); } } diff --git a/configserver/src/main/resources/configserver-app/services.xml b/configserver/src/main/resources/configserver-app/services.xml index 0cd283ca62b..d3b39e572ee 100644 --- a/configserver/src/main/resources/configserver-app/services.xml +++ b/configserver/src/main/resources/configserver-app/services.xml @@ -106,7 +106,6 @@ </handler> <handler id='com.yahoo.vespa.config.server.http.v2.ApplicationApiHandler' bundle='configserver'> <binding>http://*/application/v2/tenant/*/prepareandactivate</binding> - <binding>http://*/application/v2/tenant/*/session/*/prepareandactivate</binding> </handler> <handler id='com.yahoo.vespa.config.server.http.v2.SessionContentHandler' bundle='configserver'> <binding>http://*/application/v2/tenant/*/session/*/content/*</binding> diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/ApplicationRepositoryTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/ApplicationRepositoryTest.java index ba035ceec59..f37f4b79f99 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/ApplicationRepositoryTest.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/ApplicationRepositoryTest.java @@ -4,7 +4,6 @@ package com.yahoo.vespa.config.server; import com.yahoo.cloud.config.ConfigserverConfig; import com.yahoo.config.application.api.ApplicationMetaData; import com.yahoo.config.model.api.ApplicationRoles; -import com.yahoo.config.model.application.provider.FilesApplicationPackage; import com.yahoo.config.provision.AllocatedHosts; import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.ApplicationName; @@ -108,8 +107,8 @@ public class ApplicationRepositoryTest { } @Test - public void prepareAndActivate() throws IOException { - PrepareResult result = prepareAndActivateApp(testApp); + public void prepareAndActivate() { + PrepareResult result = prepareAndActivate(testApp); assertTrue(result.configChangeActions().getRefeedActions().isEmpty()); assertTrue(result.configChangeActions().getRestartActions().isEmpty()); @@ -121,9 +120,9 @@ public class ApplicationRepositoryTest { } @Test - public void prepareAndActivateWithRestart() throws IOException { - prepareAndActivateApp(testAppJdiscOnly); - PrepareResult result = prepareAndActivateApp(testAppJdiscOnlyRestart); + public void prepareAndActivateWithRestart() { + prepareAndActivate(testAppJdiscOnly); + PrepareResult result = prepareAndActivate(testAppJdiscOnlyRestart); assertTrue(result.configChangeActions().getRefeedActions().isEmpty()); assertFalse(result.configChangeActions().getRestartActions().isEmpty()); } @@ -404,8 +403,8 @@ public class ApplicationRepositoryTest { } @Test - public void require_that_provision_info_can_be_read() throws Exception { - prepareAndActivateApp(testAppJdiscOnly); + public void require_that_provision_info_can_be_read() { + prepareAndActivate(testAppJdiscOnly); TenantName tenantName = applicationId().tenant(); Tenant tenant = tenantRepository.getTenant(tenantName); @@ -455,12 +454,8 @@ public class ApplicationRepositoryTest { new NullMetric()); } - private PrepareResult prepareAndActivateApp(File application) throws IOException { - FilesApplicationPackage appDir = FilesApplicationPackage.fromFile(application); - ApplicationId applicationId = applicationId(); - long sessionId = applicationRepository.createSession(applicationId, timeoutBudget, appDir.getAppDir()); - return applicationRepository.prepareAndActivate(tenantRepository.getTenant(applicationId.tenant()), - sessionId, prepareParams(), false, Instant.now()); + private PrepareResult prepareAndActivate(File application) { + return applicationRepository.deploy(application, prepareParams(), false, Instant.now()); } private PrepareResult deployApp(File applicationPackage) { diff --git a/container-core/abi-spec.json b/container-core/abi-spec.json index 82d34d88b99..b4720bd725d 100644 --- a/container-core/abi-spec.json +++ b/container-core/abi-spec.json @@ -173,7 +173,6 @@ "public com.yahoo.container.handler.ThreadpoolConfig$Builder maxthreads(int)", "public com.yahoo.container.handler.ThreadpoolConfig$Builder queueSize(int)", "public com.yahoo.container.handler.ThreadpoolConfig$Builder maxThreadExecutionTimeSeconds(int)", - "public com.yahoo.container.handler.ThreadpoolConfig$Builder softStartSeconds(double)", "public final boolean dispatchGetConfig(com.yahoo.config.ConfigInstance$Producer)", "public final java.lang.String getDefMd5()", "public final java.lang.String getDefName()", @@ -212,8 +211,7 @@ "public void <init>(com.yahoo.container.handler.ThreadpoolConfig$Builder)", "public int maxthreads()", "public int queueSize()", - "public int maxThreadExecutionTimeSeconds()", - "public double softStartSeconds()" + "public int maxThreadExecutionTimeSeconds()" ], "fields": [ "public static final java.lang.String CONFIG_DEF_MD5", diff --git a/container-core/src/main/resources/configdefinitions/threadpool.def b/container-core/src/main/resources/configdefinitions/threadpool.def index abc60f9f06d..81e77c51194 100644 --- a/container-core/src/main/resources/configdefinitions/threadpool.def +++ b/container-core/src/main/resources/configdefinitions/threadpool.def @@ -16,8 +16,3 @@ queueSize int default=0 # get out of a bad state. This should be set a bit higher than the expected max execution # time of each request when in a state of overload, i.e about "worst case execution time*2" maxThreadExecutionTimeSeconds int default=190 - -# Length of period for soft start -# During this period number of availble threads will be gradually increased. -# Currently used to avoid feeding overload in container during cold start. -softStartSeconds double default=0 diff --git a/eval/src/tests/eval/tensor_lambda/tensor_lambda_test.cpp b/eval/src/tests/eval/tensor_lambda/tensor_lambda_test.cpp index 3c35f90c521..c8091fd7c6e 100644 --- a/eval/src/tests/eval/tensor_lambda/tensor_lambda_test.cpp +++ b/eval/src/tests/eval/tensor_lambda/tensor_lambda_test.cpp @@ -8,6 +8,7 @@ #include <vespa/eval/tensor/dense/dense_replace_type_function.h> #include <vespa/eval/tensor/dense/dense_cell_range_function.h> #include <vespa/eval/tensor/dense/dense_lambda_peek_function.h> +#include <vespa/eval/tensor/dense/dense_lambda_function.h> #include <vespa/eval/tensor/dense/dense_fast_rename_optimizer.h> #include <vespa/eval/tensor/dense/dense_tensor.h> #include <vespa/eval/eval/test/tensor_model.hpp> @@ -23,11 +24,27 @@ using namespace vespalib::eval::test; using namespace vespalib::tensor; using namespace vespalib::eval::tensor_function; +using EvalMode = DenseLambdaFunction::EvalMode; + +namespace vespalib::tensor { + +std::ostream &operator<<(std::ostream &os, EvalMode eval_mode) +{ + switch(eval_mode) { + case EvalMode::COMPILED: return os << "COMPILED"; + case EvalMode::INTERPRETED: return os << "INTERPRETED"; + } + abort(); +} + +} + const TensorEngine &prod_engine = DefaultTensorEngine::ref(); EvalFixture::ParamRepo make_params() { return EvalFixture::ParamRepo() .add("a", spec(1)) + .add("b", spec(2)) .add("x3", spec({x(3)}, N())) .add("x3f", spec(float_cells({x(3)}), N())) .add("x3m", spec({x({"0", "1", "2"})}, N())) @@ -55,8 +72,14 @@ void verify_impl(const vespalib::string &expr, const vespalib::string &expect) { verify_impl<T>(expr, expect, [](const T*){}); } -void verify_generic(const vespalib::string &expr, const vespalib::string &expect) { - verify_impl<Lambda>(expr, expect); +void verify_generic(const vespalib::string &expr, const vespalib::string &expect, + EvalMode expect_eval_mode) +{ + verify_impl<DenseLambdaFunction>(expr, expect, + [&](const DenseLambdaFunction *info) + { + EXPECT_EQUAL(info->eval_mode(), expect_eval_mode); + }); } void verify_reshape(const vespalib::string &expr, const vespalib::string &expect) { @@ -67,8 +90,8 @@ void verify_range(const vespalib::string &expr, const vespalib::string &expect) verify_impl<DenseCellRangeFunction>(expr, expect); } -void verify_compiled(const vespalib::string &expr, const vespalib::string &expect, - const vespalib::string &expect_idx_fun) +void verify_idx_fun(const vespalib::string &expr, const vespalib::string &expect, + const vespalib::string &expect_idx_fun) { verify_impl<DenseLambdaPeekFunction>(expr, expect, [&](const DenseLambdaPeekFunction *info) @@ -88,22 +111,32 @@ TEST("require that simple constant tensor lambda works") { } TEST("require that simple dynamic tensor lambda works") { - TEST_DO(verify_generic("tensor(x[3])(x+a)", "tensor(x[3]):[1,2,3]")); + TEST_DO(verify_generic("tensor(x[3])(x+a)", "tensor(x[3]):[1,2,3]", EvalMode::COMPILED)); +} + +TEST("require that compiled multi-dimensional multi-param dynamic tensor lambda works") { + TEST_DO(verify_generic("tensor(x[3],y[2])((b-a)+x+y)", "tensor(x[3],y[2]):[[1,2],[2,3],[3,4]]", EvalMode::COMPILED)); + TEST_DO(verify_generic("tensor<float>(x[3],y[2])((b-a)+x+y)", "tensor<float>(x[3],y[2]):[[1,2],[2,3],[3,4]]", EvalMode::COMPILED)); +} + +TEST("require that interpreted multi-dimensional multi-param dynamic tensor lambda works") { + TEST_DO(verify_generic("tensor(x[3],y[2])((x3{x:(a)}-a)+x+y)", "tensor(x[3],y[2]):[[1,2],[2,3],[3,4]]", EvalMode::INTERPRETED)); + TEST_DO(verify_generic("tensor<float>(x[3],y[2])((x3{x:(a)}-a)+x+y)", "tensor<float>(x[3],y[2]):[[1,2],[2,3],[3,4]]", EvalMode::INTERPRETED)); } TEST("require that tensor lambda can be used for tensor slicing") { - TEST_DO(verify_generic("tensor(x[2])(x3{x:(x+a)})", "tensor(x[2]):[2,3]")); - TEST_DO(verify_generic("tensor(x[2])(a+x3{x:(x)})", "tensor(x[2]):[2,3]")); + TEST_DO(verify_generic("tensor(x[2])(x3{x:(x+a)})", "tensor(x[2]):[2,3]", EvalMode::INTERPRETED)); + TEST_DO(verify_generic("tensor(x[2])(a+x3{x:(x)})", "tensor(x[2]):[2,3]", EvalMode::INTERPRETED)); } TEST("require that tensor lambda can be used for cell type casting") { - TEST_DO(verify_compiled("tensor(x[3])(x3f{x:(x)})", "tensor(x[3]):[1,2,3]", "f(x)(x)")); - TEST_DO(verify_compiled("tensor<float>(x[3])(x3{x:(x)})", "tensor<float>(x[3]):[1,2,3]", "f(x)(x)")); + TEST_DO(verify_idx_fun("tensor(x[3])(x3f{x:(x)})", "tensor(x[3]):[1,2,3]", "f(x)(x)")); + TEST_DO(verify_idx_fun("tensor<float>(x[3])(x3{x:(x)})", "tensor<float>(x[3]):[1,2,3]", "f(x)(x)")); } TEST("require that tensor lambda can be used to convert from sparse to dense tensors") { - TEST_DO(verify_generic("tensor(x[3])(x3m{x:(x)})", "tensor(x[3]):[1,2,3]")); - TEST_DO(verify_generic("tensor(x[2])(x3m{x:(x)})", "tensor(x[2]):[1,2]")); + TEST_DO(verify_generic("tensor(x[3])(x3m{x:(x)})", "tensor(x[3]):[1,2,3]", EvalMode::INTERPRETED)); + TEST_DO(verify_generic("tensor(x[2])(x3m{x:(x)})", "tensor(x[2]):[1,2]", EvalMode::INTERPRETED)); } TEST("require that constant nested tensor lambda using tensor peek works") { @@ -111,7 +144,7 @@ TEST("require that constant nested tensor lambda using tensor peek works") { } TEST("require that dynamic nested tensor lambda using tensor peek works") { - TEST_DO(verify_generic("tensor(x[2])(tensor(y[2])((x+y)+a){y:(x)})", "tensor(x[2]):[1,3]")); + TEST_DO(verify_generic("tensor(x[2])(tensor(y[2])((x+y)+a){y:(x)})", "tensor(x[2]):[1,3]", EvalMode::INTERPRETED)); } TEST("require that tensor reshape is optimized") { @@ -121,10 +154,10 @@ TEST("require that tensor reshape is optimized") { } TEST("require that tensor reshape with non-matching cell type requires cell copy") { - TEST_DO(verify_compiled("tensor(x[15])(x3y5f{x:(x/5),y:(x%5)})", "x15", "f(x)((floor((x/5))*5)+(x%5))")); - TEST_DO(verify_compiled("tensor<float>(x[15])(x3y5{x:(x/5),y:(x%5)})", "x15f", "f(x)((floor((x/5))*5)+(x%5))")); - TEST_DO(verify_compiled("tensor(x[3],y[5])(x15f{x:(x*5+y)})", "x3y5", "f(x,y)((x*5)+y)")); - TEST_DO(verify_compiled("tensor<float>(x[3],y[5])(x15{x:(x*5+y)})", "x3y5f", "f(x,y)((x*5)+y)")); + TEST_DO(verify_idx_fun("tensor(x[15])(x3y5f{x:(x/5),y:(x%5)})", "x15", "f(x)((floor((x/5))*5)+(x%5))")); + TEST_DO(verify_idx_fun("tensor<float>(x[15])(x3y5{x:(x/5),y:(x%5)})", "x15f", "f(x)((floor((x/5))*5)+(x%5))")); + TEST_DO(verify_idx_fun("tensor(x[3],y[5])(x15f{x:(x*5+y)})", "x3y5", "f(x,y)((x*5)+y)")); + TEST_DO(verify_idx_fun("tensor<float>(x[3],y[5])(x15{x:(x*5+y)})", "x3y5f", "f(x,y)((x*5)+y)")); } TEST("require that tensor cell subrange view is optimized") { @@ -135,22 +168,22 @@ TEST("require that tensor cell subrange view is optimized") { } TEST("require that tensor cell subrange with non-matching cell type requires cell copy") { - TEST_DO(verify_compiled("tensor(x[3])(x15f{x:(x+5)})", "tensor(x[3]):[6,7,8]", "f(x)(x+5)")); - TEST_DO(verify_compiled("tensor<float>(x[3])(x15{x:(x+5)})", "tensor<float>(x[3]):[6,7,8]", "f(x)(x+5)")); + TEST_DO(verify_idx_fun("tensor(x[3])(x15f{x:(x+5)})", "tensor(x[3]):[6,7,8]", "f(x)(x+5)")); + TEST_DO(verify_idx_fun("tensor<float>(x[3])(x15{x:(x+5)})", "tensor<float>(x[3]):[6,7,8]", "f(x)(x+5)")); } TEST("require that non-continuous cell extraction is optimized") { - TEST_DO(verify_compiled("tensor(x[3])(x3y5{x:(x),y:2})", "x3y5{y:2}", "f(x)((floor(x)*5)+2)")); - TEST_DO(verify_compiled("tensor(x[3])(x3y5f{x:(x),y:2})", "x3y5{y:2}", "f(x)((floor(x)*5)+2)")); - TEST_DO(verify_compiled("tensor<float>(x[3])(x3y5{x:(x),y:2})", "x3y5f{y:2}", "f(x)((floor(x)*5)+2)")); - TEST_DO(verify_compiled("tensor<float>(x[3])(x3y5f{x:(x),y:2})", "x3y5f{y:2}", "f(x)((floor(x)*5)+2)")); + TEST_DO(verify_idx_fun("tensor(x[3])(x3y5{x:(x),y:2})", "x3y5{y:2}", "f(x)((floor(x)*5)+2)")); + TEST_DO(verify_idx_fun("tensor(x[3])(x3y5f{x:(x),y:2})", "x3y5{y:2}", "f(x)((floor(x)*5)+2)")); + TEST_DO(verify_idx_fun("tensor<float>(x[3])(x3y5{x:(x),y:2})", "x3y5f{y:2}", "f(x)((floor(x)*5)+2)")); + TEST_DO(verify_idx_fun("tensor<float>(x[3])(x3y5f{x:(x),y:2})", "x3y5f{y:2}", "f(x)((floor(x)*5)+2)")); } TEST("require that out-of-bounds cell extraction is not optimized") { - TEST_DO(verify_generic("tensor(x[3])(x3y5{x:1,y:(x+3)})", "tensor(x[3]):[9,10,0]")); - TEST_DO(verify_generic("tensor(x[3])(x3y5{x:1,y:(x-1)})", "tensor(x[3]):[0,6,7]")); - TEST_DO(verify_generic("tensor(x[3])(x3y5{x:(x+1),y:(x)})", "tensor(x[3]):[6,12,0]")); - TEST_DO(verify_generic("tensor(x[3])(x3y5{x:(x-1),y:(x)})", "tensor(x[3]):[0,2,8]")); + TEST_DO(verify_generic("tensor(x[3])(x3y5{x:1,y:(x+3)})", "tensor(x[3]):[9,10,0]", EvalMode::INTERPRETED)); + TEST_DO(verify_generic("tensor(x[3])(x3y5{x:1,y:(x-1)})", "tensor(x[3]):[0,6,7]", EvalMode::INTERPRETED)); + TEST_DO(verify_generic("tensor(x[3])(x3y5{x:(x+1),y:(x)})", "tensor(x[3]):[6,12,0]", EvalMode::INTERPRETED)); + TEST_DO(verify_generic("tensor(x[3])(x3y5{x:(x-1),y:(x)})", "tensor(x[3]):[0,2,8]", EvalMode::INTERPRETED)); } TEST("require that non-double result from inner tensor lambda function fails type resolving") { diff --git a/eval/src/vespa/eval/eval/tensor_function.cpp b/eval/src/vespa/eval/eval/tensor_function.cpp index 2656e240a5b..1aa18417b87 100644 --- a/eval/src/vespa/eval/eval/tensor_function.cpp +++ b/eval/src/vespa/eval/eval/tensor_function.cpp @@ -134,9 +134,16 @@ void op_tensor_create(State &state, uint64_t param) { state.pop_n_push(i, result); } +struct LambdaParams { + const Lambda &parent; + InterpretedFunction fun; + LambdaParams(const Lambda &parent_in, InterpretedFunction fun_in) + : parent(parent_in), fun(std::move(fun_in)) {} +}; + void op_tensor_lambda(State &state, uint64_t param) { - const Lambda::Self &self = unwrap_param<Lambda::Self>(param); - TensorSpec spec = self.parent.create_spec(*state.params, self.fun); + const LambdaParams ¶ms = unwrap_param<LambdaParams>(param); + TensorSpec spec = params.parent.create_spec(*state.params, params.fun); const Value &result = *state.stash.create<Value::UP>(state.engine.from_spec(spec)); state.stack.emplace_back(result); } @@ -439,13 +446,8 @@ InterpretedFunction::Instruction Lambda::compile_self(const TensorEngine &engine, Stash &stash) const { InterpretedFunction fun(engine, _lambda->root(), _lambda_types); - Self &self = stash.create<Self>(*this, std::move(fun)); - return Instruction(op_tensor_lambda, wrap_param<Self>(self)); -} - -void -Lambda::push_children(std::vector<Child::CREF> &) const -{ + LambdaParams ¶ms = stash.create<LambdaParams>(*this, std::move(fun)); + return Instruction(op_tensor_lambda, wrap_param<LambdaParams>(params)); } void diff --git a/eval/src/vespa/eval/eval/tensor_function.h b/eval/src/vespa/eval/eval/tensor_function.h index e1961079017..6743f37eeb1 100644 --- a/eval/src/vespa/eval/eval/tensor_function.h +++ b/eval/src/vespa/eval/eval/tensor_function.h @@ -183,7 +183,7 @@ class ConstValue : public Leaf private: const Value &_value; public: - ConstValue(const Value &value_in) : Leaf(value_in.type()), _value(value_in) {} + ConstValue(const Value &value_in) : Super(value_in.type()), _value(value_in) {} const Value &value() const { return _value; } bool result_is_mutable() const override { return false; } InterpretedFunction::Instruction compile_self(const TensorEngine &engine, Stash &stash) const final override; @@ -199,7 +199,7 @@ private: size_t _param_idx; public: Inject(const ValueType &result_type_in, size_t param_idx_in) - : Leaf(result_type_in), _param_idx(param_idx_in) {} + : Super(result_type_in), _param_idx(param_idx_in) {} size_t param_idx() const { return _param_idx; } bool result_is_mutable() const override { return false; } InterpretedFunction::Instruction compile_self(const TensorEngine &engine, Stash &stash) const final override; @@ -219,7 +219,7 @@ public: const TensorFunction &child_in, Aggr aggr_in, const std::vector<vespalib::string> &dimensions_in) - : Op1(result_type_in, child_in), _aggr(aggr_in), _dimensions(dimensions_in) {} + : Super(result_type_in, child_in), _aggr(aggr_in), _dimensions(dimensions_in) {} Aggr aggr() const { return _aggr; } const std::vector<vespalib::string> &dimensions() const { return _dimensions; } bool result_is_mutable() const override { return true; } @@ -238,7 +238,7 @@ public: Map(const ValueType &result_type_in, const TensorFunction &child_in, map_fun_t function_in) - : Op1(result_type_in, child_in), _function(function_in) {} + : Super(result_type_in, child_in), _function(function_in) {} map_fun_t function() const { return _function; } bool result_is_mutable() const override { return true; } InterpretedFunction::Instruction compile_self(const TensorEngine &engine, Stash &stash) const override; @@ -257,7 +257,7 @@ public: const TensorFunction &lhs_in, const TensorFunction &rhs_in, join_fun_t function_in) - : Op2(result_type_in, lhs_in, rhs_in), _function(function_in) {} + : Super(result_type_in, lhs_in, rhs_in), _function(function_in) {} join_fun_t function() const { return _function; } bool result_is_mutable() const override { return true; } InterpretedFunction::Instruction compile_self(const TensorEngine &engine, Stash &stash) const override; @@ -276,7 +276,7 @@ public: const TensorFunction &lhs_in, const TensorFunction &rhs_in, join_fun_t function_in) - : Op2(result_type_in, lhs_in, rhs_in), _function(function_in) {} + : Super(result_type_in, lhs_in, rhs_in), _function(function_in) {} join_fun_t function() const { return _function; } bool result_is_mutable() const override { return true; } InterpretedFunction::Instruction compile_self(const TensorEngine &engine, Stash &stash) const override; @@ -295,7 +295,7 @@ public: const TensorFunction &lhs_in, const TensorFunction &rhs_in, const vespalib::string &dimension_in) - : Op2(result_type_in, lhs_in, rhs_in), _dimension(dimension_in) {} + : Super(result_type_in, lhs_in, rhs_in), _dimension(dimension_in) {} const vespalib::string &dimension() const { return _dimension; } bool result_is_mutable() const override { return true; } InterpretedFunction::Instruction compile_self(const TensorEngine &engine, Stash &stash) const final override; @@ -311,7 +311,7 @@ private: std::map<TensorSpec::Address, Child> _spec; public: Create(const ValueType &result_type_in, const std::map<TensorSpec::Address, Node::CREF> &spec_in) - : Node(result_type_in), _spec() + : Super(result_type_in), _spec() { for (const auto &cell: spec_in) { _spec.emplace(cell.first, Child(cell.second)); @@ -326,23 +326,16 @@ public: //----------------------------------------------------------------------------- -class Lambda : public Node +class Lambda : public Leaf { - using Super = Node; -public: - struct Self { - const Lambda &parent; - InterpretedFunction fun; - Self(const Lambda &parent_in, InterpretedFunction fun_in) - : parent(parent_in), fun(std::move(fun_in)) {} - }; + using Super = Leaf; private: std::vector<size_t> _bindings; std::shared_ptr<Function const> _lambda; NodeTypes _lambda_types; public: Lambda(const ValueType &result_type_in, const std::vector<size_t> &bindings_in, const Function &lambda_in, NodeTypes lambda_types_in) - : Node(result_type_in), _bindings(bindings_in), _lambda(lambda_in.shared_from_this()), _lambda_types(std::move(lambda_types_in)) {} + : Super(result_type_in), _bindings(bindings_in), _lambda(lambda_in.shared_from_this()), _lambda_types(std::move(lambda_types_in)) {} const std::vector<size_t> &bindings() const { return _bindings; } const Function &lambda() const { return *_lambda; } const NodeTypes &types() const { return _lambda_types; } @@ -352,7 +345,6 @@ public: } bool result_is_mutable() const override { return true; } InterpretedFunction::Instruction compile_self(const TensorEngine &engine, Stash &stash) const final override; - void push_children(std::vector<Child::CREF> &children) const final override; void visit_self(vespalib::ObjectVisitor &visitor) const override; }; @@ -369,7 +361,7 @@ private: public: Peek(const ValueType &result_type_in, const Node ¶m, const std::map<vespalib::string, std::variant<TensorSpec::Label, Node::CREF>> &spec) - : Node(result_type_in), _param(param), _spec() + : Super(result_type_in), _param(param), _spec() { for (const auto &dim: spec) { std::visit(vespalib::overload @@ -404,7 +396,7 @@ public: const TensorFunction &child_in, const std::vector<vespalib::string> &from_in, const std::vector<vespalib::string> &to_in) - : Op1(result_type_in, child_in), _from(from_in), _to(to_in) {} + : Super(result_type_in, child_in), _from(from_in), _to(to_in) {} const std::vector<vespalib::string> &from() const { return _from; } const std::vector<vespalib::string> &to() const { return _to; } bool result_is_mutable() const override { return true; } diff --git a/eval/src/vespa/eval/tensor/default_tensor_engine.cpp b/eval/src/vespa/eval/tensor/default_tensor_engine.cpp index d28e420e6f2..d374848af64 100644 --- a/eval/src/vespa/eval/tensor/default_tensor_engine.cpp +++ b/eval/src/vespa/eval/tensor/default_tensor_engine.cpp @@ -17,6 +17,7 @@ #include "dense/dense_single_reduce_function.h" #include "dense/dense_remove_dimension_optimizer.h" #include "dense/dense_lambda_peek_optimizer.h" +#include "dense/dense_lambda_function.h" #include "dense/dense_simple_join_function.h" #include "dense/dense_simple_map_function.h" #include "dense/vector_from_doubles_function.h" @@ -289,6 +290,7 @@ DefaultTensorEngine::optimize(const TensorFunction &expr, Stash &stash) const child.set(DenseTensorCreateFunction::optimize(child.get(), stash)); child.set(DenseTensorPeekFunction::optimize(child.get(), stash)); child.set(DenseLambdaPeekOptimizer::optimize(child.get(), stash)); + child.set(DenseLambdaFunction::optimize(child.get(), stash)); child.set(DenseFastRenameOptimizer::optimize(child.get(), stash)); child.set(DenseSimpleMapFunction::optimize(child.get(), stash)); child.set(DenseSimpleJoinFunction::optimize(child.get(), stash)); diff --git a/eval/src/vespa/eval/tensor/dense/CMakeLists.txt b/eval/src/vespa/eval/tensor/dense/CMakeLists.txt index e0e73ecb3b8..7ababbee228 100644 --- a/eval/src/vespa/eval/tensor/dense/CMakeLists.txt +++ b/eval/src/vespa/eval/tensor/dense/CMakeLists.txt @@ -6,6 +6,7 @@ vespa_add_library(eval_tensor_dense OBJECT dense_dimension_combiner.cpp dense_dot_product_function.cpp dense_fast_rename_optimizer.cpp + dense_lambda_function.cpp dense_lambda_peek_function.cpp dense_lambda_peek_optimizer.cpp dense_matmul_function.cpp diff --git a/eval/src/vespa/eval/tensor/dense/dense_lambda_function.cpp b/eval/src/vespa/eval/tensor/dense/dense_lambda_function.cpp new file mode 100644 index 00000000000..b60d732d7a9 --- /dev/null +++ b/eval/src/vespa/eval/tensor/dense/dense_lambda_function.cpp @@ -0,0 +1,189 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include "dense_lambda_function.h" +#include "dense_tensor_view.h" +#include <vespa/vespalib/objects/objectvisitor.h> +#include <vespa/eval/tensor/default_tensor_engine.h> +#include <vespa/eval/eval/llvm/compiled_function.h> +#include <vespa/eval/eval/llvm/compile_cache.h> +#include <assert.h> + +namespace vespalib::tensor { + +using eval::CompileCache; +using eval::CompiledFunction; +using eval::InterpretedFunction; +using eval::LazyParams; +using eval::PassParams; +using eval::TensorEngine; +using eval::TensorFunction; +using eval::Value; +using eval::DoubleValue; +using eval::ValueType; +using eval::as; +using vespalib::Stash; + +using Instruction = InterpretedFunction::Instruction; +using State = InterpretedFunction::State; + +using namespace eval::tensor_function; + +const TensorEngine &prod_engine = DefaultTensorEngine::ref(); + +namespace { + +//----------------------------------------------------------------------------- + +bool step_labels(double *labels, const ValueType &type) { + for (size_t idx = type.dimensions().size(); idx-- > 0; ) { + if ((labels[idx] += 1.0) < type.dimensions()[idx].size) { + return true; + } else { + labels[idx] = 0.0; + } + } + return false; +} + +struct ParamProxy : public LazyParams { + const std::vector<double> &labels; + const LazyParams ¶ms; + const std::vector<size_t> &bindings; + ParamProxy(const std::vector<double> &labels_in, const LazyParams ¶ms_in, const std::vector<size_t> &bindings_in) + : labels(labels_in), params(params_in), bindings(bindings_in) {} + const Value &resolve(size_t idx, Stash &stash) const override { + if (idx < labels.size()) { + return stash.create<DoubleValue>(labels[idx]); + } + return params.resolve(bindings[idx - labels.size()], stash); + } +}; + +//----------------------------------------------------------------------------- + +struct CompiledParams { + const ValueType &result_type; + const std::vector<size_t> &bindings; + size_t num_cells; + CompileCache::Token::UP token; + CompiledParams(const Lambda &lambda) + : result_type(lambda.result_type()), + bindings(lambda.bindings()), + num_cells(result_type.dense_subspace_size()), + token(CompileCache::compile(lambda.lambda(), PassParams::ARRAY)) + { + assert(lambda.lambda().num_params() == (result_type.dimensions().size() + bindings.size())); + } +}; + +template <typename CT> +void my_compiled_lambda_op(eval::InterpretedFunction::State &state, uint64_t param) { + const CompiledParams ¶ms = *(const CompiledParams*)param; + std::vector<double> args(params.result_type.dimensions().size() + params.bindings.size(), 0.0); + double *bind_next = &args[params.result_type.dimensions().size()]; + for (size_t binding: params.bindings) { + *bind_next++ = state.params->resolve(binding, state.stash).as_double(); + } + auto fun = params.token->get().get_function(); + ArrayRef<CT> dst_cells = state.stash.create_array<CT>(params.num_cells); + CT *dst = &dst_cells[0]; + do { + *dst++ = fun(&args[0]); + } while (step_labels(&args[0], params.result_type)); + state.stack.push_back(state.stash.create<DenseTensorView>(params.result_type, TypedCells(dst_cells))); +} + +struct MyCompiledLambdaOp { + template <typename CT> + static auto get_fun() { return my_compiled_lambda_op<CT>; } +}; + +//----------------------------------------------------------------------------- + +struct InterpretedParams { + const ValueType &result_type; + const std::vector<size_t> &bindings; + size_t num_cells; + InterpretedFunction fun; + InterpretedParams(const Lambda &lambda) + : result_type(lambda.result_type()), + bindings(lambda.bindings()), + num_cells(result_type.dense_subspace_size()), + fun(prod_engine, lambda.lambda().root(), lambda.types()) + { + assert(lambda.lambda().num_params() == (result_type.dimensions().size() + bindings.size())); + } +}; + +template <typename CT> +void my_interpreted_lambda_op(eval::InterpretedFunction::State &state, uint64_t param) { + const InterpretedParams ¶ms = *(const InterpretedParams*)param; + std::vector<double> labels(params.result_type.dimensions().size(), 0.0); + ParamProxy param_proxy(labels, *state.params, params.bindings); + InterpretedFunction::Context ctx(params.fun); + ArrayRef<CT> dst_cells = state.stash.create_array<CT>(params.num_cells); + CT *dst = &dst_cells[0]; + do { + *dst++ = params.fun.eval(ctx, param_proxy).as_double(); + } while (step_labels(&labels[0], params.result_type)); + state.stack.push_back(state.stash.create<DenseTensorView>(params.result_type, TypedCells(dst_cells))); +} + +struct MyInterpretedLambdaOp { + template <typename CT> + static auto get_fun() { return my_interpreted_lambda_op<CT>; } +}; + +//----------------------------------------------------------------------------- + +} + +DenseLambdaFunction::DenseLambdaFunction(const Lambda &lambda_in) + : Super(lambda_in.result_type()), + _lambda(lambda_in) +{ +} + +DenseLambdaFunction::~DenseLambdaFunction() = default; + +DenseLambdaFunction::EvalMode +DenseLambdaFunction::eval_mode() const +{ + if (!CompiledFunction::detect_issues(_lambda.lambda()) && + _lambda.types().all_types_are_double()) + { + return EvalMode::COMPILED; + } else { + return EvalMode::INTERPRETED; + } +} + +Instruction +DenseLambdaFunction::compile_self(const TensorEngine &engine, Stash &stash) const +{ + assert(&engine == &prod_engine); + auto mode = eval_mode(); + if (mode == EvalMode::COMPILED) { + CompiledParams ¶ms = stash.create<CompiledParams>(_lambda); + auto op = select_1<MyCompiledLambdaOp>(result_type().cell_type()); + static_assert(sizeof(¶ms) == sizeof(uint64_t)); + return Instruction(op, (uint64_t)(¶ms)); + } else { + assert(mode == EvalMode::INTERPRETED); + InterpretedParams ¶ms = stash.create<InterpretedParams>(_lambda); + auto op = select_1<MyInterpretedLambdaOp>(result_type().cell_type()); + static_assert(sizeof(¶ms) == sizeof(uint64_t)); + return Instruction(op, (uint64_t)(¶ms)); + } +} + +const eval::TensorFunction & +DenseLambdaFunction::optimize(const TensorFunction &expr, Stash &stash) +{ + if (auto lambda = as<Lambda>(expr)) { + return stash.create<DenseLambdaFunction>(*lambda); + } + return expr; +} + +} diff --git a/eval/src/vespa/eval/tensor/dense/dense_lambda_function.h b/eval/src/vespa/eval/tensor/dense/dense_lambda_function.h new file mode 100644 index 00000000000..a1b6e5a1551 --- /dev/null +++ b/eval/src/vespa/eval/tensor/dense/dense_lambda_function.h @@ -0,0 +1,30 @@ +// Copyright Verizon Media. 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::tensor { + +/** + * Tensor function for generic tensor lambda producing dense tensor + * views directly. This is the catch-all fall-back used by the default + * (production) tensor engine to avoid having a TensorSpec as an + * intermediate result. + **/ +class DenseLambdaFunction : public eval::tensor_function::Leaf +{ + using Super = eval::tensor_function::Leaf; +private: + const eval::tensor_function::Lambda &_lambda; +public: + enum class EvalMode : uint8_t { COMPILED, INTERPRETED }; + DenseLambdaFunction(const eval::tensor_function::Lambda &lambda_in); + ~DenseLambdaFunction() override; + bool result_is_mutable() const override { return true; } + EvalMode eval_mode() const; + eval::InterpretedFunction::Instruction compile_self(const eval::TensorEngine &engine, Stash &stash) const override; + static const eval::TensorFunction &optimize(const eval::TensorFunction &expr, Stash &stash); +}; + +} 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 552878de68a..59926355bda 100644 --- a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java +++ b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java @@ -136,11 +136,6 @@ public class Flags { "Takes effect at redeployment", ZONE_ID, APPLICATION_ID); - public static final UnboundDoubleFlag DEFAULT_SOFT_START_SECONDS = defineDoubleFlag( - "default-soft-start-seconds", 0.0, - "Default number of seconds that a soft start shall use", - "Takes effect at redeployment", - ZONE_ID, APPLICATION_ID); public static final UnboundDoubleFlag DEFAULT_THREADPOOL_SIZE_FACTOR = defineDoubleFlag( "default-threadpool-size-factor", 0.0, "Default multiplication factor when computing maxthreads for main container threadpool based on available cores", @@ -246,7 +241,7 @@ public class Flags { APPLICATION_ID); public static final UnboundLongFlag CONFIGSERVER_SESSIONS_EXPIRY_INTERVAL_IN_DAYS = defineLongFlag( - "configserver-sessions-expiry-interval-in-days", 28, + "configserver-sessions-expiry-interval-in-days", 1, "Expiry time for unused sessions in config server", "Takes effect on next run of config server maintainer SessionsMaintainer"); diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/DiskSize.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/DiskSize.java index 40a11f61d3f..c76c872902d 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/DiskSize.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/task/util/file/DiskSize.java @@ -13,10 +13,11 @@ public class DiskSize { private static final char[] UNITS = "kMGTPE".toCharArray(); public enum Unit { - kB(1000), kiB(1 << 10), + kB(1_000), kiB(1 << 10), MB(1_000_000), MiB(1 << 20), GB(1_000_000_000), GiB(1 << 30), - PB(1_000_000_000_000L), PiB(1L << 40); + TB(1_000_000_000_000L), TiB(1L << 40), + PB(1_000_000_000_000_000L), PiB(1L << 50); private final long size; Unit(long size) { this.size = size; } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocatableClusterResources.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocatableClusterResources.java index 59dbe4bb8d4..e6cbddf96f2 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocatableClusterResources.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocatableClusterResources.java @@ -132,37 +132,30 @@ public class AllocatableClusterResources { .withBandwidthGbps(sum.bandwidthGbps() / nodes.size()); } - /** - * Returns the best matching allocatable node resources given ideal node resources, - * or empty if none available within the limits. - * - * @param resources the real resources that should ideally be allocated - * @param exclusive whether resources should be allocated on entire hosts - * (in which case the allocated resources will be all the real resources of the host - * and limits are required to encompass the full resources of candidate host flavors) - */ - public static Optional<AllocatableClusterResources> from(ClusterResources resources, + public static Optional<AllocatableClusterResources> from(ClusterResources wantedResources, boolean exclusive, ClusterSpec.Type clusterType, - Limits limits, + Limits applicationLimits, NodeRepository nodeRepository) { - NodeResources cappedNodeResources = limits.cap(resources.nodeResources()); - cappedNodeResources = new NodeResourceLimits(nodeRepository).enlargeToLegal(cappedNodeResources, clusterType); - + var systemLimits = new NodeResourceLimits(nodeRepository); if ( !exclusive && nodeRepository.zone().getCloud().allowHostSharing()) { // Check if any flavor can fit these hosts // We decide resources: Add overhead to what we'll request (advertised) to make sure real becomes (at least) cappedNodeResources - NodeResources realResources = cappedNodeResources; - NodeResources advertisedResources = nodeRepository.resourcesCalculator().realToRequest(realResources); + NodeResources advertisedResources = nodeRepository.resourcesCalculator().realToRequest(wantedResources.nodeResources()); + advertisedResources = systemLimits.enlargeToLegal(advertisedResources, clusterType); // Attempt to ask for something legal + advertisedResources = applicationLimits.cap(advertisedResources); // Overrides other conditions, even if it will then fail + NodeResources realResources = nodeRepository.resourcesCalculator().requestToReal(advertisedResources); // ... thus, what we really get may change + if ( ! systemLimits.isWithinRealLimits(realResources, clusterType)) return Optional.empty(); for (Flavor flavor : nodeRepository.flavors().getFlavors()) { if (flavor.resources().satisfies(advertisedResources)) - return Optional.of(new AllocatableClusterResources(resources.with(realResources), + return Optional.of(new AllocatableClusterResources(wantedResources.with(realResources), advertisedResources, - resources.nodeResources(), + wantedResources.nodeResources(), clusterType)); } return Optional.empty(); } else { // Return the cheapest flavor satisfying the requested resources, if any + NodeResources cappedWantedResources = applicationLimits.cap(wantedResources.nodeResources()); Optional<AllocatableClusterResources> best = Optional.empty(); for (Flavor flavor : nodeRepository.flavors().getFlavors()) { // Flavor decide resources: Real resources are the worst case real resources we'll get if we ask for these advertised resources @@ -171,18 +164,19 @@ public class AllocatableClusterResources { // Adjust where we don't need exact match to the flavor if (flavor.resources().storageType() == NodeResources.StorageType.remote) { - advertisedResources = advertisedResources.withDiskGb(cappedNodeResources.diskGb()); - realResources = realResources.withDiskGb(cappedNodeResources.diskGb()); + advertisedResources = advertisedResources.withDiskGb(cappedWantedResources.diskGb()); + realResources = realResources.withDiskGb(cappedWantedResources.diskGb()); } - if (flavor.resources().bandwidthGbps() >= cappedNodeResources.bandwidthGbps()) { - advertisedResources = advertisedResources.withBandwidthGbps(cappedNodeResources.bandwidthGbps()); - realResources = realResources.withBandwidthGbps(cappedNodeResources.bandwidthGbps()); + if (flavor.resources().bandwidthGbps() >= advertisedResources.bandwidthGbps()) { + advertisedResources = advertisedResources.withBandwidthGbps(cappedWantedResources.bandwidthGbps()); + realResources = realResources.withBandwidthGbps(cappedWantedResources.bandwidthGbps()); } - if ( ! between(limits.min().nodeResources(), limits.max().nodeResources(), advertisedResources)) continue; - var candidate = new AllocatableClusterResources(resources.with(realResources), + if ( ! between(applicationLimits.min().nodeResources(), applicationLimits.max().nodeResources(), advertisedResources)) continue; + if ( ! systemLimits.isWithinRealLimits(realResources, clusterType)) continue; + var candidate = new AllocatableClusterResources(wantedResources.with(realResources), advertisedResources, - resources.nodeResources(), + wantedResources.nodeResources(), clusterType); if (best.isEmpty() || candidate.preferableTo(best.get())) best = Optional.of(candidate); diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/InactiveExpirer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/InactiveExpirer.java index fc68deba957..b2c57e984eb 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/InactiveExpirer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/InactiveExpirer.java @@ -39,7 +39,7 @@ public class InactiveExpirer extends Expirer { @Override protected void expire(List<Node> expired) { expired.forEach(node -> { - if (retiredByOperator(node)) { + if (node.status().wantToDeprovision() || retiredByOperator(node)) { nodeRepository.park(node.hostname(), false, Agent.InactiveExpirer, "Expired by InactiveExpirer"); } else { nodeRepository.setDirty(node, Agent.InactiveExpirer, "Expired by InactiveExpirer"); diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeResourceLimits.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeResourceLimits.java index db54fd316f6..06085caa2ee 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeResourceLimits.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeResourceLimits.java @@ -35,12 +35,17 @@ public class NodeResourceLimits { /** Returns whether the real resources we'll end up with on a given tenant node are within limits */ public boolean isWithinRealLimits(Node candidateTenantNode, ClusterSpec cluster) { - NodeResources realResources = nodeRepository.resourcesCalculator().realResourcesOf(candidateTenantNode, nodeRepository); + return isWithinRealLimits(nodeRepository.resourcesCalculator().realResourcesOf(candidateTenantNode, nodeRepository), + cluster.type()); + } - if (realResources.memoryGb() < minRealMemoryGb(cluster.type())) return false; - if (realResources.diskGb() < minRealDiskGb()) return false; + /** Returns whether the real resources we'll end up with on a given tenant node are within limits */ + public boolean isWithinRealLimits(NodeResources realResources, ClusterSpec.Type clusterType) { + if (realResources.isUnspecified()) return true; - return true; + if (realResources.memoryGb() < minRealMemoryGb(clusterType)) return false; + if (realResources.diskGb() < minRealDiskGb()) return false; + return true; } public NodeResources enlargeToLegal(NodeResources requested, ClusterSpec.Type clusterType) { diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java index 864cfad2f41..cc5c6851a92 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java @@ -277,16 +277,16 @@ public class AutoscalingTest { @Test public void autoscaling_avoids_illegal_configurations() { - NodeResources resources = new NodeResources(3, 100, 100, 1); + NodeResources hostResources = new NodeResources(3, 100, 100, 1); ClusterResources min = new ClusterResources( 2, 1, new NodeResources(1, 1, 1, 1)); ClusterResources max = new ClusterResources(20, 1, new NodeResources(100, 1000, 1000, 1)); - AutoscalingTester tester = new AutoscalingTester(resources); + AutoscalingTester tester = new AutoscalingTester(hostResources); ApplicationId application1 = tester.applicationId("application1"); ClusterSpec cluster1 = tester.clusterSpec(ClusterSpec.Type.content, "cluster1"); // deploy - tester.deploy(application1, cluster1, 6, 1, resources); + tester.deploy(application1, cluster1, 6, 1, hostResources); tester.addMeasurements(Resource.memory, 0.02f, 0.95f, 120, application1); tester.assertResources("Scaling down", 6, 1, 2.8, 4.0, 95.0, @@ -325,7 +325,7 @@ public class AutoscalingTest { tester.addMeasurements(Resource.memory, 1.0f, 1000, application1); tester.addMeasurements(Resource.disk, 0.7f, 1000, application1); tester.assertResources("Scaling up", - 4, 1, 7.0, 35, 200, + 4, 1, 7.0, 34, 200, tester.autoscale(application1, cluster1.id(), min, max)); } } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTester.java index 963ca0d4341..b0e394c93d3 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTester.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTester.java @@ -178,11 +178,12 @@ class AutoscalingTester { Optional<ClusterResources> resources) { double delta = 0.0000000001; assertTrue(message, resources.isPresent()); - assertEquals("Node count: " + message, nodeCount, resources.get().nodes()); - assertEquals("Group count: " + message, groupCount, resources.get().groups()); - assertEquals("Cpu: " + message, approxCpu, Math.round(resources.get().nodeResources().vcpu() * 10) / 10.0, delta); - assertEquals("Memory: " + message, approxMemory, Math.round(resources.get().nodeResources().memoryGb() * 10) / 10.0, delta); - assertEquals("Disk: " + message, approxDisk, Math.round(resources.get().nodeResources().diskGb() * 10) / 10.0, delta); + NodeResources nodeResources = resources.get().nodeResources(); + assertEquals("Node count in " + resources.get() + ": " + message, nodeCount, resources.get().nodes()); + assertEquals("Group count in " + resources.get() + ": " + message, groupCount, resources.get().groups()); + assertEquals("Cpu in " + resources.get() + ": " + message, approxCpu, Math.round(nodeResources.vcpu() * 10) / 10.0, delta); + assertEquals("Memory in " + resources.get() + ": " + message, approxMemory, Math.round(nodeResources.memoryGb() * 10) / 10.0, delta); + assertEquals("Disk in: " + resources.get() + ": " + message, approxDisk, Math.round(nodeResources.diskGb() * 10) / 10.0, delta); return resources.get(); } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/InactiveAndFailedExpirerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/InactiveAndFailedExpirerTest.java index 4fcd5793b8a..e42e8e57b8c 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/InactiveAndFailedExpirerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/InactiveAndFailedExpirerTest.java @@ -19,7 +19,6 @@ import com.yahoo.vespa.hosted.provision.node.Agent; import com.yahoo.vespa.hosted.provision.node.History; import com.yahoo.vespa.hosted.provision.provisioning.ProvisioningTester; import com.yahoo.vespa.hosted.provision.testutils.MockDeployer; -import com.yahoo.vespa.hosted.provision.testutils.MockNodeMetrics; import com.yahoo.vespa.orchestrator.OrchestrationException; import com.yahoo.vespa.orchestrator.Orchestrator; import org.junit.Test; @@ -52,7 +51,7 @@ public class InactiveAndFailedExpirerTest { @Test public void inactive_and_failed_times_out() { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); - List<Node> nodes = tester.makeReadyNodes(2, nodeResources); + tester.makeReadyNodes(2, nodeResources); // Allocate then deallocate 2 nodes ClusterSpec cluster = ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("test")).vespaVersion("6.42").build(); @@ -90,7 +89,7 @@ public class InactiveAndFailedExpirerTest { @Test public void reboot_generation_is_increased_when_node_moves_to_dirty() { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); - List<Node> nodes = tester.makeReadyNodes(2, nodeResources); + tester.makeReadyNodes(2, nodeResources); // Allocate and deallocate a single node ClusterSpec cluster = ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("test")).vespaVersion("6.42").build(); @@ -164,7 +163,7 @@ public class InactiveAndFailedExpirerTest { } @Test - public void testersExpireImmediately() { + public void tester_applications_expire_immediately() { ApplicationId testerId = ApplicationId.from(applicationId.tenant().value(), applicationId.application().value(), applicationId.instance().value() + "-t"); @@ -189,4 +188,27 @@ public class InactiveAndFailedExpirerTest { } + @Test + public void nodes_marked_for_deprovisioning_move_to_parked() { + ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))).build(); + tester.makeReadyNodes(5, nodeResources); + + // Activate and deallocate + ClusterSpec cluster = ClusterSpec.request(ClusterSpec.Type.content, ClusterSpec.Id.from("test")).vespaVersion("6.42").build(); + List<HostSpec> preparedNodes = tester.prepare(applicationId, cluster, Capacity.from(new ClusterResources(2, 1, nodeResources))); + tester.activate(applicationId, new HashSet<>(preparedNodes)); + assertEquals(2, tester.getNodes(applicationId, Node.State.active).size()); + tester.deactivate(applicationId); + List<Node> inactiveNodes = tester.getNodes(applicationId, Node.State.inactive).asList(); + assertEquals(2, inactiveNodes.size()); + + // Nodes marked for deprovisioning are moved to parked + tester.nodeRepository().write(inactiveNodes.stream() + .map(node -> node.with(node.status().withWantToDeprovision(true))) + .collect(Collectors.toList()), () -> {}); + tester.advanceTime(Duration.ofMinutes(11)); + new InactiveExpirer(tester.nodeRepository(), tester.clock(), Duration.ofMinutes(10)).run(); + assertEquals(2, tester.nodeRepository().getNodes(Node.State.parked).size()); + } + } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerProvisioningTest.java index 3c1cace3dac..3ffb0dc34f0 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerProvisioningTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DockerProvisioningTest.java @@ -8,6 +8,7 @@ import com.yahoo.config.provision.Capacity; import com.yahoo.config.provision.ClusterResources; import com.yahoo.config.provision.ClusterSpec; import com.yahoo.config.provision.Environment; +import com.yahoo.config.provision.Flavor; import com.yahoo.config.provision.HostSpec; import com.yahoo.config.provision.InstanceName; import com.yahoo.config.provision.NodeResources; @@ -301,6 +302,50 @@ public class DockerProvisioningTest { } } + @Test + public void initial_allocation_is_within_limits() { + Flavor hostFlavor = new Flavor(new NodeResources(20, 40, 100, 4)); + ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))) + .resourcesCalculator(3, 0) + .flavors(List.of(hostFlavor)) + .build(); + tester.makeReadyHosts(2, hostFlavor.resources()).deployZoneApp(); + + ApplicationId app1 = tester.makeApplicationId("app1"); + ClusterSpec cluster1 = ClusterSpec.request(ClusterSpec.Type.content, new ClusterSpec.Id("cluster1")).vespaVersion("7").build(); + + var resources = new NodeResources(1, 8, 10, 1); + tester.activate(app1, cluster1, Capacity.from(new ClusterResources(2, 1, resources), + new ClusterResources(4, 1, resources))); + tester.assertNodes("Initial allocation at min with default resources", + 2, 1, 1, 8, 10, 1.0, + app1, cluster1); + } + + @Test + public void too_few_real_resources_causes_failure() { + try { + Flavor hostFlavor = new Flavor(new NodeResources(20, 40, 100, 4)); + ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))) + .resourcesCalculator(3, 0) + .flavors(List.of(hostFlavor)) + .build(); + tester.makeReadyHosts(2, hostFlavor.resources()).deployZoneApp(); + + ApplicationId app1 = tester.makeApplicationId("app1"); + ClusterSpec cluster1 = ClusterSpec.request(ClusterSpec.Type.content, new ClusterSpec.Id("cluster1")).vespaVersion("7").build(); + + // 5 Gb requested memory becomes 5-3=2 Gb real memory, which is an illegally small amount + var resources = new NodeResources(1, 5, 10, 1); + tester.activate(app1, cluster1, Capacity.from(new ClusterResources(2, 1, resources), + new ClusterResources(4, 1, resources))); + } + catch (IllegalArgumentException e) { + assertEquals("No allocation possible within limits: from 2 nodes with [vcpu: 1.0, memory: 5.0 Gb, disk 10.0 Gb, bandwidth: 1.0 Gbps] to 4 nodes with [vcpu: 1.0, memory: 5.0 Gb, disk 10.0 Gb, bandwidth: 1.0 Gbps]", + e.getMessage()); + } + } + private Set<String> hostsOf(NodeList nodes) { return nodes.asList().stream().map(Node::parentHostname).map(Optional::get).collect(Collectors.toSet()); } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicDockerProvisionTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicDockerProvisionTest.java index 25387a2746c..db6d75d724e 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicDockerProvisionTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/DynamicDockerProvisionTest.java @@ -19,7 +19,6 @@ import com.yahoo.config.provision.RegionName; import com.yahoo.config.provision.SystemName; import com.yahoo.config.provision.Zone; import com.yahoo.vespa.hosted.provision.Node; -import com.yahoo.vespa.hosted.provision.NodeRepository; import com.yahoo.vespa.hosted.provision.node.Agent; import com.yahoo.vespa.hosted.provision.node.IP; import com.yahoo.vespa.hosted.provision.testutils.MockNameResolver; @@ -168,7 +167,7 @@ public class DynamicDockerProvisionTest { .flavors(flavors) .hostProvisioner(new MockHostProvisioner(flavors, memoryTax)) .nameResolver(nameResolver) - .resourcesCalculator(new MockResourcesCalculator(memoryTax, 0)) + .resourcesCalculator(memoryTax, 0) .build(); tester.deployZoneApp(); @@ -214,7 +213,7 @@ public class DynamicDockerProvisionTest { .flavors(flavors) .hostProvisioner(new MockHostProvisioner(flavors, memoryTax)) .nameResolver(nameResolver) - .resourcesCalculator(new MockResourcesCalculator(memoryTax, 0)) + .resourcesCalculator(memoryTax, 0) .build(); tester.deployZoneApp(); @@ -289,7 +288,7 @@ public class DynamicDockerProvisionTest { .flavors(flavors) .hostProvisioner(new MockHostProvisioner(flavors, memoryTax)) .nameResolver(nameResolver) - .resourcesCalculator(new MockResourcesCalculator(memoryTax, 0)) + .resourcesCalculator(memoryTax, 0) .build(); tester.deployZoneApp(); @@ -324,7 +323,7 @@ public class DynamicDockerProvisionTest { .flavors(flavors) .hostProvisioner(new MockHostProvisioner(flavors, memoryTax)) .nameResolver(nameResolver) - .resourcesCalculator(new MockResourcesCalculator(memoryTax, localDiskTax)) + .resourcesCalculator(memoryTax, localDiskTax) .build(); tester.deployZoneApp(); @@ -364,45 +363,6 @@ public class DynamicDockerProvisionTest { }).when(hostProvisioner).provisionHosts(any(), any(), any(), any()); } - private static class MockResourcesCalculator implements HostResourcesCalculator { - - private final int memoryTaxGb; - private final int localDiskTax; - - public MockResourcesCalculator(int memoryTaxGb, int localDiskTax) { - this.memoryTaxGb = memoryTaxGb; - this.localDiskTax = localDiskTax; - } - - @Override - public NodeResources realResourcesOf(Node node, NodeRepository nodeRepository) { - NodeResources resources = node.flavor().resources(); - if (node.type() == NodeType.host) return resources; - return resources.withMemoryGb(resources.memoryGb() - memoryTaxGb) - .withDiskGb(resources.diskGb() - ( resources.storageType() == local ? localDiskTax : 0)); - } - - @Override - public NodeResources advertisedResourcesOf(Flavor flavor) { - NodeResources resources = flavor.resources(); - if ( ! flavor.isConfigured()) return resources; - return resources.withMemoryGb(resources.memoryGb() + memoryTaxGb); - } - - @Override - public NodeResources requestToReal(NodeResources resources) { - return resources.withMemoryGb(resources.memoryGb() - memoryTaxGb) - .withDiskGb(resources.diskGb() - ( resources.storageType() == local ? localDiskTax : 0) ); - } - - @Override - public NodeResources realToRequest(NodeResources resources) { - return resources.withMemoryGb(resources.memoryGb() + memoryTaxGb) - .withDiskGb(resources.diskGb() + ( resources.storageType() == local ? localDiskTax : 0) ); - } - - } - private static class MockHostProvisioner implements HostProvisioner { private final List<Flavor> hostFlavors; diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java index b35f9dc88ae..7a7f8a7d891 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java @@ -413,7 +413,7 @@ public class ProvisioningTest { ProvisioningTester tester = new ProvisioningTester.Builder().zone(new Zone(Environment.prod, RegionName.from("us-east"))) .flavors(List.of(hostFlavor)) .build(); - tester.makeReadyHosts(30, hostFlavor.resources()).deployZoneApp(); + tester.makeReadyHosts(4, hostFlavor.resources()).deployZoneApp(); ApplicationId app1 = tester.makeApplicationId("app1"); ClusterSpec cluster1 = ClusterSpec.request(ClusterSpec.Type.content, new ClusterSpec.Id("cluster1")).vespaVersion("7").build(); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java index 9a02bc17b4b..2427c0303c6 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTester.java @@ -56,6 +56,7 @@ import java.util.function.Function; import java.util.logging.Level; import java.util.stream.Collectors; +import static com.yahoo.config.provision.NodeResources.StorageType.local; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; @@ -562,6 +563,11 @@ public class ProvisioningTester { return this; } + public Builder resourcesCalculator(int memoryTax, int diskTax) { + this.resourcesCalculator = new MockResourcesCalculator(memoryTax, diskTax); + return this; + } + public Builder zone(Zone zone) { this.zone = zone; return this; @@ -640,4 +646,43 @@ public class ProvisioningTester { @Override public void log(Level level, String message) { } } + static class MockResourcesCalculator implements HostResourcesCalculator { + + private final int memoryTaxGb; + private final int localDiskTax; + + public MockResourcesCalculator(int memoryTaxGb, int localDiskTax) { + this.memoryTaxGb = memoryTaxGb; + this.localDiskTax = localDiskTax; + } + + @Override + public NodeResources realResourcesOf(Node node, NodeRepository nodeRepository) { + NodeResources resources = node.flavor().resources(); + if (node.type() == NodeType.host) return resources; + return resources.withMemoryGb(resources.memoryGb() - memoryTaxGb) + .withDiskGb(resources.diskGb() - ( resources.storageType() == local ? localDiskTax : 0)); + } + + @Override + public NodeResources advertisedResourcesOf(Flavor flavor) { + NodeResources resources = flavor.resources(); + if ( ! flavor.isConfigured()) return resources; + return resources.withMemoryGb(resources.memoryGb() + memoryTaxGb); + } + + @Override + public NodeResources requestToReal(NodeResources resources) { + return resources.withMemoryGb(resources.memoryGb() - memoryTaxGb) + .withDiskGb(resources.diskGb() - ( resources.storageType() == local ? localDiskTax : 0) ); + } + + @Override + public NodeResources realToRequest(NodeResources resources) { + return resources.withMemoryGb(resources.memoryGb() + memoryTaxGb) + .withDiskGb(resources.diskGb() + ( resources.storageType() == local ? localDiskTax : 0) ); + } + + } + } diff --git a/searchcore/src/vespa/searchcore/grouping/groupingcontext.cpp b/searchcore/src/vespa/searchcore/grouping/groupingcontext.cpp index 5c9321a6ff3..55e9ce16f70 100644 --- a/searchcore/src/vespa/searchcore/grouping/groupingcontext.cpp +++ b/searchcore/src/vespa/searchcore/grouping/groupingcontext.cpp @@ -20,7 +20,7 @@ GroupingContext::deserialize(const char *groupSpec, uint32_t groupSpecLen) uint32_t numGroupings = 0; nis >> numGroupings; for (size_t i = 0; i < numGroupings; i++) { - GroupingPtr grouping(new search::aggregation::Grouping); + auto grouping = std::make_shared<search::aggregation::Grouping>(); grouping->deserialize(nis); grouping->setClock(&_clock); grouping->setTimeOfDoom(_timeOfDoom); diff --git a/searchcore/src/vespa/searchcore/grouping/groupingsession.cpp b/searchcore/src/vespa/searchcore/grouping/groupingsession.cpp index 2c2a5ceacff..e336d5b25c9 100644 --- a/searchcore/src/vespa/searchcore/grouping/groupingsession.cpp +++ b/searchcore/src/vespa/searchcore/grouping/groupingsession.cpp @@ -41,7 +41,7 @@ GroupingSession::init(GroupingContext & groupingContext, const IAttributeContext GroupingPtr g(sessionList[i]); // Make internal copy of those we want to keep for another pass if (!_sessionId.empty() && g->getLastLevel() < g->levels().size()) { - GroupingPtr gp(new Grouping(*g)); + auto gp = std::make_shared<Grouping>(*g); gp->setLastLevel(gp->levels().size()); _groupingMap[gp->getId()] = gp; g = gp; @@ -62,7 +62,7 @@ GroupingSession::prepareThreadContextCreation(size_t num_threads) GroupingContext::UP GroupingSession::createThreadContext(size_t thread_id, const IAttributeContext &attrCtx) { - GroupingContext::UP ctx(new GroupingContext(*_mgrContext)); + auto ctx = std::make_unique<GroupingContext>(*_mgrContext); if (thread_id == 0) { GroupingContext::GroupingList &groupingList = _mgrContext->getGroupingList(); for (size_t i = 0; i < groupingList.size(); ++i) { diff --git a/searchcore/src/vespa/searchcore/proton/docsummary/docsumcontext.cpp b/searchcore/src/vespa/searchcore/proton/docsummary/docsumcontext.cpp index 4fcd5aff4f9..0869fc175a7 100644 --- a/searchcore/src/vespa/searchcore/proton/docsummary/docsumcontext.cpp +++ b/searchcore/src/vespa/searchcore/proton/docsummary/docsumcontext.cpp @@ -64,7 +64,7 @@ DocsumContext::initState() DocsumReply::UP DocsumContext::createReply() { - DocsumReply::UP reply(new DocsumReply()); + auto reply = std::make_unique<DocsumReply>(); search::RawBuf buf(4096); _docsumWriter.InitState(_attrMgr, &_docsumState); reply->docsums.resize(_docsumState._docsumcnt); diff --git a/searchcore/src/vespa/searchcore/proton/docsummary/fieldcache.cpp b/searchcore/src/vespa/searchcore/proton/docsummary/fieldcache.cpp index ecc0569cccd..4c76361cf8e 100644 --- a/searchcore/src/vespa/searchcore/proton/docsummary/fieldcache.cpp +++ b/searchcore/src/vespa/searchcore/proton/docsummary/fieldcache.cpp @@ -27,7 +27,7 @@ FieldCache::FieldCache(const ResultClass &resClass, const Field &field = docType.getField(fieldName); LOG(debug, "Caching Field instance for field '%s': %s.%u", fieldName.c_str(), field.getName().data(), field.getId()); - _cache.push_back(Field::CSP(new Field(field))); + _cache.push_back(std::make_shared<const Field>(field)); } else { _cache.push_back(Field::CSP()); } diff --git a/searchcore/src/vespa/searchcore/proton/docsummary/fieldcacherepo.cpp b/searchcore/src/vespa/searchcore/proton/docsummary/fieldcacherepo.cpp index b97eba64f4c..25fe684b949 100644 --- a/searchcore/src/vespa/searchcore/proton/docsummary/fieldcacherepo.cpp +++ b/searchcore/src/vespa/searchcore/proton/docsummary/fieldcacherepo.cpp @@ -12,17 +12,17 @@ namespace proton { FieldCacheRepo::FieldCacheRepo() : _repo(), - _defaultCache(new FieldCache()) + _defaultCache(std::make_shared<const FieldCache>()) { } FieldCacheRepo::FieldCacheRepo(const ResultConfig &resConfig, const DocumentType &docType) : _repo(), - _defaultCache(new FieldCache()) + _defaultCache(std::make_shared<const FieldCache>()) { for (ResultConfig::const_iterator it(resConfig.begin()), mt(resConfig.end()); it != mt; it++) { - FieldCache::CSP cache(new FieldCache(*it, docType)); + auto cache = std::make_shared<const FieldCache>(*it, docType); vespalib::string className(it->GetClassName()); LOG(debug, "Adding field cache for summary class '%s' to repo", className.c_str()); diff --git a/searchcore/src/vespa/searchcore/proton/documentmetastore/documentmetastore.cpp b/searchcore/src/vespa/searchcore/proton/documentmetastore/documentmetastore.cpp index 96f69179482..6016d60b880 100644 --- a/searchcore/src/vespa/searchcore/proton/documentmetastore/documentmetastore.cpp +++ b/searchcore/src/vespa/searchcore/proton/documentmetastore/documentmetastore.cpp @@ -794,8 +794,7 @@ DocumentMetaStore::createWhiteListBlueprint() const AttributeVector::SearchContext::UP DocumentMetaStore::getSearch(std::unique_ptr<search::QueryTermSimple> qTerm, const SearchContextParams &) const { - return AttributeVector::SearchContext::UP - (new documentmetastore::SearchContext(std::move(qTerm), *this)); + return std::make_unique<documentmetastore::SearchContext>(std::move(qTerm), *this); } DocumentMetaStore::ConstIterator @@ -1006,7 +1005,7 @@ void DocumentMetaStore::holdUnblockShrinkLidSpace() { assert(_shrinkLidSpaceBlockers > 0); - GenerationHeldBase::UP hold(new ShrinkBlockHeld(*this)); + auto hold = std::make_unique<ShrinkBlockHeld>(*this); getGenerationHolder().hold(std::move(hold)); incGeneration(); } diff --git a/searchcore/src/vespa/searchcore/proton/documentmetastore/documentmetastorecontext.cpp b/searchcore/src/vespa/searchcore/proton/documentmetastore/documentmetastorecontext.cpp index b6486607821..959bdfa9baf 100644 --- a/searchcore/src/vespa/searchcore/proton/documentmetastore/documentmetastorecontext.cpp +++ b/searchcore/src/vespa/searchcore/proton/documentmetastore/documentmetastorecontext.cpp @@ -15,7 +15,7 @@ DocumentMetaStoreContext::DocumentMetaStoreContext(BucketDBOwner::SP bucketDB, const vespalib::string &name, const search::GrowStrategy &grow, const DocumentMetaStore::IGidCompare::SP &gidCompare) : - _metaStoreAttr(new DocumentMetaStore(bucketDB, name, grow, gidCompare)), + _metaStoreAttr(std::make_shared<DocumentMetaStore>(bucketDB, name, grow, gidCompare)), _metaStore(std::dynamic_pointer_cast<IDocumentMetaStore>(_metaStoreAttr)) { } diff --git a/searchcore/src/vespa/searchcore/proton/feedoperation/pruneremoveddocumentsoperation.cpp b/searchcore/src/vespa/searchcore/proton/feedoperation/pruneremoveddocumentsoperation.cpp index 69f754cd594..26586da7784 100644 --- a/searchcore/src/vespa/searchcore/proton/feedoperation/pruneremoveddocumentsoperation.cpp +++ b/searchcore/src/vespa/searchcore/proton/feedoperation/pruneremoveddocumentsoperation.cpp @@ -27,7 +27,7 @@ PruneRemovedDocumentsOperation(DocumentIdT docIdLimit, uint32_t subDbId) : RemoveDocumentsOperation(FeedOperation::PRUNE_REMOVED_DOCUMENTS), _subDbId(subDbId) { - LidVectorContext::SP lidsToRemove(new LidVectorContext(docIdLimit)); + auto lidsToRemove = std::make_shared<LidVectorContext>(docIdLimit); setLidsToRemove(lidsToRemove); } diff --git a/searchcore/src/vespa/searchcore/proton/feedoperation/removedocumentsoperation.cpp b/searchcore/src/vespa/searchcore/proton/feedoperation/removedocumentsoperation.cpp index ef482a19ca3..14abade84b5 100644 --- a/searchcore/src/vespa/searchcore/proton/feedoperation/removedocumentsoperation.cpp +++ b/searchcore/src/vespa/searchcore/proton/feedoperation/removedocumentsoperation.cpp @@ -33,7 +33,7 @@ RemoveDocumentsOperation::deserializeLidsToRemove(vespalib::nbostream &is) for (i = 0; i < mapSize; ++i) { uint32_t subDbId; is >> subDbId; - LidVectorContext::SP lidsToRemove(new LidVectorContext()); + auto lidsToRemove = std::make_shared<LidVectorContext>(); lidsToRemove->deserialize(is); setLidsToRemove(subDbId, lidsToRemove); } diff --git a/searchcore/src/vespa/searchcore/proton/matching/blueprintbuilder.cpp b/searchcore/src/vespa/searchcore/proton/matching/blueprintbuilder.cpp index c8c5a3a427b..7149bf9ab7f 100644 --- a/searchcore/src/vespa/searchcore/proton/matching/blueprintbuilder.cpp +++ b/searchcore/src/vespa/searchcore/proton/matching/blueprintbuilder.cpp @@ -32,7 +32,7 @@ struct Mixer { Blueprint::UP mix(Blueprint::UP indexes) { if (attributes.get() == 0) { if (indexes.get() == 0) { - return Blueprint::UP(new EmptyBlueprint()); + return std::make_unique<EmptyBlueprint>(); } return Blueprint::UP(std::move(indexes)); } diff --git a/searchcore/src/vespa/searchcore/proton/matching/fakesearchcontext.cpp b/searchcore/src/vespa/searchcore/proton/matching/fakesearchcontext.cpp index 5758b9a796f..316cf92597e 100644 --- a/searchcore/src/vespa/searchcore/proton/matching/fakesearchcontext.cpp +++ b/searchcore/src/vespa/searchcore/proton/matching/fakesearchcontext.cpp @@ -7,8 +7,8 @@ namespace proton::matching { FakeSearchContext::FakeSearchContext(size_t initialNumDocs) : _clock(), _doom(_clock, vespalib::steady_time()), - _selector(new search::FixedSourceSelector(0, "fs", initialNumDocs)), - _indexes(new IndexCollection(_selector)), + _selector(std::make_shared<search::FixedSourceSelector>(0, "fs", initialNumDocs)), + _indexes(std::make_shared<IndexCollection>(_selector)), _attrSearchable(), _docIdLimit(initialNumDocs) { diff --git a/searchcore/src/vespa/searchcore/proton/matching/fakesearchcontext.h b/searchcore/src/vespa/searchcore/proton/matching/fakesearchcontext.h index 5a4ccc892b3..d23dd2ac551 100644 --- a/searchcore/src/vespa/searchcore/proton/matching/fakesearchcontext.h +++ b/searchcore/src/vespa/searchcore/proton/matching/fakesearchcontext.h @@ -35,7 +35,7 @@ public: ~FakeSearchContext(); FakeSearchContext &addIdx(uint32_t id) { - _indexes->append(id, IndexSearchable::SP(new FakeIndexSearchable())); + _indexes->append(id, std::make_shared<FakeIndexSearchable>()); return *this; } diff --git a/searchcore/src/vespa/searchcore/proton/metrics/documentdb_job_trackers.cpp b/searchcore/src/vespa/searchcore/proton/metrics/documentdb_job_trackers.cpp index 8b3257ff47b..18475f06fc2 100644 --- a/searchcore/src/vespa/searchcore/proton/metrics/documentdb_job_trackers.cpp +++ b/searchcore/src/vespa/searchcore/proton/metrics/documentdb_job_trackers.cpp @@ -17,14 +17,14 @@ namespace proton { DocumentDBJobTrackers::DocumentDBJobTrackers() : _lock(), _now(std::chrono::steady_clock::now()), - _attributeFlush(new JobTracker(_now, _lock)), - _memoryIndexFlush(new JobTracker(_now, _lock)), - _diskIndexFusion(new JobTracker(_now, _lock)), - _documentStoreFlush(new JobTracker(_now, _lock)), - _documentStoreCompact(new JobTracker(_now, _lock)), - _bucketMove(new JobTracker(_now, _lock)), - _lidSpaceCompact(new JobTracker(_now, _lock)), - _removedDocumentsPrune(new JobTracker(_now, _lock)) + _attributeFlush(std::make_shared<JobTracker>(_now, _lock)), + _memoryIndexFlush(std::make_shared<JobTracker>(_now, _lock)), + _diskIndexFusion(std::make_shared<JobTracker>(_now, _lock)), + _documentStoreFlush(std::make_shared<JobTracker>(_now, _lock)), + _documentStoreCompact(std::make_shared<JobTracker>(_now, _lock)), + _bucketMove(std::make_shared<JobTracker>(_now, _lock)), + _lidSpaceCompact(std::make_shared<JobTracker>(_now, _lock)), + _removedDocumentsPrune(std::make_shared<JobTracker>(_now, _lock)) { } @@ -36,7 +36,7 @@ IFlushTarget::SP trackFlushTarget(const IJobTracker::SP &tracker, const IFlushTarget::SP &target) { - return IFlushTarget::SP(new JobTrackedFlushTarget(tracker, target)); + return std::make_shared<JobTrackedFlushTarget>(tracker, target); } } diff --git a/searchcore/src/vespa/searchcore/proton/metrics/job_tracked_flush_target.cpp b/searchcore/src/vespa/searchcore/proton/metrics/job_tracked_flush_target.cpp index 9eebe5010d2..14d76645fc7 100644 --- a/searchcore/src/vespa/searchcore/proton/metrics/job_tracked_flush_target.cpp +++ b/searchcore/src/vespa/searchcore/proton/metrics/job_tracked_flush_target.cpp @@ -25,7 +25,7 @@ JobTrackedFlushTarget::initFlush(SerialNum currentSerial) FlushTask::UP targetTask = _target->initFlush(currentSerial); _tracker->end(); if (targetTask.get() != nullptr) { - return FlushTask::UP(new JobTrackedFlushTask(_tracker, std::move(targetTask))); + return std::make_unique<JobTrackedFlushTask>(_tracker, std::move(targetTask)); } return FlushTask::UP(); } diff --git a/searchcore/src/vespa/searchcore/proton/metrics/trans_log_server_metrics.cpp b/searchcore/src/vespa/searchcore/proton/metrics/trans_log_server_metrics.cpp index a6e8ac54e86..85644c2111a 100644 --- a/searchcore/src/vespa/searchcore/proton/metrics/trans_log_server_metrics.cpp +++ b/searchcore/src/vespa/searchcore/proton/metrics/trans_log_server_metrics.cpp @@ -33,7 +33,7 @@ TransLogServerMetrics::considerAddDomains(const DomainStats &stats) for (const auto &elem : stats) { const vespalib::string &documentType = elem.first; if (_domainMetrics.find(documentType) == _domainMetrics.end()) { - _domainMetrics[documentType] = DomainMetrics::UP(new DomainMetrics(_parent, documentType)); + _domainMetrics[documentType] = std::make_unique<DomainMetrics>(_parent, documentType); } } } diff --git a/searchcore/src/vespa/searchcore/proton/reprocessing/attribute_reprocessing_initializer.cpp b/searchcore/src/vespa/searchcore/proton/reprocessing/attribute_reprocessing_initializer.cpp index 9b1c66780cd..e939b07c26b 100644 --- a/searchcore/src/vespa/searchcore/proton/reprocessing/attribute_reprocessing_initializer.cpp +++ b/searchcore/src/vespa/searchcore/proton/reprocessing/attribute_reprocessing_initializer.cpp @@ -101,9 +101,8 @@ getFieldsToPopulate(const ARIConfig &newCfg, attrCfg.basicType().asString(), toStr(populateField)); if (populateField) { - fieldsToPopulate.push_back(IReprocessingRewriter::SP - (new DocumentFieldPopulator(name, - guard.getSP(), subDbName))); + fieldsToPopulate.push_back(std::make_shared<DocumentFieldPopulator> + (name, guard.getSP(), subDbName)); } } return fieldsToPopulate; diff --git a/searchcore/src/vespa/searchcore/proton/server/attribute_writer_factory.h b/searchcore/src/vespa/searchcore/proton/server/attribute_writer_factory.h index fe0820b9a39..3333041fb91 100644 --- a/searchcore/src/vespa/searchcore/proton/server/attribute_writer_factory.h +++ b/searchcore/src/vespa/searchcore/proton/server/attribute_writer_factory.h @@ -19,7 +19,7 @@ struct AttributeWriterFactory : public IAttributeWriterFactory const AttributeWriter &oldAdapter = dynamic_cast<const AttributeWriter &>(*old.get()); const proton::IAttributeManager::SP &oldMgr = oldAdapter.getAttributeManager(); proton::IAttributeManager::SP newMgr = oldMgr->create(attrSpec); - return IAttributeWriter::SP(new AttributeWriter(newMgr)); + return std::make_shared<AttributeWriter>(newMgr); } }; diff --git a/searchcore/src/vespa/searchcore/proton/server/bootstrapconfigmanager.cpp b/searchcore/src/vespa/searchcore/proton/server/bootstrapconfigmanager.cpp index edbf0c631a5..baf89a55ae3 100644 --- a/searchcore/src/vespa/searchcore/proton/server/bootstrapconfigmanager.cpp +++ b/searchcore/src/vespa/searchcore/proton/server/bootstrapconfigmanager.cpp @@ -78,7 +78,7 @@ BootstrapConfigManager::update(const ConfigSnapshot & snapshot) if (snapshot.isChanged<ProtonConfig>(_configId, currentGen)) { LOG(spam, "Proton config is changed"); std::unique_ptr<ProtonConfig> protonConfig = snapshot.getConfig<ProtonConfig>(_configId); - TuneFileDocumentDB::SP tuneFileDocumentDB(new TuneFileDocumentDB); + auto tuneFileDocumentDB = std::make_shared<TuneFileDocumentDB>(); TuneFileDocumentDB &tune = *tuneFileDocumentDB; ProtonConfig &conf = *protonConfig; tune._index._indexing._write.setFromConfig<ProtonConfig::Indexing::Write>(conf.indexing.write.io); diff --git a/searchcore/src/vespa/searchcore/proton/server/clusterstatehandler.cpp b/searchcore/src/vespa/searchcore/proton/server/clusterstatehandler.cpp index fa0e0f33469..eb3c8ce6aa4 100644 --- a/searchcore/src/vespa/searchcore/proton/server/clusterstatehandler.cpp +++ b/searchcore/src/vespa/searchcore/proton/server/clusterstatehandler.cpp @@ -64,7 +64,7 @@ ClusterStateHandler::performSetClusterState(const ClusterState *calc, (calc->nodeInitializing() ? "true" : "false"), _changedHandlers.size()); if (!_changedHandlers.empty()) { - IBucketStateCalculator::SP newCalc(new ClusterStateAdapter(*calc)); + auto newCalc = std::make_shared<ClusterStateAdapter>(*calc); typedef std::vector<IClusterStateChangedHandler *> Chv; Chv &chs(_changedHandlers); for (Chv::const_iterator it = chs.begin(), ite = chs.end(); it != ite; diff --git a/searchlib/src/vespa/searchlib/attribute/attribute_blueprint_factory.cpp b/searchlib/src/vespa/searchlib/attribute/attribute_blueprint_factory.cpp index d838013c0ef..a9a593b429d 100644 --- a/searchlib/src/vespa/searchlib/attribute/attribute_blueprint_factory.cpp +++ b/searchlib/src/vespa/searchlib/attribute/attribute_blueprint_factory.cpp @@ -141,7 +141,7 @@ public: SearchIteratorUP createFilterSearch(bool strict, FilterConstraint constraint) const override { (void) constraint; // We provide an iterator with exact results, so no need to take constraint into consideration. - auto wrapper = std::make_unique<FilterWrapper>(getState()); + auto wrapper = std::make_unique<FilterWrapper>(getState().numFields()); wrapper->wrap(createLeafSearch(wrapper->tfmda(), strict)); return wrapper; } diff --git a/searchlib/src/vespa/searchlib/diskindex/disktermblueprint.cpp b/searchlib/src/vespa/searchlib/diskindex/disktermblueprint.cpp index 27aa070d514..09024505450 100644 --- a/searchlib/src/vespa/searchlib/diskindex/disktermblueprint.cpp +++ b/searchlib/src/vespa/searchlib/diskindex/disktermblueprint.cpp @@ -100,7 +100,7 @@ DiskTermBlueprint::createLeafSearch(const TermFieldMatchDataArray & tfmda, bool SearchIterator::UP DiskTermBlueprint::createFilterSearch(bool strict, FilterConstraint) const { - auto wrapper = std::make_unique<queryeval::FilterWrapper>(getState()); + auto wrapper = std::make_unique<queryeval::FilterWrapper>(getState().numFields()); auto & tfmda = wrapper->tfmda(); if (_bitVector) { wrapper->wrap(BitVectorIterator::create(_bitVector.get(), *tfmda[0], strict)); diff --git a/searchlib/src/vespa/searchlib/queryeval/filter_wrapper.h b/searchlib/src/vespa/searchlib/queryeval/filter_wrapper.h index b67bacca118..27740df6ba6 100644 --- a/searchlib/src/vespa/searchlib/queryeval/filter_wrapper.h +++ b/searchlib/src/vespa/searchlib/queryeval/filter_wrapper.h @@ -3,7 +3,7 @@ #pragma once #include "searchiterator.h" -#include "blueprint.h" +#include <vespa/searchlib/common/bitvector.h> #include <vespa/searchlib/fef/termfieldmatchdata.h> #include <vespa/searchlib/fef/termfieldmatchdataarray.h> @@ -20,12 +20,12 @@ private: fef::TermFieldMatchDataArray _tfmda; std::unique_ptr<SearchIterator> _wrapped_search; public: - FilterWrapper(const Blueprint::State &state) - : _unused_md(state.numFields()), + FilterWrapper(size_t num_fields) + : _unused_md(num_fields), _tfmda(), _wrapped_search() { - for (size_t i = 0; i < state.numFields(); ++i) { + for (size_t i = 0; i < num_fields; ++i) { _tfmda.add(&_unused_md[i]); } } diff --git a/vespaclient-container-plugin/src/main/java/com/yahoo/document/restapi/resource/RestApi.java b/vespaclient-container-plugin/src/main/java/com/yahoo/document/restapi/resource/RestApi.java index ccd2d80efb2..cf33b6033cd 100644 --- a/vespaclient-container-plugin/src/main/java/com/yahoo/document/restapi/resource/RestApi.java +++ b/vespaclient-container-plugin/src/main/java/com/yahoo/document/restapi/resource/RestApi.java @@ -99,10 +99,7 @@ public class RestApi extends LoggingRequestHandler { } // For testing and development - public RestApi(Executor executor, - AccessLog accessLog, - OperationHandler operationHandler, - int threadsAvailable) { + RestApi(Executor executor, AccessLog accessLog, OperationHandler operationHandler, int threadsAvailable) { super(executor, accessLog, null); this.operationHandler = operationHandler; this.threadsAvailableForApi = new AtomicInteger(threadsAvailable); diff --git a/vespaclient-container-plugin/src/main/java/com/yahoo/vespa/http/server/FeedHandlerV3.java b/vespaclient-container-plugin/src/main/java/com/yahoo/vespa/http/server/FeedHandlerV3.java index 05a64d633a4..03916949cae 100644 --- a/vespaclient-container-plugin/src/main/java/com/yahoo/vespa/http/server/FeedHandlerV3.java +++ b/vespaclient-container-plugin/src/main/java/com/yahoo/vespa/http/server/FeedHandlerV3.java @@ -45,9 +45,6 @@ public class FeedHandlerV3 extends LoggingRequestHandler { protected final ReplyHandler feedReplyHandler; private final Metric metric; private final Object monitor = new Object(); - private int remainingThreadsForFeedingAllowance; - private final Duration timeBetweenBumpingMaxThreads; - private Instant nextTimeToAllocateAnotherThread = Instant.now(); private final AtomicInteger threadsAvailableForFeeding; private static final Logger log = Logger.getLogger(FeedHandlerV3.class.getName()); @@ -65,20 +62,10 @@ public class FeedHandlerV3 extends LoggingRequestHandler { this.metric = parentCtx.getMetric(); // 40% of the threads can be blocking on feeding before we deny requests. if (threadpoolConfig != null) { - remainingThreadsForFeedingAllowance = Math.max((int) (0.4 * threadpoolConfig.maxthreads()), 1); - if (threadpoolConfig.softStartSeconds() > 0.0) { - threadsAvailableForFeeding = new AtomicInteger(0); - timeBetweenBumpingMaxThreads = Duration.ofMillis((long)(threadpoolConfig.softStartSeconds() * 1000) / remainingThreadsForFeedingAllowance); - } else { - threadsAvailableForFeeding = new AtomicInteger(remainingThreadsForFeedingAllowance); - remainingThreadsForFeedingAllowance = 0; - timeBetweenBumpingMaxThreads = null; - } + threadsAvailableForFeeding = new AtomicInteger(Math.max((int) (0.4 * threadpoolConfig.maxthreads()), 1)); } else { log.warning("No config for threadpool, using 200 for max blocking threads for feeding."); threadsAvailableForFeeding = new AtomicInteger(200); - remainingThreadsForFeedingAllowance = 0; - timeBetweenBumpingMaxThreads = null; } } @@ -93,12 +80,6 @@ public class FeedHandlerV3 extends LoggingRequestHandler { String clientId = clientId(request); ClientFeederV3 clientFeederV3; synchronized (monitor) { - Instant now = Instant.now(); - if ((remainingThreadsForFeedingAllowance > 0) && (now.isAfter(nextTimeToAllocateAnotherThread))) { - threadsAvailableForFeeding.incrementAndGet(); - remainingThreadsForFeedingAllowance --; - nextTimeToAllocateAnotherThread = now.plus(timeBetweenBumpingMaxThreads); - } if (! clientFeederByClientId.containsKey(clientId)) { SourceSessionParams sourceSessionParams = sourceSessionParams(request); clientFeederByClientId.put(clientId, diff --git a/vespaclient-container-plugin/src/test/java/com/yahoo/feedhandler/v3/FeedTesterV3.java b/vespaclient-container-plugin/src/test/java/com/yahoo/feedhandler/v3/FeedTesterV3.java index 0bb42851347..1efa8129cdb 100644 --- a/vespaclient-container-plugin/src/test/java/com/yahoo/feedhandler/v3/FeedTesterV3.java +++ b/vespaclient-container-plugin/src/test/java/com/yahoo/feedhandler/v3/FeedTesterV3.java @@ -77,20 +77,6 @@ public class FeedTesterV3 { assertThat(Splitter.on("\n").splitToList(result).size(), is(101)); } - @Test - public void softRestart() throws Exception { - ThreadpoolConfig.Builder builder = new ThreadpoolConfig.Builder().softStartSeconds(5); - final FeedHandlerV3 feedHandlerV3 = setupFeederHandler(builder.build()); - for (int i= 0; i < 100; i++) { - HttpResponse httpResponse = feedHandlerV3.handle(createRequest(100)); - ByteArrayOutputStream outStream = new ByteArrayOutputStream(); - httpResponse.render(outStream); - assertThat(httpResponse.getContentType(), is("text/plain")); - String result = Utf8.toString(outStream.toByteArray()); - assertThat(Splitter.on("\n").splitToList(result).size(), is(101)); - } - } - private static DocumentTypeManager createDoctypeManager() { DocumentTypeManager docTypeManager = new DocumentTypeManager(); DocumentType documentType = new DocumentType("testdocument"); diff --git a/zookeeper-server/zookeeper-server-3.5.8/src/main/java/com/yahoo/vespa/zookeeper/VespaZooKeeperServerImpl.java b/zookeeper-server/zookeeper-server-3.5.8/src/main/java/com/yahoo/vespa/zookeeper/VespaZooKeeperServerImpl.java index 15d5d2f6f31..7f5b6170947 100644 --- a/zookeeper-server/zookeeper-server-3.5.8/src/main/java/com/yahoo/vespa/zookeeper/VespaZooKeeperServerImpl.java +++ b/zookeeper-server/zookeeper-server-3.5.8/src/main/java/com/yahoo/vespa/zookeeper/VespaZooKeeperServerImpl.java @@ -28,7 +28,7 @@ public class VespaZooKeeperServerImpl extends AbstractComponent implements Runna this.zookeeperServerConfig = zookeeperServerConfig; new Configurator(zookeeperServerConfig).writeConfigToDisk(TransportSecurityUtils.getOptions()); zkServerThread = new Thread(this, "zookeeper server"); - zkServerThread.start(); + zkServerThread.start(); } private void shutdown() { diff --git a/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/Configurator.java b/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/Configurator.java index 119509dd9cc..44ea8cece34 100644 --- a/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/Configurator.java +++ b/zookeeper-server/zookeeper-server-common/src/main/java/com/yahoo/vespa/zookeeper/Configurator.java @@ -12,9 +12,9 @@ import com.yahoo.security.X509CertificateUtils; import com.yahoo.security.tls.TlsContext; import com.yahoo.security.tls.TransportSecurityOptions; import com.yahoo.text.Utf8; +import com.yahoo.vespa.defaults.Defaults; import javax.net.ssl.SSLContext; -import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.nio.file.Files; @@ -26,29 +26,33 @@ import java.util.List; import java.util.Optional; import java.util.Set; import java.util.TreeSet; +import java.util.logging.Level; import java.util.stream.Collectors; import static com.yahoo.vespa.defaults.Defaults.getDefaults; public class Configurator { + + private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(Configurator.class.getName()); private static final String ZOOKEEPER_JMX_LOG4J_DISABLE = "zookeeper.jmx.log4j.disable"; static final String ZOOKEEPER_JUTE_MAX_BUFFER = "jute.maxbuffer"; private final ZookeeperServerConfig zookeeperServerConfig; - private final String configFilePath; - private final String jksKeyStoreFilePath; + private final Path configFilePath; + private final Path jksKeyStoreFilePath; public Configurator(ZookeeperServerConfig zookeeperServerConfig) { + log.log(Level.FINE, zookeeperServerConfig.toString()); this.zookeeperServerConfig = zookeeperServerConfig; - this.configFilePath = zookeeperServerConfig.zooKeeperConfigFile(); - this.jksKeyStoreFilePath = zookeeperServerConfig.jksKeyStoreFile(); + this.configFilePath = makeAbsolutePath(zookeeperServerConfig.zooKeeperConfigFile()); + this.jksKeyStoreFilePath = makeAbsolutePath(zookeeperServerConfig.jksKeyStoreFile()); System.setProperty(ZOOKEEPER_JMX_LOG4J_DISABLE, "true"); System.setProperty("zookeeper.snapshot.trust.empty", Boolean.valueOf(zookeeperServerConfig.trustEmptySnapshot()).toString()); System.setProperty(ZOOKEEPER_JUTE_MAX_BUFFER, Integer.valueOf(zookeeperServerConfig.juteMaxBuffer()).toString()); } void writeConfigToDisk(Optional<TransportSecurityOptions> transportSecurityOptions) { - new File(configFilePath).getParentFile().mkdirs(); + configFilePath.toFile().getParentFile().mkdirs(); try { writeZooKeeperConfigFile(zookeeperServerConfig, transportSecurityOptions); @@ -61,7 +65,7 @@ public class Configurator { private void writeZooKeeperConfigFile(ZookeeperServerConfig config, Optional<TransportSecurityOptions> transportSecurityOptions) throws IOException { - try (FileWriter writer = new FileWriter(configFilePath)) { + try (FileWriter writer = new FileWriter(configFilePath.toFile())) { writer.write(transformConfigToString(config, transportSecurityOptions)); } } @@ -118,7 +122,7 @@ public class Configurator { .withType(KeyStoreType.JKS) .withKeyEntry("foo", privateKey, certificates); - KeyStoreUtils.writeKeyStoreToFile(keyStoreBuilder.build(), Paths.get(jksKeyStoreFilePath)); + KeyStoreUtils.writeKeyStoreToFile(keyStoreBuilder.build(), jksKeyStoreFilePath); } private void ensureThisServerIsRepresented(int myid, List<ZookeeperServerConfig.Server> servers) { @@ -138,13 +142,18 @@ public class Configurator { sb.append("server.").append(server.id()).append("=").append(server.hostname()).append(":").append(server.quorumPort()).append(":").append(server.electionPort()).append("\n"); } - - - static Set<String> zookeeperServerHostnames(ZookeeperServerConfig zookeeperServerConfig) { return zookeeperServerConfig.server().stream().map(ZookeeperServerConfig.Server::hostname).collect(Collectors.toSet()); } + Path makeAbsolutePath(String filename) { + Path path = Paths.get(filename); + if (path.isAbsolute()) + return path; + else + return Paths.get(Defaults.getDefaults().underVespaHome(filename)); + } + private interface TlsConfig { default Set<String> allowedCiphers(SSLContext sslContext) { return new TreeSet<>(TlsContext.getAllowedCipherSuites(sslContext)); } @@ -162,7 +171,7 @@ public class Configurator { String configFieldPrefix(); - String jksKeyStoreFilePath(); + Path jksKeyStoreFilePath(); SSLContext sslContext(); @@ -195,9 +204,9 @@ public class Configurator { static class TlsClientServerConfig implements TlsConfig { private final SSLContext sslContext; - private final String jksKeyStoreFilePath; + private final Path jksKeyStoreFilePath; - TlsClientServerConfig(SSLContext sslContext, String jksKeyStoreFilePath) { + TlsClientServerConfig(SSLContext sslContext, Path jksKeyStoreFilePath) { this.sslContext = sslContext; this.jksKeyStoreFilePath = jksKeyStoreFilePath; } @@ -233,7 +242,7 @@ public class Configurator { } @Override - public String jksKeyStoreFilePath() { + public Path jksKeyStoreFilePath() { return jksKeyStoreFilePath; } @@ -246,9 +255,9 @@ public class Configurator { static class TlsQuorumConfig implements TlsConfig { private final SSLContext sslContext; - private final String jksKeyStoreFilePath; + private final Path jksKeyStoreFilePath; - TlsQuorumConfig(SSLContext sslContext, String jksKeyStoreFilePath) { + TlsQuorumConfig(SSLContext sslContext, Path jksKeyStoreFilePath) { this.sslContext = sslContext; this.jksKeyStoreFilePath = jksKeyStoreFilePath; } @@ -293,7 +302,7 @@ public class Configurator { } @Override - public String jksKeyStoreFilePath() { + public Path jksKeyStoreFilePath() { return jksKeyStoreFilePath; } |