summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJon Marius Venstad <jonmv@users.noreply.github.com>2021-01-28 14:19:12 +0100
committerGitHub <noreply@github.com>2021-01-28 14:19:12 +0100
commite5459aafc13a5114b853fc372b014843a2c2d922 (patch)
tree847eee9e808a5984c7760e32cd50d5883525bfb1
parent2ae42f68257689846c9066d9cf10adbede82d96b (diff)
parent04436e6600aa66d6ef500565d799083aa652412f (diff)
Merge pull request #16270 from vespa-engine/jonmv/reapply-docprot-config
Jonmv/reapply docprot config [run-systemtest]
-rw-r--r--config-model/src/main/java/com/yahoo/config/model/ApplicationConfigProducerRoot.java28
-rw-r--r--config-model/src/main/java/com/yahoo/config/model/CommonConfigsProducer.java4
-rw-r--r--config-model/src/main/java/com/yahoo/config/model/provision/SingleNodeProvisioner.java1
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/content/cluster/ContentCluster.java37
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/routing/DocumentProtocol.java47
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/routing/Routing.java22
-rw-r--r--config-model/src/test/cfg/routing/defaultconfig/document-protocol-policies.cfg1
-rw-r--r--config-model/src/test/cfg/routing/hopconfig/document-protocol-policies.cfg1
-rw-r--r--config-model/src/test/cfg/routing/replacehop/document-protocol-policies.cfg8
-rw-r--r--config-model/src/test/cfg/routing/replaceroute/document-protocol-policies.cfg8
-rw-r--r--config-model/src/test/cfg/routing/routeconfig/document-protocol-policies.cfg1
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/content/ContentClusterTest.java38
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/content/IndexedHierarchicDistributionTest.java6
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/content/StorageGroupTest.java73
-rwxr-xr-xconfig-model/src/test/java/com/yahoo/vespa/model/routing/test/RoutingTestCase.java14
-rw-r--r--configdefinitions/src/vespa/CMakeLists.txt2
-rw-r--r--configdefinitions/src/vespa/distribution.def46
-rw-r--r--container-core/src/main/java/com/yahoo/container/core/documentapi/DocumentAccessProvider.java9
-rw-r--r--container-core/src/main/java/com/yahoo/container/core/documentapi/VespaDocumentAccess.java9
-rw-r--r--documentapi/abi-spec.json154
-rwxr-xr-xdocumentapi/src/main/java/com/yahoo/documentapi/messagebus/MessageBusParams.java15
-rw-r--r--documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/ContentPolicy.java28
-rwxr-xr-xdocumentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/DocumentProtocol.java32
-rwxr-xr-xdocumentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/DocumentRouteSelectorPolicy.java21
-rw-r--r--documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/MessageTypePolicy.java10
-rwxr-xr-xdocumentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/RoutingPolicyFactories.java73
-rwxr-xr-xdocumentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/RoutingPolicyFactory.java7
-rw-r--r--documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/SlobrokPolicy.java4
-rw-r--r--documentapi/src/main/resources/configdefinitions/document-protocol-policies.def25
-rw-r--r--documentapi/src/test/java/com/yahoo/documentapi/messagebus/protocol/test/storagepolicy/ContentPolicyTest.java8
-rw-r--r--documentapi/src/test/java/com/yahoo/documentapi/messagebus/protocol/test/storagepolicy/ContentPolicyTestEnvironment.java22
-rw-r--r--documentapi/src/test/java/com/yahoo/documentapi/messagebus/protocol/test/storagepolicy/Simulator.java20
-rw-r--r--messagebus/src/main/java/com/yahoo/messagebus/test/SimpleMessage.java2
-rw-r--r--messagebus/src/test/java/com/yahoo/messagebus/DynamicThrottlePolicyTest.java5
-rw-r--r--vdslib/src/main/java/com/yahoo/vdslib/distribution/Distribution.java180
-rw-r--r--vdslib/src/main/java/com/yahoo/vdslib/distribution/Group.java2
-rw-r--r--vdslib/src/test/java/com/yahoo/vdslib/distribution/CrossPlatformTestFactory.java5
-rw-r--r--vdslib/src/test/java/com/yahoo/vdslib/distribution/DistributionTestCase.java1
-rw-r--r--vespaclient-container-plugin/src/main/java/com/yahoo/vespa/http/server/FeedErrorMessage.java43
39 files changed, 757 insertions, 255 deletions
diff --git a/config-model/src/main/java/com/yahoo/config/model/ApplicationConfigProducerRoot.java b/config-model/src/main/java/com/yahoo/config/model/ApplicationConfigProducerRoot.java
index 1cc5c93c28a..061ad42e028 100644
--- a/config-model/src/main/java/com/yahoo/config/model/ApplicationConfigProducerRoot.java
+++ b/config-model/src/main/java/com/yahoo/config/model/ApplicationConfigProducerRoot.java
@@ -4,22 +4,24 @@ package com.yahoo.config.model;
import com.yahoo.cloud.config.ApplicationIdConfig;
import com.yahoo.cloud.config.ClusterListConfig;
import com.yahoo.cloud.config.ModelConfig;
-import com.yahoo.cloud.config.SlobroksConfig;
-import com.yahoo.cloud.config.ZookeepersConfig;
-import com.yahoo.config.model.deploy.DeployState;
-import com.yahoo.config.provision.ApplicationId;
-import com.yahoo.component.Version;
-import com.yahoo.vespa.config.content.LoadTypeConfig;
import com.yahoo.cloud.config.ModelConfig.Hosts;
import com.yahoo.cloud.config.ModelConfig.Hosts.Services;
import com.yahoo.cloud.config.ModelConfig.Hosts.Services.Ports;
+import com.yahoo.cloud.config.SlobroksConfig;
+import com.yahoo.cloud.config.ZookeepersConfig;
import com.yahoo.cloud.config.log.LogdConfig;
+import com.yahoo.component.Version;
+import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.config.model.producer.AbstractConfigProducer;
+import com.yahoo.config.provision.ApplicationId;
import com.yahoo.document.DocumenttypesConfig;
import com.yahoo.document.config.DocumentmanagerConfig;
import com.yahoo.documentapi.messagebus.protocol.DocumentrouteselectorpolicyConfig;
+import com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig;
import com.yahoo.messagebus.MessagebusConfig;
import com.yahoo.vespa.config.content.AllClustersBucketSpacesConfig;
+import com.yahoo.vespa.config.content.DistributionConfig;
+import com.yahoo.vespa.config.content.LoadTypeConfig;
import com.yahoo.vespa.configmodel.producers.DocumentManager;
import com.yahoo.vespa.configmodel.producers.DocumentTypes;
import com.yahoo.vespa.documentmodel.DocumentModel;
@@ -165,6 +167,13 @@ public class ApplicationConfigProducerRoot extends AbstractConfigProducer<Abstra
}
@Override
+ public void getConfig(DocumentProtocolPoliciesConfig.Builder builder) {
+ if (routing != null) {
+ routing.getConfig(builder);
+ }
+ }
+
+ @Override
public void getConfig(MessagebusConfig.Builder builder) {
if (routing != null) {
routing.getConfig(builder);
@@ -213,6 +222,13 @@ public class ApplicationConfigProducerRoot extends AbstractConfigProducer<Abstra
}
@Override
+ public void getConfig(DistributionConfig.Builder builder) {
+ for (ContentCluster cluster : ((VespaModel) getRoot()).getContentClusters().values()) {
+ cluster.getConfig(builder);
+ }
+ }
+
+ @Override
public void getConfig(AllClustersBucketSpacesConfig.Builder builder) {
VespaModel model = (VespaModel) getRoot();
for (ContentCluster cluster : model.getContentClusters().values()) {
diff --git a/config-model/src/main/java/com/yahoo/config/model/CommonConfigsProducer.java b/config-model/src/main/java/com/yahoo/config/model/CommonConfigsProducer.java
index 9dcd94bf455..312890aac13 100644
--- a/config-model/src/main/java/com/yahoo/config/model/CommonConfigsProducer.java
+++ b/config-model/src/main/java/com/yahoo/config/model/CommonConfigsProducer.java
@@ -2,6 +2,8 @@
package com.yahoo.config.model;
import com.yahoo.cloud.config.ApplicationIdConfig;
+import com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig;
+import com.yahoo.vespa.config.content.DistributionConfig;
import com.yahoo.vespa.config.content.LoadTypeConfig;
import com.yahoo.cloud.config.log.LogdConfig;
import com.yahoo.cloud.config.SlobroksConfig;
@@ -25,11 +27,13 @@ public interface CommonConfigsProducer extends DocumentmanagerConfig.Producer,
DocumenttypesConfig.Producer,
MessagebusConfig.Producer,
DocumentrouteselectorpolicyConfig.Producer,
+ DocumentProtocolPoliciesConfig.Producer,
LogdConfig.Producer,
SlobroksConfig.Producer,
ZookeepersConfig.Producer,
LoadTypeConfig.Producer,
ClusterListConfig.Producer,
+ DistributionConfig.Producer,
AllClustersBucketSpacesConfig.Producer,
ModelConfig.Producer,
ApplicationIdConfig.Producer {
diff --git a/config-model/src/main/java/com/yahoo/config/model/provision/SingleNodeProvisioner.java b/config-model/src/main/java/com/yahoo/config/model/provision/SingleNodeProvisioner.java
index d6cccc9f2be..0cfe35a51b5 100644
--- a/config-model/src/main/java/com/yahoo/config/model/provision/SingleNodeProvisioner.java
+++ b/config-model/src/main/java/com/yahoo/config/model/provision/SingleNodeProvisioner.java
@@ -10,7 +10,6 @@ import com.yahoo.config.provision.HostSpec;
import com.yahoo.config.provision.NodeResources;
import com.yahoo.config.provision.ProvisionLogger;
import com.yahoo.net.HostName;
-import com.yahoo.vespa.config.content.StorDistributionConfig;
import java.util.ArrayList;
import java.util.List;
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 7ec2dc67cf2..a627e030156 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
@@ -15,6 +15,7 @@ import com.yahoo.documentapi.messagebus.protocol.DocumentProtocol;
import com.yahoo.documentmodel.NewDocumentType;
import com.yahoo.metrics.MetricsmanagerConfig;
import com.yahoo.vespa.config.content.AllClustersBucketSpacesConfig;
+import com.yahoo.vespa.config.content.DistributionConfig;
import com.yahoo.vespa.config.content.FleetcontrollerConfig;
import com.yahoo.vespa.config.content.MessagetyperouteselectorpolicyConfig;
import com.yahoo.vespa.config.content.StorDistributionConfig;
@@ -67,6 +68,8 @@ import java.util.TreeMap;
import java.util.logging.Level;
import java.util.stream.Collectors;
+import static java.util.stream.Collectors.toList;
+
/**
* A content cluster.
*
@@ -74,6 +77,7 @@ import java.util.stream.Collectors;
* @author bratseth
*/
public class ContentCluster extends AbstractConfigProducer implements
+ DistributionConfig.Producer,
StorDistributionConfig.Producer,
StorDistributormanagerConfig.Producer,
FleetcontrollerConfig.Producer,
@@ -748,6 +752,39 @@ public class ContentCluster extends AbstractConfigProducer implements
}
}
+ @Override
+ public void getConfig(DistributionConfig.Builder builder) {
+ DistributionConfig.Cluster.Builder clusterBuilder = new DistributionConfig.Cluster.Builder();
+ StorDistributionConfig.Builder storDistributionBuilder = new StorDistributionConfig.Builder();
+ getConfig(storDistributionBuilder);
+ StorDistributionConfig config = storDistributionBuilder.build();
+
+ clusterBuilder.active_per_leaf_group(config.active_per_leaf_group());
+ clusterBuilder.ready_copies(config.ready_copies());
+ clusterBuilder.redundancy(config.redundancy());
+ clusterBuilder.initial_redundancy(config.initial_redundancy());
+
+ for (StorDistributionConfig.Group group : config.group()) {
+ DistributionConfig.Cluster.Group.Builder groupBuilder = new DistributionConfig.Cluster.Group.Builder();
+ groupBuilder.index(group.index())
+ .name(group.name())
+ .capacity(group.capacity())
+ .partitions(group.partitions());
+
+ for (var node : group.nodes()) {
+ DistributionConfig.Cluster.Group.Nodes.Builder nodesBuilder = new DistributionConfig.Cluster.Group.Nodes.Builder();
+ nodesBuilder.index(node.index())
+ .retired(node.retired());
+
+ groupBuilder.nodes(nodesBuilder);
+ }
+
+ clusterBuilder.group(groupBuilder);
+ }
+
+ builder.cluster(getConfigId(), clusterBuilder);
+ }
+
/**
* Mark whether the config emitted by this cluster currently should be applied by clients already running with
* a previous generation of it only by restarting the consuming processes.
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/routing/DocumentProtocol.java b/config-model/src/main/java/com/yahoo/vespa/model/routing/DocumentProtocol.java
index e6f4969f593..15e6c5993b3 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/routing/DocumentProtocol.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/routing/DocumentProtocol.java
@@ -2,8 +2,9 @@
package com.yahoo.vespa.model.routing;
import com.yahoo.config.model.ConfigModelRepo;
-import com.yahoo.documentapi.messagebus.protocol.DocumentrouteselectorpolicyConfig;
import com.yahoo.document.select.DocumentSelector;
+import com.yahoo.documentapi.messagebus.protocol.DocumentrouteselectorpolicyConfig;
+import com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig;
import com.yahoo.messagebus.routing.ApplicationSpec;
import com.yahoo.messagebus.routing.HopSpec;
import com.yahoo.messagebus.routing.RouteSpec;
@@ -12,9 +13,9 @@ import com.yahoo.vespa.model.container.Container;
import com.yahoo.vespa.model.container.ContainerCluster;
import com.yahoo.vespa.model.container.ContainerModel;
import com.yahoo.vespa.model.container.docproc.ContainerDocproc;
-import com.yahoo.vespa.model.content.cluster.ContentCluster;
-import com.yahoo.vespa.model.content.Content;
import com.yahoo.vespa.model.container.docproc.DocprocChain;
+import com.yahoo.vespa.model.content.Content;
+import com.yahoo.vespa.model.content.cluster.ContentCluster;
import java.util.ArrayList;
import java.util.Collection;
@@ -31,7 +32,9 @@ import java.util.TreeMap;
*
* @author Simon Thoresen Hult
*/
-public final class DocumentProtocol implements Protocol, DocumentrouteselectorpolicyConfig.Producer {
+public final class DocumentProtocol implements Protocol,
+ DocumentrouteselectorpolicyConfig.Producer,
+ DocumentProtocolPoliciesConfig.Producer {
private static final String NAME = "document";
private final ApplicationSpec application;
@@ -101,6 +104,42 @@ public final class DocumentProtocol implements Protocol, Documentrouteselectorpo
}
}
+ @Override
+ public void getConfig(DocumentProtocolPoliciesConfig.Builder builder) {
+ for (ContentCluster cluster : Content.getContentClusters(repo)) {
+ DocumentProtocolPoliciesConfig.Cluster.Builder clusterBuilder = new DocumentProtocolPoliciesConfig.Cluster.Builder();
+ addSelector(cluster.getConfigId(), cluster.getRoutingSelector(), clusterBuilder);
+ if (cluster.getSearch().hasIndexedCluster())
+ addRoutes(getDirectRouteName(cluster.getConfigId()), getIndexedRouteName(cluster.getConfigId()), clusterBuilder);
+
+ builder.cluster(cluster.getConfigId(), clusterBuilder);
+ }
+ }
+
+ private static void addRoutes(String directRoute, String indexedRoute, DocumentProtocolPoliciesConfig.Cluster.Builder builder) {
+ builder.defaultRoute(directRoute)
+ .route(new DocumentProtocolPoliciesConfig.Cluster.Route.Builder()
+ .messageType(com.yahoo.documentapi.messagebus.protocol.DocumentProtocol.MESSAGE_PUTDOCUMENT)
+ .name(indexedRoute))
+ .route(new DocumentProtocolPoliciesConfig.Cluster.Route.Builder()
+ .messageType(com.yahoo.documentapi.messagebus.protocol.DocumentProtocol.MESSAGE_REMOVEDOCUMENT)
+ .name(indexedRoute))
+ .route(new DocumentProtocolPoliciesConfig.Cluster.Route.Builder()
+ .messageType(com.yahoo.documentapi.messagebus.protocol.DocumentProtocol.MESSAGE_UPDATEDOCUMENT)
+ .name(indexedRoute));
+ }
+
+ private static void addSelector(String clusterConfigId, String selector, DocumentProtocolPoliciesConfig.Cluster.Builder builder) {
+ try {
+ new DocumentSelector(selector);
+ } catch (com.yahoo.document.select.parser.ParseException e) {
+ throw new IllegalArgumentException("Failed to parse selector '" + selector +
+ "' for route '" + clusterConfigId +
+ "' in policy 'DocumentRouteSelector'.");
+ }
+ builder.selector(selector);
+ }
+
private static void addRoute(String clusterConfigId, String selector, DocumentrouteselectorpolicyConfig.Builder builder) {
try {
new DocumentSelector(selector);
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/routing/Routing.java b/config-model/src/main/java/com/yahoo/vespa/model/routing/Routing.java
index 36beb766f5b..6637c84df10 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/routing/Routing.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/routing/Routing.java
@@ -4,10 +4,20 @@ package com.yahoo.vespa.model.routing;
import com.yahoo.config.model.ConfigModel;
import com.yahoo.config.model.ConfigModelContext;
import com.yahoo.config.model.ConfigModelRepo;
-import com.yahoo.messagebus.routing.*;
+import com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig;
import com.yahoo.messagebus.MessagebusConfig;
import com.yahoo.documentapi.messagebus.protocol.DocumentrouteselectorpolicyConfig;
-import java.util.*;
+import com.yahoo.messagebus.routing.ApplicationSpec;
+import com.yahoo.messagebus.routing.HopSpec;
+import com.yahoo.messagebus.routing.RouteSpec;
+import com.yahoo.messagebus.routing.RoutingSpec;
+import com.yahoo.messagebus.routing.RoutingTableSpec;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
/**
* This is the routing plugin of the Vespa model. This class is responsible for parsing all routing information given
@@ -82,6 +92,14 @@ public class Routing extends ConfigModel {
}
}
+ public void getConfig(DocumentProtocolPoliciesConfig.Builder builder) {
+ for (Protocol protocol : protocols) {
+ if (protocol instanceof DocumentProtocol) {
+ ((DocumentProtocol) protocol).getConfig(builder);
+ }
+ }
+ }
+
public void getConfig(DocumentrouteselectorpolicyConfig.Builder builder) {
for (Protocol protocol : protocols) {
if (protocol instanceof DocumentProtocol) {
diff --git a/config-model/src/test/cfg/routing/defaultconfig/document-protocol-policies.cfg b/config-model/src/test/cfg/routing/defaultconfig/document-protocol-policies.cfg
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/config-model/src/test/cfg/routing/defaultconfig/document-protocol-policies.cfg
@@ -0,0 +1 @@
+
diff --git a/config-model/src/test/cfg/routing/hopconfig/document-protocol-policies.cfg b/config-model/src/test/cfg/routing/hopconfig/document-protocol-policies.cfg
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/config-model/src/test/cfg/routing/hopconfig/document-protocol-policies.cfg
@@ -0,0 +1 @@
+
diff --git a/config-model/src/test/cfg/routing/replacehop/document-protocol-policies.cfg b/config-model/src/test/cfg/routing/replacehop/document-protocol-policies.cfg
new file mode 100644
index 00000000000..68659362350
--- /dev/null
+++ b/config-model/src/test/cfg/routing/replacehop/document-protocol-policies.cfg
@@ -0,0 +1,8 @@
+cluster{music}.defaultRoute "music-direct"
+cluster{music}.route[0].name "music-index"
+cluster{music}.route[0].messageType 100004
+cluster{music}.route[1].name "music-index"
+cluster{music}.route[1].messageType 100005
+cluster{music}.route[2].name "music-index"
+cluster{music}.route[2].messageType 100006
+cluster{music}.selector "(music)"
diff --git a/config-model/src/test/cfg/routing/replaceroute/document-protocol-policies.cfg b/config-model/src/test/cfg/routing/replaceroute/document-protocol-policies.cfg
new file mode 100644
index 00000000000..68659362350
--- /dev/null
+++ b/config-model/src/test/cfg/routing/replaceroute/document-protocol-policies.cfg
@@ -0,0 +1,8 @@
+cluster{music}.defaultRoute "music-direct"
+cluster{music}.route[0].name "music-index"
+cluster{music}.route[0].messageType 100004
+cluster{music}.route[1].name "music-index"
+cluster{music}.route[1].messageType 100005
+cluster{music}.route[2].name "music-index"
+cluster{music}.route[2].messageType 100006
+cluster{music}.selector "(music)"
diff --git a/config-model/src/test/cfg/routing/routeconfig/document-protocol-policies.cfg b/config-model/src/test/cfg/routing/routeconfig/document-protocol-policies.cfg
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/config-model/src/test/cfg/routing/routeconfig/document-protocol-policies.cfg
@@ -0,0 +1 @@
+
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 9f17a1c4142..095434c8e04 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
@@ -14,6 +14,7 @@ import com.yahoo.container.ComponentsConfig;
import com.yahoo.messagebus.routing.RoutingTableSpec;
import com.yahoo.metrics.MetricsmanagerConfig;
import com.yahoo.vespa.config.content.AllClustersBucketSpacesConfig;
+import com.yahoo.vespa.config.content.DistributionConfig;
import com.yahoo.vespa.config.content.FleetcontrollerConfig;
import com.yahoo.vespa.config.content.StorDistributionConfig;
import com.yahoo.vespa.config.content.StorFilestorConfig;
@@ -99,12 +100,22 @@ public class ContentClusterTest extends ContentBaseTest {
" </group>" +
"</content>"
);
+ DistributionConfig.Builder distributionBuilder = new DistributionConfig.Builder();
+ cc.getConfig(distributionBuilder);
+ DistributionConfig distributionConfig = distributionBuilder.build();
+ assertEquals(3, distributionConfig.cluster("storage").ready_copies());
+ assertEquals(15, distributionConfig.cluster("storage").initial_redundancy());
+ assertEquals(15, distributionConfig.cluster("storage").redundancy());
+ assertEquals(4, distributionConfig.cluster("storage").group().size());
+ assertEquals(1, distributionConfig.cluster().size());
+
StorDistributionConfig.Builder storBuilder = new StorDistributionConfig.Builder();
cc.getConfig(storBuilder);
StorDistributionConfig storConfig = new StorDistributionConfig(storBuilder);
assertEquals(15, storConfig.initial_redundancy());
assertEquals(15, storConfig.redundancy());
assertEquals(3, storConfig.ready_copies());
+
ProtonConfig.Builder protonBuilder = new ProtonConfig.Builder();
cc.getSearch().getConfig(protonBuilder);
ProtonConfig protonConfig = new ProtonConfig(protonBuilder);
@@ -132,12 +143,20 @@ public class ContentClusterTest extends ContentBaseTest {
" </group>" +
"</content>"
);
+ DistributionConfig.Builder distributionBuilder = new DistributionConfig.Builder();
+ cc.getConfig(distributionBuilder);
+ DistributionConfig distributionConfig = distributionBuilder.build();
+ assertEquals(3, distributionConfig.cluster("storage").ready_copies());
+ assertEquals(4, distributionConfig.cluster("storage").initial_redundancy());
+ assertEquals(5, distributionConfig.cluster("storage").redundancy());
+
StorDistributionConfig.Builder storBuilder = new StorDistributionConfig.Builder();
cc.getConfig(storBuilder);
StorDistributionConfig storConfig = new StorDistributionConfig(storBuilder);
assertEquals(4, storConfig.initial_redundancy());
assertEquals(5, storConfig.redundancy());
assertEquals(3, storConfig.ready_copies());
+
ProtonConfig.Builder protonBuilder = new ProtonConfig.Builder();
cc.getSearch().getConfig(protonBuilder);
ProtonConfig protonConfig = new ProtonConfig(protonBuilder);
@@ -163,8 +182,7 @@ public class ContentClusterTest extends ContentBaseTest {
@Test
public void testRedundancyDefaults() {
- StorDistributionConfig.Builder builder = new StorDistributionConfig.Builder();
- parse(
+ ContentCluster cc = parse(
"<content version=\"1.0\" id=\"storage\">\n" +
" <documents/>" +
" <group>" +
@@ -173,8 +191,15 @@ public class ContentClusterTest extends ContentBaseTest {
" <node hostalias=\"mockhost\" distribution-key=\"2\"/>\"" +
" </group>" +
"</content>"
- ).getConfig(builder);
+ );
+
+ DistributionConfig.Builder distributionBuilder = new DistributionConfig.Builder();
+ cc.getConfig(distributionBuilder);
+ DistributionConfig distributionConfig = distributionBuilder.build();
+ assertEquals(3, distributionConfig.cluster("storage").redundancy());
+ StorDistributionConfig.Builder builder = new StorDistributionConfig.Builder();
+ cc.getConfig(builder);
StorDistributionConfig config = new StorDistributionConfig(builder);
assertEquals(2, config.initial_redundancy());
assertEquals(3, config.redundancy());
@@ -548,6 +573,13 @@ public class ContentClusterTest extends ContentBaseTest {
"</content>"
);
+ DistributionConfig.Builder bob = new DistributionConfig.Builder();
+ cluster.getConfig(bob);
+ DistributionConfig.Cluster.Group group = bob.build().cluster("test").group(0);
+ assertEquals("invalid", group.name());
+ assertEquals("invalid", group.index());
+ assertEquals(2, group.nodes().size());
+
StorDistributionConfig.Builder builder = new StorDistributionConfig.Builder();
cluster.getConfig(builder);
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/content/IndexedHierarchicDistributionTest.java b/config-model/src/test/java/com/yahoo/vespa/model/content/IndexedHierarchicDistributionTest.java
index d290d4ec953..80ab6745b79 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/content/IndexedHierarchicDistributionTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/content/IndexedHierarchicDistributionTest.java
@@ -2,10 +2,6 @@
package com.yahoo.vespa.model.content;
import com.yahoo.vespa.config.content.StorDistributionConfig;
-import com.yahoo.config.model.test.MockRoot;
-import com.yahoo.vespa.model.Host;
-import com.yahoo.vespa.model.HostResource;
-import com.yahoo.vespa.model.SimpleConfigProducer;
import com.yahoo.vespa.model.content.cluster.ContentCluster;
import com.yahoo.vespa.model.search.DispatchGroup;
import com.yahoo.vespa.model.search.SearchInterface;
@@ -17,9 +13,9 @@ import java.util.List;
import java.util.Optional;
import static com.yahoo.config.model.test.TestUtil.joinLines;
-import static org.hamcrest.Matchers.containsString;
import static com.yahoo.vespa.model.content.utils.ContentClusterUtils.createCluster;
import static com.yahoo.vespa.model.content.utils.ContentClusterUtils.createClusterXml;
+import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
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..b9495d45e08 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
@@ -2,13 +2,14 @@
package com.yahoo.vespa.model.content;
import com.yahoo.config.model.test.MockRoot;
+import com.yahoo.vespa.config.content.DistributionConfig;
import com.yahoo.vespa.config.content.StorDistributionConfig;
import com.yahoo.vespa.model.content.cluster.ContentCluster;
import com.yahoo.vespa.model.content.utils.ContentClusterUtils;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
/**
* Test for storage groups.
@@ -21,7 +22,6 @@ public class StorageGroupTest {
@Test
public void testSingleGroup() throws Exception {
- StorDistributionConfig.Builder builder = new StorDistributionConfig.Builder();
ContentCluster cluster = parse(
"<content id=\"storage\">\n" +
" <documents/>" +
@@ -32,8 +32,6 @@ public class StorageGroupTest {
"</content>"
);
- cluster.getConfig(builder);
-
assertEquals("content", cluster.getStorageNodes().getChildren().get("0").getServicePropertyString("clustertype"));
assertEquals("storage", cluster.getStorageNodes().getChildren().get("0").getServicePropertyString("clustername"));
assertEquals("0", cluster.getStorageNodes().getChildren().get("0").getServicePropertyString("index"));
@@ -42,6 +40,8 @@ public class StorageGroupTest {
assertEquals("storage", cluster.getDistributorNodes().getChildren().get("0").getServicePropertyString("clustername"));
assertEquals("0", cluster.getDistributorNodes().getChildren().get("0").getServicePropertyString("index"));
+ StorDistributionConfig.Builder builder = new StorDistributionConfig.Builder();
+ cluster.getConfig(builder);
StorDistributionConfig config = new StorDistributionConfig(builder);
assertEquals(1, config.group().size());
@@ -51,6 +51,17 @@ public class StorageGroupTest {
assertEquals(0, config.group(0).nodes(0).index());
assertEquals(1, config.group(0).nodes(1).index());
//assertNotNull(cluster.getRootGroup().getNodes().get(0).getHost());
+
+ DistributionConfig.Builder distributionBuilder = new DistributionConfig.Builder();
+ cluster.getConfig(distributionBuilder);
+ DistributionConfig.Cluster clusterConfig = distributionBuilder.build().cluster("storage");
+
+ assertEquals(1, clusterConfig.group().size());
+ assertEquals("invalid", clusterConfig.group(0).index());
+ assertEquals("invalid", clusterConfig.group(0).name());
+ assertEquals(2, clusterConfig.group(0).nodes().size());
+ assertEquals(0, clusterConfig.group(0).nodes(0).index());
+ assertEquals(1, clusterConfig.group(0).nodes(1).index());
}
@Test
@@ -70,15 +81,14 @@ public class StorageGroupTest {
" </group>\n" +
"</cluster>"
);
- assertTrue(false);
+ fail();
} catch (Exception e) {
}
}
@Test
public void testNestedGroups() throws Exception {
- StorDistributionConfig.Builder builder = new StorDistributionConfig.Builder();
- parse(
+ ContentCluster cluster = parse(
"<content version=\"1.0\" id=\"storage\">\n" +
" <redundancy>4</redundancy>" +
" <documents/>" +
@@ -101,8 +111,10 @@ public class StorageGroupTest {
" </group>\n" +
" </group>\n" +
"</content>"
- ).getConfig(builder);
+ );
+ StorDistributionConfig.Builder builder = new StorDistributionConfig.Builder();
+ cluster.getConfig(builder);
StorDistributionConfig config = new StorDistributionConfig(builder);
assertEquals(5, config.group().size());
@@ -128,12 +140,39 @@ public class StorageGroupTest {
assertEquals(5, config.group(4).nodes(1).index());
assertEquals("1|*", config.group(0).partitions());
+
+ DistributionConfig.Builder distributionBuilder = new DistributionConfig.Builder();
+ cluster.getConfig(distributionBuilder);
+ DistributionConfig.Cluster clusterConfig = distributionBuilder.build().cluster("storage");
+
+ assertEquals(5, clusterConfig.group().size());
+ assertEquals("invalid", clusterConfig.group(0).index());
+ assertEquals("0", clusterConfig.group(1).index());
+ assertEquals("1", clusterConfig.group(2).index());
+ assertEquals("1.0", clusterConfig.group(3).index());
+ assertEquals("1.1", clusterConfig.group(4).index());
+ assertEquals("invalid", clusterConfig.group(0).name());
+ assertEquals("sub1", clusterConfig.group(1).name());
+ assertEquals("sub2", clusterConfig.group(2).name());
+ assertEquals("sub3", clusterConfig.group(3).name());
+ assertEquals("sub4", clusterConfig.group(4).name());
+ assertEquals(2, clusterConfig.group(1).nodes().size());
+ assertEquals(0, clusterConfig.group(1).nodes(0).index());
+ assertEquals(1, clusterConfig.group(1).nodes(1).index());
+ assertEquals(0, clusterConfig.group(2).nodes().size());
+ assertEquals(2, clusterConfig.group(3).nodes().size());
+ assertEquals(2, clusterConfig.group(3).nodes(0).index());
+ assertEquals(3, clusterConfig.group(3).nodes(1).index());
+ assertEquals(2, clusterConfig.group(4).nodes().size());
+ assertEquals(4, clusterConfig.group(4).nodes(0).index());
+ assertEquals(5, clusterConfig.group(4).nodes(1).index());
+
+ assertEquals("1|*", clusterConfig.group(0).partitions());
}
@Test
public void testGroupCapacity() throws Exception {
- StorDistributionConfig.Builder builder = new StorDistributionConfig.Builder();
- parse(
+ ContentCluster cluster = parse(
"<content version=\"1.0\" id=\"storage\">\n" +
" <redundancy>2</redundancy>" +
" <documents/>" +
@@ -149,13 +188,25 @@ public class StorageGroupTest {
" </group>\n" +
" </group>\n" +
"</content>"
- ).getConfig(builder);
+ );
+ StorDistributionConfig.Builder builder = new StorDistributionConfig.Builder();
+ cluster.getConfig(builder);
StorDistributionConfig config = new StorDistributionConfig(builder);
assertEquals(3, config.group().size());
assertEquals(5.5, config.group(0).capacity(), 0.001);
assertEquals(2, config.group(1).capacity(), 0.001);
assertEquals(3.5, config.group(2).capacity(), 0.001);
+
+ DistributionConfig.Builder distributionBuilder = new DistributionConfig.Builder();
+ cluster.getConfig(distributionBuilder);
+ DistributionConfig.Cluster clusterConfig = distributionBuilder.build().cluster("storage");
+
+ assertEquals(3, clusterConfig.group().size());
+ assertEquals(5.5, clusterConfig.group(0).capacity(), 0.001);
+ assertEquals(2, clusterConfig.group(1).capacity(), 0.001);
+ assertEquals(3.5, clusterConfig.group(2).capacity(), 0.001);
}
+
}
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/routing/test/RoutingTestCase.java b/config-model/src/test/java/com/yahoo/vespa/model/routing/test/RoutingTestCase.java
index 9e7370a933c..2663ad1f348 100755
--- a/config-model/src/test/java/com/yahoo/vespa/model/routing/test/RoutingTestCase.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/routing/test/RoutingTestCase.java
@@ -5,12 +5,20 @@ import com.yahoo.config.ConfigInstance;
import com.yahoo.documentapi.messagebus.protocol.DocumentrouteselectorpolicyConfig;
import com.yahoo.io.IOUtils;
import com.yahoo.messagebus.MessagebusConfig;
+import com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig;
import com.yahoo.vespa.model.VespaModel;
import com.yahoo.vespa.model.test.utils.VespaModelCreatorWithFilePkg;
import org.junit.Ignore;
import org.junit.Test;
-import java.io.*;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.PrintWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -96,6 +104,10 @@ public class RoutingTestCase {
model.getConfig(drB, "");
DocumentrouteselectorpolicyConfig dr = new DocumentrouteselectorpolicyConfig(drB);
assertConfigFileContains(application, files, "documentrouteselectorpolicy.cfg", dr);
+
+ DocumentProtocolPoliciesConfig.Builder policies = new DocumentProtocolPoliciesConfig.Builder();
+ model.getConfig(policies, "");
+ assertConfigFileContains(application, files, "document-protocol-policies.cfg", policies.build());
} else {
StringBuilder msg = new StringBuilder();
for (String error : errors) {
diff --git a/configdefinitions/src/vespa/CMakeLists.txt b/configdefinitions/src/vespa/CMakeLists.txt
index c6e4d612a0a..4868a6bba2e 100644
--- a/configdefinitions/src/vespa/CMakeLists.txt
+++ b/configdefinitions/src/vespa/CMakeLists.txt
@@ -56,6 +56,8 @@ vespa_generate_config(configdefinitions slobroks.def)
install_config_definition(slobroks.def cloud.config.slobroks.def)
vespa_generate_config(configdefinitions specialtokens.def)
install_config_definition(specialtokens.def vespa.configdefinition.specialtokens.def)
+vespa_generate_config(configdefinitions distribution.def)
+install_config_definition(distribution.def vespa.config.content.distribution.def)
vespa_generate_config(configdefinitions stor-distribution.def)
install_config_definition(stor-distribution.def vespa.config.content.stor-distribution.def)
vespa_generate_config(configdefinitions stor-filestor.def)
diff --git a/configdefinitions/src/vespa/distribution.def b/configdefinitions/src/vespa/distribution.def
new file mode 100644
index 00000000000..d0cb4165ac9
--- /dev/null
+++ b/configdefinitions/src/vespa/distribution.def
@@ -0,0 +1,46 @@
+# Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+namespace=vespa.config.content
+
+##
+## Super config for distribution in each content cluster, keyed by cluster id.
+##
+
+# If this is set to true, the distributor will try to enforce one active copy of
+# buckets per hierarchical leaf group. This lets the top level dispatcher send
+# queries only to the nodes of one group, saving computational effort.
+# If used, hierarchical grouping can not be used for other purposes.
+# Using this option implies that:
+# - ready_copies == redundancy
+# - Only one level of hierarchical grouping may be defined.
+# - That level distributes copies to all defined groups.
+cluster{}.active_per_leaf_group bool default=false
+
+# The number of copies that should be "ready" to be active. Maximum is redundancy.
+cluster{}.ready_copies int default=0
+
+# How many copies of a document are stored, across nodes.
+cluster{}.redundancy int default=3
+
+# Initial redundancy allows put-operations to return as completed after
+# a subset of all copies have been stored.
+# A value of 0 disable this, and causes normal redundancy behavior instead.
+cluster{}.initial_redundancy int default=0
+
+# Hierarchical grouping divides the nodes into a tree of groups. The index is the
+# string representation of a path from the root node in this tree, e.g., "1.2.1".
+cluster{}.group[].index string
+
+# Each group needs to have a name. Obviously. Duh.
+cluster{}.group[].name string
+
+# Capacity of the given group.
+cluster{}.group[].capacity double default=1
+
+# Partitions define how copies are divided among child groups/nodes.
+cluster{}.group[].partitions string default=""
+
+# Leaf groups will have a set of nodes within them. Branch groups will have none.
+cluster{}.group[].nodes[].index int
+
+# Whether this node is retired, and data should migrate out of it.
+cluster{}.group[].nodes[].retired bool default=false \ No newline at end of file
diff --git a/container-core/src/main/java/com/yahoo/container/core/documentapi/DocumentAccessProvider.java b/container-core/src/main/java/com/yahoo/container/core/documentapi/DocumentAccessProvider.java
index 5e3f873bba9..8b75e2d7660 100644
--- a/container-core/src/main/java/com/yahoo/container/core/documentapi/DocumentAccessProvider.java
+++ b/container-core/src/main/java/com/yahoo/container/core/documentapi/DocumentAccessProvider.java
@@ -7,6 +7,8 @@ import com.yahoo.component.AbstractComponent;
import com.yahoo.container.di.componentgraph.Provider;
import com.yahoo.document.config.DocumentmanagerConfig;
import com.yahoo.messagebus.MessagebusConfig;
+import com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig;
+import com.yahoo.vespa.config.content.DistributionConfig;
import com.yahoo.vespa.config.content.LoadTypeConfig;
/**
@@ -19,10 +21,11 @@ public class DocumentAccessProvider extends AbstractComponent implements Provide
private final VespaDocumentAccess access;
@Inject
- // TODO jonmv: Have Slobrok and RPC config injected as well.
public DocumentAccessProvider(DocumentmanagerConfig documentmanagerConfig, LoadTypeConfig loadTypeConfig,
- SlobroksConfig slobroksConfig, MessagebusConfig messagebusConfig) {
- this.access = new VespaDocumentAccess(documentmanagerConfig, loadTypeConfig, slobroksConfig, messagebusConfig);
+ SlobroksConfig slobroksConfig, MessagebusConfig messagebusConfig,
+ DocumentProtocolPoliciesConfig policiesConfig, DistributionConfig distributionConfig) {
+ this.access = new VespaDocumentAccess(documentmanagerConfig, loadTypeConfig, slobroksConfig, messagebusConfig,
+ policiesConfig, distributionConfig);
}
@Override
diff --git a/container-core/src/main/java/com/yahoo/container/core/documentapi/VespaDocumentAccess.java b/container-core/src/main/java/com/yahoo/container/core/documentapi/VespaDocumentAccess.java
index 2918ffb2c80..d55df15b2fd 100644
--- a/container-core/src/main/java/com/yahoo/container/core/documentapi/VespaDocumentAccess.java
+++ b/container-core/src/main/java/com/yahoo/container/core/documentapi/VespaDocumentAccess.java
@@ -20,6 +20,8 @@ import com.yahoo.documentapi.messagebus.MessageBusDocumentAccess;
import com.yahoo.documentapi.messagebus.MessageBusParams;
import com.yahoo.documentapi.messagebus.loadtypes.LoadTypeSet;
import com.yahoo.messagebus.MessagebusConfig;
+import com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig;
+import com.yahoo.vespa.config.content.DistributionConfig;
import com.yahoo.vespa.config.content.LoadTypeConfig;
/**
@@ -39,9 +41,12 @@ public class VespaDocumentAccess extends DocumentAccess {
VespaDocumentAccess(DocumentmanagerConfig documentmanagerConfig,
LoadTypeConfig loadTypeConfig,
SlobroksConfig slobroksConfig,
- MessagebusConfig messagebusConfig) {
+ MessagebusConfig messagebusConfig,
+ DocumentProtocolPoliciesConfig policiesConfig,
+ DistributionConfig distributionConfig) {
super(new DocumentAccessParams().setDocumentmanagerConfig(documentmanagerConfig));
- this.parameters = new MessageBusParams(new LoadTypeSet(loadTypeConfig));
+ this.parameters = new MessageBusParams(new LoadTypeSet(loadTypeConfig))
+ .setDocumentProtocolPoliciesConfig(policiesConfig, distributionConfig);
this.parameters.setDocumentmanagerConfig(documentmanagerConfig);
this.parameters.getRPCNetworkParams().setSlobroksConfig(slobroksConfig);
this.parameters.getMessageBusParams().setMessageBusConfig(messagebusConfig);
diff --git a/documentapi/abi-spec.json b/documentapi/abi-spec.json
index 39d6898215c..36c2e1fda99 100644
--- a/documentapi/abi-spec.json
+++ b/documentapi/abi-spec.json
@@ -1128,6 +1128,7 @@
"public com.yahoo.documentapi.messagebus.MessageBusParams setRoutingConfigId(java.lang.String)",
"public java.lang.String getProtocolConfigId()",
"public com.yahoo.documentapi.messagebus.MessageBusParams setProtocolConfigId(java.lang.String)",
+ "public com.yahoo.documentapi.messagebus.MessageBusParams setDocumentProtocolPoliciesConfig(com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig, com.yahoo.vespa.config.content.DistributionConfig)",
"public com.yahoo.documentapi.messagebus.MessageBusParams setRouteName(java.lang.String)",
"public com.yahoo.documentapi.messagebus.MessageBusParams setRoute(java.lang.String)",
"public com.yahoo.documentapi.messagebus.MessageBusParams setRouteNameForGet(java.lang.String)",
@@ -1573,6 +1574,7 @@
"fields": [
"protected final java.lang.String clusterName",
"protected final java.lang.String distributionConfigId",
+ "protected final com.yahoo.vespa.config.content.DistributionConfig distributionConfig",
"protected final com.yahoo.documentapi.messagebus.protocol.ContentPolicy$SlobrokHostPatternGenerator slobrokHostPatternGenerator"
]
},
@@ -1595,8 +1597,7 @@
"public"
],
"methods": [
- "public void <init>(java.lang.String)",
- "public void <init>(java.util.Map)",
+ "public void <init>(java.lang.String, com.yahoo.vespa.config.content.DistributionConfig)",
"public void <init>(com.yahoo.documentapi.messagebus.protocol.ContentPolicy$Parameters)",
"public void select(com.yahoo.messagebus.routing.RoutingContext)",
"public void merge(com.yahoo.messagebus.routing.RoutingContext)",
@@ -1806,6 +1807,7 @@
"public static com.yahoo.documentapi.messagebus.protocol.DocumentProtocol$Priority getPriorityByName(java.lang.String)",
"public void <init>(com.yahoo.document.DocumentTypeManager)",
"public void <init>(com.yahoo.document.DocumentTypeManager, java.lang.String)",
+ "public void <init>(com.yahoo.document.DocumentTypeManager, com.yahoo.documentapi.messagebus.loadtypes.LoadTypeSet, com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig, com.yahoo.vespa.config.content.DistributionConfig)",
"public void <init>(com.yahoo.document.DocumentTypeManager, java.lang.String, com.yahoo.documentapi.messagebus.loadtypes.LoadTypeSet)",
"public com.yahoo.documentapi.messagebus.protocol.DocumentProtocol putRoutingPolicyFactory(java.lang.String, com.yahoo.documentapi.messagebus.protocol.RoutingPolicyFactory)",
"public com.yahoo.documentapi.messagebus.protocol.DocumentProtocol putRoutableFactory(int, com.yahoo.documentapi.messagebus.protocol.RoutableFactory, com.yahoo.component.VersionSpecification)",
@@ -1890,6 +1892,138 @@
"public static final int ERROR_SUSPENDED"
]
},
+ "com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig$Builder": {
+ "superClass": "java.lang.Object",
+ "interfaces": [
+ "com.yahoo.config.ConfigInstance$Builder"
+ ],
+ "attributes": [
+ "public"
+ ],
+ "methods": [
+ "public void <init>()",
+ "public void <init>(com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig)",
+ "public com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig$Builder cluster(java.lang.String, com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig$Cluster$Builder)",
+ "public com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig$Builder cluster(java.util.Map)",
+ "public final boolean dispatchGetConfig(com.yahoo.config.ConfigInstance$Producer)",
+ "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.DocumentProtocolPoliciesConfig build()"
+ ],
+ "fields": [
+ "public java.util.Map cluster"
+ ]
+ },
+ "com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig$Cluster$Builder": {
+ "superClass": "java.lang.Object",
+ "interfaces": [
+ "com.yahoo.config.ConfigBuilder"
+ ],
+ "attributes": [
+ "public"
+ ],
+ "methods": [
+ "public void <init>()",
+ "public void <init>(com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig$Cluster)",
+ "public com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig$Cluster$Builder defaultRoute(java.lang.String)",
+ "public com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig$Cluster$Builder route(com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig$Cluster$Route$Builder)",
+ "public com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig$Cluster$Builder route(java.util.List)",
+ "public com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig$Cluster$Builder selector(java.lang.String)",
+ "public com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig$Cluster build()"
+ ],
+ "fields": [
+ "public java.util.List route"
+ ]
+ },
+ "com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig$Cluster$Route$Builder": {
+ "superClass": "java.lang.Object",
+ "interfaces": [
+ "com.yahoo.config.ConfigBuilder"
+ ],
+ "attributes": [
+ "public"
+ ],
+ "methods": [
+ "public void <init>()",
+ "public void <init>(com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig$Cluster$Route)",
+ "public com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig$Cluster$Route$Builder name(java.lang.String)",
+ "public com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig$Cluster$Route$Builder messageType(int)",
+ "public com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig$Cluster$Route build()"
+ ],
+ "fields": []
+ },
+ "com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig$Cluster$Route": {
+ "superClass": "com.yahoo.config.InnerNode",
+ "interfaces": [],
+ "attributes": [
+ "public",
+ "final"
+ ],
+ "methods": [
+ "public void <init>(com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig$Cluster$Route$Builder)",
+ "public java.lang.String name()",
+ "public int messageType()"
+ ],
+ "fields": []
+ },
+ "com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig$Cluster": {
+ "superClass": "com.yahoo.config.InnerNode",
+ "interfaces": [],
+ "attributes": [
+ "public",
+ "final"
+ ],
+ "methods": [
+ "public void <init>(com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig$Cluster$Builder)",
+ "public java.lang.String defaultRoute()",
+ "public java.util.List route()",
+ "public com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig$Cluster$Route route(int)",
+ "public java.lang.String selector()"
+ ],
+ "fields": []
+ },
+ "com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig$Producer": {
+ "superClass": "java.lang.Object",
+ "interfaces": [
+ "com.yahoo.config.ConfigInstance$Producer"
+ ],
+ "attributes": [
+ "public",
+ "interface",
+ "abstract"
+ ],
+ "methods": [
+ "public abstract void getConfig(com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig$Builder)"
+ ],
+ "fields": []
+ },
+ "com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig": {
+ "superClass": "com.yahoo.config.ConfigInstance",
+ "interfaces": [],
+ "attributes": [
+ "public",
+ "final"
+ ],
+ "methods": [
+ "public static java.lang.String getDefMd5()",
+ "public static java.lang.String getDefName()",
+ "public static java.lang.String getDefNamespace()",
+ "public static java.lang.String getDefVersion()",
+ "public void <init>(com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig$Builder)",
+ "public java.util.Map cluster()",
+ "public com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig$Cluster cluster(java.lang.String)"
+ ],
+ "fields": [
+ "public static final java.lang.String CONFIG_DEF_MD5",
+ "public static final java.lang.String CONFIG_DEF_NAME",
+ "public static final java.lang.String CONFIG_DEF_NAMESPACE",
+ "public static final java.lang.String CONFIG_DEF_VERSION",
+ "public static final java.lang.String[] CONFIG_DEF_SCHEMA"
+ ]
+ },
"com.yahoo.documentapi.messagebus.protocol.DocumentProtocolRoutingPolicy": {
"superClass": "java.lang.Object",
"interfaces": [
@@ -1928,6 +2062,7 @@
"public"
],
"methods": [
+ "public void <init>(com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig)",
"public void <init>(java.lang.String)",
"public synchronized java.lang.String getError()",
"public void configure(com.yahoo.documentapi.messagebus.protocol.DocumentrouteselectorpolicyConfig)",
@@ -2952,18 +3087,6 @@
],
"fields": []
},
- "com.yahoo.documentapi.messagebus.protocol.RoutingPolicyFactories": {
- "superClass": "java.lang.Object",
- "interfaces": [],
- "attributes": [
- "public",
- "abstract"
- ],
- "methods": [
- "public void <init>()"
- ],
- "fields": []
- },
"com.yahoo.documentapi.messagebus.protocol.RoutingPolicyFactory": {
"superClass": "java.lang.Object",
"interfaces": [],
@@ -2973,8 +3096,7 @@
"abstract"
],
"methods": [
- "public abstract com.yahoo.documentapi.messagebus.protocol.DocumentProtocolRoutingPolicy createPolicy(java.lang.String)",
- "public abstract void destroy()"
+ "public abstract com.yahoo.documentapi.messagebus.protocol.DocumentProtocolRoutingPolicy createPolicy(java.lang.String)"
],
"fields": []
},
diff --git a/documentapi/src/main/java/com/yahoo/documentapi/messagebus/MessageBusParams.java b/documentapi/src/main/java/com/yahoo/documentapi/messagebus/MessageBusParams.java
index a838f3b8723..e167e0057e2 100755
--- a/documentapi/src/main/java/com/yahoo/documentapi/messagebus/MessageBusParams.java
+++ b/documentapi/src/main/java/com/yahoo/documentapi/messagebus/MessageBusParams.java
@@ -3,8 +3,13 @@ package com.yahoo.documentapi.messagebus;
import com.yahoo.documentapi.DocumentAccessParams;
import com.yahoo.documentapi.messagebus.loadtypes.LoadTypeSet;
+import com.yahoo.documentapi.messagebus.protocol.DocumentProtocol;
+import com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig;
import com.yahoo.messagebus.SourceSessionParams;
import com.yahoo.messagebus.network.rpc.RPCNetworkParams;
+import com.yahoo.vespa.config.content.DistributionConfig;
+
+import static java.util.Objects.requireNonNull;
/**
* @author Einar M R Rosenvinge
@@ -13,6 +18,8 @@ public class MessageBusParams extends DocumentAccessParams {
private String routingConfigId = null;
private String protocolConfigId = null;
+ private DocumentProtocolPoliciesConfig policiesConfig = null;
+ private DistributionConfig distributionConfig = null;
private String route = "route:default";
private String routeForGet = "route:default-get";
private int traceLevel = 0;
@@ -79,6 +86,14 @@ public class MessageBusParams extends DocumentAccessParams {
return this;
}
+ /** Sets the config used by the {@link DocumentProtocol} policies. */
+ public MessageBusParams setDocumentProtocolPoliciesConfig(DocumentProtocolPoliciesConfig policiesConfig,
+ DistributionConfig distributionConfig) {
+ this.policiesConfig = requireNonNull(policiesConfig);
+ this.distributionConfig = requireNonNull(distributionConfig);
+ return this;
+ }
+
/**
* Sets the name of the route to send appropriate requests to. This is a convenience method for prefixing a route
* with "route:", and using {@link #setRoute} instead.
diff --git a/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/ContentPolicy.java b/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/ContentPolicy.java
index c03231543df..f8e6989bbfa 100644
--- a/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/ContentPolicy.java
+++ b/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/ContentPolicy.java
@@ -6,7 +6,6 @@ import com.yahoo.document.BucketId;
import com.yahoo.document.BucketIdFactory;
import com.yahoo.jrt.slobrok.api.IMirror;
import com.yahoo.jrt.slobrok.api.Mirror;
-import java.util.logging.Level;
import com.yahoo.messagebus.EmptyReply;
import com.yahoo.messagebus.Error;
import com.yahoo.messagebus.ErrorCode;
@@ -22,6 +21,7 @@ import com.yahoo.vdslib.state.ClusterState;
import com.yahoo.vdslib.state.Node;
import com.yahoo.vdslib.state.NodeType;
import com.yahoo.vdslib.state.State;
+import com.yahoo.vespa.config.content.DistributionConfig;
import java.util.ArrayList;
import java.util.Collections;
@@ -32,6 +32,7 @@ import java.util.Random;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
+import java.util.logging.Level;
import java.util.logging.Logger;
/**
@@ -221,18 +222,28 @@ public class ContentPolicy extends SlobrokPolicy {
/** Class parsing the semicolon separated parameter string and exposes the appropriate value to the policy. */
public static class Parameters {
+
protected final String clusterName;
protected final String distributionConfigId;
+ protected final DistributionConfig distributionConfig;
protected final SlobrokHostPatternGenerator slobrokHostPatternGenerator;
public Parameters(Map<String, String> params) {
+ this(params, null);
+ }
+
+ private Parameters(Map<String, String> params, DistributionConfig config) {
clusterName = params.get("cluster");
+ if (clusterName == null)
+ throw new IllegalArgumentException("Required parameter 'cluster', the name of the content cluster, not set");
+ distributionConfig = config;
+ if (distributionConfig != null && distributionConfig.cluster(clusterName) == null)
+ throw new IllegalArgumentException("Distribution config for cluster '" + clusterName + "' not found");
distributionConfigId = params.get("clusterconfigid"); // TODO jonmv: remove
slobrokHostPatternGenerator = createPatternGenerator();
- if (clusterName == null) throw new IllegalArgumentException("Required parameter 'cluster', the name of the content cluster, not set");
}
- String getDistributionConfigId() {
+ private String getDistributionConfigId() {
return distributionConfigId == null ? clusterName : distributionConfigId;
}
public String getClusterName() {
@@ -245,7 +256,8 @@ public class ContentPolicy extends SlobrokPolicy {
return new TargetCachingSlobrokHostFetcher(slobrokHostPatternGenerator, policy, percent);
}
public Distribution createDistribution(SlobrokPolicy policy) {
- return new Distribution(getDistributionConfigId());
+ return distributionConfig == null ? new Distribution(getDistributionConfigId())
+ : new Distribution(distributionConfig.cluster(clusterName));
}
/**
@@ -548,12 +560,8 @@ public class ContentPolicy extends SlobrokPolicy {
private final Parameters parameters;
/** Constructor used in production. */
- public ContentPolicy(String param) {
- this(parse(param));
- }
-
- public ContentPolicy(Map<String, String> params) {
- this(new Parameters(params));
+ public ContentPolicy(String param, DistributionConfig config) {
+ this(new Parameters(parse(param), config));
}
/** Constructor specifying a bit more in detail, so we can override what needs to be overridden in tests */
diff --git a/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/DocumentProtocol.java b/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/DocumentProtocol.java
index 2680ed011af..547d7f76dc5 100755
--- a/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/DocumentProtocol.java
+++ b/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/DocumentProtocol.java
@@ -15,6 +15,7 @@ import com.yahoo.messagebus.routing.RoutingContext;
import com.yahoo.messagebus.routing.RoutingNodeIterator;
import com.yahoo.messagebus.routing.RoutingPolicy;
import com.yahoo.text.Utf8String;
+import com.yahoo.vespa.config.content.DistributionConfig;
import java.util.Collections;
import java.util.HashSet;
@@ -24,6 +25,8 @@ import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
+import static java.util.Objects.requireNonNull;
+
/**
* Implements the message bus protocol that is used by all components of Vespa.
*
@@ -243,27 +246,36 @@ public class DocumentProtocol implements Protocol {
this(docMan, configId, new LoadTypeSet());
}
+ public DocumentProtocol(DocumentTypeManager documentTypeManager, LoadTypeSet loadTypes,
+ DocumentProtocolPoliciesConfig policiesConfig, DistributionConfig distributionConfig) {
+ this(requireNonNull(documentTypeManager), null, requireNonNull(loadTypes),
+ requireNonNull(policiesConfig), requireNonNull(distributionConfig));
+ }
+
public DocumentProtocol(DocumentTypeManager docMan, String configId, LoadTypeSet set) {
- // Prepare config string for routing policy factories.
- String cfg = (configId == null ? "client" : configId);
- if (docMan != null) {
+ this(docMan, configId == null ? "client" : configId, set, null, null);
+ }
+
+ private DocumentProtocol(DocumentTypeManager docMan, String configId, LoadTypeSet set,
+ DocumentProtocolPoliciesConfig policiesConfig, DistributionConfig distributionConfig) {
+ if (docMan != null)
this.docMan = docMan;
- } else {
+ else {
this.docMan = new DocumentTypeManager();
- DocumentTypeManagerConfigurer.configure(this.docMan, cfg);
+ DocumentTypeManagerConfigurer.configure(this.docMan, configId);
}
- routableRepository = new RoutableRepository(set);
+ this.routableRepository = new RoutableRepository(set);
// When adding factories to this list, please KEEP THEM ORDERED alphabetically like they are now.
putRoutingPolicyFactory("AND", new RoutingPolicyFactories.AndPolicyFactory());
- putRoutingPolicyFactory("Content", new RoutingPolicyFactories.ContentPolicyFactory());
- putRoutingPolicyFactory("DocumentRouteSelector", new RoutingPolicyFactories.DocumentRouteSelectorPolicyFactory(cfg));
+ putRoutingPolicyFactory("Content", new RoutingPolicyFactories.ContentPolicyFactory(distributionConfig));
+ putRoutingPolicyFactory("DocumentRouteSelector", new RoutingPolicyFactories.DocumentRouteSelectorPolicyFactory(configId, policiesConfig));
putRoutingPolicyFactory("Extern", new RoutingPolicyFactories.ExternPolicyFactory());
putRoutingPolicyFactory("LocalService", new RoutingPolicyFactories.LocalServicePolicyFactory());
- putRoutingPolicyFactory("MessageType", new RoutingPolicyFactories.MessageTypePolicyFactory(cfg));
+ putRoutingPolicyFactory("MessageType", new RoutingPolicyFactories.MessageTypePolicyFactory(configId, policiesConfig));
putRoutingPolicyFactory("RoundRobin", new RoutingPolicyFactories.RoundRobinPolicyFactory());
putRoutingPolicyFactory("LoadBalancer", new RoutingPolicyFactories.LoadBalancerPolicyFactory());
- putRoutingPolicyFactory("Storage", new RoutingPolicyFactories.ContentPolicyFactory());
+ putRoutingPolicyFactory("Storage", new RoutingPolicyFactories.ContentPolicyFactory(distributionConfig));
putRoutingPolicyFactory("SubsetService", new RoutingPolicyFactories.SubsetServicePolicyFactory());
// Prepare version specifications to use when adding routable factories.
diff --git a/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/DocumentRouteSelectorPolicy.java b/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/DocumentRouteSelectorPolicy.java
index 8fbd1548f68..07fd098c9b4 100755
--- a/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/DocumentRouteSelectorPolicy.java
+++ b/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/DocumentRouteSelectorPolicy.java
@@ -5,13 +5,14 @@ import com.yahoo.config.subscription.ConfigSubscriber;
import com.yahoo.document.DocumentGet;
import com.yahoo.document.select.DocumentSelector;
import com.yahoo.document.select.Result;
-import java.util.logging.Level;
+import com.yahoo.document.select.parser.ParseException;
import com.yahoo.messagebus.Message;
import com.yahoo.messagebus.routing.Route;
import com.yahoo.messagebus.routing.RoutingContext;
import java.util.HashMap;
import java.util.Map;
+import java.util.logging.Level;
import java.util.logging.Logger;
/**
@@ -30,6 +31,24 @@ public class DocumentRouteSelectorPolicy
private String error = "Not configured.";
private ConfigSubscriber subscriber;
+ /** This policy is constructed with the proper config at its time of creation. */
+ public DocumentRouteSelectorPolicy(DocumentProtocolPoliciesConfig config) {
+ Map<String, DocumentSelector> selectors = new HashMap<>();
+ config.cluster().forEach((name, cluster) -> {
+ try {
+ selectors.put(name, new DocumentSelector(cluster.selector()));
+ }
+ catch (ParseException e) {
+ throw new IllegalArgumentException("Error parsing selector '" +
+ cluster.selector() +
+ "' for route '" + name +"'",
+ e);
+ }
+ });
+ this.config = Map.copyOf(selectors);
+ this.error = null;
+ }
+
/**
* This policy is constructed with a configuration identifier that can be subscribed to for the document selector
* config. If the string is either null or empty it will default to the proper one.
diff --git a/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/MessageTypePolicy.java b/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/MessageTypePolicy.java
index 4226c1e6cac..34124cf48db 100644
--- a/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/MessageTypePolicy.java
+++ b/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/MessageTypePolicy.java
@@ -5,10 +5,13 @@ import com.yahoo.config.subscription.ConfigSubscriber;
import com.yahoo.messagebus.routing.Route;
import com.yahoo.messagebus.routing.RoutingContext;
import com.yahoo.vespa.config.content.MessagetyperouteselectorpolicyConfig;
+
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
+import static java.util.stream.Collectors.toUnmodifiableMap;
+
/**
* @author baldersheim
*/
@@ -18,6 +21,13 @@ public class MessageTypePolicy implements DocumentProtocolRoutingPolicy, ConfigS
private ConfigSubscriber subscriber;
private volatile Route defaultRoute;
+ MessageTypePolicy(DocumentProtocolPoliciesConfig.Cluster config) {
+ configRef.set(config.route().stream()
+ .collect(toUnmodifiableMap(route -> route.messageType(),
+ route -> Route.parse(route.name()))));
+ defaultRoute = Route.parse(config.defaultRoute());
+ }
+
MessageTypePolicy(String configId) {
subscriber = new ConfigSubscriber();
subscriber.subscribe(this, MessagetyperouteselectorpolicyConfig.class, configId);
diff --git a/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/RoutingPolicyFactories.java b/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/RoutingPolicyFactories.java
index 7b44a1a4f0d..c313422ab1b 100755
--- a/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/RoutingPolicyFactories.java
+++ b/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/RoutingPolicyFactories.java
@@ -1,54 +1,72 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.documentapi.messagebus.protocol;
+import com.yahoo.documentapi.messagebus.protocol.DocumentProtocolPoliciesConfig;
+import com.yahoo.vespa.config.content.DistributionConfig;
+
/**
* @author Simon Thoresen Hult
+ * @author jonmv
*/
-public abstract class RoutingPolicyFactories {
+class RoutingPolicyFactories {
+
+ private RoutingPolicyFactories() { }
static class AndPolicyFactory implements RoutingPolicyFactory {
public DocumentProtocolRoutingPolicy createPolicy(String param) {
return new ANDPolicy(param);
}
-
-
- public void destroy() {
- }
}
static class ContentPolicyFactory implements RoutingPolicyFactory {
+ private final DistributionConfig distributionConfig;
+ public ContentPolicyFactory(DistributionConfig config) { this.distributionConfig = config; }
public DocumentProtocolRoutingPolicy createPolicy(String param) {
- return new ContentPolicy(param);
- }
-
- public void destroy() {
+ return new ContentPolicy(param, distributionConfig);
}
}
static class MessageTypePolicyFactory implements RoutingPolicyFactory {
+
private final String configId;
+ private final DocumentProtocolPoliciesConfig config;
- public MessageTypePolicyFactory(String configId) {
+ public MessageTypePolicyFactory(String configId, DocumentProtocolPoliciesConfig config) {
this.configId = configId;
+ this.config = config;
}
+
public DocumentProtocolRoutingPolicy createPolicy(String param) {
- return new MessageTypePolicy((param == null || param.isEmpty()) ? configId : param);
- }
+ if (config != null) {
+ if (config.cluster(param) == null)
+ return new ErrorPolicy("No message type config for cluster '" + param + "'");
- public void destroy() {
+ return new MessageTypePolicy(config.cluster(param));
+ }
+ return new MessageTypePolicy(param == null || param.isEmpty() ? configId : param);
}
}
static class DocumentRouteSelectorPolicyFactory implements RoutingPolicyFactory {
private final String configId;
+ private final DocumentProtocolPoliciesConfig config;
- public DocumentRouteSelectorPolicyFactory(String configId) {
+ public DocumentRouteSelectorPolicyFactory(String configId, DocumentProtocolPoliciesConfig config) {
this.configId = configId;
+ this.config = config;
}
public DocumentProtocolRoutingPolicy createPolicy(String param) {
- DocumentRouteSelectorPolicy ret = new DocumentRouteSelectorPolicy((param == null || param.isEmpty()) ?
+ if (config != null) {
+ try {
+ return new DocumentRouteSelectorPolicy(config);
+ }
+ catch (IllegalArgumentException e) {
+ return new ErrorPolicy(e.getMessage());
+ }
+ }
+ DocumentRouteSelectorPolicy ret = new DocumentRouteSelectorPolicy(param == null || param.isEmpty() ?
configId : param);
String error = ret.getError();
if (error != null) {
@@ -56,10 +74,6 @@ public abstract class RoutingPolicyFactories {
}
return ret;
}
-
-
- public void destroy() {
- }
}
static class ExternPolicyFactory implements RoutingPolicyFactory {
@@ -71,49 +85,30 @@ public abstract class RoutingPolicyFactories {
}
return ret;
}
-
-
- public void destroy() {
- }
}
static class LocalServicePolicyFactory implements RoutingPolicyFactory {
public DocumentProtocolRoutingPolicy createPolicy(String param) {
return new LocalServicePolicy(param);
}
-
-
- public void destroy() {
- }
}
static class RoundRobinPolicyFactory implements RoutingPolicyFactory {
public DocumentProtocolRoutingPolicy createPolicy(String param) {
return new RoundRobinPolicy();
}
-
-
- public void destroy() {
- }
}
static class LoadBalancerPolicyFactory implements RoutingPolicyFactory {
public DocumentProtocolRoutingPolicy createPolicy(String param) {
return new LoadBalancerPolicy(param);
}
-
-
- public void destroy() {
- }
}
static class SubsetServicePolicyFactory implements RoutingPolicyFactory {
public DocumentProtocolRoutingPolicy createPolicy(String param) {
return new SubsetServicePolicy(param);
}
-
-
- public void destroy() {
- }
}
+
}
diff --git a/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/RoutingPolicyFactory.java b/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/RoutingPolicyFactory.java
index 6ea5020607e..3e368832c98 100755
--- a/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/RoutingPolicyFactory.java
+++ b/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/RoutingPolicyFactory.java
@@ -24,11 +24,6 @@ public interface RoutingPolicyFactory {
* @param param The parameter to use when creating the policy.
* @return The created routing policy.
*/
- public DocumentProtocolRoutingPolicy createPolicy(String param);
+ DocumentProtocolRoutingPolicy createPolicy(String param);
- /**
- * Destroys this factory and frees up any resources it has held. Making further calls on a destroyed
- * factory causes a runtime exception.
- */
- public void destroy();
}
diff --git a/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/SlobrokPolicy.java b/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/SlobrokPolicy.java
index f4e1bb33dd1..1ffce622d78 100644
--- a/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/SlobrokPolicy.java
+++ b/documentapi/src/main/java/com/yahoo/documentapi/messagebus/protocol/SlobrokPolicy.java
@@ -10,10 +10,10 @@ import java.util.Map;
import java.util.TreeMap;
/**
- * Abstract class for policies that allow you to specify which slobrok to use for the
- * routing.
+ * Abstract class for policies that allow you to specify which slobrok to use for the routing.
*/
public abstract class SlobrokPolicy implements DocumentProtocolRoutingPolicy {
+
private boolean firstTry = true;
protected List<Mirror.Entry> lookup(RoutingContext context, String pattern) {
diff --git a/documentapi/src/main/resources/configdefinitions/document-protocol-policies.def b/documentapi/src/main/resources/configdefinitions/document-protocol-policies.def
new file mode 100644
index 00000000000..ace4f254821
--- /dev/null
+++ b/documentapi/src/main/resources/configdefinitions/document-protocol-policies.def
@@ -0,0 +1,25 @@
+# Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+namespace=documentapi.messagebus.protocol
+
+##
+## Super config for all policies in the document protocol, keyed by content cluster ids.
+## Note: ContentPolicy also uses the "distribution" config.
+##
+
+#
+# Config used by MessageTypeRouteSelectorPolicy
+#
+# Default route if no override is set for a type.
+cluster{}.defaultRoute string
+
+# The name of the route.
+cluster{}.route[].name string
+
+# The document protocol message type triggering this route.
+cluster{}.route[].messageType int
+
+#
+# Config used by DocumentRouteSelectorPolicy
+#
+# The document selector for this cluster route.
+cluster{}.selector string
diff --git a/documentapi/src/test/java/com/yahoo/documentapi/messagebus/protocol/test/storagepolicy/ContentPolicyTest.java b/documentapi/src/test/java/com/yahoo/documentapi/messagebus/protocol/test/storagepolicy/ContentPolicyTest.java
index f324245b612..5aa3994a757 100644
--- a/documentapi/src/test/java/com/yahoo/documentapi/messagebus/protocol/test/storagepolicy/ContentPolicyTest.java
+++ b/documentapi/src/test/java/com/yahoo/documentapi/messagebus/protocol/test/storagepolicy/ContentPolicyTest.java
@@ -5,6 +5,7 @@ import org.junit.Ignore;
import org.junit.Test;
public class ContentPolicyTest extends Simulator {
+
/**
* Verify that a resent message with failures doesn't ruin overall performance. (By dumping the cached state too often
* so other requests are sent to wrong target)
@@ -17,6 +18,7 @@ public class ContentPolicyTest extends Simulator {
+ "Last correctnode 99, wrongnode 1, downnode 0, worked 92, failed 8",
new PersistentFailureTestParameters().addBadNode(new BadNode(3, FailureType.TRANSIENT_ERROR)));
}
+
/**
* Verify that a resent message with failures doesn't ruin overall performance. (By dumping the cached state too often
* so other requests are sent to wrong target)
@@ -29,6 +31,7 @@ public class ContentPolicyTest extends Simulator {
+ "Last correctnode 99, wrongnode 1, downnode 0, worked 92, failed 8",
new PersistentFailureTestParameters().addBadNode(new BadNode(3, FailureType.FATAL_ERROR)));
}
+
/**
* Verify that a node responding with old cluster state doesn't ruin overall performance (By dumping/switching cached
* state too often)
@@ -41,6 +44,7 @@ public class ContentPolicyTest extends Simulator {
+ "Last correctnode 100, wrongnode 0, downnode 0, worked 100, failed 0",
new PersistentFailureTestParameters().addBadNode(new BadNode(3, FailureType.OLD_CLUSTER_STATE).setDownInCurrentState()));
}
+
/**
* Verify that a reset cluster state version doesn't keep sending requests to the wrong node.
* We expect a few failures in first half. We should have detected the issue before second half, so there all should be fine.
@@ -52,6 +56,7 @@ public class ContentPolicyTest extends Simulator {
+ "Last correctnode .*, wrongnode 0, downnode 0, worked .*, failed 0",
new PersistentFailureTestParameters().addBadNode(new BadNode(3, FailureType.RESET_CLUSTER_STATE).setDownInCurrentState()));
}
+
/**
* Verify that a reset cluster state version doesn't keep sending requests to the wrong node.
* We expect a few failures in first half. We should have detected the issue before second half, so there all should be fine.
@@ -70,6 +75,7 @@ public class ContentPolicyTest extends Simulator {
+ "Last correctnode .*, wrongnode 100, downnode 100, worked 0, failed 100",
new PersistentFailureTestParameters().addBadNode(new BadNode(3, FailureType.RESET_CLUSTER_STATE_NO_GOOD_NODES).setDownInCurrentState()));
}
+
/**
* Verify that a reset cluster state version doesn't keep sending requests to the wrong node.
* We expect a few failures in first half. We should have detected the issue before second half, so there all should be fine.
@@ -86,6 +92,7 @@ public class ContentPolicyTest extends Simulator {
+ "Last correctnode .*, wrongnode 91, downnode 0, worked 0, failed 100",
new PersistentFailureTestParameters().addBadNode(new BadNode(3, FailureType.RESET_CLUSTER_STATE_NO_GOOD_NODES)));
}
+
/**
* Verify that a reset cluster state version doesn't keep sending requests to the wrong node.
* Another scenario where we have a node coming up in correct state.
@@ -98,6 +105,7 @@ public class ContentPolicyTest extends Simulator {
+ "Last correctnode .*, wrongnode 0, downnode 0, worked .*, failed 0",
new PersistentFailureTestParameters().newNodeAdded().addBadNode(new BadNode(3, FailureType.RESET_CLUSTER_STATE).setDownInCurrentState()));
}
+
/** Test node that is not in slobrok. Until fleetcontroller detects this, we expect 10% of the requests to go to wrong node. */
@Test
@Ignore // FIXME test has been implicitly disabled for ages, figure out and fix
diff --git a/documentapi/src/test/java/com/yahoo/documentapi/messagebus/protocol/test/storagepolicy/ContentPolicyTestEnvironment.java b/documentapi/src/test/java/com/yahoo/documentapi/messagebus/protocol/test/storagepolicy/ContentPolicyTestEnvironment.java
index 479e0b0f422..6d2477e1871 100644
--- a/documentapi/src/test/java/com/yahoo/documentapi/messagebus/protocol/test/storagepolicy/ContentPolicyTestEnvironment.java
+++ b/documentapi/src/test/java/com/yahoo/documentapi/messagebus/protocol/test/storagepolicy/ContentPolicyTestEnvironment.java
@@ -34,11 +34,13 @@ import java.util.TreeSet;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
public abstract class ContentPolicyTestEnvironment {
- protected StoragePolicyTestFactory policyFactory;
+ protected ContentPolicyTestFactory policyFactory;
protected PolicyTestFrame frame;
private Set<Integer> nodes;
protected static int[] bucketOneNodePreference = new int[]{ 3, 5, 7, 6, 8, 0, 9, 2, 1, 4 };
@@ -51,7 +53,7 @@ public abstract class ContentPolicyTestEnvironment {
frame = new PolicyTestFrame(manager);
nodes = new TreeSet<>();
DocumentProtocol protocol = (DocumentProtocol) frame.getMessageBus().getProtocol((Utf8Array)DocumentProtocol.NAME);
- policyFactory = new StoragePolicyTestFactory(nodes);
+ policyFactory = new ContentPolicyTestFactory(nodes);
protocol.putRoutingPolicyFactory("storage", policyFactory);
frame.setMessage(createMessage("id:ns:testdoc:n=1:foo"));
frame.setHop(new HopSpec("test", "[storage:cluster=foo]"));
@@ -104,7 +106,7 @@ public abstract class ContentPolicyTestEnvironment {
public static class TestHostFetcher extends ContentPolicy.HostFetcher {
private final String clusterName;
- private RandomGen randomizer = new RandomGen(1234);
+ private final RandomGen randomizer = new RandomGen(1234);
private final Set<Integer> nodes;
private Integer avoidPickingAtRandom = null;
@@ -121,13 +123,14 @@ public abstract class ContentPolicyTestEnvironment {
try{
if (distributor == null) {
if (nodes.size() == 1) {
- assertTrue(avoidPickingAtRandom != nodes.iterator().next());
+ assertNotSame(avoidPickingAtRandom, nodes.iterator().next());
distributor = nodes.iterator().next();
} else {
Iterator<Integer> it = nodes.iterator();
for (int i = 0, n = randomizer.nextInt(nodes.size() - 1); i<n; ++i) it.next();
distributor = it.next();
- if (avoidPickingAtRandom != null && distributor == avoidPickingAtRandom) distributor = it.next();
+ if (avoidPickingAtRandom != null && avoidPickingAtRandom.equals(distributor))
+ distributor = it.next();
}
}
if (nodes.contains(distributor)) {
@@ -137,8 +140,7 @@ public abstract class ContentPolicyTestEnvironment {
}
} catch (RuntimeException e) {
e.printStackTrace();
- assertTrue(e.getMessage(), false);
- throw e;
+ throw new AssertionError(e.getMessage());
}
}
}
@@ -160,12 +162,12 @@ public abstract class ContentPolicyTestEnvironment {
public Distribution createDistribution(SlobrokPolicy policy) { return distribution; }
}
- public static class StoragePolicyTestFactory implements RoutingPolicyFactory {
+ public static class ContentPolicyTestFactory implements RoutingPolicyFactory {
private Set<Integer> nodes;
- private final LinkedList<TestParameters> parameterInstances = new LinkedList<TestParameters>();
+ private final LinkedList<TestParameters> parameterInstances = new LinkedList<>();
private Integer avoidPickingAtRandom = null;
- public StoragePolicyTestFactory(Set<Integer> nodes) {
+ public ContentPolicyTestFactory(Set<Integer> nodes) {
this.nodes = nodes;
}
public DocumentProtocolRoutingPolicy createPolicy(String parameters) {
diff --git a/documentapi/src/test/java/com/yahoo/documentapi/messagebus/protocol/test/storagepolicy/Simulator.java b/documentapi/src/test/java/com/yahoo/documentapi/messagebus/protocol/test/storagepolicy/Simulator.java
index d23dd9ea998..be880e69781 100644
--- a/documentapi/src/test/java/com/yahoo/documentapi/messagebus/protocol/test/storagepolicy/Simulator.java
+++ b/documentapi/src/test/java/com/yahoo/documentapi/messagebus/protocol/test/storagepolicy/Simulator.java
@@ -31,7 +31,7 @@ public abstract class Simulator extends ContentPolicyTestEnvironment {
RESET_CLUSTER_STATE_NO_GOOD_NODES,
NODE_NOT_IN_SLOBROK
};
- private Integer getIdealTarget(String idString, String clusterState) {
+ private int getIdealTarget(String idString, String clusterState) {
DocumentId did = new DocumentId(idString);
BucketIdFactory factory = new BucketIdFactory();
BucketId bid = factory.getBucketId(did);
@@ -145,6 +145,7 @@ public abstract class Simulator extends ContentPolicyTestEnvironment {
return currentClusterState;
}
}
+
public void runSimulation(String expected, PersistentFailureTestParameters params) {
params.validate();
// Set nodes in slobrok
@@ -157,16 +158,16 @@ public abstract class Simulator extends ContentPolicyTestEnvironment {
replyWrongDistribution(target, "foo", null, params.getInitialClusterState().toString());
}
RandomGen randomizer = new RandomGen(432121);
- int correctnode[] = new int[2],
- wrongnode[] = new int[2],
- failed[] = new int[2],
- worked[] = new int[2],
- downnode[] = new int[2];
+ int[] correctnode = new int[2],
+ wrongnode = new int[2],
+ failed = new int[2],
+ worked = new int[2],
+ downnode = new int[2];
for (int step = 0, steps = (params.getTotalRequests() / params.getParallellRequests()); step < steps; ++step) {
int half = (step < steps / 2 ? 0 : 1);
if (debug) System.err.println("Starting step " + step + " in half " + half);
- String docId[] = new String[params.getParallellRequests()];
- RoutingNode targets[] = new RoutingNode[params.getParallellRequests()];
+ String[] docId = new String[params.getParallellRequests()];
+ RoutingNode[] targets = new RoutingNode[params.getParallellRequests()];
for (int i=0; i<params.getParallellRequests(); ++i) {
docId[i] = "id:ns:testdoc::" + (step * params.getParallellRequests() + i);
frame.setMessage(createMessage(docId[i]));
@@ -206,7 +207,6 @@ public abstract class Simulator extends ContentPolicyTestEnvironment {
}
}
StringBuilder actual = new StringBuilder();
- String result[][] = new String[2][];
for (int i=0; i<2; ++i) {
actual.append(i == 0 ? "First " : " Last ")
.append("correctnode ").append(correctnode[i])
@@ -215,7 +215,7 @@ public abstract class Simulator extends ContentPolicyTestEnvironment {
.append(", worked ").append(worked[i])
.append(", failed ").append(failed[i]);
}
- if (!Pattern.matches(expected, actual.toString())) {
+ if ( ! Pattern.matches(expected, actual.toString())) {
assertEquals(expected, actual.toString());
}
}
diff --git a/messagebus/src/main/java/com/yahoo/messagebus/test/SimpleMessage.java b/messagebus/src/main/java/com/yahoo/messagebus/test/SimpleMessage.java
index 0e77d94497e..f87bcdbe1bb 100644
--- a/messagebus/src/main/java/com/yahoo/messagebus/test/SimpleMessage.java
+++ b/messagebus/src/main/java/com/yahoo/messagebus/test/SimpleMessage.java
@@ -5,7 +5,7 @@ import com.yahoo.messagebus.Message;
import com.yahoo.text.Utf8String;
/**
- * @author <a href="mailto:havardpe@yahoo-inc.com">Haavard Pettersen</a>
+ * @author havardpe
*/
public class SimpleMessage extends Message {
diff --git a/messagebus/src/test/java/com/yahoo/messagebus/DynamicThrottlePolicyTest.java b/messagebus/src/test/java/com/yahoo/messagebus/DynamicThrottlePolicyTest.java
index 7f48edfd48c..63747803e75 100644
--- a/messagebus/src/test/java/com/yahoo/messagebus/DynamicThrottlePolicyTest.java
+++ b/messagebus/src/test/java/com/yahoo/messagebus/DynamicThrottlePolicyTest.java
@@ -101,7 +101,7 @@ public class DynamicThrottlePolicyTest {
CustomTimer timer = new CustomTimer();
DynamicThrottlePolicy policy = new DynamicThrottlePolicy(timer);
int scaleFactor = (int) Math.pow(10, i);
- long operations = 3_000 * scaleFactor;
+ long operations = 3_000L * scaleFactor;
int workPerSuccess = 6;
int numberOfWorkers = 1;
int maximumTasksPerWorker = 100000;
@@ -124,7 +124,7 @@ public class DynamicThrottlePolicyTest {
CustomTimer timer = new CustomTimer();
DynamicThrottlePolicy policy = new DynamicThrottlePolicy(timer);
int scaleFactor = (int) Math.pow(10, i);
- long operations = 5_000 * scaleFactor;
+ long operations = 5_000L * scaleFactor;
// workPerSuccess determines the latency of the simulated server, which again determines the impact of the
// synthetic attractors of the algorithm, around latencies which give (close to) integer log10(1 / latency).
// With a value of 5, the impact is that the algorithm is pushed upwards slightly above 10k window size,
@@ -319,7 +319,6 @@ public class DynamicThrottlePolicyTest {
.collect(toUnmodifiableList());
}
- /** Performs a tick, and returns whether work was done. */
void tick() {
for (int i = 0; i < numberOfWorkers; i++)
tick(i);
diff --git a/vdslib/src/main/java/com/yahoo/vdslib/distribution/Distribution.java b/vdslib/src/main/java/com/yahoo/vdslib/distribution/Distribution.java
index c9acd625373..accf3942e4d 100644
--- a/vdslib/src/main/java/com/yahoo/vdslib/distribution/Distribution.java
+++ b/vdslib/src/main/java/com/yahoo/vdslib/distribution/Distribution.java
@@ -9,6 +9,7 @@ import com.yahoo.vdslib.state.Node;
import com.yahoo.vdslib.state.NodeState;
import com.yahoo.vdslib.state.NodeType;
import com.yahoo.vdslib.state.State;
+import com.yahoo.vespa.config.content.DistributionConfig;
import com.yahoo.vespa.config.content.StorDistributionConfig;
import com.yahoo.document.BucketId;
@@ -40,7 +41,6 @@ public class Distribution {
private final boolean distributorAutoOwnershipTransferOnWholeGroupDown;
}
- private final int[] distributionBitMasks = new int[65];
private ConfigSubscriber configSub;
private final AtomicReference<Config> config = new AtomicReference<>(new Config(null, 1, false));
@@ -52,67 +52,103 @@ public class Distribution {
return config.getAcquire().redundancy;
}
- private ConfigSubscriber.SingleSubscriber<StorDistributionConfig> configSubscriber = new ConfigSubscriber.SingleSubscriber<>() {
- private int[] getGroupPath(String path) {
- if (path.equals("invalid")) { return new int[0]; }
- StringTokenizer st = new StringTokenizer(path, ".");
- int[] p = new int[st.countTokens()];
- for (int i=0; i<p.length; ++i) {
- p[i] = Integer.valueOf(st.nextToken());
- }
- return p;
+ private static int[] getGroupPath(String path) {
+ if (path.equals("invalid")) { return new int[0]; }
+ StringTokenizer st = new StringTokenizer(path, ".");
+ int[] p = new int[st.countTokens()];
+ for (int i=0; i<p.length; ++i) {
+ p[i] = Integer.valueOf(st.nextToken());
}
+ return p;
+ }
- @Override
- public void configure(StorDistributionConfig config) {
- try{
- Group root = null;
- for (int i=0; i<config.group().size(); ++i) {
- StorDistributionConfig.Group cg = config.group().get(i);
- int[] path = new int[0];
- if (root != null) {
- path = getGroupPath(cg.index());
- }
- boolean isLeafGroup = (cg.nodes().size() > 0);
- Group group;
- int index = (path.length == 0 ? 0 : path[path.length - 1]);
- if (isLeafGroup) {
- group = new Group(index, cg.name());
- List<ConfiguredNode> nodes = new ArrayList<>();
- for (StorDistributionConfig.Group.Nodes node : cg.nodes()) {
- nodes.add(new ConfiguredNode(node.index(), node.retired()));
- }
- group.setNodes(nodes);
- } else {
- group = new Group(index, cg.name(), new Group.Distribution(cg.partitions(), config.redundancy()));
+ // NOTE: keep in sync with the below
+ private ConfigSubscriber.SingleSubscriber<StorDistributionConfig> configSubscriber = config -> {
+ try {
+ Group root = null;
+ for (int i=0; i<config.group().size(); ++i) {
+ StorDistributionConfig.Group cg = config.group(i);
+ int[] path = new int[0];
+ if (root != null) {
+ path = getGroupPath(cg.index());
+ }
+ boolean isLeafGroup = (cg.nodes().size() > 0);
+ Group group;
+ int index = (path.length == 0 ? 0 : path[path.length - 1]);
+ if (isLeafGroup) {
+ group = new Group(index, cg.name());
+ List<ConfiguredNode> nodes = new ArrayList<>();
+ for (StorDistributionConfig.Group.Nodes node : cg.nodes()) {
+ nodes.add(new ConfiguredNode(node.index(), node.retired()));
}
- group.setCapacity(cg.capacity());
- if (path.length == 0) {
- root = group;
- } else {
- Group parent = root;
- for (int j=0; j<path.length - 1; ++j) {
- parent = parent.getSubgroups().get(path[j]);
- }
- parent.addSubGroup(group);
+ group.setNodes(nodes);
+ } else {
+ group = new Group(index, cg.name(), new Group.Distribution(cg.partitions(), config.redundancy()));
+ }
+ group.setCapacity(cg.capacity());
+ if (path.length == 0) {
+ root = group;
+ } else {
+ Group parent = root;
+ for (int j=0; j<path.length - 1; ++j) {
+ parent = parent.getSubgroups().get(path[j]);
}
+ parent.addSubGroup(group);
}
- if (root == null)
- throw new IllegalStateException("Config does not specify a root group");
- root.calculateDistributionHashValues();
- Distribution.this.config.setRelease(new Config(root, config.redundancy(), config.distributor_auto_ownership_transfer_on_whole_group_down()));
- } catch (ParseException e) {
- throw new IllegalStateException("Failed to parse config", e);
}
+ if (root == null)
+ throw new IllegalStateException("Config does not specify a root group");
+ root.calculateDistributionHashValues();
+ Distribution.this.config.setRelease(new Config(root, config.redundancy(), config.distributor_auto_ownership_transfer_on_whole_group_down()));
+ } catch (ParseException e) {
+ throw new IllegalStateException("Failed to parse config", e);
}
};
- public Distribution(String configId) {
- int mask = 0;
- for (int i=0; i<=64; ++i) {
- distributionBitMasks[i] = mask;
- mask = (mask << 1) | 1;
+ // TODO jonmv: De-dupe with this.configSubscriber once common config is used
+ private void configure(DistributionConfig.Cluster config) {
+ try {
+ Group root = null;
+ for (int i=0; i<config.group().size(); ++i) {
+ DistributionConfig.Cluster.Group cg = config.group(i);
+ int[] path = new int[0];
+ if (root != null) {
+ path = getGroupPath(cg.index());
+ }
+ boolean isLeafGroup = (cg.nodes().size() > 0);
+ Group group;
+ int index = (path.length == 0 ? 0 : path[path.length - 1]);
+ if (isLeafGroup) {
+ group = new Group(index, cg.name());
+ List<ConfiguredNode> nodes = new ArrayList<>();
+ for (DistributionConfig.Cluster.Group.Nodes node : cg.nodes()) {
+ nodes.add(new ConfiguredNode(node.index(), node.retired()));
+ }
+ group.setNodes(nodes);
+ } else {
+ group = new Group(index, cg.name(), new Group.Distribution(cg.partitions(), config.redundancy()));
+ }
+ group.setCapacity(cg.capacity());
+ if (path.length == 0) {
+ root = group;
+ } else {
+ Group parent = root;
+ for (int j=0; j<path.length - 1; ++j) {
+ parent = parent.getSubgroups().get(path[j]);
+ }
+ parent.addSubGroup(group);
+ }
+ }
+ if (root == null)
+ throw new IllegalStateException("Config does not specify a root group");
+ root.calculateDistributionHashValues();
+ Distribution.this.config.setRelease(new Config(root, config.redundancy(), true));
+ } catch (ParseException e) {
+ throw new IllegalStateException("Failed to parse config", e);
}
+ }
+
+ public Distribution(String configId) {
try {
configSub = new ConfigSubscriber();
configSub.subscribe(configSubscriber, StorDistributionConfig.class, configId);
@@ -123,14 +159,20 @@ public class Distribution {
}
public Distribution(StorDistributionConfig config) {
- int mask = 0;
- for (int i=0; i<=64; ++i) {
- distributionBitMasks[i] = mask;
- mask = (mask << 1) | 1;
- }
configSubscriber.configure(config);
}
+ public Distribution(DistributionConfig.Cluster config) {
+ configure(config);
+ }
+
+ private static long lastNBits(long value, int n) {
+ if (n < 0 || n > 63)
+ throw new IllegalArgumentException("n must be in [0, 63], but was " + n);
+
+ return value & ((1L << n) - 1);
+ }
+
public void close() {
if (configSub!=null) {
configSub.close();
@@ -140,22 +182,21 @@ public class Distribution {
}
private int getGroupSeed(BucketId bucket, ClusterState state, Group group) {
- int seed = ((int) bucket.getRawId()) & distributionBitMasks[state.getDistributionBitCount()];
+ int seed = (int) lastNBits(bucket.getRawId(), state.getDistributionBitCount());
seed ^= group.getDistributionHash();
return seed;
}
private int getDistributorSeed(BucketId bucket, ClusterState state) {
- return ((int) bucket.getRawId()) & distributionBitMasks[state.getDistributionBitCount()];
+ return (int) lastNBits(bucket.getRawId(), state.getDistributionBitCount());
}
private int getStorageSeed(BucketId bucket, ClusterState state) {
- int seed = ((int) bucket.getRawId()) & distributionBitMasks[state.getDistributionBitCount()];
+ int seed = (int) lastNBits(bucket.getRawId(), state.getDistributionBitCount());
if (bucket.getUsedBits() > 33) {
int usedBits = bucket.getUsedBits() - 1;
- seed ^= (distributionBitMasks[usedBits - 32]
- & (bucket.getRawId() >> 32)) << 6;
+ seed ^= lastNBits(bucket.getRawId() >> 32, usedBits - 32) << 6;
}
return seed;
}
@@ -172,6 +213,7 @@ public class Distribution {
return Double.compare(o.score, score);
}
}
+
private static class ScoredNode {
int index;
int reliability;
@@ -179,6 +221,7 @@ public class Distribution {
ScoredNode(int index, int reliability, double score) { this.index = index; this.reliability = reliability; this.score = score; }
}
+
private static boolean allDistributorsDown(Group g, ClusterState clusterState) {
if (g.isLeafGroup()) {
for (ConfiguredNode node : g.getNodes()) {
@@ -192,6 +235,7 @@ public class Distribution {
}
return true;
}
+
private Group getIdealDistributorGroup(boolean distributorAutoOwnershipTransferOnWholeGroupDown,
BucketId bucket, ClusterState clusterState, Group parent, int redundancy) {
if (parent.isLeafGroup()) {
@@ -220,6 +264,7 @@ public class Distribution {
}
return getIdealDistributorGroup(distributorAutoOwnershipTransferOnWholeGroupDown, bucket, clusterState, results.first().group, redundancyArray[0]);
}
+
private static class ResultGroup implements Comparable<ResultGroup> {
Group group;
int redundancy;
@@ -234,6 +279,7 @@ public class Distribution {
return group.compareTo(o.group);
}
}
+
private void getIdealGroups(BucketId bucketId, ClusterState clusterState, Group parent,
int redundancy, List<ResultGroup> results) {
if (parent.isLeafGroup()) {
@@ -424,11 +470,13 @@ public class Distribution {
super(message);
}
}
+
public static class NoDistributorsAvailableException extends Exception {
NoDistributorsAvailableException(String message) {
super(message);
}
}
+
public int getIdealDistributorNode(ClusterState state, BucketId bucket, String upStates) throws TooFewBucketBitsInUseException, NoDistributorsAvailableException {
if (bucket.getUsedBits() < state.getDistributionBitCount()) {
throw new TooFewBucketBitsInUseException("Cannot get ideal state for bucket " + bucket + " using " + bucket.getUsedBits()
@@ -474,6 +522,7 @@ public class Distribution {
}
return node.index;
}
+
private boolean visitGroups(GroupVisitor visitor, Map<Integer, Group> groups) {
for (Group g : groups.values()) {
if (!visitor.visitGroup(g)) return false;
@@ -485,12 +534,14 @@ public class Distribution {
}
return true;
}
+
public void visitGroups(GroupVisitor visitor) {
Map<Integer, Group> groups = new TreeMap<>();
Group nodeGraph = config.getAcquire().nodeGraph;
groups.put(nodeGraph.getIndex(), nodeGraph);
visitGroups(visitor, groups);
}
+
public Set<ConfiguredNode> getNodes() {
final Set<ConfiguredNode> nodes = new HashSet<>();
GroupVisitor visitor = new GroupVisitor() {
@@ -524,9 +575,11 @@ public class Distribution {
sb.append("disk_distribution ").append(diskDistribution.toString()).append("\n");
return sb.toString();
}
+
public static String getSimpleGroupConfig(int redundancy, int nodeCount) {
return getSimpleGroupConfig(redundancy, nodeCount, StorDistributionConfig.Disk_distribution.Enum.MODULO_BID);
}
+
private static String getSimpleGroupConfig(int redundancy, int nodeCount, StorDistributionConfig.Disk_distribution.Enum diskDistribution) {
StringBuilder sb = new StringBuilder();
sb.append("raw:redundancy ").append(redundancy).append("\n").append("group[4]\n");
@@ -561,6 +614,5 @@ public class Distribution {
sb.append("disk_distribution ").append(diskDistribution.toString()).append("\n");
return sb.toString();
}
-}
-
+}
diff --git a/vdslib/src/main/java/com/yahoo/vdslib/distribution/Group.java b/vdslib/src/main/java/com/yahoo/vdslib/distribution/Group.java
index 680021893f7..458ab6e291c 100644
--- a/vdslib/src/main/java/com/yahoo/vdslib/distribution/Group.java
+++ b/vdslib/src/main/java/com/yahoo/vdslib/distribution/Group.java
@@ -196,7 +196,7 @@ public class Group implements Comparable<Group> {
/**
* The distribution class keeps precalculated arrays for distributions for all legal redundancies. The class is
- * immutable, such that it can be returned safely out from the group object.
+ * immutable, such that it can be returned safely out from the group object. (Actually, it's not immutable.)
*/
public static class Distribution {
diff --git a/vdslib/src/test/java/com/yahoo/vdslib/distribution/CrossPlatformTestFactory.java b/vdslib/src/test/java/com/yahoo/vdslib/distribution/CrossPlatformTestFactory.java
index 94f7d7a8c94..7dadd9560b5 100644
--- a/vdslib/src/test/java/com/yahoo/vdslib/distribution/CrossPlatformTestFactory.java
+++ b/vdslib/src/test/java/com/yahoo/vdslib/distribution/CrossPlatformTestFactory.java
@@ -1,7 +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.vdslib.distribution;
-import java.io.*;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
/**
* Helper class to implement unit tests that should produce the same result in different implementations.
diff --git a/vdslib/src/test/java/com/yahoo/vdslib/distribution/DistributionTestCase.java b/vdslib/src/test/java/com/yahoo/vdslib/distribution/DistributionTestCase.java
index 8c877704169..0d34cd70953 100644
--- a/vdslib/src/test/java/com/yahoo/vdslib/distribution/DistributionTestCase.java
+++ b/vdslib/src/test/java/com/yahoo/vdslib/distribution/DistributionTestCase.java
@@ -418,4 +418,5 @@ public class DistributionTestCase {
Distribution distr = new Distribution(new StorDistributionConfig(config));
distr.getIdealDistributorNode(clusterState, new BucketId(16, 0), "uim");
}
+
}
diff --git a/vespaclient-container-plugin/src/main/java/com/yahoo/vespa/http/server/FeedErrorMessage.java b/vespaclient-container-plugin/src/main/java/com/yahoo/vespa/http/server/FeedErrorMessage.java
deleted file mode 100644
index 1d7e8535909..00000000000
--- a/vespaclient-container-plugin/src/main/java/com/yahoo/vespa/http/server/FeedErrorMessage.java
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.http.server;
-
-import com.yahoo.document.DocumentId;
-import com.yahoo.messagebus.Message;
-import com.yahoo.text.Utf8String;
-
-import java.util.Arrays;
-
-public class FeedErrorMessage extends Message {
-
- private long sequenceId;
-
- public FeedErrorMessage(String operationId) {
- try {
- DocumentId id = new DocumentId(operationId);
- sequenceId = Arrays.hashCode(id.getGlobalId());
- } catch (Exception e) {
- sequenceId = 0;
- }
- }
-
- @Override
- public Utf8String getProtocol() {
- return new Utf8String("vespa-feed-handler-internal-bogus-protocol");
- }
-
- @Override
- public int getType() {
- return 1234;
- }
-
- @Override
- public boolean hasSequenceId() {
- return true;
- }
-
- @Override
- public long getSequenceId() {
- return sequenceId;
- }
-
-}