From d5982ee7479179b6754b1b9cd4cdbc8140c5e961 Mon Sep 17 00:00:00 2001 From: Jon Bratseth Date: Wed, 2 Dec 2020 07:53:44 +0100 Subject: Revert "Merge pull request #15581 from vespa-engine/revert-15578-bratseth/apply-on-restart-take-10" This reverts commit 4cf13bc7db215e77f7688e429f700880c115fe76, reversing changes made to e21f385bd4f21326608f3a69325df4e96d4a65e5. --- CMakeLists.txt | 1 + application/abi-spec.json | 2 + config-lib/abi-spec.json | 4 +- config-lib/pom.xml | 6 ++ .../main/java/com/yahoo/config/ConfigBuilder.java | 1 - .../main/java/com/yahoo/config/ConfigInstance.java | 6 ++ .../src/main/java/com/yahoo/config/Node.java | 4 +- .../java/com/yahoo/config/model/api/Model.java | 42 ++++---- config-model-fat/pom.xml | 2 +- .../com/yahoo/vespa/model/InstanceResolver.java | 5 +- .../java/com/yahoo/vespa/model/VespaModel.java | 15 +++ .../com/yahoo/vespa/model/container/Container.java | 5 +- .../vespa/model/container/ContainerCluster.java | 1 + .../RestartChangesDefersConfigChangesTest.java | 10 +- .../vespa/config/proxy/ConfigProxyRpcServer.java | 6 +- .../com/yahoo/vespa/config/proxy/ConfigTester.java | 4 +- .../yahoo/vespa/config/proxy/MemoryCacheTest.java | 6 +- .../yahoo/vespa/config/proxy/ProxyServerTest.java | 6 +- config/src/apps/vespa-get-config/getconfig.cpp | 2 +- .../config/subscription/ConfigSubscriber.java | 24 ++++- .../subscription/impl/ConfigSubscription.java | 34 ++++-- .../impl/GenericJRTConfigSubscription.java | 14 ++- .../subscription/impl/JRTConfigSubscription.java | 3 +- .../subscription/impl/JarConfigSubscription.java | 2 +- .../config/subscription/impl/MockConnection.java | 2 +- .../subscription/impl/RawConfigSubscription.java | 2 +- .../java/com/yahoo/vespa/config/ConfigPayload.java | 2 +- .../yahoo/vespa/config/ConfigPayloadApplier.java | 1 + .../java/com/yahoo/vespa/config/GenericConfig.java | 2 + .../java/com/yahoo/vespa/config/RawConfig.java | 43 ++++---- .../vespa/config/buildergen/ConfigDefinition.java | 4 +- .../vespa/config/protocol/ConfigResponse.java | 2 + .../config/protocol/JRTClientConfigRequest.java | 3 + .../config/protocol/JRTClientConfigRequestV3.java | 6 ++ .../config/protocol/JRTServerConfigRequest.java | 7 +- .../config/protocol/JRTServerConfigRequestV3.java | 9 +- .../vespa/config/protocol/SlimeConfigResponse.java | 11 +- .../vespa/config/protocol/SlimeResponseData.java | 6 ++ .../subscription/impl/JRTConfigRequesterTest.java | 6 +- .../java/com/yahoo/vespa/config/RawConfigTest.java | 26 ++--- .../vespa/config/protocol/ConfigResponseTest.java | 4 +- .../config/protocol/JRTConfigRequestV3Test.java | 16 +-- config/src/tests/configagent/configagent.cpp | 3 +- config/src/tests/frt/frt.cpp | 8 +- config/src/vespa/config/common/configstate.h | 9 +- config/src/vespa/config/frt/protocol.cpp | 1 + config/src/vespa/config/frt/protocol.h | 1 + .../src/vespa/config/frt/slimeconfigresponse.cpp | 5 +- configgen/CMakeLists.txt | 2 + configgen/pom.xml | 32 ++++++ .../com/yahoo/config/codegen/BuilderGenerator.java | 42 +++++--- configgen/src/test/resources/allfeatures.reference | 14 ++- configserver/pom.xml | 18 ++++ .../vespa/config/server/SuperModelController.java | 2 +- .../config/server/application/Application.java | 45 ++++++-- .../server/application/ConfigInstanceBuilder.java | 117 +++++++++++++++++++++ .../config/server/rpc/ConfigResponseFactory.java | 5 +- .../config/server/rpc/GetConfigProcessor.java | 6 +- .../server/rpc/LZ4ConfigResponseFactory.java | 5 +- .../rpc/UncompressedConfigResponseFactory.java | 5 +- .../config/server/session/SessionRepository.java | 4 +- .../com/yahoo/vespa/config/server/ModelStub.java | 7 ++ .../yahoo/vespa/config/server/ServerCacheTest.java | 6 +- .../vespa/config/server/application/MockModel.java | 8 ++ .../config/server/http/HttpConfigResponseTest.java | 2 +- .../metrics/DeploymentMetricsRetrieverTest.java | 7 ++ .../server/metrics/ProtonMetricsRetrieverTest.java | 7 ++ .../server/rpc/ConfigResponseFactoryTest.java | 4 +- .../vespa/config/server/rpc/MockRpcServer.java | 2 +- container-core/abi-spec.json | 2 + container-disc/pom.xml | 1 + container-search/abi-spec.json | 12 +++ dist/vespa.spec | 1 + document/abi-spec.json | 2 + documentapi/abi-spec.json | 2 + jdisc_http_service/abi-spec.json | 6 ++ messagebus/abi-spec.json | 2 + .../com/yahoo/vespa/service/duper/HostsModel.java | 9 ++ 78 files changed, 594 insertions(+), 167 deletions(-) create mode 100644 configgen/CMakeLists.txt create mode 100644 configserver/src/main/java/com/yahoo/vespa/config/server/application/ConfigInstanceBuilder.java diff --git a/CMakeLists.txt b/CMakeLists.txt index b2d43dec0ab..6f88e5bc901 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,6 +56,7 @@ add_subdirectory(config) add_subdirectory(config-model-fat) add_subdirectory(configd) add_subdirectory(configdefinitions) +add_subdirectory(configgen) add_subdirectory(configserver) add_subdirectory(configserver-flags) add_subdirectory(configutil) diff --git a/application/abi-spec.json b/application/abi-spec.json index 690facffae7..5c298471b9c 100644 --- a/application/abi-spec.json +++ b/application/abi-spec.json @@ -105,6 +105,8 @@ "public final java.lang.String getDefMd5()", "public final java.lang.String getDefName()", "public final java.lang.String getDefNamespace()", + "public final boolean getApplyOnRestart()", + "public final void setApplyOnRestart(boolean)", "public com.yahoo.application.MockApplicationConfig build()" ], "fields": [ diff --git a/config-lib/abi-spec.json b/config-lib/abi-spec.json index fa352d8f6bd..8a1cfa9834e 100644 --- a/config-lib/abi-spec.json +++ b/config-lib/abi-spec.json @@ -73,7 +73,9 @@ "public abstract boolean dispatchGetConfig(com.yahoo.config.ConfigInstance$Producer)", "public abstract java.lang.String getDefName()", "public abstract java.lang.String getDefNamespace()", - "public abstract java.lang.String getDefMd5()" + "public abstract java.lang.String getDefMd5()", + "public boolean getApplyOnRestart()", + "public void setApplyOnRestart(boolean)" ], "fields": [] }, diff --git a/config-lib/pom.xml b/config-lib/pom.xml index 1002d43bc37..90c61725466 100644 --- a/config-lib/pom.xml +++ b/config-lib/pom.xml @@ -26,6 +26,12 @@ annotations ${project.version} + + com.yahoo.vespa + configgen + ${project.version} + provided + diff --git a/config-lib/src/main/java/com/yahoo/config/ConfigBuilder.java b/config-lib/src/main/java/com/yahoo/config/ConfigBuilder.java index e35e6916849..30bef223045 100644 --- a/config-lib/src/main/java/com/yahoo/config/ConfigBuilder.java +++ b/config-lib/src/main/java/com/yahoo/config/ConfigBuilder.java @@ -5,7 +5,6 @@ package com.yahoo.config; * Root interface for all config builders. * * @author gjoranv - * @since 5.1.6 */ public interface ConfigBuilder { } diff --git a/config-lib/src/main/java/com/yahoo/config/ConfigInstance.java b/config-lib/src/main/java/com/yahoo/config/ConfigInstance.java index 04405839a9b..113e622a503 100644 --- a/config-lib/src/main/java/com/yahoo/config/ConfigInstance.java +++ b/config-lib/src/main/java/com/yahoo/config/ConfigInstance.java @@ -17,6 +17,7 @@ public abstract class ConfigInstance extends InnerNode { /** * Dispatches a getConfig() call if this instance's producer is of the right type + * * @param producer a config producer * @return true if this instance's producer was the correct type, and hence a getConfig call was dispatched */ @@ -26,6 +27,11 @@ public abstract class ConfigInstance extends InnerNode { String getDefNamespace(); String getDefMd5(); + /** Returns true if this instance should be applied on restart, false if it should be applied immediately */ + default boolean getApplyOnRestart() { return false; } + + default void setApplyOnRestart(boolean applyOnRestart) { throw new java.lang.UnsupportedOperationException(); } + } public interface Producer {} diff --git a/config-lib/src/main/java/com/yahoo/config/Node.java b/config-lib/src/main/java/com/yahoo/config/Node.java index 8d16b9727c1..ed11bdc9891 100644 --- a/config-lib/src/main/java/com/yahoo/config/Node.java +++ b/config-lib/src/main/java/com/yahoo/config/Node.java @@ -5,7 +5,6 @@ package com.yahoo.config; * The Node class is superclass for all nodes in a {@link * ConfigInstance}. Important subclasses of this node are {@link * InnerNode} and {@link LeafNode}. - * */ public abstract class Node { @@ -13,7 +12,7 @@ public abstract class Node { * Postinitialize this node. Any node needing to process its values depending on the config * id should override this method. * - * @param configId the configId of the ConfigInstance that owns (or is) this node + * @param configId the configId of the ConfigInstance that owns (or is) this node */ public void postInitialize(String configId) { return; } @@ -26,4 +25,5 @@ public abstract class Node { protected Object clone() throws CloneNotSupportedException { return super.clone(); } + } diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/Model.java b/config-model-api/src/main/java/com/yahoo/config/model/api/Model.java index d25de9fb334..6481c4cb2c7 100644 --- a/config-model-api/src/main/java/com/yahoo/config/model/api/Model.java +++ b/config-model-api/src/main/java/com/yahoo/config/model/api/Model.java @@ -2,6 +2,7 @@ package com.yahoo.config.model.api; import com.yahoo.component.Version; +import com.yahoo.config.ConfigInstance; import com.yahoo.config.FileReference; import com.yahoo.config.provision.AllocatedHosts; import com.yahoo.vespa.config.ConfigKey; @@ -23,41 +24,45 @@ public interface Model { /** * Resolves config for a given key and config definition * - * @param configKey The key to resolve - * @param configDefinition The config definition to use for the schema + * @param configKey the key to resolve + * @param configDefinition the config definition to use for the schema */ + @Deprecated // TODO: Return after December 2020 ConfigPayload getConfig(ConfigKey configKey, ConfigDefinition configDefinition); /** - * Produces a set of the valid config keys for this model. + * Resolves config for a given key and config definition + * + * @param configKey the key to resolve + * @param configDefinition the config definition to use for the schema */ + default ConfigInstance.Builder getConfigInstance(ConfigKey configKey, ConfigDefinition configDefinition) { + return null; // TODO: Remove this default implementation after December 2020 + } + + /** Produces a set of the valid config keys for this model. */ Set> allConfigsProduced(); - /** - * Returns information about all hosts used in this model. - */ + /** Returns information about all hosts used in this model. */ Collection getHosts(); - /** - * Returns all the config ids available for this model. - */ + /** Returns all the config ids available for this model. */ Set allConfigIds(); /** * Asks the {@link Model} instance to distribute files using provided filedistribution instance. - * @param fileDistribution {@link com.yahoo.config.model.api.FileDistribution} instance that can be called to distribute files. + * + * @param fileDistribution instance that can be called to distribute files */ void distributeFiles(FileDistribution fileDistribution); - /** - * The set of files that should be distributed to the hosts in this model. - */ + /** The set of files that should be distributed to the hosts in this model. */ Set fileReferences(); /** * Gets the allocated hosts for this model. * - * @return {@link AllocatedHosts} instance, if available. + * @return {@link AllocatedHosts} instance, if available */ AllocatedHosts allocatedHosts(); @@ -80,13 +85,10 @@ public interface Model { */ default boolean skipOldConfigModels(Instant now) { return false; } - /** - * Returns the version of this model - */ + /** Returns the version of this model. */ default Version version() { return Version.emptyVersion; } - /** - * Returns the provisioned hosts of this - */ + /** Returns the provisioned hosts of this. */ default Provisioned provisioned() { return new Provisioned(); } + } diff --git a/config-model-fat/pom.xml b/config-model-fat/pom.xml index 0c8d45c9ea2..8a839b228a0 100644 --- a/config-model-fat/pom.xml +++ b/config-model-fat/pom.xml @@ -105,7 +105,7 @@ com.yahoo.vespa.config, com.yahoo.vespa.config.buildergen, - com.yahoo.config.codegen + com.yahoo.config.codegen diff --git a/config-model/src/main/java/com/yahoo/vespa/model/InstanceResolver.java b/config-model/src/main/java/com/yahoo/vespa/model/InstanceResolver.java index a8404b076d4..11e97bc8a95 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/InstanceResolver.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/InstanceResolver.java @@ -31,7 +31,8 @@ import java.util.Map; * * @author Vegard Havdal */ -// TODO This functionality should be on VespaModel itself, but we don't have a way right now to apply a config override to a ConfigInstance.Builder +// TODO: Most of this has been copied to ConfigInstance.Builder.buildInstance() and can be removed from here +// when Model.getConfig is removed class InstanceResolver { private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(InstanceResolver.class.getName()); @@ -138,7 +139,6 @@ class InstanceResolver { return packagePrefix.value + cKey.getNamespace(); } - enum PackagePrefix { COM_YAHOO("com.yahoo."), NONE(""); @@ -148,4 +148,5 @@ class InstanceResolver { this.value = value; } } + } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/VespaModel.java b/config-model/src/main/java/com/yahoo/vespa/model/VespaModel.java index 2ffc24239f9..9fdaaff9d5e 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/VespaModel.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/VespaModel.java @@ -313,6 +313,7 @@ public final class VespaModel extends AbstractConfigProducerRoot implements Seri * @param configId the config id * @return a config instance of the given type */ + @Override public CONFIGTYPE getConfig(Class clazz, String configId) { try { ConfigInstance.Builder builder = newBuilder(clazz); @@ -393,6 +394,7 @@ public final class VespaModel extends AbstractConfigProducerRoot implements Seri * @param targetDef The config definition to use for the schema * @return The payload as a list of strings */ + @Deprecated // TODO: Remove after December 2020 @Override public ConfigPayload getConfig(ConfigKey configKey, com.yahoo.vespa.config.buildergen.ConfigDefinition targetDef) { Objects.requireNonNull(targetDef, "config definition cannot be null"); @@ -404,6 +406,19 @@ public final class VespaModel extends AbstractConfigProducerRoot implements Seri return (innerCNode != null) ? payload.applyDefaultsFromDef(innerCNode) : payload; } + /** + * Resolve config for a given key and config definition + * + * @param configKey the key to resolve. + * @param targetDef the config definition to use for the schema + * @return the resolved config instance + */ + @Override + public ConfigInstance.Builder getConfigInstance(ConfigKey configKey, com.yahoo.vespa.config.buildergen.ConfigDefinition targetDef) { + Objects.requireNonNull(targetDef, "config definition cannot be null"); + return resolveToBuilder(configKey); + } + /** * Resolves the given config key into a correctly typed ConfigBuilder * and fills in the config from this model. diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/Container.java b/config-model/src/main/java/com/yahoo/vespa/model/container/Container.java index 6e470b24f9f..5e95403313c 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/container/Container.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/container/Container.java @@ -306,9 +306,7 @@ public abstract class Container extends AbstractService implements .port(getRpcPort()) .slobrokId(serviceSlobrokId())) .filedistributor(filedistributorConfig()) - .discriminator((clusterName != null ? clusterName + "." : "" ) + name) - .restartOnDeploy(owner != null && owner.getDeferChangesUntilRestart()); - + .discriminator((clusterName != null ? clusterName + "." : "" ) + name); } /** Returns the jvm args set explicitly for this node */ @@ -330,6 +328,7 @@ public abstract class Container extends AbstractService implements @Override public void getConfig(ComponentsConfig.Builder builder) { + builder.setApplyOnRestart(owner.getDeferChangesUntilRestart()); // Sufficient to set on one config builder.components.addAll(ComponentsConfigGenerator.generate(allEnabledComponents())); } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/ContainerCluster.java b/config-model/src/main/java/com/yahoo/vespa/model/container/ContainerCluster.java index 813247d1ae9..c0fd4eb7b05 100755 --- a/config-model/src/main/java/com/yahoo/vespa/model/container/ContainerCluster.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/container/ContainerCluster.java @@ -413,6 +413,7 @@ public abstract class ContainerCluster @Override public void getConfig(ComponentsConfig.Builder builder) { + builder.setApplyOnRestart(getDeferChangesUntilRestart()); // Sufficient to set on one config builder.components.addAll(ComponentsConfigGenerator.generate(getAllComponents())); builder.components(new ComponentsConfig.Components.Builder().id("com.yahoo.container.core.config.HandlersConfigurerDi$RegistriesHack")); } diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/RestartChangesDefersConfigChangesTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/RestartChangesDefersConfigChangesTest.java index 35aa9a3c988..fda4c54c154 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/RestartChangesDefersConfigChangesTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/RestartChangesDefersConfigChangesTest.java @@ -1,9 +1,11 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.model.application.validation.change; +import com.yahoo.cloud.config.log.LogdConfig; import com.yahoo.config.model.provision.InMemoryProvisioner; import com.yahoo.config.provision.Environment; import com.yahoo.config.provision.NodeResources; +import com.yahoo.container.ComponentsConfig; import com.yahoo.container.QrConfig; import com.yahoo.vespa.model.VespaModel; import com.yahoo.vespa.model.application.validation.ValidationTester; @@ -26,15 +28,15 @@ public class RestartChangesDefersConfigChangesTest { // Change node count - no restart VespaModel gen2 = tester.deploy(gen1, getServices(4, 3), Environment.prod, null).getFirst(); - var config2 = new QrConfig.Builder(); + var config2 = new ComponentsConfig.Builder(); gen2.getContainerClusters().get("default").getContainers().get(0).getConfig(config2); - assertFalse(config2.build().restartOnDeploy()); + assertFalse(config2.getApplyOnRestart()); // Change memory amount - requires restart VespaModel gen3 = tester.deploy(gen2, getServices(4, 2), Environment.prod, null).getFirst(); - var config3 = new QrConfig.Builder(); + var config3 = new ComponentsConfig.Builder(); gen3.getContainerClusters().get("default").getContainers().get(0).getConfig(config3); - assertTrue(config3.build().restartOnDeploy()); + assertTrue(config3.getApplyOnRestart()); } private static String getServices(int nodes, int memory) { diff --git a/config-proxy/src/main/java/com/yahoo/vespa/config/proxy/ConfigProxyRpcServer.java b/config-proxy/src/main/java/com/yahoo/vespa/config/proxy/ConfigProxyRpcServer.java index 30f4884c737..81ecd8620b9 100644 --- a/config-proxy/src/main/java/com/yahoo/vespa/config/proxy/ConfigProxyRpcServer.java +++ b/config-proxy/src/main/java/com/yahoo/vespa/config/proxy/ConfigProxyRpcServer.java @@ -350,7 +350,11 @@ public class ConfigProxyRpcServer implements Runnable, TargetWatcher, RpcServer public void returnOkResponse(JRTServerConfigRequest request, RawConfig config) { request.getRequestTrace().trace(TRACELEVEL, "Config proxy returnOkResponse()"); - request.addOkResponse(config.getPayload(), config.getGeneration(), config.isInternalRedeploy(), config.getConfigMd5()); + request.addOkResponse(config.getPayload(), + config.getGeneration(), + config.isInternalRedeploy(), + config.applyOnRestart(), + config.getConfigMd5()); log.log(Level.FINE, () -> "Return response: " + request.getShortDescription() + ",configMd5=" + config.getConfigMd5() + ",generation=" + config.getGeneration()); log.log(Level.FINEST, () -> "Config payload in response for " + request.getShortDescription() + ":" + config.getPayload()); diff --git a/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/ConfigTester.java b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/ConfigTester.java index 33e798da15e..87a8764310a 100644 --- a/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/ConfigTester.java +++ b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/ConfigTester.java @@ -44,11 +44,11 @@ public class ConfigTester { String defMd5 = ConfigUtils.getDefMd5(defContent); String configMd5 = ConfigUtils.getMd5(fooConfigPayload); fooConfig = new RawConfig(configKey, defMd5, fooPayload, configMd5, - generation, false, defContent, Optional.empty()); + generation, false, false, defContent, Optional.empty()); String defName2 = "bar"; barConfig = new RawConfig(new ConfigKey<>(defName2, configId, namespace), defMd5, fooPayload, configMd5, - generation, false, defContent, Optional.empty()); + generation, false, false, defContent, Optional.empty()); } JRTServerConfigRequest createRequest(RawConfig config) { diff --git a/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/MemoryCacheTest.java b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/MemoryCacheTest.java index 485a091d9ae..c5e680f950a 100644 --- a/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/MemoryCacheTest.java +++ b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/MemoryCacheTest.java @@ -63,9 +63,9 @@ public class MemoryCacheTest { slime.setString("bar \"value2\""); payloadDifferentMd5 = Payload.from(new ConfigPayload(slime)); - config = new RawConfig(configKey, defMd5, payload, configMd5, generation, false, defContent, Optional.empty()); - config2 = new RawConfig(configKey2, defMd52, payload2, configMd5, generation, false, defContent, Optional.empty()); - configDifferentMd5 = new RawConfig(configKey, differentDefMd5, payloadDifferentMd5, configMd5, generation, false, defContent, Optional.empty()); + config = new RawConfig(configKey, defMd5, payload, configMd5, generation, false, false, defContent, Optional.empty()); + config2 = new RawConfig(configKey2, defMd52, payload2, configMd5, generation, false, false, defContent, Optional.empty()); + configDifferentMd5 = new RawConfig(configKey, differentDefMd5, payloadDifferentMd5, configMd5, generation, false, false, defContent, Optional.empty()); cacheKey = new ConfigCacheKey(configKey, config.getDefMd5()); cacheKey2 = new ConfigCacheKey(configKey2, config2.getDefMd5()); diff --git a/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/ProxyServerTest.java b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/ProxyServerTest.java index f52598b3ee5..c858f894fc4 100644 --- a/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/ProxyServerTest.java +++ b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/ProxyServerTest.java @@ -36,7 +36,7 @@ public class ProxyServerTest { private static final ConfigKey errorConfigKey = new ConfigKey<>("error", fooConfig.getConfigId(), fooConfig.getNamespace()); static final RawConfig errorConfig = new RawConfig(errorConfigKey, fooConfig.getDefMd5(), fooConfig.getPayload(), fooConfig.getConfigMd5(), - fooConfig.getGeneration(), false, ErrorCode.UNKNOWN_DEFINITION, fooConfig.getDefContent(), Optional.empty()); + fooConfig.getGeneration(), false, false, ErrorCode.UNKNOWN_DEFINITION, fooConfig.getDefContent(), Optional.empty()); @Rule public TemporaryFolder temporaryFolder = new TemporaryFolder(); @@ -180,7 +180,7 @@ public class ProxyServerTest { // Simulate an empty response RawConfig emptyConfig = new RawConfig(fooConfig.getKey(), fooConfig.getDefMd5(), Payload.from("{}"), fooConfig.getConfigMd5(), - 0, false, 0, fooConfig.getDefContent(), Optional.empty()); + 0, false, false, 0, fooConfig.getDefContent(), Optional.empty()); source.put(fooConfig.getKey(), emptyConfig); res = proxy.resolveConfig(tester.createRequest(fooConfig)); @@ -239,7 +239,7 @@ public class ProxyServerTest { static RawConfig createConfigWithNextConfigGeneration(RawConfig config, int errorCode, Payload payload, long configGeneration) { return new RawConfig(config.getKey(), config.getDefMd5(), payload, config.getConfigMd5(), - configGeneration, false, + configGeneration, false, false, errorCode, config.getDefContent(), Optional.empty()); } diff --git a/config/src/apps/vespa-get-config/getconfig.cpp b/config/src/apps/vespa-get-config/getconfig.cpp index a5e400bd354..92966b934f1 100644 --- a/config/src/apps/vespa-get-config/getconfig.cpp +++ b/config/src/apps/vespa-get-config/getconfig.cpp @@ -220,7 +220,7 @@ GetConfig::Main() FRTConfigRequestFactory requestFactory(protocolVersion, traceLevel, vespaVersion, config::protocol::readProtocolCompressionType()); FRTConnection connection(spec, _server->supervisor(), TimingValues()); ConfigKey key(configId, defName, defNamespace, defMD5, defSchema); - ConfigState state(configMD5, generation, false); + ConfigState state(configMD5, generation, false, false); FRTConfigRequest::UP request = requestFactory.createConfigRequest(key, &connection, state, serverTimeout * 1000); _target->InvokeSync(request->getRequest(), clientTimeout); // seconds diff --git a/config/src/main/java/com/yahoo/config/subscription/ConfigSubscriber.java b/config/src/main/java/com/yahoo/config/subscription/ConfigSubscriber.java index 6bfaa992eb1..ad131f8e0dd 100644 --- a/config/src/main/java/com/yahoo/config/subscription/ConfigSubscriber.java +++ b/config/src/main/java/com/yahoo/config/subscription/ConfigSubscriber.java @@ -33,6 +33,7 @@ import static java.util.stream.Collectors.toList; public class ConfigSubscriber implements AutoCloseable { private static final Logger log = Logger.getLogger(ConfigSubscriber.class.getName()); + private State state = State.OPEN; protected final List> subscriptionHandles = new CopyOnWriteArrayList<>(); private final ConfigSource source; @@ -45,6 +46,13 @@ public class ConfigSubscriber implements AutoCloseable { /** Whether the last generation received was due to a system-internal redeploy, not an application package change */ private boolean internalRedeploy = false; + /** + * Whether the last generation should only be applied on restart, not immediately. + * Once this is set it will not be unset, as no future generation should be applied + * once there is a generation which require restart. + */ + private boolean applyOnRestart = false; + /** * Reuse requesters for equal source sets, limit number if many subscriptions. */ @@ -235,12 +243,15 @@ public class ConfigSubscriber implements AutoCloseable { * @param timeoutInMillis timeout to wait in milliseconds * @param requireChange if set, at least one config have to change * @return true, if a new config generation has been found for all configs (additionally requires - * that at lest one of them has changed if requireChange is true), false otherwise + * that at lest one of them has changed if requireChange is true), and + * the config should be applied at this time, false otherwise */ private boolean acquireSnapshot(long timeoutInMillis, boolean requireChange) { + boolean applyOnRestartOnly; synchronized (monitor) { if (state == State.CLOSED) return false; state = State.FROZEN; + applyOnRestartOnly = applyOnRestart; } long started = System.currentTimeMillis(); long timeLeftMillis = timeoutInMillis; @@ -269,9 +280,18 @@ public class ConfigSubscriber implements AutoCloseable { allGenerationsChanged &= config.isGenerationChanged(); anyConfigChanged |= config.isConfigChanged(); internalRedeployOnly &= config.isInternalRedeploy(); + applyOnRestartOnly |= requireChange && config.applyOnRestart(); // only if this is reconfig timeLeftMillis = timeoutInMillis + started - System.currentTimeMillis(); } - reconfigDue = (anyConfigChanged || !requireChange) && allGenerationsChanged && allGenerationsTheSame; + reconfigDue = ((anyConfigChanged && !applyOnRestartOnly) || !requireChange) + && allGenerationsChanged && allGenerationsTheSame; + + if (requireChange && applyOnRestartOnly) { // if this is a reconfig, disable future reconfigs until restart + synchronized (monitor) { + applyOnRestart = applyOnRestartOnly; + } + } + if (!reconfigDue && timeLeftMillis > 0) { sleep(timeLeftMillis); } diff --git a/config/src/main/java/com/yahoo/config/subscription/impl/ConfigSubscription.java b/config/src/main/java/com/yahoo/config/subscription/impl/ConfigSubscription.java index 3bf6093e872..15f6395c417 100644 --- a/config/src/main/java/com/yahoo/config/subscription/impl/ConfigSubscription.java +++ b/config/src/main/java/com/yahoo/config/subscription/impl/ConfigSubscription.java @@ -40,21 +40,28 @@ public abstract class ConfigSubscription { private final T config; private final Long generation; private final boolean internalRedeploy; - - private ConfigState(boolean generationChanged, Long generation, boolean internalRedeploy, boolean configChanged, T config) { + private final boolean applyOnRestart; + + private ConfigState(boolean generationChanged, + Long generation, + boolean internalRedeploy, + boolean applyOnRestart, + boolean configChanged, + T config) { this.generationChanged = generationChanged; this.generation = generation; this.internalRedeploy = internalRedeploy; + this.applyOnRestart = applyOnRestart; this.configChanged = configChanged; this.config = config; } private ConfigState(Long generation, T config) { - this(false, generation, false, false, config); + this(false, generation, false, false, false, config); } private ConfigState() { - this(false, 0L, false, false, null); + this(false, 0L, false, false, false, null); } private ConfigState createUnchanged() { return new ConfigState<>(generation, config); } @@ -68,6 +75,8 @@ public abstract class ConfigSubscription { */ public boolean isInternalRedeploy() { return internalRedeploy; } + public boolean applyOnRestart() { return applyOnRestart; } + public T getConfig() { return config; } } @@ -181,29 +190,34 @@ public abstract class ConfigSubscription { return !prev.getGeneration().equals(requiredGen) || prev.isConfigChanged(); } - void setConfig(Long generation, boolean internalRedeploy, T config) { - this.config.set(new ConfigState<>(true, generation, internalRedeploy, true, config)); + void setConfig(Long generation, boolean internalRedeploy, boolean applyOnRestart, T config) { + this.config.set(new ConfigState<>(true, generation, internalRedeploy, applyOnRestart, true, config)); } /** Used by {@link FileConfigSubscription} and {@link ConfigSetSubscription} */ protected void setConfigIncGen(T config) { ConfigState prev = this.config.get(); - this.config.set(new ConfigState<>(true, prev.getGeneration() + 1, prev.isInternalRedeploy(), true, config)); + this.config.set(new ConfigState<>(true, prev.getGeneration() + 1, prev.isInternalRedeploy(), prev.applyOnRestart(), true, config)); } protected void setConfigIfChanged(T config) { ConfigState prev = this.config.get(); - this.config.set(new ConfigState<>(true, prev.getGeneration(), prev.isInternalRedeploy(), !config.equals(prev.getConfig()), config)); + this.config.set(new ConfigState<>(true, prev.getGeneration(), prev.isInternalRedeploy(), prev.applyOnRestart(), !config.equals(prev.getConfig()), config)); } void setGeneration(Long generation) { ConfigState prev = config.get(); - this.config.set(new ConfigState<>(true, generation, prev.isInternalRedeploy(), prev.isConfigChanged(), prev.getConfig())); + this.config.set(new ConfigState<>(true, generation, prev.isInternalRedeploy(), prev.applyOnRestart(), prev.isConfigChanged(), prev.getConfig())); } void setInternalRedeploy(boolean internalRedeploy) { ConfigState prev = config.get(); - this.config.set(new ConfigState<>(prev.isGenerationChanged(), prev.getGeneration(), internalRedeploy, prev.isConfigChanged(), prev.getConfig())); + this.config.set(new ConfigState<>(prev.isGenerationChanged(), prev.getGeneration(), internalRedeploy, prev.applyOnRestart(), prev.isConfigChanged(), prev.getConfig())); + } + + void setApplyOnRestart(boolean applyOnRestart) { + ConfigState prev = config.get(); + this.config.set(new ConfigState<>(prev.isGenerationChanged(), prev.getGeneration(), prev.isInternalRedeploy(), applyOnRestart, prev.isConfigChanged(), prev.getConfig())); } /** diff --git a/config/src/main/java/com/yahoo/config/subscription/impl/GenericJRTConfigSubscription.java b/config/src/main/java/com/yahoo/config/subscription/impl/GenericJRTConfigSubscription.java index eec18b93e71..ba8fc8a5e19 100644 --- a/config/src/main/java/com/yahoo/config/subscription/impl/GenericJRTConfigSubscription.java +++ b/config/src/main/java/com/yahoo/config/subscription/impl/GenericJRTConfigSubscription.java @@ -18,7 +18,6 @@ import static java.util.logging.Level.FINE; * Used by config proxy. * * @author Vegard Havdal - * */ public class GenericJRTConfigSubscription extends JRTConfigSubscription { @@ -33,7 +32,7 @@ public class GenericJRTConfigSubscription extends JRTConfigSubscription "in setNewConfig, config=" + this.getConfigState().getConfig()); } @@ -60,6 +59,17 @@ public class GenericJRTConfigSubscription extends JRTConfigSubscription configState = getConfigState(); + + if (configState.getConfig() != null) { + configState.getConfig().setApplyOnRestart(applyOnRestart); + } + } + public RawConfig getRawConfig() { return getConfigState().getConfig(); } diff --git a/config/src/main/java/com/yahoo/config/subscription/impl/JRTConfigSubscription.java b/config/src/main/java/com/yahoo/config/subscription/impl/JRTConfigSubscription.java index 44f6d65ee65..e9d5d317995 100644 --- a/config/src/main/java/com/yahoo/config/subscription/impl/JRTConfigSubscription.java +++ b/config/src/main/java/com/yahoo/config/subscription/impl/JRTConfigSubscription.java @@ -94,6 +94,7 @@ public class JRTConfigSubscription extends ConfigSubsc log.log(FINE, () -> "Polled queue and found config " + jrtReq); if (jrtReq.hasUpdatedGeneration()) { setInternalRedeploy(jrtReq.responseIsInternalRedeploy()); + setApplyOnRestart(jrtReq.responseIsApplyOnRestart()); if (jrtReq.hasUpdatedConfig()) { setNewConfig(jrtReq); } else { @@ -111,7 +112,7 @@ public class JRTConfigSubscription extends ConfigSubsc } catch (IllegalArgumentException e) { badConfigE = e; } - setConfig(jrtReq.getNewGeneration(), jrtReq.responseIsInternalRedeploy(), configInstance); + setConfig(jrtReq.getNewGeneration(), jrtReq.responseIsInternalRedeploy(), jrtReq.responseIsApplyOnRestart(), configInstance); if (badConfigE != null) { throw new IllegalArgumentException("Bad config from jrt", badConfigE); } diff --git a/config/src/main/java/com/yahoo/config/subscription/impl/JarConfigSubscription.java b/config/src/main/java/com/yahoo/config/subscription/impl/JarConfigSubscription.java index 05da9a72837..9fc5d9d3300 100644 --- a/config/src/main/java/com/yahoo/config/subscription/impl/JarConfigSubscription.java +++ b/config/src/main/java/com/yahoo/config/subscription/impl/JarConfigSubscription.java @@ -63,7 +63,7 @@ public class JarConfigSubscription extends ConfigSubsc } catch (IOException e) { throw new ConfigurationRuntimeException(e); } - setConfig(0L, false, config); + setConfig(0L, false, false, config); try { jarFile.close(); } catch (IOException e) { diff --git a/config/src/main/java/com/yahoo/config/subscription/impl/MockConnection.java b/config/src/main/java/com/yahoo/config/subscription/impl/MockConnection.java index 58eed7f9e78..3a284489109 100644 --- a/config/src/main/java/com/yahoo/config/subscription/impl/MockConnection.java +++ b/config/src/main/java/com/yahoo/config/subscription/impl/MockConnection.java @@ -115,7 +115,7 @@ public class MockConnection implements ConnectionPool, com.yahoo.vespa.config.Co JRTServerConfigRequestV3 jrtReq = JRTServerConfigRequestV3.createFromRequest(request); Payload payload = Payload.from(ConfigPayload.empty()); long generation = 1; - jrtReq.addOkResponse(payload, generation, false, ConfigUtils.getMd5(payload.getData())); + jrtReq.addOkResponse(payload, generation, false, false, ConfigUtils.getMd5(payload.getData())); } } diff --git a/config/src/main/java/com/yahoo/config/subscription/impl/RawConfigSubscription.java b/config/src/main/java/com/yahoo/config/subscription/impl/RawConfigSubscription.java index 68ff6bb0135..1ff0a058a93 100644 --- a/config/src/main/java/com/yahoo/config/subscription/impl/RawConfigSubscription.java +++ b/config/src/main/java/com/yahoo/config/subscription/impl/RawConfigSubscription.java @@ -35,7 +35,7 @@ public class RawConfigSubscription extends ConfigSubsc if (payload == null) { payload = inputPayload; ConfigPayload configPayload = new CfgConfigPayloadBuilder().deserialize(Arrays.asList(payload.split("\n"))); - setConfig(0L, false, configPayload.toInstance(configClass, key.getConfigId())); + setConfig(0L, false, false, configPayload.toInstance(configClass, key.getConfigId())); return true; } try { diff --git a/config/src/main/java/com/yahoo/vespa/config/ConfigPayload.java b/config/src/main/java/com/yahoo/vespa/config/ConfigPayload.java index 2f3a4bd2172..8153179e49c 100644 --- a/config/src/main/java/com/yahoo/vespa/config/ConfigPayload.java +++ b/config/src/main/java/com/yahoo/vespa/config/ConfigPayload.java @@ -17,7 +17,7 @@ import java.io.IOException; import java.io.OutputStream; /** - * A class that holds a representation of a config payload. + * A config payload. * * @author Ulf Lilleengen */ diff --git a/config/src/main/java/com/yahoo/vespa/config/ConfigPayloadApplier.java b/config/src/main/java/com/yahoo/vespa/config/ConfigPayloadApplier.java index b4df42c802e..d24f09bda12 100644 --- a/config/src/main/java/com/yahoo/vespa/config/ConfigPayloadApplier.java +++ b/config/src/main/java/com/yahoo/vespa/config/ConfigPayloadApplier.java @@ -38,6 +38,7 @@ import static java.util.logging.Level.INFO; * @author Ulf Lilleengen, hmusum, Tony Vaagenes */ public class ConfigPayloadApplier { + private final static Logger log = Logger.getLogger(ConfigPayloadApplier.class.getPackage().getName()); private final ConfigInstance.Builder rootBuilder; diff --git a/config/src/main/java/com/yahoo/vespa/config/GenericConfig.java b/config/src/main/java/com/yahoo/vespa/config/GenericConfig.java index 2f351cc2bd4..123d7c22093 100644 --- a/config/src/main/java/com/yahoo/vespa/config/GenericConfig.java +++ b/config/src/main/java/com/yahoo/vespa/config/GenericConfig.java @@ -12,6 +12,7 @@ import com.yahoo.config.ConfigInstance; * @author Ulf Lilleengen */ public class GenericConfig { + public static class GenericConfigBuilder implements ConfigInstance.Builder { private final ConfigPayloadBuilder payloadBuilder; @@ -49,6 +50,7 @@ public class GenericConfig { public String getDefMd5() { return ""; } + } } diff --git a/config/src/main/java/com/yahoo/vespa/config/RawConfig.java b/config/src/main/java/com/yahoo/vespa/config/RawConfig.java index 96908f055f1..cf0f1243acf 100755 --- a/config/src/main/java/com/yahoo/vespa/config/RawConfig.java +++ b/config/src/main/java/com/yahoo/vespa/config/RawConfig.java @@ -32,6 +32,7 @@ public class RawConfig extends ConfigInstance { private final Optional vespaVersion; private long generation; private boolean internalRedeploy; + private boolean applyOnRestart; /** * Constructor for an empty config (not yet resolved). @@ -40,29 +41,32 @@ public class RawConfig extends ConfigInstance { * @param defMd5 The md5 sum of the .def-file. */ public RawConfig(ConfigKey key, String defMd5) { - this(key, defMd5, null, "", 0L, false, 0, Collections.emptyList(), Optional.empty()); + this(key, defMd5, null, "", 0L, false, false, 0, Collections.emptyList(), Optional.empty()); } public RawConfig(ConfigKey key, String defMd5, Payload payload, String configMd5, long generation, - boolean internalRedeploy, List defContent, Optional vespaVersion) { - this(key, defMd5, payload, configMd5, generation, internalRedeploy, 0, defContent, vespaVersion); + boolean internalRedeploy, boolean applyOnRestart, List defContent, + Optional vespaVersion) { + this(key, defMd5, payload, configMd5, generation, internalRedeploy, applyOnRestart, 0, defContent, vespaVersion); } /** Copy constructor */ public RawConfig(RawConfig rawConfig) { this(rawConfig.key, rawConfig.defMd5, rawConfig.payload, rawConfig.configMd5, - rawConfig.generation, rawConfig.internalRedeploy, rawConfig.errorCode, - rawConfig.defContent, rawConfig.getVespaVersion()); + rawConfig.generation, rawConfig.internalRedeploy, rawConfig.applyOnRestart, + rawConfig.errorCode, rawConfig.defContent, rawConfig.getVespaVersion()); } public RawConfig(ConfigKey key, String defMd5, Payload payload, String configMd5, long generation, - boolean internalRedeploy, int errorCode, List defContent, Optional vespaVersion) { + boolean internalRedeploy, boolean applyOnRestart, int errorCode, List defContent, + Optional vespaVersion) { this.key = key; this.defMd5 = ConfigUtils.getDefMd5FromRequest(defMd5, defContent); this.payload = payload; this.configMd5 = configMd5; this.generation = generation; this.internalRedeploy = internalRedeploy; + this.applyOnRestart = applyOnRestart; this.errorCode = errorCode; this.defContent = defContent; this.vespaVersion = vespaVersion; @@ -80,6 +84,7 @@ public class RawConfig extends ConfigInstance { req.getNewConfigMd5(), req.getNewGeneration(), req.responseIsInternalRedeploy(), + req.responseIsApplyOnRestart(), 0, req.getDefContent().asList(), req.getVespaVersion()); @@ -97,6 +102,7 @@ public class RawConfig extends ConfigInstance { req.getRequestConfigMd5(), req.getRequestGeneration(), req.isInternalRedeploy(), + req.applyOnRestart(), 0, req.getDefContent().asList(), req.getVespaVersion()); @@ -121,12 +127,16 @@ public class RawConfig extends ConfigInstance { public void setInternalRedeploy(boolean internalRedeploy) { this.internalRedeploy = internalRedeploy; } + public void setApplyOnRestart(boolean applyOnRestart) { this.applyOnRestart = applyOnRestart; } + /** * Returns whether this config generation was created by a system internal redeploy, not an * application package change. */ public boolean isInternalRedeploy() { return internalRedeploy; } + public boolean applyOnRestart() { return applyOnRestart; } + public Payload getPayload() { return payload; } public int errorCode() { return errorCode; } @@ -165,24 +175,17 @@ public class RawConfig extends ConfigInstance { @Override public boolean equals(Object o) { - if (o == this) { - return true; - } - if (! (o instanceof RawConfig)) { - return false; - } + if (o == this) return true; + if (! (o instanceof RawConfig)) return false; + RawConfig other = (RawConfig) o; - if (! (key.equals(other.key) && - defMd5.equals(other.defMd5) && - (errorCode == other.errorCode)) ) { + if (! (key.equals(other.key) && defMd5.equals(other.defMd5) && (errorCode == other.errorCode)) ) return false; - } + // Need to check error codes before isError, since unequal error codes always means unequal requests, // while non-zero and equal error codes means configs are equal. - if (isError()) - return true; - if (generation != other.generation) - return false; + if (isError()) return true; + if (generation != other.generation) return false; if (configMd5 != null) { return configMd5.equals(other.configMd5); } else { diff --git a/config/src/main/java/com/yahoo/vespa/config/buildergen/ConfigDefinition.java b/config/src/main/java/com/yahoo/vespa/config/buildergen/ConfigDefinition.java index e145f8ee090..3fe42ce90ad 100644 --- a/config/src/main/java/com/yahoo/vespa/config/buildergen/ConfigDefinition.java +++ b/config/src/main/java/com/yahoo/vespa/config/buildergen/ConfigDefinition.java @@ -1,13 +1,10 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.config.buildergen; -import com.google.common.io.Files; import com.yahoo.config.codegen.DefParser; import com.yahoo.config.codegen.InnerCNode; -import com.yahoo.config.codegen.JavaClassBuilder; import com.yahoo.text.StringUtilities; -import java.io.File; import java.io.StringReader; /** @@ -15,6 +12,7 @@ import java.io.StringReader; * @author Ulf Lilleengen */ public class ConfigDefinition { + private final String name; private final String[] defSchema; private final InnerCNode cnode; diff --git a/config/src/main/java/com/yahoo/vespa/config/protocol/ConfigResponse.java b/config/src/main/java/com/yahoo/vespa/config/protocol/ConfigResponse.java index bb0ee2bb935..27f4816849d 100644 --- a/config/src/main/java/com/yahoo/vespa/config/protocol/ConfigResponse.java +++ b/config/src/main/java/com/yahoo/vespa/config/protocol/ConfigResponse.java @@ -22,6 +22,8 @@ public interface ConfigResponse { boolean isInternalRedeploy(); + boolean applyOnRestart(); + String getConfigMd5(); void serialize(OutputStream os, CompressionType uncompressed) throws IOException; diff --git a/config/src/main/java/com/yahoo/vespa/config/protocol/JRTClientConfigRequest.java b/config/src/main/java/com/yahoo/vespa/config/protocol/JRTClientConfigRequest.java index ab47fec0641..8f85e2353a5 100644 --- a/config/src/main/java/com/yahoo/vespa/config/protocol/JRTClientConfigRequest.java +++ b/config/src/main/java/com/yahoo/vespa/config/protocol/JRTClientConfigRequest.java @@ -56,6 +56,9 @@ public interface JRTClientConfigRequest extends JRTConfigRequest { /** Returns whether this config change is due to an internal change not an application package change */ boolean responseIsInternalRedeploy(); + /** Returns true if this config should only be applied at the last restart, false if it should be applied immediately */ + boolean responseIsApplyOnRestart(); + /** * Get the config md5 of the config returned by the server. Return an empty string if no response has been returned. * diff --git a/config/src/main/java/com/yahoo/vespa/config/protocol/JRTClientConfigRequestV3.java b/config/src/main/java/com/yahoo/vespa/config/protocol/JRTClientConfigRequestV3.java index 12e5968ab83..e04a2179602 100644 --- a/config/src/main/java/com/yahoo/vespa/config/protocol/JRTClientConfigRequestV3.java +++ b/config/src/main/java/com/yahoo/vespa/config/protocol/JRTClientConfigRequestV3.java @@ -181,6 +181,7 @@ public class JRTClientConfigRequestV3 implements JRTClientConfigRequest { sb.append("response='").append(getNewConfigMd5()) .append(",").append(getNewGeneration()) .append(",").append(responseIsInternalRedeploy()) + .append(",").append(responseIsApplyOnRestart()) .append("'\n"); return sb.toString(); } @@ -294,6 +295,11 @@ public class JRTClientConfigRequestV3 implements JRTClientConfigRequest { return responseData.getResponseInternalRedeployment(); } + @Override + public boolean responseIsApplyOnRestart() { + return responseData.getResponseApplyOnRestart(); + } + @Override public long getRequestGeneration() { return requestData.getRequestGeneration(); diff --git a/config/src/main/java/com/yahoo/vespa/config/protocol/JRTServerConfigRequest.java b/config/src/main/java/com/yahoo/vespa/config/protocol/JRTServerConfigRequest.java index 763f672a513..dbc6a7bb98d 100644 --- a/config/src/main/java/com/yahoo/vespa/config/protocol/JRTServerConfigRequest.java +++ b/config/src/main/java/com/yahoo/vespa/config/protocol/JRTServerConfigRequest.java @@ -34,9 +34,12 @@ public interface JRTServerConfigRequest extends JRTConfigRequest, GetConfigReque * @param generation The config generation of the given payload. * @param internalRedeployment whether this payload was generated from an internal redeployment not an * application package change + * @param applyOnRestart true if this config should only be applied on the next restart, + * false if it should be applied right away * @param configMd5 The md5sum of the given payload. */ - void addOkResponse(Payload payload, long generation, boolean internalRedeployment, String configMd5); + void addOkResponse(Payload payload, long generation, boolean internalRedeployment, boolean applyOnRestart, + String configMd5); /** * Get the current config md5 of the client config. @@ -65,6 +68,8 @@ public interface JRTServerConfigRequest extends JRTConfigRequest, GetConfigReque */ boolean isInternalRedeploy(); + boolean applyOnRestart(); + /** * Get the request trace for this request. The trace can be used to trace config execution to provide useful * debug info in production environments. diff --git a/config/src/main/java/com/yahoo/vespa/config/protocol/JRTServerConfigRequestV3.java b/config/src/main/java/com/yahoo/vespa/config/protocol/JRTServerConfigRequestV3.java index 3609ba04424..0bc7c44fe9d 100644 --- a/config/src/main/java/com/yahoo/vespa/config/protocol/JRTServerConfigRequestV3.java +++ b/config/src/main/java/com/yahoo/vespa/config/protocol/JRTServerConfigRequestV3.java @@ -37,6 +37,7 @@ public class JRTServerConfigRequestV3 implements JRTServerConfigRequest { private final SlimeRequestData requestData; /** Response field */ private boolean internalRedeploy = false; + private boolean applyOnRestart = false; // Response values private boolean isDelayed = false; private Trace requestTrace = null; @@ -67,8 +68,10 @@ public class JRTServerConfigRequestV3 implements JRTServerConfigRequest { } @Override - public void addOkResponse(Payload payload, long generation, boolean internalRedeploy, String configMd5) { + public void addOkResponse(Payload payload, long generation, boolean internalRedeploy, boolean applyOnRestart, + String configMd5) { this.internalRedeploy = internalRedeploy; + this.applyOnRestart = applyOnRestart; boolean changedConfig = !configMd5.equals(getRequestConfigMd5()); boolean changedConfigAndNewGeneration = changedConfig && ConfigUtils.isGenerationNewer(generation, getRequestGeneration()); Payload responsePayload = payload.withCompression(getCompressionType()); @@ -80,6 +83,7 @@ public class JRTServerConfigRequestV3 implements JRTServerConfigRequest { setResponseField(jsonGenerator, SlimeResponseData.RESPONSE_CONFIG_MD5, configMd5); setResponseField(jsonGenerator, SlimeResponseData.RESPONSE_CONFIG_GENERATION, generation); setResponseField(jsonGenerator, SlimeResponseData.RESPONSE_INTERNAL_REDEPLOY, internalRedeploy); + setResponseField(jsonGenerator, SlimeResponseData.RESPONSE_APPLY_ON_RESTART, applyOnRestart); jsonGenerator.writeObjectFieldStart(SlimeResponseData.RESPONSE_COMPRESSION_INFO); if (responsePayload == null) { throw new RuntimeException("Payload is null for ' " + this + ", not able to create response"); @@ -113,6 +117,9 @@ public class JRTServerConfigRequestV3 implements JRTServerConfigRequest { @Override public boolean isInternalRedeploy() { return internalRedeploy; } + @Override + public boolean applyOnRestart() { return applyOnRestart; } + public static JRTServerConfigRequestV3 createFromRequest(Request req) { return new JRTServerConfigRequestV3(req); } diff --git a/config/src/main/java/com/yahoo/vespa/config/protocol/SlimeConfigResponse.java b/config/src/main/java/com/yahoo/vespa/config/protocol/SlimeConfigResponse.java index ff0b7f964bf..8bdd336fd5c 100644 --- a/config/src/main/java/com/yahoo/vespa/config/protocol/SlimeConfigResponse.java +++ b/config/src/main/java/com/yahoo/vespa/config/protocol/SlimeConfigResponse.java @@ -18,12 +18,14 @@ public class SlimeConfigResponse implements ConfigResponse { private final CompressionInfo compressionInfo; private final long generation; private final boolean internalRedeploy; + private final boolean applyOnRestart; private final String configMd5; public static SlimeConfigResponse fromConfigPayload(ConfigPayload payload, long generation, - boolean internalRedeploy, String configMd5) { + boolean internalRedeploy, boolean applyOnRestart, + String configMd5) { Utf8Array data = payload.toUtf8Array(true); - return new SlimeConfigResponse(data, generation, internalRedeploy, + return new SlimeConfigResponse(data, generation, internalRedeploy, applyOnRestart, configMd5, CompressionInfo.create(CompressionType.UNCOMPRESSED, data.getByteLength())); } @@ -31,11 +33,13 @@ public class SlimeConfigResponse implements ConfigResponse { public SlimeConfigResponse(Utf8Array payload, long generation, boolean internalRedeploy, + boolean applyOnRestart, String configMd5, CompressionInfo compressionInfo) { this.payload = payload; this.generation = generation; this.internalRedeploy = internalRedeploy; + this.applyOnRestart = applyOnRestart; this.configMd5 = configMd5; this.compressionInfo = compressionInfo; } @@ -57,6 +61,9 @@ public class SlimeConfigResponse implements ConfigResponse { @Override public boolean isInternalRedeploy() { return internalRedeploy; } + @Override + public boolean applyOnRestart() { return applyOnRestart; } + @Override public String getConfigMd5() { return configMd5; diff --git a/config/src/main/java/com/yahoo/vespa/config/protocol/SlimeResponseData.java b/config/src/main/java/com/yahoo/vespa/config/protocol/SlimeResponseData.java index ba1e7a8c72e..1c9afa550d4 100644 --- a/config/src/main/java/com/yahoo/vespa/config/protocol/SlimeResponseData.java +++ b/config/src/main/java/com/yahoo/vespa/config/protocol/SlimeResponseData.java @@ -24,6 +24,7 @@ class SlimeResponseData { static final String RESPONSE_CONFIG_MD5 = "configMD5"; static final String RESPONSE_CONFIG_GENERATION = "generation"; static final String RESPONSE_INTERNAL_REDEPLOY = "internalRedeploy"; + static final String RESPONSE_APPLY_ON_RESTART = "applyOnRestart"; static final String RESPONSE_COMPRESSION_INFO = "compressionInfo"; private final Request request; @@ -72,4 +73,9 @@ class SlimeResponseData { return inspector.valid() && inspector.asBool(); } + boolean getResponseApplyOnRestart() { + Inspector inspector = getResponseField(RESPONSE_APPLY_ON_RESTART); + return inspector.valid() && inspector.asBool(); + } + } diff --git a/config/src/test/java/com/yahoo/config/subscription/impl/JRTConfigRequesterTest.java b/config/src/test/java/com/yahoo/config/subscription/impl/JRTConfigRequesterTest.java index 4211345dff7..07ff27a0154 100644 --- a/config/src/test/java/com/yahoo/config/subscription/impl/JRTConfigRequesterTest.java +++ b/config/src/test/java/com/yahoo/config/subscription/impl/JRTConfigRequesterTest.java @@ -184,7 +184,7 @@ public class JRTConfigRequesterTest { ConfigSubscriber subscriber = new ConfigSubscriber(); final TimingValues timingValues = getTestTimingValues(); JRTConfigSubscription sub = createSubscription(subscriber, timingValues); - sub.setConfig(1L, false, config()); + sub.setConfig(1L, false, false, config()); final MockConnection connection = new MockConnection(new ErrorResponseHandler()); JRTConfigRequester requester = new JRTConfigRequester(connection, timingValues); @@ -212,7 +212,7 @@ public class JRTConfigRequesterTest { ConfigSubscriber subscriber = new ConfigSubscriber(); final TimingValues timingValues = getTestTimingValues(); JRTConfigSubscription sub = createSubscription(subscriber, timingValues); - sub.setConfig(1L, false, config()); + sub.setConfig(1L, false, false, config()); final MockConnection connection = new MockConnection(new ErrorResponseHandler(com.yahoo.jrt.ErrorCode.TIMEOUT)); JRTConfigRequester requester = new JRTConfigRequester(connection, timingValues); @@ -227,7 +227,7 @@ public class JRTConfigRequesterTest { ConfigSubscriber subscriber = new ConfigSubscriber(); final TimingValues timingValues = getTestTimingValues(); JRTConfigSubscription sub = createSubscription(subscriber, timingValues); - sub.setConfig(1L, false, config()); + sub.setConfig(1L, false, false, config()); final MockConnection connection = new MockConnection(new ErrorResponseHandler(ErrorCode.UNKNOWN_DEFINITION)); JRTConfigRequester requester = new JRTConfigRequester(connection, timingValues); diff --git a/config/src/test/java/com/yahoo/vespa/config/RawConfigTest.java b/config/src/test/java/com/yahoo/vespa/config/RawConfigTest.java index 3f6c54ea46e..9fd0b9ba1fa 100644 --- a/config/src/test/java/com/yahoo/vespa/config/RawConfigTest.java +++ b/config/src/test/java/com/yahoo/vespa/config/RawConfigTest.java @@ -61,14 +61,14 @@ public class RawConfigTest { assertThat(config.hashCode(), is(not(new RawConfig(key, "a").hashCode()))); // different def md5 // different generation - config = new RawConfig(key, defMd5, payload, configMd5, generation, false, defContent, Optional.empty()); - RawConfig config2 = new RawConfig(key, defMd5, payload, configMd5, 2L, false, defContent, Optional.empty()); + config = new RawConfig(key, defMd5, payload, configMd5, generation, false, false, defContent, Optional.empty()); + RawConfig config2 = new RawConfig(key, defMd5, payload, configMd5, 2L, false, false, defContent, Optional.empty()); assertThat(config, is(not(config2))); assertThat(config.hashCode(), is(not(config2.hashCode()))); // different config md5 and with vespa version final VespaVersion vespaVersion = VespaVersion.fromString("5.37.38"); - RawConfig config3 = new RawConfig(key, defMd5, payload, "9999", generation, false, defContent, Optional.of(vespaVersion)); + RawConfig config3 = new RawConfig(key, defMd5, payload, "9999", generation, false, false, defContent, Optional.of(vespaVersion)); assertThat(config, is(not(config3))); assertThat(config.hashCode(), is(not(config3.hashCode()))); // Check that vespa version is set correctly @@ -82,19 +82,19 @@ public class RawConfigTest { assertNotEquals(config, key); // errors - RawConfig errorConfig1 = new RawConfig(key, defMd5, payload, configMd5, generation, false, 1, defContent, Optional.empty()); + RawConfig errorConfig1 = new RawConfig(key, defMd5, payload, configMd5, generation, false, false, 1, defContent, Optional.empty()); assertThat(errorConfig1, is(errorConfig1)); assertThat(config, is(not(errorConfig1))); assertThat(config.hashCode(), is(not(errorConfig1.hashCode()))); assertThat(errorConfig1, is(errorConfig1)); - RawConfig errorConfig2 = new RawConfig(key, defMd5, payload, configMd5, generation, false, 2, defContent, Optional.empty()); + RawConfig errorConfig2 = new RawConfig(key, defMd5, payload, configMd5, generation, false, false, 2, defContent, Optional.empty()); assertThat(errorConfig1, is(not(errorConfig2))); assertThat(errorConfig1.hashCode(), is(not(errorConfig2.hashCode()))); } @Test public void payload() { - RawConfig config = new RawConfig(key, defMd5, payload, configMd5, generation, false, defContent, Optional.empty()); + RawConfig config = new RawConfig(key, defMd5, payload, configMd5, generation, false, false, defContent, Optional.empty()); assertThat(config.getPayload(), is(payload)); assertThat(config.getConfigMd5(), is(configMd5)); assertThat(config.getGeneration(), is(generation)); @@ -105,19 +105,19 @@ public class RawConfigTest { public void require_correct_defmd5() { final String defMd5ForEmptyDefContent = "d41d8cd98f00b204e9800998ecf8427e"; - RawConfig config = new RawConfig(key, null, payload, configMd5, generation, false, defContent, Optional.empty()); + RawConfig config = new RawConfig(key, null, payload, configMd5, generation, false, false, defContent, Optional.empty()); assertThat(config.getDefMd5(), is(defMd5)); - config = new RawConfig(key, "", payload, configMd5, generation, false, defContent, Optional.empty()); + config = new RawConfig(key, "", payload, configMd5, generation, false, false, defContent, Optional.empty()); assertThat(config.getDefMd5(), is(defMd5)); - config = new RawConfig(key, defMd5, payload, configMd5, generation, false, defContent, Optional.empty()); + config = new RawConfig(key, defMd5, payload, configMd5, generation, false, false, defContent, Optional.empty()); assertThat(config.getDefMd5(), is(defMd5)); - config = new RawConfig(key, null, payload, configMd5, generation, false, null, Optional.empty()); + config = new RawConfig(key, null, payload, configMd5, generation, false, false, null, Optional.empty()); assertNull(config.getDefMd5()); - config = new RawConfig(key, null, payload, configMd5, generation, false,List.of(""), Optional.empty()); + config = new RawConfig(key, null, payload, configMd5, generation, false,false, List.of(""), Optional.empty()); assertThat(config.getDefMd5(), is(defMd5ForEmptyDefContent)); - config = new RawConfig(key, "", payload, configMd5, generation, false, null, Optional.empty()); + config = new RawConfig(key, "", payload, configMd5, generation, false, false, null, Optional.empty()); assertThat(config.getDefMd5(), is("")); - config = new RawConfig(key, "", payload, configMd5, generation, false, List.of(""), Optional.empty()); + config = new RawConfig(key, "", payload, configMd5, generation, false, false, List.of(""), Optional.empty()); assertThat(config.getDefMd5(), is(defMd5ForEmptyDefContent)); } diff --git a/config/src/test/java/com/yahoo/vespa/config/protocol/ConfigResponseTest.java b/config/src/test/java/com/yahoo/vespa/config/protocol/ConfigResponseTest.java index a56c7ef2daa..98eda868bbf 100644 --- a/config/src/test/java/com/yahoo/vespa/config/protocol/ConfigResponseTest.java +++ b/config/src/test/java/com/yahoo/vespa/config/protocol/ConfigResponseTest.java @@ -24,7 +24,7 @@ public class ConfigResponseTest { @Test public void require_that_slime_response_is_initialized() throws IOException { ConfigPayload configPayload = ConfigPayload.fromInstance(new SimpletypesConfig(new SimpletypesConfig.Builder())); - ConfigResponse response = SlimeConfigResponse.fromConfigPayload(configPayload, 3, false, "mymd5"); + ConfigResponse response = SlimeConfigResponse.fromConfigPayload(configPayload, 3, false, false, "mymd5"); ByteArrayOutputStream baos = new ByteArrayOutputStream(); response.serialize(baos, CompressionType.UNCOMPRESSED); String payload = baos.toString(StandardCharsets.UTF_8); @@ -43,7 +43,7 @@ public class ConfigResponseTest { ConfigPayload configPayload = ConfigPayload.fromInstance(new SimpletypesConfig(new SimpletypesConfig.Builder())); Utf8Array data = configPayload.toUtf8Array(true); Utf8Array bytes = new Utf8Array(new LZ4PayloadCompressor().compress(data.getBytes())); - ConfigResponse response = new SlimeConfigResponse(bytes, 3, false, "mymd5", CompressionInfo.create(CompressionType.LZ4, data.getByteLength())); + ConfigResponse response = new SlimeConfigResponse(bytes, 3, false, false, "mymd5", CompressionInfo.create(CompressionType.LZ4, data.getByteLength())); ByteArrayOutputStream baos = new ByteArrayOutputStream(); response.serialize(baos, CompressionType.UNCOMPRESSED); String payload = baos.toString(StandardCharsets.UTF_8); diff --git a/config/src/test/java/com/yahoo/vespa/config/protocol/JRTConfigRequestV3Test.java b/config/src/test/java/com/yahoo/vespa/config/protocol/JRTConfigRequestV3Test.java index d4f8b771880..6fc55e60a54 100644 --- a/config/src/test/java/com/yahoo/vespa/config/protocol/JRTConfigRequestV3Test.java +++ b/config/src/test/java/com/yahoo/vespa/config/protocol/JRTConfigRequestV3Test.java @@ -73,8 +73,8 @@ public class JRTConfigRequestV3Test { @Test public void emptypayload() { ConfigPayload payload = ConfigPayload.empty(); - SlimeConfigResponse response = SlimeConfigResponse.fromConfigPayload(payload, 0, false, ConfigUtils.getMd5(payload)); - serverReq.addOkResponse(serverReq.payloadFromResponse(response), response.getGeneration(), false, response.getConfigMd5()); + SlimeConfigResponse response = SlimeConfigResponse.fromConfigPayload(payload, 0, false, false, ConfigUtils.getMd5(payload)); + serverReq.addOkResponse(serverReq.payloadFromResponse(response), response.getGeneration(), false, false, response.getConfigMd5()); assertTrue(clientReq.validateResponse()); assertTrue(clientReq.hasUpdatedGeneration()); assertThat(clientReq.getNewPayload().withCompression(CompressionType.UNCOMPRESSED).getData().toString(), is("{}")); @@ -92,7 +92,7 @@ public class JRTConfigRequestV3Test { @Test public void next_request_when_error_is_correct() { - serverReq.addOkResponse(createPayload(), 999999, false, "newmd5"); + serverReq.addOkResponse(createPayload(), 999999, false, false, "newmd5"); serverReq.addErrorResponse(ErrorCode.OUTDATED_CONFIG, "error message"); System.out.println(serverReq); JRTClientConfigRequest next = clientReq.nextRequest(6); @@ -108,7 +108,7 @@ public class JRTConfigRequestV3Test { Payload payload = createPayload("vale"); String md5 = ConfigUtils.getMd5(payload.getData()); long generation = 4L; - serverReq.addOkResponse(payload, generation, false, md5); + serverReq.addOkResponse(payload, generation, false, false, md5); assertTrue(clientReq.validateResponse()); assertThat(clientReq.getNewPayload().withCompression(CompressionType.UNCOMPRESSED).getData().toString(), is(payload.getData().toString())); assertThat(clientReq.getNewGeneration(), is(4L)); @@ -134,7 +134,7 @@ public class JRTConfigRequestV3Test { @Test public void generation_only_is_updated() { Payload payload = createPayload(); - serverReq.addOkResponse(payload, 4L, false, ConfigUtils.getMd5(payload.getData())); + serverReq.addOkResponse(payload, 4L, false, false, ConfigUtils.getMd5(payload.getData())); boolean value = clientReq.validateResponse(); assertTrue(clientReq.errorMessage(), value); assertFalse(clientReq.hasUpdatedConfig()); @@ -144,7 +144,7 @@ public class JRTConfigRequestV3Test { @Test public void nothing_is_updated() { Payload payload = createPayload(); - serverReq.addOkResponse(payload, currentGeneration, false, configMd5); + serverReq.addOkResponse(payload, currentGeneration, false, false, configMd5); assertTrue(clientReq.validateResponse()); assertFalse(clientReq.hasUpdatedConfig()); assertFalse(clientReq.hasUpdatedGeneration()); @@ -155,7 +155,7 @@ public class JRTConfigRequestV3Test { Payload payload = Payload.from(ConfigPayload.empty()); clientReq = createReq(payload); serverReq = createReq(clientReq.getRequest()); - serverReq.addOkResponse(payload, currentGeneration, false, ConfigUtils.getMd5(payload.getData())); + serverReq.addOkResponse(payload, currentGeneration, false, false, ConfigUtils.getMd5(payload.getData())); boolean val = clientReq.validateResponse(); assertTrue(clientReq.errorMessage(), val); assertFalse(clientReq.hasUpdatedConfig()); @@ -192,7 +192,7 @@ public class JRTConfigRequestV3Test { @Override public void createResponse() { JRTServerConfigRequest serverRequest = createReq(request); - serverRequest.addOkResponse(createPayload(), currentGeneration, false, configMd5); + serverRequest.addOkResponse(createPayload(), currentGeneration, false, false, configMd5); } }); diff --git a/config/src/tests/configagent/configagent.cpp b/config/src/tests/configagent/configagent.cpp index a7cc95ab883..7cc0abee0bc 100644 --- a/config/src/tests/configagent/configagent.cpp +++ b/config/src/tests/configagent/configagent.cpp @@ -36,7 +36,7 @@ public: _value(value), _fillCalled(false), _valid(valid), - _state(md5, timestamp, false), + _state(md5, timestamp, false, false), _errorMessage(errorMsg), _errorCode(errorC0de), _isError(iserror) @@ -142,6 +142,7 @@ TEST("require that agent returns correct values") { ASSERT_EQUAL(cs.md5, handler.getConfigState().md5); ASSERT_EQUAL(cs.generation, handler.getConfigState().generation); ASSERT_EQUAL(cs.internalRedeploy, handler.getConfigState().internalRedeploy); + ASSERT_EQUAL(cs.applyOnRestart, handler.getConfigState().applyOnRestart); } TEST("require that successful request is delivered to holder") { diff --git a/config/src/tests/frt/frt.cpp b/config/src/tests/frt/frt.cpp index 0d70605fa62..60973aea2bf 100644 --- a/config/src/tests/frt/frt.cpp +++ b/config/src/tests/frt/frt.cpp @@ -276,10 +276,10 @@ TEST("require that v3 request is correctly initialized") { traceIn.trace(2, "Hei"); FRTConfigRequestV3 v3req(&conn, key, md5, currentGeneration, hostName, timeout, traceIn, VespaVersion::fromString("1.2.3"), CompressionType::LZ4); - ASSERT_TRUE(v3req.verifyState(ConfigState(md5, 3, false))); - ASSERT_FALSE(v3req.verifyState(ConfigState(md5, 2, false))); - ASSERT_FALSE(v3req.verifyState(ConfigState("xxx", 3, false))); - ASSERT_FALSE(v3req.verifyState(ConfigState("xxx", 2, false))); + ASSERT_TRUE(v3req.verifyState(ConfigState(md5, 3, false, false))); + ASSERT_FALSE(v3req.verifyState(ConfigState(md5, 2, false, false))); + ASSERT_FALSE(v3req.verifyState(ConfigState("xxx", 3, false, false))); + ASSERT_FALSE(v3req.verifyState(ConfigState("xxx", 2, false, false))); ConfigDefinition origDef(MyConfig::CONFIG_DEF_SCHEMA); diff --git a/config/src/vespa/config/common/configstate.h b/config/src/vespa/config/common/configstate.h index fe415f038e3..155c182271b 100644 --- a/config/src/vespa/config/common/configstate.h +++ b/config/src/vespa/config/common/configstate.h @@ -15,17 +15,20 @@ public: ConfigState() : md5(""), generation(0), - internalRedeploy(false) + internalRedeploy(false), + applyOnRestart(false) { } - ConfigState(const vespalib::string & md5sum, int64_t gen, bool value) + ConfigState(const vespalib::string & md5sum, int64_t gen, bool _internalRedeploy, bool _applyOnRestart) : md5(md5sum), generation(gen), - internalRedeploy(value) + internalRedeploy(_internalRedeploy), + applyOnRestart(_applyOnRestart) { } vespalib::string md5; int64_t generation; bool internalRedeploy; + bool applyOnRestart; bool isNewerGenerationThan(const ConfigState & other) const { return isGenerationNewer(generation, other.generation); diff --git a/config/src/vespa/config/frt/protocol.cpp b/config/src/vespa/config/frt/protocol.cpp index cfd248e5d86..5019cce23c5 100644 --- a/config/src/vespa/config/frt/protocol.cpp +++ b/config/src/vespa/config/frt/protocol.cpp @@ -41,6 +41,7 @@ const Memory RESPONSE_CONFIG_GENERATION = "generation"; const Memory RESPONSE_PAYLOAD = "payload"; const Memory RESPONSE_TRACE = "trace"; const Memory RESPONSE_INTERNAL_REDEPLOY = "internalRedeploy"; +const Memory RESPONSE_APPLY_ON_RESTART = "applyOnRestart"; const Inspector & extractPayload(const Slime & data) diff --git a/config/src/vespa/config/frt/protocol.h b/config/src/vespa/config/frt/protocol.h index a14fa492ac7..a7465ef979d 100644 --- a/config/src/vespa/config/frt/protocol.h +++ b/config/src/vespa/config/frt/protocol.h @@ -53,6 +53,7 @@ extern const vespalib::Memory RESPONSE_CONFIG_GENERATION; extern const vespalib::Memory RESPONSE_PAYLOAD; extern const vespalib::Memory RESPONSE_TRACE; extern const vespalib::Memory RESPONSE_INTERNAL_REDEPLOY; +extern const vespalib::Memory RESPONSE_APPLY_ON_RESTART; const vespalib::slime::Inspector & extractPayload(const vespalib::Slime & data); diff --git a/config/src/vespa/config/frt/slimeconfigresponse.cpp b/config/src/vespa/config/frt/slimeconfigresponse.cpp index 155515d2ed6..f778fe574f1 100644 --- a/config/src/vespa/config/frt/slimeconfigresponse.cpp +++ b/config/src/vespa/config/frt/slimeconfigresponse.cpp @@ -66,7 +66,10 @@ ConfigState SlimeConfigResponse::readState() const { const Slime & data(*_data); - return ConfigState(data.get()[RESPONSE_CONFIG_MD5].asString().make_string(), data.get()[RESPONSE_CONFIG_GENERATION].asLong(), data.get()[RESPONSE_INTERNAL_REDEPLOY].asBool()); + return ConfigState(data.get()[RESPONSE_CONFIG_MD5].asString().make_string(), + data.get()[RESPONSE_CONFIG_GENERATION].asLong(), + data.get()[RESPONSE_INTERNAL_REDEPLOY].asBool(), + data.get()[RESPONSE_APPLY_ON_RESTART].asBool()); } vespalib::string diff --git a/configgen/CMakeLists.txt b/configgen/CMakeLists.txt new file mode 100644 index 00000000000..107037f8008 --- /dev/null +++ b/configgen/CMakeLists.txt @@ -0,0 +1,2 @@ +# Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +install_java_artifact(configgen) diff --git a/configgen/pom.xml b/configgen/pom.xml index 7d316061a99..a335e345234 100644 --- a/configgen/pom.xml +++ b/configgen/pom.xml @@ -52,6 +52,38 @@ org.apache.maven.plugins maven-install-plugin + + + org.apache.maven.plugins + maven-shade-plugin + + ${project.artifactId} + + + + com.yahoo.config.codegen + 2 + ${project.artifactId} + 7.0.0 + ${project.artifactId} + Yahoo! + . + + + + + + + package + + shade + + + + diff --git a/configgen/src/main/java/com/yahoo/config/codegen/BuilderGenerator.java b/configgen/src/main/java/com/yahoo/config/codegen/BuilderGenerator.java index b3c4d0c5ff8..2ebe7ad03bf 100644 --- a/configgen/src/main/java/com/yahoo/config/codegen/BuilderGenerator.java +++ b/configgen/src/main/java/com/yahoo/config/codegen/BuilderGenerator.java @@ -44,7 +44,7 @@ public class BuilderGenerator { } private static String getSpecialRootBuilderCode(InnerCNode node) { - return (node.getParent() == null) ? "\n" + getDispatchCode() + "\n" : ""; + return (node.getParent() == null) ? "\n" + getRootDeclarations() + "\n" : ""; } private static String getBuildMethod(InnerCNode node) { @@ -53,26 +53,36 @@ public class BuilderGenerator { "}\n"; } - private static String getDispatchCode() { + private static String getRootDeclarations() { // Use full path to @Override, as users are free to define an inner node called // 'override'. (summarymap.def does) // The generated inner 'Override' class would otherwise be mistaken for the // annotation. - return "@java.lang.Override\n" + // - "public final boolean dispatchGetConfig(ConfigInstance.Producer producer) {\n" + // - " if (producer instanceof Producer) {\n" + // - " ((Producer)producer).getConfig(this);\n" + // - " return true;\n" + // + return "private boolean _applyOnRestart = false;\n" + + "\n" + + "@java.lang.Override\n" + + "public final boolean dispatchGetConfig(ConfigInstance.Producer producer) {\n" + + " if (producer instanceof Producer) {\n" + + " ((Producer)producer).getConfig(this);\n" + + " return true;\n" + " }\n" + // - " return false;\n" + // - "}\n" + // - "\n" + // - "@java.lang.Override\n" + // - "public final String getDefMd5() { return CONFIG_DEF_MD5; }\n" + // - "@java.lang.Override\n" + // - "public final String getDefName() { return CONFIG_DEF_NAME; }\n" + // - "@java.lang.Override\n" + // - "public final String getDefNamespace() { return CONFIG_DEF_NAMESPACE; }"; + " return false;\n" + + "}\n" + + "\n" + + "@java.lang.Override\n" + + "public final String getDefMd5() { return CONFIG_DEF_MD5; }\n" + + "\n" + + "@java.lang.Override\n" + + "public final String getDefName() { return CONFIG_DEF_NAME; }\n" + + "\n" + + "@java.lang.Override\n" + + "public final String getDefNamespace() { return CONFIG_DEF_NAMESPACE; }\n" + + "\n" + + "@java.lang.Override\n" + + "public final boolean getApplyOnRestart() { return _applyOnRestart; }\n" + + "\n" + + "@java.lang.Override\n" + + "public final void setApplyOnRestart(boolean applyOnRestart) { _applyOnRestart = applyOnRestart; }"; } private static String getUninitializedScalars(InnerCNode node) { diff --git a/configgen/src/test/resources/allfeatures.reference b/configgen/src/test/resources/allfeatures.reference index b84f01f380b..2008bbf6b52 100644 --- a/configgen/src/test/resources/allfeatures.reference +++ b/configgen/src/test/resources/allfeatures.reference @@ -601,6 +601,8 @@ public final class AllfeaturesConfig extends ConfigInstance { return this; } + private boolean _applyOnRestart = false; + @java.lang.Override public final boolean dispatchGetConfig(ConfigInstance.Producer producer) { if (producer instanceof Producer) { @@ -611,12 +613,20 @@ public final class AllfeaturesConfig extends ConfigInstance { } @java.lang.Override - public final String getDefMd5() { return CONFIG_DEF_MD5; } + public final String getDefMd5() { return CONFIG_DEF_MD5; } + @java.lang.Override - public final String getDefName() { return CONFIG_DEF_NAME; } + public final String getDefName() { return CONFIG_DEF_NAME; } + @java.lang.Override public final String getDefNamespace() { return CONFIG_DEF_NAMESPACE; } + @java.lang.Override + public final boolean getApplyOnRestart() { return _applyOnRestart; } + + @java.lang.Override + public final void setApplyOnRestart(boolean applyOnRestart) { _applyOnRestart = applyOnRestart; } + public AllfeaturesConfig build() { return new AllfeaturesConfig(this); } diff --git a/configserver/pom.xml b/configserver/pom.xml index 35c38eb7d7d..3b7fef085b1 100644 --- a/configserver/pom.xml +++ b/configserver/pom.xml @@ -62,11 +62,29 @@ ${project.version} provided + + com.yahoo.vespa + config-lib + ${project.version} + provided + com.yahoo.vespa config-bundle ${project.version} provided + + + com.yahoo.vespa + config-lib + + + + + com.yahoo.vespa + configgen + ${project.version} + provided com.yahoo.vespa diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/SuperModelController.java b/configserver/src/main/java/com/yahoo/vespa/config/server/SuperModelController.java index 0bddd8d0637..933a8d86230 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/SuperModelController.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/SuperModelController.java @@ -46,7 +46,7 @@ public class SuperModelController { ConfigKey configKey = request.getConfigKey(); validateConfigDefinition(request.getConfigKey(), request.getDefContent()); ConfigPayload payload = model.getConfig(configKey); - return responseFactory.createResponse(payload, generation, false); + return responseFactory.createResponse(payload, generation, false, false); } private void validateConfigDefinition(ConfigKey configKey, DefContent defContent) { diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/application/Application.java b/configserver/src/main/java/com/yahoo/vespa/config/server/application/Application.java index 8d001d5d5df..156b4be392e 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/application/Application.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/application/Application.java @@ -2,6 +2,7 @@ package com.yahoo.vespa.config.server.application; import com.yahoo.component.Version; +import com.yahoo.config.ConfigInstance; import com.yahoo.config.ConfigurationRuntimeException; import com.yahoo.config.model.api.ApplicationInfo; import com.yahoo.config.model.api.Model; @@ -11,6 +12,8 @@ import com.yahoo.vespa.config.ConfigCacheKey; import com.yahoo.vespa.config.ConfigDefinitionKey; import com.yahoo.vespa.config.ConfigKey; import com.yahoo.vespa.config.ConfigPayload; +import com.yahoo.vespa.config.ConfigPayloadBuilder; +import com.yahoo.vespa.config.GenericConfig; import com.yahoo.vespa.config.GetConfigRequest; import com.yahoo.vespa.config.buildergen.ConfigDefinition; import com.yahoo.vespa.config.protocol.ConfigResponse; @@ -23,6 +26,7 @@ import com.yahoo.vespa.config.server.rpc.ConfigResponseFactory; import com.yahoo.vespa.config.server.rpc.UncompressedConfigResponseFactory; import com.yahoo.vespa.config.server.tenant.TenantRepository; import com.yahoo.vespa.config.util.ConfigUtils; +import com.yahoo.yolean.Exceptions; import java.util.Objects; import java.util.Set; @@ -98,6 +102,7 @@ public class Application implements ModelResult { /** * Gets a config from ZK. Returns null if not found. */ + @SuppressWarnings("deprecation") public ConfigResponse resolveConfig(GetConfigRequest req, ConfigResponseFactory responseFactory) { long start = System.currentTimeMillis(); metricUpdater.incrementRequests(); @@ -131,18 +136,43 @@ public class Application implements ModelResult { debug("Resolving " + configKey + " with config definition " + def); } - ConfigPayload payload = null; + ConfigInstance.Builder builder; + ConfigPayload payload; + boolean applyOnRestart = false; try { - payload = model.getConfig(configKey, def); + builder = model.getConfigInstance(configKey, def); + if (builder == null) { // TODO: Remove this condition after December 2020 + payload = model.getConfig(configKey, def); + if (def.getCNode() != null) + payload.applyDefaultsFromDef(def.getCNode()); + } + else if (builder instanceof GenericConfig.GenericConfigBuilder) { + payload = ((GenericConfig.GenericConfigBuilder) builder).getPayload(); + applyOnRestart = builder.getApplyOnRestart(); + } + else { + try { + ConfigInstance instance = ConfigInstanceBuilder.buildInstance(builder, def.getCNode()); + payload = ConfigPayload.fromInstance(instance); + applyOnRestart = builder.getApplyOnRestart(); + } catch (ConfigurationRuntimeException e) { + // This can happen in cases where services ask for config that no longer exist before they have been able + // to reconfigure themselves + log.log(Level.INFO, "Error resolving instance for builder '" + builder.getClass().getName() + + "', returning empty config: " + Exceptions.toMessageString(e)); + payload = ConfigPayload.fromBuilder(new ConfigPayloadBuilder()); + } + if (def.getCNode() != null) + payload.applyDefaultsFromDef(def.getCNode()); + } } catch (Exception e) { throw new ConfigurationRuntimeException("Unable to get config for " + app, e); } - if (payload == null) { - metricUpdater.incrementFailedRequests(); - throw new ConfigurationRuntimeException("Unable to resolve config " + configKey); - } - ConfigResponse configResponse = responseFactory.createResponse(payload, applicationGeneration, internalRedeploy); + ConfigResponse configResponse = responseFactory.createResponse(payload, + applicationGeneration, + internalRedeploy, + applyOnRestart); metricUpdater.incrementProcTime(System.currentTimeMillis() - start); if (useCache(req)) { cache.put(cacheKey, configResponse, configResponse.getConfigMd5()); @@ -197,4 +227,5 @@ public class Application implements ModelResult { public Set allConfigIds() { return model.allConfigIds(); } + } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/application/ConfigInstanceBuilder.java b/configserver/src/main/java/com/yahoo/vespa/config/server/application/ConfigInstanceBuilder.java new file mode 100644 index 00000000000..389e8394c9e --- /dev/null +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/application/ConfigInstanceBuilder.java @@ -0,0 +1,117 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.config.server.application; + +import com.yahoo.config.ConfigBuilder; +import com.yahoo.config.ConfigInstance; +import com.yahoo.config.ConfigurationRuntimeException; +import com.yahoo.config.codegen.CNode; +import com.yahoo.config.codegen.InnerCNode; +import com.yahoo.config.codegen.LeafCNode; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; + +/** + * Builds a ConfigInstance from a ConfigInstance.Builder. + * (Put here not in ConfigInstance.Builder temporarily to work around dependency problems.) + */ +class ConfigInstanceBuilder { + + private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(ConfigInstanceBuilder.class.getName()); + + static ConfigInstance buildInstance(ConfigInstance.Builder builder, InnerCNode targetDef) { + try { + if (targetDef != null) applyDef(builder, targetDef); + Class clazz = getConfigClass(builder.getClass()); + return clazz.getConstructor(builder.getClass()).newInstance(builder); + } catch (Exception e) { + throw new ConfigurationRuntimeException(e); + } + } + + /** + * If some fields on the builder are null now, set them from the def. Do recursively. + *

+ * If the targetDef has some schema incompatibilities, they are not handled here + * (except logging in some cases), but in ConfigInstance.serialize(). + * + * @param builder a {@link com.yahoo.config.ConfigBuilder} + * @param targetDef a config definition + * @throws Exception if applying values form config definitions fails + */ + static void applyDef(ConfigBuilder builder, InnerCNode targetDef) throws Exception { + for (Map.Entry e: targetDef.children().entrySet()) { + CNode node = e.getValue(); + if (node instanceof LeafCNode) { + setLeafValueIfUnset(targetDef, builder, (LeafCNode)node); + } else if (node instanceof InnerCNode) { + // Is there a private field on the builder that matches this inner node in the def? + if (hasField(builder.getClass(), node.getName())) { + Field innerField = builder.getClass().getDeclaredField(node.getName()); + innerField.setAccessible(true); + Object innerFieldVal = innerField.get(builder); + if (innerFieldVal instanceof List) { + // inner array? Check that list elems are ConfigBuilder + List innerList = (List) innerFieldVal; + for (Object b : innerList) { + if (b instanceof ConfigBuilder) { + applyDef((ConfigBuilder) b, (InnerCNode) node); + } + } + } else if (innerFieldVal instanceof ConfigBuilder) { + // Struct perhaps + applyDef((ConfigBuilder) innerFieldVal, (InnerCNode) node); + } else { + // Likely a config value mismatch. That is handled in ConfigInstance.serialize() (error message, omit from response.) + } + } + } + } + } + + private static boolean hasField(Class aClass, String name) { + for (Field field : aClass.getDeclaredFields()) { + if (name.equals(field.getName())) { + return true; + } + } + return false; + } + + private static void setLeafValueIfUnset(InnerCNode targetDef, Object builder, LeafCNode node) throws Exception { + if (hasField(builder.getClass(), node.getName())) { + Field field = builder.getClass().getDeclaredField(node.getName()); + field.setAccessible(true); + Object val = field.get(builder); + if (val==null) { + // Not set on builder, if the leaf node has a default value, try the private setter that takes String + try { + if (node.getDefaultValue()!=null) { + Method setter = builder.getClass().getDeclaredMethod(node.getName(), String.class); + setter.setAccessible(true); + setter.invoke(builder, node.getDefaultValue().getValue()); + } + } catch (Exception e) { + log.log(Level.SEVERE, + "For config '" + targetDef.getFullName() + "': " + + "Unable to apply the default value for field '" + node.getName() + + "' to config Builder (where it wasn't set)", + e); + } + } + } + } + + @SuppressWarnings("unchecked") + private static Class getConfigClass(Class builderClass) { + Class configClass = builderClass.getEnclosingClass(); + if (configClass == null || ! ConfigInstance.class.isAssignableFrom(configClass)) { + throw new ConfigurationRuntimeException("Builder class " + builderClass + " has enclosing class " + configClass + ", which is not a ConfigInstance"); + } + return (Class) configClass; + } + +} diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/ConfigResponseFactory.java b/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/ConfigResponseFactory.java index 415fa764823..00a0e6f8f2e 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/ConfigResponseFactory.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/ConfigResponseFactory.java @@ -26,12 +26,15 @@ public interface ConfigResponseFactory { /** * Creates a {@link ConfigResponse} for a given payload and generation. + * * @param payload the {@link ConfigPayload} to put in the response * @param generation the payload generation * @param internalRedeploy whether this config generation was produced by an internal redeployment * not a change to the application package + * @param applyOnRestart true if this config change should only be applied on restart, + * false if it should be applied immediately * @return a {@link ConfigResponse} that can be sent to the client */ - ConfigResponse createResponse(ConfigPayload payload, long generation, boolean internalRedeploy); + ConfigResponse createResponse(ConfigPayload payload, long generation, boolean internalRedeploy, boolean applyOnRestart); } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/GetConfigProcessor.java b/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/GetConfigProcessor.java index 62f7d3ce5d0..5d637c0e0bd 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/GetConfigProcessor.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/GetConfigProcessor.java @@ -125,7 +125,7 @@ class GetConfigProcessor implements Runnable { // config == null is not an error, but indicates that the config will be returned later. if ((config != null) && (!config.hasEqualConfig(request) || config.hasNewerGeneration(request) || forceResponse)) { // debugLog(trace, "config response before encoding:" + config.toString()); - request.addOkResponse(request.payloadFromResponse(config), config.getGeneration(), config.isInternalRedeploy(), config.getConfigMd5()); + request.addOkResponse(request.payloadFromResponse(config), config.getGeneration(), config.isInternalRedeploy(), config.applyOnRestart(), config.getConfigMd5()); if (logDebug(trace)) { debugLog(trace, "return response: " + request.getShortDescription()); } @@ -166,8 +166,8 @@ class GetConfigProcessor implements Runnable { log.log(Level.FINE, () -> "Returning empty sentinel config for request from " + request.getClientHostName()); ConfigPayload emptyPayload = ConfigPayload.empty(); String configMd5 = ConfigUtils.getMd5(emptyPayload); - ConfigResponse config = SlimeConfigResponse.fromConfigPayload(emptyPayload, 0, false, configMd5); - request.addOkResponse(request.payloadFromResponse(config), config.getGeneration(), false, config.getConfigMd5()); + ConfigResponse config = SlimeConfigResponse.fromConfigPayload(emptyPayload, 0, false, false, configMd5); + request.addOkResponse(request.payloadFromResponse(config), config.getGeneration(), false, false, config.getConfigMd5()); respond(request); } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/LZ4ConfigResponseFactory.java b/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/LZ4ConfigResponseFactory.java index cba1316a131..a818eaeb8f5 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/LZ4ConfigResponseFactory.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/LZ4ConfigResponseFactory.java @@ -22,12 +22,13 @@ public class LZ4ConfigResponseFactory implements ConfigResponseFactory { @Override public ConfigResponse createResponse(ConfigPayload payload, long generation, - boolean internalRedeploy) { + boolean internalRedeploy, + boolean applyOnRestart) { Utf8Array rawPayload = payload.toUtf8Array(true); String configMd5 = ConfigUtils.getMd5(rawPayload); CompressionInfo info = CompressionInfo.create(CompressionType.LZ4, rawPayload.getByteLength()); Utf8Array compressed = new Utf8Array(compressor.compress(rawPayload.getBytes())); - return new SlimeConfigResponse(compressed, generation, internalRedeploy, configMd5, info); + return new SlimeConfigResponse(compressed, generation, internalRedeploy, applyOnRestart, configMd5, info); } } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/UncompressedConfigResponseFactory.java b/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/UncompressedConfigResponseFactory.java index 2de88ab44cc..e3f3f1c1395 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/UncompressedConfigResponseFactory.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/rpc/UncompressedConfigResponseFactory.java @@ -19,11 +19,12 @@ public class UncompressedConfigResponseFactory implements ConfigResponseFactory @Override public ConfigResponse createResponse(ConfigPayload payload, long generation, - boolean internalRedeploy) { + boolean internalRedeploy, + boolean applyOnRestart) { Utf8Array rawPayload = payload.toUtf8Array(true); String configMd5 = ConfigUtils.getMd5(rawPayload); CompressionInfo info = CompressionInfo.create(CompressionType.UNCOMPRESSED, rawPayload.getByteLength()); - return new SlimeConfigResponse(rawPayload, generation, internalRedeploy, configMd5, info); + return new SlimeConfigResponse(rawPayload, generation, internalRedeploy, applyOnRestart, configMd5, info); } } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java index 93c1e4c2b50..dfe4055d844 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java @@ -171,7 +171,9 @@ public class SessionRepository { * @param timeoutBudget timeout for creating session and waiting for other servers. * @return a new session */ - public LocalSession createSessionFromExisting(Session existingSession, boolean internalRedeploy, TimeoutBudget timeoutBudget) { + public LocalSession createSessionFromExisting(Session existingSession, + boolean internalRedeploy, + TimeoutBudget timeoutBudget) { ApplicationId existingApplicationId = existingSession.getApplicationId(); File existingApp = getSessionAppDir(existingSession.getSessionId()); LocalSession session = createSessionFromApplication(existingApp, existingApplicationId, internalRedeploy, timeoutBudget); diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/ModelStub.java b/configserver/src/test/java/com/yahoo/vespa/config/server/ModelStub.java index 8b515ff837b..88f7d352ad7 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/ModelStub.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/ModelStub.java @@ -1,6 +1,7 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.config.server; +import com.yahoo.config.ConfigInstance; import com.yahoo.config.FileReference; import com.yahoo.config.model.api.FileDistribution; import com.yahoo.config.model.api.HostInfo; @@ -20,10 +21,16 @@ import java.util.Set; public class ModelStub implements Model { @Override + @SuppressWarnings("deprecation") public ConfigPayload getConfig(ConfigKey configKey, ConfigDefinition targetDef) { return null; } + @Override + public ConfigInstance.Builder getConfigInstance(ConfigKey configKey, ConfigDefinition targetDef) { + throw new UnsupportedOperationException(); + } + @Override public Set> allConfigsProduced() { return null; diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/ServerCacheTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/ServerCacheTest.java index 35449238f78..fa69df9f628 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/ServerCacheTest.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/ServerCacheTest.java @@ -48,9 +48,9 @@ public class ServerCacheTest { cache = new ServerCache(new TestConfigDefinitionRepo(), userConfigDefinitionRepo); - cache.put(fooBarCacheKey, SlimeConfigResponse.fromConfigPayload(ConfigPayload.empty(), 2, false, configMd5), configMd5); - cache.put(bazQuuxCacheKey, SlimeConfigResponse.fromConfigPayload(ConfigPayload.empty(), 2, false, configMd5), configMd5); - cache.put(fooBarCacheKeyDifferentMd5, SlimeConfigResponse.fromConfigPayload(ConfigPayload.empty(), 2, false, configMd5_2), configMd5_2); + cache.put(fooBarCacheKey, SlimeConfigResponse.fromConfigPayload(ConfigPayload.empty(), 2, false, false, configMd5), configMd5); + cache.put(bazQuuxCacheKey, SlimeConfigResponse.fromConfigPayload(ConfigPayload.empty(), 2, false, false, configMd5), configMd5); + cache.put(fooBarCacheKeyDifferentMd5, SlimeConfigResponse.fromConfigPayload(ConfigPayload.empty(), 2, false, false, configMd5_2), configMd5_2); } @Test diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/application/MockModel.java b/configserver/src/test/java/com/yahoo/vespa/config/server/application/MockModel.java index c9f25451ea4..0288a551cd3 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/application/MockModel.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/application/MockModel.java @@ -1,6 +1,7 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.config.server.application; +import com.yahoo.config.ConfigInstance; import com.yahoo.config.FileReference; import com.yahoo.config.model.api.FileDistribution; import com.yahoo.config.model.api.HostInfo; @@ -29,6 +30,7 @@ import java.util.stream.Collectors; * @author hakonhall */ public class MockModel implements Model { + private final Collection hosts; static MockModel createContainer(String hostname, int statePort) { @@ -72,10 +74,16 @@ public class MockModel implements Model { } @Override + @SuppressWarnings("deprecation") public ConfigPayload getConfig(ConfigKey configKey, ConfigDefinition targetDef) { throw new UnsupportedOperationException(); } + @Override + public ConfigInstance.Builder getConfigInstance(ConfigKey configKey, ConfigDefinition targetDef) { + throw new UnsupportedOperationException(); + } + @Override public Set> allConfigsProduced() { throw new UnsupportedOperationException(); diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/http/HttpConfigResponseTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/http/HttpConfigResponseTest.java index ef0a5f6113d..336a8c623b8 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/http/HttpConfigResponseTest.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/http/HttpConfigResponseTest.java @@ -20,7 +20,7 @@ public class HttpConfigResponseTest { public void require_that_response_is_created_from_config() throws IOException { final long generation = 1L; ConfigPayload payload = ConfigPayload.fromInstance(new SimpletypesConfig(new SimpletypesConfig.Builder())); - ConfigResponse configResponse = SlimeConfigResponse.fromConfigPayload(payload, generation, false, "mymd5"); + ConfigResponse configResponse = SlimeConfigResponse.fromConfigPayload(payload, generation, false, false, "mymd5"); HttpConfigResponse response = HttpConfigResponse.createFromConfig(configResponse); assertThat(SessionHandlerTest.getRenderedString(response), is("{\"boolval\":false,\"doubleval\":0.0,\"enumval\":\"VAL1\",\"intval\":0,\"longval\":0,\"stringval\":\"s\"}")); } diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/metrics/DeploymentMetricsRetrieverTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/metrics/DeploymentMetricsRetrieverTest.java index a0025d086f5..3a68e0f4c65 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/metrics/DeploymentMetricsRetrieverTest.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/metrics/DeploymentMetricsRetrieverTest.java @@ -1,6 +1,7 @@ // Copyright 2020 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.config.server.metrics; +import com.yahoo.config.ConfigInstance; import com.yahoo.config.FileReference; import com.yahoo.config.model.api.FileDistribution; import com.yahoo.config.model.api.HostInfo; @@ -83,10 +84,16 @@ public class DeploymentMetricsRetrieverTest { } @Override + @SuppressWarnings("deprecation") public ConfigPayload getConfig(ConfigKey configKey, ConfigDefinition targetDef) { throw new UnsupportedOperationException(); } + @Override + public ConfigInstance.Builder getConfigInstance(ConfigKey configKey, ConfigDefinition targetDef) { + throw new UnsupportedOperationException(); + } + @Override public Set> allConfigsProduced() { throw new UnsupportedOperationException(); diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/metrics/ProtonMetricsRetrieverTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/metrics/ProtonMetricsRetrieverTest.java index e97c4dc6682..bbf9bd0bcb7 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/metrics/ProtonMetricsRetrieverTest.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/metrics/ProtonMetricsRetrieverTest.java @@ -1,5 +1,6 @@ package com.yahoo.vespa.config.server.metrics; +import com.yahoo.config.ConfigInstance; import com.yahoo.config.FileReference; import com.yahoo.config.model.api.FileDistribution; import com.yahoo.config.model.api.HostInfo; @@ -76,10 +77,16 @@ public class ProtonMetricsRetrieverTest { } @Override + @SuppressWarnings("deprecation") public ConfigPayload getConfig(ConfigKey configKey, ConfigDefinition targetDef) { throw new UnsupportedOperationException(); } + @Override + public ConfigInstance.Builder getConfigInstance(ConfigKey configKey, ConfigDefinition targetDef) { + throw new UnsupportedOperationException(); + } + @Override public Set> allConfigsProduced() { throw new UnsupportedOperationException(); diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/rpc/ConfigResponseFactoryTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/rpc/ConfigResponseFactoryTest.java index 5d8b8c92472..c932627ce6a 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/rpc/ConfigResponseFactoryTest.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/rpc/ConfigResponseFactoryTest.java @@ -16,7 +16,7 @@ public class ConfigResponseFactoryTest { @Test public void testUncompressedFactory() { UncompressedConfigResponseFactory responseFactory = new UncompressedConfigResponseFactory(); - ConfigResponse response = responseFactory.createResponse(ConfigPayload.empty(), 3, false); + ConfigResponse response = responseFactory.createResponse(ConfigPayload.empty(), 3, false, false); assertEquals(CompressionType.UNCOMPRESSED, response.getCompressionInfo().getCompressionType()); assertEquals(3L,response.getGeneration()); assertEquals(2, response.getPayload().getByteLength()); @@ -25,7 +25,7 @@ public class ConfigResponseFactoryTest { @Test public void testLZ4CompressedFactory() { LZ4ConfigResponseFactory responseFactory = new LZ4ConfigResponseFactory(); - ConfigResponse response = responseFactory.createResponse(ConfigPayload.empty(), 3, false); + ConfigResponse response = responseFactory.createResponse(ConfigPayload.empty(), 3, false, false); assertEquals(CompressionType.LZ4, response.getCompressionInfo().getCompressionType()); assertEquals(3L, response.getGeneration()); assertEquals(3, response.getPayload().getByteLength()); diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/rpc/MockRpcServer.java b/configserver/src/test/java/com/yahoo/vespa/config/server/rpc/MockRpcServer.java index 6ca3f6c67ea..7f4733f0b7c 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/rpc/MockRpcServer.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/rpc/MockRpcServer.java @@ -25,7 +25,7 @@ import java.util.concurrent.CompletionService; */ public class MockRpcServer extends RpcServer { - public final RuntimeException exception = null; + public RuntimeException exception = null; public int errorCode = 0; public final ConfigResponse response = null; diff --git a/container-core/abi-spec.json b/container-core/abi-spec.json index e734ceee046..a5483d12b24 100644 --- a/container-core/abi-spec.json +++ b/container-core/abi-spec.json @@ -181,6 +181,8 @@ "public final java.lang.String getDefMd5()", "public final java.lang.String getDefName()", "public final java.lang.String getDefNamespace()", + "public final boolean getApplyOnRestart()", + "public final void setApplyOnRestart(boolean)", "public com.yahoo.container.handler.ThreadpoolConfig build()" ], "fields": [] diff --git a/container-disc/pom.xml b/container-disc/pom.xml index 413af786f2c..399686bd9cc 100644 --- a/container-disc/pom.xml +++ b/container-disc/pom.xml @@ -190,6 +190,7 @@ true + configgen.jar, config-bundle-jar-with-dependencies.jar, configdefinitions-jar-with-dependencies.jar, container-jersey2-jar-with-dependencies.jar, diff --git a/container-search/abi-spec.json b/container-search/abi-spec.json index 49c8d6c82d6..6f48ae5b41a 100644 --- a/container-search/abi-spec.json +++ b/container-search/abi-spec.json @@ -4264,6 +4264,8 @@ "public final java.lang.String getDefMd5()", "public final java.lang.String getDefName()", "public final java.lang.String getDefNamespace()", + "public final boolean getApplyOnRestart()", + "public final void setApplyOnRestart(boolean)", "public com.yahoo.search.handler.SearchWithRendererHandlerConfig build()" ], "fields": [] @@ -4505,6 +4507,8 @@ "public final java.lang.String getDefMd5()", "public final java.lang.String getDefName()", "public final java.lang.String getDefNamespace()", + "public final boolean getApplyOnRestart()", + "public final void setApplyOnRestart(boolean)", "public com.yahoo.search.pagetemplates.PageTemplatesConfig build()" ], "fields": [ @@ -4567,6 +4571,8 @@ "public final java.lang.String getDefMd5()", "public final java.lang.String getDefName()", "public final java.lang.String getDefNamespace()", + "public final boolean getApplyOnRestart()", + "public final void setApplyOnRestart(boolean)", "public com.yahoo.search.pagetemplates.ResolversConfig build()" ], "fields": [ @@ -6823,6 +6829,8 @@ "public final java.lang.String getDefMd5()", "public final java.lang.String getDefName()", "public final java.lang.String getDefNamespace()", + "public final boolean getApplyOnRestart()", + "public final void setApplyOnRestart(boolean)", "public com.yahoo.search.query.rewrite.RewritesConfig build()" ], "fields": [ @@ -8073,6 +8081,8 @@ "public final java.lang.String getDefMd5()", "public final java.lang.String getDefName()", "public final java.lang.String getDefNamespace()", + "public final boolean getApplyOnRestart()", + "public final void setApplyOnRestart(boolean)", "public com.yahoo.search.statistics.MeasureQpsConfig build()" ], "fields": [] @@ -8267,6 +8277,8 @@ "public final java.lang.String getDefMd5()", "public final java.lang.String getDefName()", "public final java.lang.String getDefNamespace()", + "public final boolean getApplyOnRestart()", + "public final void setApplyOnRestart(boolean)", "public com.yahoo.search.statistics.TimingSearcherConfig build()" ], "fields": [ diff --git a/dist/vespa.spec b/dist/vespa.spec index 0d26258dc5a..d0605bb96f1 100644 --- a/dist/vespa.spec +++ b/dist/vespa.spec @@ -597,6 +597,7 @@ fi %{_prefix}/lib/jars/component-jar-with-dependencies.jar %{_prefix}/lib/jars/config-bundle-jar-with-dependencies.jar %{_prefix}/lib/jars/configdefinitions-jar-with-dependencies.jar +%{_prefix}/lib/jars/configgen.jar %{_prefix}/lib/jars/config-model-api-jar-with-dependencies.jar %{_prefix}/lib/jars/config-model-jar-with-dependencies.jar %{_prefix}/lib/jars/config-provisioning-jar-with-dependencies.jar diff --git a/document/abi-spec.json b/document/abi-spec.json index 903b7a897df..03a336ad36e 100644 --- a/document/abi-spec.json +++ b/document/abi-spec.json @@ -619,6 +619,8 @@ "public final java.lang.String getDefMd5()", "public final java.lang.String getDefName()", "public final java.lang.String getDefNamespace()", + "public final boolean getApplyOnRestart()", + "public final void setApplyOnRestart(boolean)", "public com.yahoo.document.DocumenttypesConfig build()" ], "fields": [ diff --git a/documentapi/abi-spec.json b/documentapi/abi-spec.json index 337cff774c5..a70f59bb9fb 100644 --- a/documentapi/abi-spec.json +++ b/documentapi/abi-spec.json @@ -1934,6 +1934,8 @@ "public final java.lang.String getDefMd5()", "public final java.lang.String getDefName()", "public final java.lang.String getDefNamespace()", + "public final boolean getApplyOnRestart()", + "public final void setApplyOnRestart(boolean)", "public com.yahoo.documentapi.messagebus.protocol.DocumentrouteselectorpolicyConfig build()" ], "fields": [ diff --git a/jdisc_http_service/abi-spec.json b/jdisc_http_service/abi-spec.json index 8b48631d4aa..6e2836cad6e 100644 --- a/jdisc_http_service/abi-spec.json +++ b/jdisc_http_service/abi-spec.json @@ -50,6 +50,8 @@ "public final java.lang.String getDefMd5()", "public final java.lang.String getDefName()", "public final java.lang.String getDefNamespace()", + "public final boolean getApplyOnRestart()", + "public final void setApplyOnRestart(boolean)", "public com.yahoo.jdisc.http.ConnectorConfig build()" ], "fields": [ @@ -753,6 +755,8 @@ "public final java.lang.String getDefMd5()", "public final java.lang.String getDefName()", "public final java.lang.String getDefNamespace()", + "public final boolean getApplyOnRestart()", + "public final void setApplyOnRestart(boolean)", "public com.yahoo.jdisc.http.ServerConfig build()" ], "fields": [ @@ -964,6 +968,8 @@ "public final java.lang.String getDefMd5()", "public final java.lang.String getDefName()", "public final java.lang.String getDefNamespace()", + "public final boolean getApplyOnRestart()", + "public final void setApplyOnRestart(boolean)", "public com.yahoo.jdisc.http.ServletPathsConfig build()" ], "fields": [ diff --git a/messagebus/abi-spec.json b/messagebus/abi-spec.json index 4bec4bd91fe..f3e7c5664d6 100644 --- a/messagebus/abi-spec.json +++ b/messagebus/abi-spec.json @@ -398,6 +398,8 @@ "public final java.lang.String getDefMd5()", "public final java.lang.String getDefName()", "public final java.lang.String getDefNamespace()", + "public final boolean getApplyOnRestart()", + "public final void setApplyOnRestart(boolean)", "public com.yahoo.messagebus.MessagebusConfig build()" ], "fields": [ diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/duper/HostsModel.java b/service-monitor/src/main/java/com/yahoo/vespa/service/duper/HostsModel.java index 48e20fb5989..97b9313a06a 100644 --- a/service-monitor/src/main/java/com/yahoo/vespa/service/duper/HostsModel.java +++ b/service-monitor/src/main/java/com/yahoo/vespa/service/duper/HostsModel.java @@ -1,6 +1,7 @@ // Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.service.duper; +import com.yahoo.config.ConfigInstance; import com.yahoo.config.FileReference; import com.yahoo.config.model.api.FileDistribution; import com.yahoo.config.model.api.HostInfo; @@ -22,6 +23,7 @@ import java.util.Set; * @author hakon */ public class HostsModel implements Model { + private final Collection hosts; public HostsModel(List hosts) { @@ -34,10 +36,16 @@ public class HostsModel implements Model { } @Override + @SuppressWarnings("deprecation") // yes, this is needed public ConfigPayload getConfig(ConfigKey configKey, ConfigDefinition configDefinition) { throw new UnsupportedOperationException(); } + @Override + public ConfigInstance.Builder getConfigInstance(ConfigKey configKey, ConfigDefinition configDefinition) { + throw new UnsupportedOperationException(); + } + @Override public Set> allConfigsProduced() { throw new UnsupportedOperationException(); @@ -72,4 +80,5 @@ public class HostsModel implements Model { public boolean skipOldConfigModels(Instant now) { throw new UnsupportedOperationException(); } + } -- cgit v1.2.3