diff options
8 files changed, 111 insertions, 32 deletions
diff --git a/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java b/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java index c72aa23a836..540905bef4c 100644 --- a/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java +++ b/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java @@ -83,6 +83,7 @@ public class TestProperties implements ModelContext.Properties, ModelContext.Fea private boolean useRestrictedDataPlaneBindings = false; private Optional<CloudAccount> cloudAccount = Optional.empty(); private boolean allowUserFilters = true; + private boolean allowMoreThanOneContentGroupDown = false; @Override public ModelContext.FeatureFlags featureFlags() { return this; } @Override public boolean multitenant() { return multitenant; } @@ -140,6 +141,7 @@ public class TestProperties implements ModelContext.Properties, ModelContext.Fea @Override public Optional<CloudAccount> cloudAccount() { return cloudAccount; } @Override public boolean allowUserFilters() { return allowUserFilters; } @Override public boolean enableGlobalPhase() { return true; } // Enable global-phase by default for unit tests only + @Override public boolean allowMoreThanOneContentGroupDown(ClusterSpec.Id id) { return allowMoreThanOneContentGroupDown; } public TestProperties sharedStringRepoNoReclaim(boolean sharedStringRepoNoReclaim) { this.sharedStringRepoNoReclaim = sharedStringRepoNoReclaim; @@ -368,6 +370,11 @@ public class TestProperties implements ModelContext.Properties, ModelContext.Fea return this; } + public TestProperties setAllowMoreThanOneContentGroupDown(boolean allowMoreThanOneContentGroupDown) { + this.allowMoreThanOneContentGroupDown = allowMoreThanOneContentGroupDown; + return this; + } + public TestProperties setAllowUserFilters(boolean b) { this.allowUserFilters = b; return this; } public static class Spec implements ConfigServerSpec { diff --git a/config-model/src/main/java/com/yahoo/vespa/model/content/ClusterControllerConfig.java b/config-model/src/main/java/com/yahoo/vespa/model/content/ClusterControllerConfig.java index 49d63cbfba3..5a96e33c522 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/content/ClusterControllerConfig.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/content/ClusterControllerConfig.java @@ -94,12 +94,14 @@ public class ClusterControllerConfig extends AnyConfigProducer implements Fleetc tuning.minStorageUpRatio.ifPresent(builder::min_storage_up_ratio); tuning.minSplitBits.ifPresent(builder::ideal_distribution_bits); tuning.minNodeRatioPerGroup.ifPresent(builder::min_node_ratio_per_group); + tuning.maxGroupsAllowedDown.ifPresent(max -> builder.max_number_of_groups_allowed_to_be_down(allowMoreThanOneContentGroupDown ? max : -1)); resourceLimits.getConfig(builder); - builder.max_number_of_groups_allowed_to_be_down(allowMoreThanOneContentGroupDown ? 1 : -1); } - private static class ClusterControllerTuning { + public ClusterControllerTuning tuning() { return tuning; } + + public static class ClusterControllerTuning { private final Optional<Double> minNodeRatioPerGroup; private final Optional<Duration> initProgressTime; @@ -109,6 +111,7 @@ public class ClusterControllerConfig extends AnyConfigProducer implements Fleetc private final Optional<Double> minDistributorUpRatio; private final Optional<Double> minStorageUpRatio; private final Optional<Integer> minSplitBits; + final Optional<Integer> maxGroupsAllowedDown; ClusterControllerTuning(ModelElement tuning, Optional<Double> minNodeRatioPerGroup, @@ -122,6 +125,7 @@ public class ClusterControllerConfig extends AnyConfigProducer implements Fleetc this.stableStateTimePeriod = Optional.empty(); this.minDistributorUpRatio = Optional.empty(); this.minStorageUpRatio = Optional.empty(); + this.maxGroupsAllowedDown = Optional.empty(); } else { this.initProgressTime = Optional.ofNullable(tuning.childAsDuration("init-progress-time")); this.transitionTime = Optional.ofNullable(tuning.childAsDuration("transition-time")); @@ -129,8 +133,11 @@ public class ClusterControllerConfig extends AnyConfigProducer implements Fleetc this.stableStateTimePeriod = Optional.ofNullable(tuning.childAsDuration("stable-state-period")); this.minDistributorUpRatio = Optional.ofNullable(tuning.childAsDouble("min-distributor-up-ratio")); this.minStorageUpRatio = Optional.ofNullable(tuning.childAsDouble("min-storage-up-ratio")); + this.maxGroupsAllowedDown = Optional.ofNullable(tuning.childAsInteger("max-groups-allowed-down")); } } + + public Optional<Integer> maxGroupsAllowedDown() { return maxGroupsAllowedDown; } } } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/content/cluster/ContentCluster.java b/config-model/src/main/java/com/yahoo/vespa/model/content/cluster/ContentCluster.java index 217c26516a9..f1f210b013c 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/content/cluster/ContentCluster.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/content/cluster/ContentCluster.java @@ -125,11 +125,6 @@ public class ContentCluster extends TreeConfigProducer<AnyConfigProducer> implem deployState.featureFlags().resourceLimitDisk(), deployState.featureFlags().resourceLimitMemory()) .build(contentElement); - c.clusterControllerConfig = new ClusterControllerConfig.Builder(clusterId, - contentElement, - resourceLimits.getClusterControllerLimits(), - deployState.featureFlags().allowMoreThanOneContentGroupDown(new ClusterSpec.Id(clusterId))) - .build(deployState, c, contentElement.getXml()); c.search = new ContentSearchCluster.Builder(documentDefinitions, globallyDistributedDocuments, fractionOfMemoryReserved(clusterId, containers), @@ -139,6 +134,7 @@ public class ContentCluster extends TreeConfigProducer<AnyConfigProducer> implem c.storageNodes = new StorageCluster.Builder().build(deployState, c, w3cContentElement); c.distributorNodes = new DistributorCluster.Builder(c).build(deployState, c, w3cContentElement); c.rootGroup = new StorageGroup.Builder(contentElement, context).buildRootGroup(deployState, redundancyBuilder, c); + c.clusterControllerConfig = createClusterControllerConfig(contentElement, deployState, c, resourceLimits); validateThatGroupSiblingsAreUnique(c.clusterId, c.rootGroup); c.search.handleRedundancy(c.redundancy); setupSearchCluster(c.search, contentElement, deployState.getDeployLogger()); @@ -164,6 +160,24 @@ public class ContentCluster extends TreeConfigProducer<AnyConfigProducer> implem return c; } + private ClusterControllerConfig createClusterControllerConfig(ModelElement contentElement, + DeployState deployState, + ContentCluster c, + ClusterResourceLimits resourceLimits) { + var config = new ClusterControllerConfig.Builder(c.clusterId, + contentElement, + resourceLimits.getClusterControllerLimits(), + deployState.featureFlags() + .allowMoreThanOneContentGroupDown(new ClusterSpec.Id(c.clusterId))) + .build(deployState, c, contentElement.getXml()); + config.tuning().maxGroupsAllowedDown().ifPresent(m -> { + int numberOfLeafGroups = c.getRootGroup().getNumberOfLeafGroups(); + if (m > numberOfLeafGroups) + throw new IllegalArgumentException("Cannot set max-groups-allowed-down (" + m + ") larger than number of groups (" + numberOfLeafGroups + ")"); + }); + return config; + } + private void setupSearchCluster(ContentSearchCluster csc, ModelElement element, DeployLogger logger) { ContentSearch search = DomContentSearchBuilder.build(element); Double visibilityDelay = search.getVisibilityDelay(); @@ -435,6 +449,7 @@ public class ContentCluster extends TreeConfigProducer<AnyConfigProducer> implem public final ContentSearchCluster getSearch() { return search; } public Redundancy redundancy() { return redundancy; } + public ContentCluster setRedundancy(Redundancy redundancy) { this.redundancy = redundancy; return this; diff --git a/config-model/src/main/resources/schema/content.rnc b/config-model/src/main/resources/schema/content.rnc index 84338d49314..6486fdacc18 100644 --- a/config-model/src/main/resources/schema/content.rnc +++ b/config-model/src/main/resources/schema/content.rnc @@ -81,7 +81,8 @@ ClusterControllerTuning = element cluster-controller { element max-premature-crashes { xsd:nonNegativeInteger }? & element stable-state-period { xsd:string { pattern = "([0-9\.]+)\s*([a-z]+)?" } }? & element min-distributor-up-ratio { xsd:double }? & - element min-storage-up-ratio { xsd:double }? + element min-storage-up-ratio { xsd:double }? & + element max-groups-allowed-down { xsd:nonNegativeInteger }? } DispatchTuning = element dispatch { diff --git a/config-model/src/test/java/com/yahoo/vespa/model/content/ContentClusterTest.java b/config-model/src/test/java/com/yahoo/vespa/model/content/ContentClusterTest.java index 488ad9f8484..a33b30f7d93 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/content/ContentClusterTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/content/ContentClusterTest.java @@ -70,7 +70,7 @@ public class ContentClusterTest extends ContentBaseTest { " </proton>" + " </engine>" + " <redundancy>15</redundancy>\n" + - " <group name='root' distribution-key='0'>" + + " <group name='root'>" + " <distribution partitions='1|1|*'/>" + " <group name='g-1' distribution-key='0'>" + " <node hostalias='mockhost' distribution-key='0'/>" + @@ -167,7 +167,7 @@ public class ContentClusterTest extends ContentBaseTest { <content version='1.0' id='storage'> <documents/> <min-redundancy>2</min-redundancy> - <group name='root' distribution-key='0'>" + <group name='root'>" <distribution partitions='1|*'/> <group name='g0' distribution-key='0'> <node hostalias='mockhost' distribution-key='0'/> @@ -214,7 +214,7 @@ public class ContentClusterTest extends ContentBaseTest { <content version='1.0' id='storage'> <documents/> <min-redundancy>4</min-redundancy> - <group name='root' distribution-key='0'>" + <group name='root'>" <distribution partitions='1|*'/> <group name='g0' distribution-key='0'> <node hostalias='mockhost' distribution-key='0'/> @@ -1294,4 +1294,52 @@ public class ContentClusterTest extends ContentBaseTest { clusterControllers); } + @Test + void testAllow2GroupsDown() { + String services = "<?xml version='1.0' encoding='UTF-8' ?>" + + "<services version='1.0'>" + + " <container id='default' version='1.0' />" + + " <content id='storage' version='1.0'>" + + " <redundancy>4</redundancy>" + + " <documents>" + + " <document mode='index' type='type1' />" + + " </documents>" + + " <group name='root'>" + + " <distribution partitions='1|1|1|*'/>" + + " <group name='g-1' distribution-key='0'>" + + " <node hostalias='mockhost' distribution-key='0'/>" + + " </group>" + + " <group name='g-2' distribution-key='1'>" + + " <node hostalias='mockhost' distribution-key='1'/>" + + " </group>" + + " <group name='g-3' distribution-key='2'>" + + " <node hostalias='mockhost' distribution-key='2'/>" + + " </group>" + + " <group name='g-4' distribution-key='3'>" + + " <node hostalias='mockhost' distribution-key='3'/>" + + " </group>" + + " </group>" + + " <tuning>" + + " <cluster-controller>" + + " <max-groups-allowed-down>2</max-groups-allowed-down>" + + " </cluster-controller>" + + " </tuning>" + + " <engine>" + + " <proton>" + + " <searchable-copies>4</searchable-copies>" + + " </proton>" + + " </engine>" + + " </content>" + + " </services>"; + VespaModel model = createEnd2EndOneNode(new TestProperties() + .setHostedVespa(false) + .setMultitenant(true) + .setAllowMoreThanOneContentGroupDown(true), + services); + + var fleetControllerConfigBuilder = new FleetcontrollerConfig.Builder(); + model.getConfig(fleetControllerConfigBuilder, "admin/standalone/cluster-controllers/0/components/clustercontroller-storage-configurer"); + assertEquals(2, fleetControllerConfigBuilder.build().max_number_of_groups_allowed_to_be_down()); + } + } diff --git a/config-model/src/test/java/com/yahoo/vespa/model/content/FleetControllerClusterTest.java b/config-model/src/test/java/com/yahoo/vespa/model/content/FleetControllerClusterTest.java index 1f8dea41a3e..ae22542de6c 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/content/FleetControllerClusterTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/content/FleetControllerClusterTest.java @@ -1,10 +1,10 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.model.content; -import com.yahoo.config.model.api.ModelContext; import com.yahoo.config.model.deploy.DeployState; import com.yahoo.config.model.deploy.TestProperties; import com.yahoo.config.model.test.MockRoot; +import com.yahoo.config.provision.ClusterSpec; import com.yahoo.text.XML; import com.yahoo.vespa.config.content.FleetcontrollerConfig; import com.yahoo.vespa.model.builder.xml.dom.ModelElement; @@ -21,14 +21,13 @@ public class FleetControllerClusterTest { var deployState = new DeployState.Builder().properties(props).build(); MockRoot root = new MockRoot("", deployState); var clusterElement = new ModelElement(doc.getDocumentElement()); - ModelContext.FeatureFlags featureFlags = new TestProperties(); return new ClusterControllerConfig.Builder("storage", clusterElement, new ClusterResourceLimits.Builder(false, - featureFlags.resourceLimitDisk(), - featureFlags.resourceLimitMemory()) + props.resourceLimitDisk(), + props.resourceLimitMemory()) .build(clusterElement).getClusterControllerLimits(), - false) + props.allowMoreThanOneContentGroupDown(new ClusterSpec.Id("default"))) .build(root.getDeployState(), root, clusterElement.getXml()); } @@ -39,20 +38,21 @@ public class FleetControllerClusterTest { @Test void testParameters() { FleetcontrollerConfig.Builder builder = new FleetcontrollerConfig.Builder(); - parse("<cluster id=\"storage\">\n" + - " <documents/>" + - " <tuning>\n" + - " <bucket-splitting minimum-bits=\"7\" />" + - " <cluster-controller>\n" + - " <init-progress-time>13</init-progress-time>\n" + - " <transition-time>27</transition-time>\n" + - " <max-premature-crashes>4</max-premature-crashes>\n" + - " <stable-state-period>72</stable-state-period>\n" + - " <min-distributor-up-ratio>0.7</min-distributor-up-ratio>\n" + - " <min-storage-up-ratio>0.3</min-storage-up-ratio>\n" + - " </cluster-controller>\n" + - " </tuning>\n" + - "</cluster>"). + parse(""" + <cluster id="storage"> + <documents/> <tuning> + <bucket-splitting minimum-bits="7" /> <cluster-controller> + <init-progress-time>13</init-progress-time> + <transition-time>27</transition-time> + <max-premature-crashes>4</max-premature-crashes> + <stable-state-period>72</stable-state-period> + <min-distributor-up-ratio>0.7</min-distributor-up-ratio> + <min-storage-up-ratio>0.3</min-storage-up-ratio> + <max-groups-allowed-down>2</max-groups-allowed-down> + </cluster-controller> + </tuning> + </cluster>""", + new TestProperties().setAllowMoreThanOneContentGroupDown(true)). getConfig(builder); FleetcontrollerConfig config = new FleetcontrollerConfig(builder); @@ -63,6 +63,7 @@ public class FleetControllerClusterTest { assertEquals(0.7, config.min_distributor_up_ratio(), 0.01); assertEquals(0.3, config.min_storage_up_ratio(), 0.01); assertEquals(7, config.ideal_distribution_bits()); + assertEquals(2, config.max_number_of_groups_allowed_to_be_down()); } @Test diff --git a/config-model/src/test/java/com/yahoo/vespa/model/content/utils/ContentClusterUtils.java b/config-model/src/test/java/com/yahoo/vespa/model/content/utils/ContentClusterUtils.java index 291ae97696b..a7c019f162b 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/content/utils/ContentClusterUtils.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/content/utils/ContentClusterUtils.java @@ -60,7 +60,7 @@ public class ContentClusterUtils { Admin admin = new Admin(root, new DefaultMonitoring(), new Metrics(), - false, + root.getDeployState().getProperties().multitenant(), root.getDeployState().isHosted(), applicationType); Document doc = XML.getDocument(clusterXml); diff --git a/config-model/src/test/java/com/yahoo/vespa/model/test/utils/VespaModelCreatorWithMockPkg.java b/config-model/src/test/java/com/yahoo/vespa/model/test/utils/VespaModelCreatorWithMockPkg.java index 2c70c7b2da5..0ca3cb4af2e 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/test/utils/VespaModelCreatorWithMockPkg.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/test/utils/VespaModelCreatorWithMockPkg.java @@ -66,7 +66,7 @@ public class VespaModelCreatorWithMockPkg { try { this.deployState = deployState; VespaModel model = new VespaModel(configModelRegistry, deployState); - Version vespaVersion = new Version(6); + Version vespaVersion = new Version(8); if (validate) { SchemaValidators validators = new SchemaValidators(vespaVersion); try { |