diff options
author | Henning Baldersheim <balder@yahoo-inc.com> | 2019-08-02 22:39:15 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-08-02 22:39:15 +0200 |
commit | cef3960c32187712b6aa16e6243e0233846725e3 (patch) | |
tree | 57abfff0b8849192a4f22a5aa5aa686ba53a9a79 /config-model | |
parent | c8e788d9bd47fa1184fe843b4efd05c914a33c7e (diff) |
Revert "As redundancy and searchable copies depends on group setup normally,"
Diffstat (limited to 'config-model')
11 files changed, 131 insertions, 116 deletions
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/content/ContentSearchCluster.java b/config-model/src/main/java/com/yahoo/vespa/model/content/ContentSearchCluster.java index a6228af8991..b324b496b1a 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/content/ContentSearchCluster.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/content/ContentSearchCluster.java @@ -233,7 +233,7 @@ public class ContentSearchCluster extends AbstractConfigProducer implements Prot Optional<Tuning> tuning = Optional.ofNullable(this.tuning); if (element == null) { snode = SearchNode.create(parent, "" + node.getDistributionKey(), node.getDistributionKey(), spec, - clusterName, node, flushOnShutdown, tuning, parentGroup.isHosted()); + clusterName, node, flushOnShutdown, tuning, parentGroup.getOwner().isHostedVespa()); snode.setHostResource(node.getHostResource()); snode.initService(deployState.getDeployLogger()); @@ -283,12 +283,12 @@ public class ContentSearchCluster extends AbstractConfigProducer implements Prot if (usesHierarchicDistribution()) { indexedCluster.setMaxNodesDownPerFixedRow((redundancy.effectiveFinalRedundancy() / groupToSpecMap.size()) - 1); } - indexedCluster.setSearchableCopies(redundancy.readyCopies()); + indexedCluster.setSearchableCopies(redundancy.searchableCopies()); } this.redundancy = redundancy; for (SearchNode node : getSearchNodes()) { - node.setRedundancy(redundancy.finalRedundancy()); - node.setSearchableCopies(redundancy.readyCopies()); + node.setRedundancy(redundancy.redundancyFromSearchNodePerspective()); + node.setSearchableCopies(redundancy.searchableCopies()); } } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/content/IndexedHierarchicDistributionValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/content/IndexedHierarchicDistributionValidator.java index 7ab5ee9fd80..c721d3d48bc 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/content/IndexedHierarchicDistributionValidator.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/content/IndexedHierarchicDistributionValidator.java @@ -33,15 +33,15 @@ public class IndexedHierarchicDistributionValidator { public void validate() throws Exception { validateThatWeHaveOneGroupLevel(); validateThatLeafGroupsHasEqualNumberOfNodes(); - validateThatLeafGroupsCountIsAFactorOfRedundancy(clusterName, redundancy.effectiveFinalRedundancy(), rootGroup.getSubgroups().size()); + validateThatLeafGroupsCountIsAFactorOfRedundancy(); validateThatRedundancyPerGroupIsEqual(); - validateThatReadyCopiesIsCompatibleWithRedundancy(clusterName, redundancy.effectiveFinalRedundancy(), redundancy.effectiveReadyCopies(), rootGroup.getSubgroups().size()); + validateThatReadyCopiesIsCompatibleWithRedundancy(rootGroup.getSubgroups().size()); } private void validateThatWeHaveOneGroupLevel() { for (StorageGroup group : rootGroup.getSubgroups()) { if (group.getSubgroups().size() > 0) { - throw new IllegalArgumentException(getErrorMsgPrefix(clusterName) + "Expected all groups under root group '" + + throw new IllegalArgumentException(getErrorMsgPrefix() + "Expected all groups under root group '" + rootGroup.getName() + "' to be leaf groups only containing nodes, but sub group '" + group.getName() + "' contains " + group.getSubgroups().size() + " sub groups."); } @@ -59,18 +59,18 @@ public class IndexedHierarchicDistributionValidator { } if (group.getNodes().size() != previousGroup.getNodes().size()) - throw new IllegalArgumentException(getErrorMsgPrefix(clusterName) + "Expected leaf groups to contain an equal number of nodes, but leaf group '" + + throw new IllegalArgumentException(getErrorMsgPrefix() + "Expected leaf groups to contain an equal number of nodes, but leaf group '" + previousGroup.getName() + "' contains " + previousGroup.getNodes().size() + " node(s) while leaf group '" + group.getName() + "' contains " + group.getNodes().size() + " node(s)."); previousGroup = group; } } - static public void validateThatLeafGroupsCountIsAFactorOfRedundancy(String clusterName, int totalRedundancy, int subGroups) { - if (totalRedundancy % subGroups != 0) { - throw new IllegalArgumentException(getErrorMsgPrefix(clusterName) + "Expected number of leaf groups (" + - subGroups + ") to be a factor of redundancy (" + - totalRedundancy + "), but it is not."); + private void validateThatLeafGroupsCountIsAFactorOfRedundancy() { + if (redundancy.effectiveFinalRedundancy() % rootGroup.getSubgroups().size() != 0) { + throw new IllegalArgumentException(getErrorMsgPrefix() + "Expected number of leaf groups (" + + rootGroup.getSubgroups().size() + ") to be a factor of redundancy (" + + redundancy.effectiveFinalRedundancy() + "), but it is not."); } } @@ -78,7 +78,7 @@ public class IndexedHierarchicDistributionValidator { int redundancyPerGroup = redundancy.effectiveFinalRedundancy() / rootGroup.getSubgroups().size(); String expPartitions = createDistributionPartitions(redundancyPerGroup, rootGroup.getSubgroups().size()); if (!rootGroup.getPartitions().get().equals(expPartitions)) { - throw new IllegalArgumentException(getErrorMsgPrefix(clusterName) + "Expected redundancy per leaf group to be " + + throw new IllegalArgumentException(getErrorMsgPrefix() + "Expected redundancy per leaf group to be " + redundancyPerGroup + ", but it is not according to distribution partitions '" + rootGroup.getPartitions().get() + "'. Expected distribution partitions should be '" + expPartitions + "'."); } @@ -98,20 +98,20 @@ public class IndexedHierarchicDistributionValidator { return sb.toString(); } - static public void validateThatReadyCopiesIsCompatibleWithRedundancy(String clusterName, int totalRedundancy, int totalReadyCopies, int groupCount) { - if (totalRedundancy % groupCount != 0) { - throw new IllegalArgumentException(getErrorMsgPrefix(clusterName) + "Expected equal redundancy per group."); + private void validateThatReadyCopiesIsCompatibleWithRedundancy(int groupCount) throws Exception { + if (redundancy.effectiveFinalRedundancy() % groupCount != 0) { + throw new Exception(getErrorMsgPrefix() + "Expected equal redundancy per group."); } - if (totalReadyCopies % groupCount != 0) { - throw new IllegalArgumentException(getErrorMsgPrefix(clusterName) + "Expected equal amount of ready copies per group, but " + - totalReadyCopies + " ready copies is specified with " + groupCount + " groups"); + if (redundancy.effectiveReadyCopies() % groupCount != 0) { + throw new Exception(getErrorMsgPrefix() + "Expected equal amount of ready copies per group, but " + + redundancy.effectiveReadyCopies() + " ready copies is specified with " + groupCount + " groups"); } - if (totalReadyCopies == 0) { - System.err.println(getErrorMsgPrefix(clusterName) + "Warning. No ready copies configured. At least one is recommended."); + if (redundancy.effectiveReadyCopies() == 0) { + System.err.println(getErrorMsgPrefix() + "Warning. No ready copies configured. At least one is recommended."); } } - static private String getErrorMsgPrefix(String clusterName) { + private String getErrorMsgPrefix() { return "In indexed content cluster '" + clusterName + "' using hierarchic distribution: "; } } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/content/Redundancy.java b/config-model/src/main/java/com/yahoo/vespa/model/content/Redundancy.java index 0ff41019ae8..09a6f9b5c53 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/content/Redundancy.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/content/Redundancy.java @@ -11,35 +11,55 @@ import com.yahoo.vespa.config.search.core.ProtonConfig; */ public class Redundancy implements StorDistributionConfig.Producer, ProtonConfig.Producer { - // This numbers are all per group as wanted numbers. private final int initialRedundancy ; private final int finalRedundancy; private final int readyCopies; - private final int groups; + private int implicitGroups = 1; + private int explicitGroups = 1; /** The total number of nodes available in this cluster (assigned when this becomes known) */ - private final int totalNodes; + private int totalNodes = 0; - public Redundancy(int initialRedundancy, int finalRedundancy, int readyCopies, int groups, int totalNodes) { + public Redundancy(int initialRedundancy, int finalRedundancy, int readyCopies) { this.initialRedundancy = initialRedundancy; this.finalRedundancy = finalRedundancy; this.readyCopies = readyCopies; - this.groups = groups; - this.totalNodes = totalNodes; } - public int finalRedundancy() { return effectiveFinalRedundancy()/groups; } - public int readyCopies() { return effectiveReadyCopies()/groups; } - public int groups() { return groups; } + /** + * Set the total number of nodes available in this cluster. + * This impacts the effective redundancy in the case where there are fewer nodes available than + * the requested redundancy. + */ + public void setTotalNodes(int totalNodes) { this.totalNodes = totalNodes; } - public int effectiveInitialRedundancy() { return Math.min(totalNodes, initialRedundancy * groups); } - public int effectiveFinalRedundancy() { return Math.min(totalNodes, finalRedundancy * groups); } - public int effectiveReadyCopies() { return Math.min(totalNodes, readyCopies * groups); } + /** + * Sets the number of groups resulting from implicit setup (groups attribute) + * in this cluster. With implicit groups the redundancy settings are taken to be + * <i>per group</i> and are multiplied by this number to get the effective <i>total</i> + * values returned in the config. + */ + public void setImplicitGroups(int implicitGroups) { this.implicitGroups = implicitGroups; } + + public void setExplicitGroups(int explicitGroups) { this.explicitGroups = explicitGroups; } + + public int initialRedundancy() { return initialRedundancy; } + public int finalRedundancy() { return finalRedundancy; } + public int readyCopies() { return readyCopies; } + public int totalNodes() { + return totalNodes; + } + + public int effectiveInitialRedundancy() { return Math.min(totalNodes, initialRedundancy * implicitGroups); } + public int effectiveFinalRedundancy() { return Math.min(totalNodes, finalRedundancy * implicitGroups); } + public int effectiveReadyCopies() { return Math.min(totalNodes, readyCopies * implicitGroups); } public boolean isEffectivelyGloballyDistributed() { return totalNodes == effectiveFinalRedundancy(); } + public int redundancyFromSearchNodePerspective() { return finalRedundancy/explicitGroups; } + public int searchableCopies() { return readyCopies/(explicitGroups*implicitGroups); } @Override public void getConfig(StorDistributionConfig.Builder builder) { @@ -50,8 +70,8 @@ public class Redundancy implements StorDistributionConfig.Producer, ProtonConfig @Override public void getConfig(ProtonConfig.Builder builder) { ProtonConfig.Distribution.Builder distBuilder = new ProtonConfig.Distribution.Builder(); - distBuilder.redundancy(finalRedundancy()); - distBuilder.searchablecopies(readyCopies()); + distBuilder.redundancy(redundancyFromSearchNodePerspective()); + distBuilder.searchablecopies(searchableCopies()); builder.distribution(distBuilder); } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/content/StorageGroup.java b/config-model/src/main/java/com/yahoo/vespa/model/content/StorageGroup.java index 4d1252a2618..84132427427 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/content/StorageGroup.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/content/StorageGroup.java @@ -15,7 +15,6 @@ import com.yahoo.vespa.model.builder.xml.dom.NodesSpecification; import com.yahoo.vespa.model.builder.xml.dom.VespaDomBuilder; import com.yahoo.vespa.model.container.Container; import com.yahoo.vespa.model.content.cluster.ContentCluster; -import com.yahoo.vespa.model.content.cluster.RedundancyBuilder; import com.yahoo.vespa.model.content.engines.PersistenceEngine; import java.util.ArrayList; @@ -38,7 +37,7 @@ public class StorageGroup { private final String index; private Optional<String> partitions; String name; - private final boolean isHosted; + private final ContentCluster owner; private final Optional<Long> mmapNoCoreLimit; private final Optional<Boolean> coreOnOOM; private final Optional<String> noVespaMalloc; @@ -52,7 +51,7 @@ public class StorageGroup { /** * Creates a storage group * - * @param isHosted true if this is in a hosted setup + * @param owner the cluster this group belongs to * @param name the name of this group * @param index the distribution-key index og this group * @param partitions the distribution strategy to use to distribute content to subgroups or empty @@ -60,12 +59,12 @@ public class StorageGroup { * (having nodes, not subgroups as children). * @param useCpuSocketAffinity whether processes should be started with socket affinity */ - private StorageGroup(boolean isHosted, String name, String index, Optional<String> partitions, + private StorageGroup(ContentCluster owner, String name, String index, Optional<String> partitions, boolean useCpuSocketAffinity, Optional<Long> mmapNoCoreLimit, Optional<Boolean> coreOnOOM, Optional<String> noVespaMalloc, Optional<String> vespaMalloc, Optional<String> vespaMallocDebug, Optional<String> vespaMallocDebugStackTrace) { - this.isHosted = isHosted; + this.owner = owner; this.index = index; this.name = name; this.partitions = partitions; @@ -77,8 +76,8 @@ public class StorageGroup { this.vespaMallocDebug = vespaMallocDebug; this.vespaMallocDebugStackTrace = vespaMallocDebugStackTrace; } - private StorageGroup(boolean isHosted, String name, String index) { - this(isHosted, name, index, Optional.empty(), false, Optional.empty(),Optional.empty(), Optional.empty(), + private StorageGroup(ContentCluster owner, String name, String index) { + this(owner, name, index, Optional.empty(), false, Optional.empty(),Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty()); } @@ -91,7 +90,7 @@ public class StorageGroup { /** Returns the nodes of this, or an empty list of it is not a leaf group */ public List<StorageNode> getNodes() { return nodes; } - public boolean isHosted() { return isHosted; } + public ContentCluster getOwner() { return owner; } /** Returns the index of this group, or null if it is the root group */ public String getIndex() { return index; } @@ -195,14 +194,16 @@ public class StorageGroup { public static class Builder { private final ModelElement clusterElement; + private final ContentCluster owner; private final ConfigModelContext context; - public Builder(ModelElement clusterElement, ConfigModelContext context) { + public Builder(ModelElement clusterElement, ContentCluster owner, ConfigModelContext context) { this.clusterElement = clusterElement; + this.owner = owner; this.context = context; } - public StorageGroup buildRootGroup(DeployState deployState, RedundancyBuilder redundancyBuilder, ContentCluster owner) { + public StorageGroup buildRootGroup(DeployState deployState) { Optional<ModelElement> group = Optional.ofNullable(clusterElement.child("group")); Optional<ModelElement> nodes = getNodes(clusterElement); @@ -211,28 +212,12 @@ public class StorageGroup { if (group.isPresent() && (group.get().stringAttribute("name") != null || group.get().integerAttribute("distribution-key") != null)) deployState.getDeployLogger().log(LogLevel.INFO, "'distribution-key' attribute on a content cluster's root group is ignored"); - GroupBuilder groupBuilder = collectGroup(owner.isHosted(), group, nodes, null, null); - StorageGroup storageGroup = (owner.isHosted()) - ? groupBuilder.buildHosted(deployState, owner, Optional.empty()) - : groupBuilder.buildNonHosted(deployState, owner, Optional.empty()); - Redundancy redundancy = redundancyBuilder.build(owner.getName(), owner.isHosted(), storageGroup.subgroups.size(), storageGroup.getNumberOfLeafGroups(), storageGroup.countNodes()); - owner.setRedundancy(redundancy); - if (storageGroup.partitions.isEmpty() && (redundancy.groups() > 1)) { - storageGroup.partitions = Optional.of(computePartitions(redundancy.finalRedundancy(), redundancy.groups())); + GroupBuilder groupBuilder = collectGroup(group, nodes, null, null); + if (owner.isHostedVespa()) { + return groupBuilder.buildHosted(deployState, owner, Optional.empty()); + } else { + return groupBuilder.buildNonHosted(deployState, owner, Optional.empty()); } - return storageGroup; - } - - /** This returns a partition string which specifies equal distribution between all groups */ - // TODO: Make a partitions object - static private String computePartitions(int redundancyPerGroup, int numGroups) { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < numGroups - 1; ++i) { - sb.append(redundancyPerGroup); - sb.append("|"); - } - sb.append("*"); - return sb.toString(); } /** @@ -277,6 +262,9 @@ public class StorageGroup { if ( ! parent.isPresent() && subGroups.isEmpty() && nodeBuilders.isEmpty()) // no nodes or groups: create single node storageGroup.nodes.add(buildSingleNode(deployState, owner)); + + if ( ! parent.isPresent()) + owner.redundancy().setTotalNodes(storageGroup.countNodes()); return storageGroup; } @@ -309,11 +297,19 @@ public class StorageGroup { if (hostGroups.size() > 1) { if (parent.isPresent()) throw new IllegalArgumentException("Cannot specify groups using the groups attribute in nested content groups"); + owner.redundancy().setTotalNodes(hostMapping.size()); + + // Switch redundancy settings to meaning "per group" + owner.redundancy().setImplicitGroups(hostGroups.size()); + + // Compute partitions expression + int redundancyPerGroup = (int)Math.floor(owner.redundancy().effectiveFinalRedundancy() / hostGroups.size()); + storageGroup.partitions = Optional.of(computePartitions(redundancyPerGroup, hostGroups.size())); // create subgroups as returned from allocation for (Map.Entry<Optional<ClusterSpec.Group>, Map<HostResource, ClusterMembership>> hostGroup : hostGroups.entrySet()) { String groupIndex = String.valueOf(hostGroup.getKey().get().index()); - StorageGroup subgroup = new StorageGroup(true, groupIndex, groupIndex); + StorageGroup subgroup = new StorageGroup(owner, groupIndex, groupIndex); for (Map.Entry<HostResource, ClusterMembership> host : hostGroup.getValue().entrySet()) { subgroup.nodes.add(createStorageNode(deployState, owner, host.getKey(), subgroup, host.getValue())); } @@ -327,10 +323,24 @@ public class StorageGroup { for (GroupBuilder subGroup : subGroups) { storageGroup.subgroups.add(subGroup.buildHosted(deployState, owner, Optional.of(this))); } + if ( ! parent.isPresent()) + owner.redundancy().setTotalNodes(storageGroup.countNodes()); } return storageGroup; } + /** This returns a partition string which specifies equal distribution between all groups */ + // TODO: Make a partitions object + private String computePartitions(int redundancyPerGroup, int numGroups) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < numGroups - 1; ++i) { + sb.append(redundancyPerGroup); + sb.append("|"); + } + sb.append("*"); + return sb.toString(); + } + /** Collect hosts per group */ private Map<Optional<ClusterSpec.Group>, Map<HostResource, ClusterMembership>> collectAllocatedSubgroups(Map<HostResource, ClusterMembership> hostMapping) { Map<Optional<ClusterSpec.Group>, Map<HostResource, ClusterMembership>> hostsPerGroup = new LinkedHashMap<>(); @@ -377,9 +387,9 @@ public class StorageGroup { * <li>Neither element is present: Create a single node. * </ul> */ - private GroupBuilder collectGroup(boolean isHosted, Optional<ModelElement> groupElement, Optional<ModelElement> nodesElement, String name, String index) { + private GroupBuilder collectGroup(Optional<ModelElement> groupElement, Optional<ModelElement> nodesElement, String name, String index) { StorageGroup group = new StorageGroup( - isHosted, name, index, + owner, name, index, childAsString(groupElement, "distribution.partitions"), booleanAttributeOr(groupElement, VespaDomBuilder.CPU_SOCKET_AFFINITY_ATTRIB_NAME, false), childAsLong(groupElement, VespaDomBuilder.MMAP_NOCORE_LIMIT), @@ -389,7 +399,7 @@ public class StorageGroup { childAsString(groupElement, VespaDomBuilder.VESPAMALLOC_DEBUG), childAsString(groupElement, VespaDomBuilder.VESPAMALLOC_DEBUG_STACKTRACE)); - List<GroupBuilder> subGroups = groupElement.isPresent() ? collectSubGroups(isHosted, group, groupElement.get()) : Collections.emptyList(); + List<GroupBuilder> subGroups = groupElement.isPresent() ? collectSubGroups(group, groupElement.get()) : Collections.emptyList(); List<XmlNodeBuilder> explicitNodes = new ArrayList<>(); explicitNodes.addAll(collectExplicitNodes(groupElement)); @@ -440,7 +450,7 @@ public class StorageGroup { return nodes; } - private List<GroupBuilder> collectSubGroups(boolean isHosted, StorageGroup parentGroup, ModelElement parentGroupElement) { + private List<GroupBuilder> collectSubGroups(StorageGroup parentGroup, ModelElement parentGroupElement) { List<ModelElement> subGroupElements = parentGroupElement.subElements("group"); if (subGroupElements.size() > 1 && ! parentGroup.getPartitions().isPresent()) throw new IllegalArgumentException("'distribution' attribute is required with multiple subgroups"); @@ -451,7 +461,7 @@ public class StorageGroup { indexPrefix = parentGroup.index + "."; } for (ModelElement g : subGroupElements) { - subGroups.add(collectGroup(isHosted, Optional.of(g), Optional.ofNullable(g.child("nodes")), g.stringAttribute("name"), + subGroups.add(collectGroup(Optional.of(g), Optional.ofNullable(g.child("nodes")), g.stringAttribute("name"), indexPrefix + g.integerAttribute("distribution-key"))); } return subGroups; 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 48779657162..833afb67f58 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 @@ -80,9 +80,9 @@ public class ContentCluster extends AbstractConfigProducer implements MessagetyperouteselectorpolicyConfig.Producer, BucketspacesConfig.Producer { - private final String documentSelection; + private String documentSelection; private ContentSearchCluster search; - private final boolean isHosted; + private final boolean isHostedVespa; private final Map<String, NewDocumentType> documentDefinitions; private final Set<NewDocumentType> globallyDistributedDocuments; private com.yahoo.vespa.model.content.StorageGroup rootGroup; @@ -91,9 +91,9 @@ public class ContentCluster extends AbstractConfigProducer implements private Redundancy redundancy; private ClusterControllerConfig clusterControllerConfig; private PersistenceEngine.PersistenceFactory persistenceFactory; - private final String clusterName; + private String clusterName; private Integer maxNodesPerMerge; - private final Zone zone; + private Zone zone; /** * If multitenant or a cluster controller was explicitly configured in this cluster: @@ -124,20 +124,21 @@ public class ContentCluster extends AbstractConfigProducer implements new SearchDefinitionBuilder().build(deployState.getDocumentModel().getDocumentManager(), documentsElement); String routingSelection = new DocumentSelectionBuilder().build(documentsElement); - RedundancyBuilder redundancyBuilder = new RedundancyBuilder(contentElement); + Redundancy redundancy = new RedundancyBuilder().build(contentElement); Set<NewDocumentType> globallyDistributedDocuments = new GlobalDistributionBuilder(documentDefinitions).build(documentsElement); ContentCluster c = new ContentCluster(context.getParentProducer(), getClusterName(contentElement), documentDefinitions, - globallyDistributedDocuments, routingSelection, + globallyDistributedDocuments, routingSelection, redundancy, deployState.zone(), deployState.isHosted()); c.clusterControllerConfig = new ClusterControllerConfig.Builder(getClusterName(contentElement), contentElement).build(deployState, c, contentElement.getXml()); c.search = new ContentSearchCluster.Builder(documentDefinitions, globallyDistributedDocuments).build(deployState, c, contentElement.getXml()); c.persistenceFactory = new EngineFactoryBuilder().build(contentElement, c); 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.rootGroup = new StorageGroup.Builder(contentElement, c, context).buildRootGroup(deployState); validateThatGroupSiblingsAreUnique(c.clusterName, c.rootGroup); - c.search.handleRedundancy(c.redundancy); + redundancy.setExplicitGroups(c.getRootGroup().getNumberOfLeafGroups()); + c.search.handleRedundancy(redundancy); IndexedSearchCluster index = c.search.getIndexed(); if (index != null) { @@ -491,13 +492,14 @@ public class ContentCluster extends AbstractConfigProducer implements private ContentCluster(AbstractConfigProducer parent, String clusterName, Map<String, NewDocumentType> documentDefinitions, Set<NewDocumentType> globallyDistributedDocuments, - String routingSelection, Zone zone, boolean isHosted) { + String routingSelection, Redundancy redundancy, Zone zone, boolean isHostedVespa) { super(parent, clusterName); - this.isHosted = isHosted; + this.isHostedVespa = isHostedVespa; this.clusterName = clusterName; this.documentDefinitions = documentDefinitions; this.globallyDistributedDocuments = globallyDistributedDocuments; this.documentSelection = routingSelection; + this.redundancy = redundancy; this.zone = zone; } @@ -551,10 +553,6 @@ public class ContentCluster extends AbstractConfigProducer implements public final ContentSearchCluster getSearch() { return search; } public Redundancy redundancy() { return redundancy; } - public ContentCluster setRedundancy(Redundancy redundancy) { - this.redundancy = redundancy; - return this; - } @Override public void getConfig(MessagetyperouteselectorpolicyConfig.Builder builder) { @@ -641,14 +639,14 @@ public class ContentCluster extends AbstractConfigProducer implements } } - public boolean isHosted() { - return isHosted; + public boolean isHostedVespa() { + return isHostedVespa; } @Override public void validate() throws Exception { super.validate(); - if (search.usesHierarchicDistribution() && !isHosted) { + if (search.usesHierarchicDistribution() && ! isHostedVespa) { // validate manually configured groups new IndexedHierarchicDistributionValidator(search.getClusterName(), rootGroup, redundancy, search.getIndexed().getTuning().dispatch.policy).validate(); if (search.getIndexed().useMultilevelDispatchSetup()) { diff --git a/config-model/src/main/java/com/yahoo/vespa/model/content/cluster/RedundancyBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/content/cluster/RedundancyBuilder.java index 3b6ba6a6b85..fe73fcc904b 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/content/cluster/RedundancyBuilder.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/content/cluster/RedundancyBuilder.java @@ -2,22 +2,22 @@ package com.yahoo.vespa.model.content.cluster; import com.yahoo.vespa.model.builder.xml.dom.ModelElement; -import com.yahoo.vespa.model.content.IndexedHierarchicDistributionValidator; import com.yahoo.vespa.model.content.Redundancy; /** * Builds redundancy config for a content cluster. */ public class RedundancyBuilder { - Integer initialRedundancy = 2; - Integer finalRedundancy = 3; - Integer readyCopies = 2; - RedundancyBuilder(ModelElement clusterXml) { + Redundancy build(ModelElement clusterXml) { + Integer initialRedundancy = 2; + Integer finalRedundancy = 3; + Integer readyCopies = 2; + ModelElement redundancyElement = clusterXml.child("redundancy"); if (redundancyElement != null) { initialRedundancy = redundancyElement.integerAttribute("reply-after"); - finalRedundancy = (int) redundancyElement.asLong(); + finalRedundancy = (int)redundancyElement.asLong(); if (initialRedundancy == null) { initialRedundancy = finalRedundancy; @@ -35,16 +35,8 @@ public class RedundancyBuilder { throw new IllegalArgumentException("Number of searchable copies can not be higher than final redundancy"); } } - } - public Redundancy build(String clusterName, boolean isHosted, int subGroups, int leafGroups, int totalNodes) { - if (isHosted) { - return new Redundancy(initialRedundancy, finalRedundancy, readyCopies, leafGroups, totalNodes); - } else { - subGroups = Math.max(1, subGroups); - IndexedHierarchicDistributionValidator.validateThatLeafGroupsCountIsAFactorOfRedundancy(clusterName, finalRedundancy, subGroups); - IndexedHierarchicDistributionValidator.validateThatReadyCopiesIsCompatibleWithRedundancy(clusterName, finalRedundancy, readyCopies, subGroups); - return new Redundancy(initialRedundancy/leafGroups, finalRedundancy/leafGroups, readyCopies/leafGroups, leafGroups, totalNodes); - } + + return new Redundancy(initialRedundancy, finalRedundancy, readyCopies); } } diff --git a/config-model/src/test/java/com/yahoo/vespa/model/content/DistributorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/content/DistributorTest.java index f36ef6c3ba3..8ae68468374 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/content/DistributorTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/content/DistributorTest.java @@ -113,7 +113,6 @@ public class DistributorTest { assertEquals(true, conf.inlinebucketsplitting()); cluster = parseCluster("<cluster id=\"storage\">\n" + - " <redundancy>2</redundancy>" + " <documents/>" + " <tuning>" + " <distribution type=\"legacy\"/>" + diff --git a/config-model/src/test/java/com/yahoo/vespa/model/content/RedundancyTest.java b/config-model/src/test/java/com/yahoo/vespa/model/content/RedundancyTest.java index eef48120da8..3b2a741a177 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/content/RedundancyTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/content/RedundancyTest.java @@ -22,7 +22,9 @@ public class RedundancyTest { } private static Redundancy createRedundancy(int redundancy, int implicitGroups, int totalNodes) { - Redundancy r = new Redundancy(1, redundancy, 1, implicitGroups, totalNodes); + Redundancy r = new Redundancy(1, redundancy, 1); + r.setImplicitGroups(implicitGroups); + r.setTotalNodes(totalNodes); return r; } diff --git a/config-model/src/test/java/com/yahoo/vespa/model/content/StorageClusterTest.java b/config-model/src/test/java/com/yahoo/vespa/model/content/StorageClusterTest.java index 21c384dfc69..bbb101dbb08 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/content/StorageClusterTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/content/StorageClusterTest.java @@ -305,8 +305,7 @@ public class StorageClusterTest { public void requireThatGroupNamesMustBeUniqueAmongstSiblings() { String xml = "<cluster id=\"storage\">\n" + - " <redundancy>2</redundancy>" + - " <documents/>\n" + + "<documents/>\n" + " <group>\n" + " <distribution partitions=\"*\"/>\n" + " <group distribution-key=\"0\" name=\"bar\">\n" + @@ -331,7 +330,6 @@ public class StorageClusterTest { public void requireThatGroupNamesCanBeDuplicatedAcrossLevels() { String xml = "<cluster id=\"storage\">\n" + - " <redundancy>2</redundancy>" + "<documents/>\n" + " <group>\n" + " <distribution partitions=\"*\"/>\n" + diff --git a/config-model/src/test/java/com/yahoo/vespa/model/content/StorageGroupTest.java b/config-model/src/test/java/com/yahoo/vespa/model/content/StorageGroupTest.java index cb457cabf6c..c1789a05f3c 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/content/StorageGroupTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/content/StorageGroupTest.java @@ -80,7 +80,6 @@ public class StorageGroupTest { StorDistributionConfig.Builder builder = new StorDistributionConfig.Builder(); parse( "<content version=\"1.0\" id=\"storage\">\n" + - " <redundancy>4</redundancy>" + " <documents/>" + " <group>\n" + " <distribution partitions=\"1|*\"/>\n" + @@ -135,7 +134,6 @@ public class StorageGroupTest { StorDistributionConfig.Builder builder = new StorDistributionConfig.Builder(); parse( "<content version=\"1.0\" id=\"storage\">\n" + - " <redundancy>2</redundancy>" + " <documents/>" + " <group>\n" + " <distribution partitions=\"1|*\"/>\n" + diff --git a/config-model/src/test/java/com/yahoo/vespa/model/content/cluster/ClusterTest.java b/config-model/src/test/java/com/yahoo/vespa/model/content/cluster/ClusterTest.java index 4fadea74feb..e4decbc9a10 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/content/cluster/ClusterTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/content/cluster/ClusterTest.java @@ -124,8 +124,6 @@ public class ClusterTest { " </engine>", " <group>", " <node hostalias='my_host' distribution-key='0' />", - " <node hostalias='my_host' distribution-key='1' />", - " <node hostalias='my_host' distribution-key='2' />", " </group>", contentSearchXml, " </content>", |