summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHÃ¥kon Hallingstad <hakon.hallingstad@gmail.com>2022-04-22 15:58:21 +0200
committerGitHub <noreply@github.com>2022-04-22 15:58:21 +0200
commitf58b136d4fc80e8752dab4bfae70e4c029ccf63d (patch)
treeff610868f86c3349db4a3beec01f0c75a32d58c3
parent4646ccafd4e6c119b7821b35e4ee648dee9a79e9 (diff)
parentc9a3f8ca712a9b96b93c89d6a5077048f21c5e8f (diff)
Merge pull request #22181 from vespa-engine/hakonhall/remove-orphaned-wanted-states
Remove orphaned wanted state
-rw-r--r--clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/ClusterInfo.java25
-rw-r--r--clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/ClusterStateGenerator.java2
-rw-r--r--clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/ContentCluster.java25
-rw-r--r--clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/FleetController.java43
-rw-r--r--clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/NodeLookup.java4
-rw-r--r--clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/NodeStateChangeChecker.java8
-rw-r--r--clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/NodeStateGatherer.java8
-rw-r--r--clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/RemoteClusterControllerTask.java8
-rw-r--r--clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/StateChangeHandler.java24
-rw-r--r--clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/SystemStateBroadcaster.java30
-rw-r--r--clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/database/DatabaseFactory.java6
-rw-r--r--clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/database/DatabaseHandler.java28
-rw-r--r--clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/database/MasterDataGatherer.java16
-rw-r--r--clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/database/ZooKeeperDatabase.java82
-rw-r--r--clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/database/ZooKeeperDatabaseFactory.java3
-rw-r--r--clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/database/ZooKeeperPaths.java26
-rw-r--r--clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/listeners/NodeListener.java25
-rw-r--r--clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/listeners/NodeStateOrHostInfoChangeHandler.java21
-rw-r--r--clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/listeners/SlobrokListener.java (renamed from clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/listeners/NodeAddedOrRemovedListener.java)4
-rw-r--r--clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/restapiv2/requests/SetNodeStateRequest.java12
-rw-r--r--clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/restapiv2/requests/SetNodeStatesForClusterRequest.java2
-rw-r--r--clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/restapiv2/requests/WantedStateSetter.java4
-rw-r--r--clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/rpc/RpcServer.java10
-rw-r--r--clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/rpc/SlobrokClient.java8
-rw-r--r--clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/ClusterFixture.java8
-rw-r--r--clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/DatabaseHandlerTest.java62
-rw-r--r--clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/DummyCommunicator.java6
-rw-r--r--clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/GroupAutoTakedownTest.java13
-rw-r--r--clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/ResourceExhaustionCalculatorTest.java24
-rw-r--r--clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/ResourceUsageStatsTest.java2
-rw-r--r--clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/SlobrokTest.java4
-rw-r--r--clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/StateChangeHandlerTest.java13
-rw-r--r--clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/StateChangeTest.java4
-rw-r--r--clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/SystemStateBroadcasterTest.java20
-rw-r--r--clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/ZooKeeperDatabaseTest.java2
-rw-r--r--clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/restapiv2/ClusterControllerMock.java22
-rw-r--r--clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/restapiv2/requests/SetNodeStateRequestTest.java4
-rw-r--r--clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/testutils/WaitTask.java2
38 files changed, 356 insertions, 254 deletions
diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/ClusterInfo.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/ClusterInfo.java
index c25dd5a5965..2cfaf64fe83 100644
--- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/ClusterInfo.java
+++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/ClusterInfo.java
@@ -4,6 +4,7 @@ package com.yahoo.vespa.clustercontroller.core;
import com.yahoo.vdslib.distribution.ConfiguredNode;
import com.yahoo.vdslib.distribution.Distribution;
import com.yahoo.vdslib.state.Node;
+import com.yahoo.vespa.clustercontroller.core.listeners.NodeListener;
import java.util.Collection;
import java.util.Collections;
@@ -40,11 +41,11 @@ public class ClusterInfo {
/** Returns information about the given node id, or null if this node does not exist */
public NodeInfo getNodeInfo(Node node) { return allNodeInfo.get(node); }
- Collection<DistributorNodeInfo> getDistributorNodeInfo() { return Collections.unmodifiableCollection(distributorNodeInfo.values()); }
+ Collection<DistributorNodeInfo> getDistributorNodeInfos() { return Collections.unmodifiableCollection(distributorNodeInfo.values()); }
- Collection<StorageNodeInfo> getStorageNodeInfo() { return Collections.unmodifiableCollection(storageNodeInfo.values()); }
+ Collection<StorageNodeInfo> getStorageNodeInfos() { return Collections.unmodifiableCollection(storageNodeInfo.values()); }
- Collection<NodeInfo> getAllNodeInfo() { return Collections.unmodifiableCollection(allNodeInfo.values()); }
+ Collection<NodeInfo> getAllNodeInfos() { return Collections.unmodifiableCollection(allNodeInfo.values()); }
/** Returns the configured nodes of this as a read-only map indexed on node index (distribution key) */
Map<Integer, ConfiguredNode> getConfiguredNodes() { return Collections.unmodifiableMap(nodes); }
@@ -52,15 +53,23 @@ public class ClusterInfo {
boolean hasConfiguredNode(int index) { return nodes.containsKey(index); }
/** Sets the nodes which belongs to this cluster */
- void setNodes(Collection<ConfiguredNode> newNodes, ContentCluster owner, Distribution distribution) {
+ void setNodes(Collection<ConfiguredNode> newNodes, ContentCluster owner,
+ Distribution distribution, NodeListener nodeListener) {
// Remove info for removed nodes
Set<ConfiguredNode> newNodesSet = new HashSet<>(newNodes);
for (ConfiguredNode existingNode : this.nodes.values()) {
if ( ! newNodesSet.contains(existingNode)) {
- Node existingStorageNode = storageNodeInfo.remove(existingNode.index()).getNode();
- Node existingDistributorNode = distributorNodeInfo.remove(existingNode.index()).getNode();
- allNodeInfo.remove(existingDistributorNode);
- allNodeInfo.remove(existingStorageNode);
+ {
+ Node existingStorageNode = storageNodeInfo.remove(existingNode.index()).getNode();
+ allNodeInfo.remove(existingStorageNode);
+ nodeListener.handleRemovedNode(existingStorageNode);
+ }
+
+ {
+ Node existingDistributorNode = distributorNodeInfo.remove(existingNode.index()).getNode();
+ allNodeInfo.remove(existingDistributorNode);
+ nodeListener.handleRemovedNode(existingDistributorNode);
+ }
}
}
diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/ClusterStateGenerator.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/ClusterStateGenerator.java
index f984c3cb3a2..75c6dbe6cec 100644
--- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/ClusterStateGenerator.java
+++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/ClusterStateGenerator.java
@@ -129,7 +129,7 @@ public class ClusterStateGenerator {
final ClusterState workingState = ClusterState.emptyState();
final Map<Node, NodeStateReason> nodeStateReasons = new HashMap<>();
- for (final NodeInfo nodeInfo : cluster.getNodeInfo()) {
+ for (final NodeInfo nodeInfo : cluster.getNodeInfos()) {
final NodeState nodeState = computeEffectiveNodeState(nodeInfo, params, nodeStateReasons);
workingState.setNodeState(nodeInfo.getNode(), nodeState);
}
diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/ContentCluster.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/ContentCluster.java
index fabc4999fe5..f2a4a9736c3 100644
--- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/ContentCluster.java
+++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/ContentCluster.java
@@ -10,6 +10,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.clustercontroller.core.listeners.NodeListener;
import com.yahoo.vespa.clustercontroller.core.status.statuspage.HtmlTable;
import com.yahoo.vespa.clustercontroller.core.status.statuspage.VdsClusterHtmlRenderer;
import com.yahoo.vespa.clustercontroller.utils.staterestapi.requests.SetUnitStateRequest;
@@ -42,7 +43,7 @@ public class ContentCluster {
if (configuredNodes == null) throw new IllegalArgumentException("Nodes must be set");
this.clusterName = clusterName;
this.distribution = distribution;
- setNodes(configuredNodes);
+ setNodes(configuredNodes, new NodeListener() {});
}
// TODO move out, this doesn't belong in a domain model class
@@ -104,14 +105,14 @@ public class ContentCluster {
public void setDistribution(Distribution distribution) {
this.distribution = distribution;
- for (NodeInfo info : clusterInfo.getAllNodeInfo()) {
+ for (NodeInfo info : clusterInfo.getAllNodeInfos()) {
info.setGroup(distribution);
}
}
/** Sets the configured nodes of this cluster */
- public final void setNodes(Collection<ConfiguredNode> configuredNodes) {
- clusterInfo.setNodes(configuredNodes, this, distribution);
+ public final void setNodes(Collection<ConfiguredNode> configuredNodes, NodeListener nodeListener) {
+ clusterInfo.setNodes(configuredNodes, this, distribution, nodeListener);
}
public void setStartTimestamp(Node n, long startTimestamp) {
@@ -128,7 +129,7 @@ public class ContentCluster {
}
public void clearStates() {
- for (NodeInfo info : clusterInfo.getAllNodeInfo()) {
+ for (NodeInfo info : clusterInfo.getAllNodeInfos()) {
info.setReportedState(null, 0);
}
}
@@ -145,8 +146,8 @@ public class ContentCluster {
return clusterInfo.getConfiguredNodes();
}
- public Collection<NodeInfo> getNodeInfo() {
- return Collections.unmodifiableCollection(clusterInfo.getAllNodeInfo());
+ public Collection<NodeInfo> getNodeInfos() {
+ return Collections.unmodifiableCollection(clusterInfo.getAllNodeInfos());
}
public ClusterInfo clusterInfo() { return clusterInfo; }
@@ -158,7 +159,7 @@ public class ContentCluster {
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("ContentCluster(").append(clusterName).append(") {");
- for (NodeInfo node : clusterInfo.getAllNodeInfo()) {
+ for (NodeInfo node : clusterInfo.getAllNodeInfos()) {
sb.append("\n ").append(node);
}
sb.append("\n}");
@@ -197,14 +198,14 @@ public class ContentCluster {
switch (state) {
case MAINTENANCE: // Orchestrator's ALLOWED_TO_BE_DOWN
case DOWN: // Orchestrator's PERMANENTLY_DOWN
- return clusterInfo.getStorageNodeInfo().stream()
- .filter(storageNodeInfo -> {
+ return clusterInfo.getStorageNodeInfos().stream()
+ .filter(storageNodeInfo -> {
NodeState userWantedState = storageNodeInfo.getUserWantedState();
return userWantedState.getState() == state &&
Objects.equals(userWantedState.getDescription(), ORCHESTRATOR_RESERVED_DESCRIPTION);
})
- .map(NodeInfo::getNodeIndex)
- .collect(Collectors.toList());
+ .map(NodeInfo::getNodeIndex)
+ .collect(Collectors.toList());
default:
// Note: There is no trace left if the Orchestrator set the state to UP, so that's handled
// like any other state:
diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/FleetController.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/FleetController.java
index 3137dfff606..7f385c6077c 100644
--- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/FleetController.java
+++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/FleetController.java
@@ -12,8 +12,8 @@ import com.yahoo.vdslib.state.State;
import com.yahoo.vespa.clustercontroller.core.database.DatabaseHandler;
import com.yahoo.vespa.clustercontroller.core.database.ZooKeeperDatabaseFactory;
import com.yahoo.vespa.clustercontroller.core.hostinfo.HostInfo;
-import com.yahoo.vespa.clustercontroller.core.listeners.NodeAddedOrRemovedListener;
-import com.yahoo.vespa.clustercontroller.core.listeners.NodeStateOrHostInfoChangeHandler;
+import com.yahoo.vespa.clustercontroller.core.listeners.SlobrokListener;
+import com.yahoo.vespa.clustercontroller.core.listeners.NodeListener;
import com.yahoo.vespa.clustercontroller.core.listeners.SystemStateListener;
import com.yahoo.vespa.clustercontroller.core.rpc.RPCCommunicator;
import com.yahoo.vespa.clustercontroller.core.rpc.RpcServer;
@@ -47,7 +47,7 @@ import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.Stream;
-public class FleetController implements NodeStateOrHostInfoChangeHandler, NodeAddedOrRemovedListener, SystemStateListener,
+public class FleetController implements NodeListener, SlobrokListener, SystemStateListener,
Runnable, RemoteClusterControllerTaskScheduler {
private static final Logger logger = Logger.getLogger(FleetController.class.getName());
@@ -332,6 +332,13 @@ public class FleetController implements NodeStateOrHostInfoChangeHandler, NodeAd
}
@Override
+ public void handleRemovedNode(Node node) {
+ verifyInControllerThread();
+ // Prune orphaned wanted states
+ wantedStateChanged = true;
+ }
+
+ @Override
public void handleUpdatedHostInfo(NodeInfo nodeInfo, HostInfo newHostInfo) {
verifyInControllerThread();
triggerBundleRecomputationIfResourceExhaustionStateChanged(nodeInfo, newHostInfo);
@@ -380,7 +387,7 @@ public class FleetController implements NodeStateOrHostInfoChangeHandler, NodeAd
ClusterState baselineState = stateBundle.getBaselineClusterState();
newStates.add(stateBundle);
metricUpdater.updateClusterStateMetrics(cluster, baselineState,
- ResourceUsageStats.calculateFrom(cluster.getNodeInfo(), options.clusterFeedBlockLimit, stateBundle.getFeedBlock()));
+ ResourceUsageStats.calculateFrom(cluster.getNodeInfos(), options.clusterFeedBlockLimit, stateBundle.getFeedBlock()));
lastMetricUpdateCycleCount = cycleCount;
systemStateBroadcaster.handleNewClusterStates(stateBundle);
// Iff master, always store new version in ZooKeeper _before_ publishing to any
@@ -399,7 +406,7 @@ public class FleetController implements NodeStateOrHostInfoChangeHandler, NodeAd
ClusterStateBundle stateBundle = stateVersionTracker.getVersionedClusterStateBundle();
ClusterState baselineState = stateBundle.getBaselineClusterState();
metricUpdater.updateClusterStateMetrics(cluster, baselineState,
- ResourceUsageStats.calculateFrom(cluster.getNodeInfo(), options.clusterFeedBlockLimit, stateBundle.getFeedBlock()));
+ ResourceUsageStats.calculateFrom(cluster.getNodeInfos(), options.clusterFeedBlockLimit, stateBundle.getFeedBlock()));
lastMetricUpdateCycleCount = cycleCount;
return true;
} else {
@@ -511,7 +518,7 @@ public class FleetController implements NodeStateOrHostInfoChangeHandler, NodeAd
eventLog.setMaxSize(options.eventLogMaxSize, options.eventNodeLogMaxSize);
cluster.setPollingFrequency(options.statePollingFrequency);
cluster.setDistribution(options.storageDistribution);
- cluster.setNodes(options.nodes);
+ cluster.setNodes(options.nodes, databaseContext.getNodeStateUpdateListener());
database.setZooKeeperAddress(options.zooKeeperServerAddress, databaseContext);
database.setZooKeeperSessionTimeout(options.zooKeeperSessionTimeout, databaseContext);
stateGatherer.setMaxSlobrokDisconnectGracePeriod(options.maxSlobrokDisconnectGracePeriod);
@@ -790,8 +797,8 @@ public class FleetController implements NodeStateOrHostInfoChangeHandler, NodeAd
@Override public boolean inMasterMoratorium() { return inMasterMoratorium; }
};
- context.nodeStateOrHostInfoChangeHandler = this;
- context.nodeAddedOrRemovedListener = this;
+ context.nodeListener = this;
+ context.slobrokListener = this;
return context;
}
@@ -806,10 +813,10 @@ public class FleetController implements NodeStateOrHostInfoChangeHandler, NodeAd
if (bundle == null) {
return List.of();
}
- return cluster.getNodeInfo().stream().
- filter(n -> effectiveActivatedStateVersion(n, bundle) < version).
- map(NodeInfo::getNode).
- collect(Collectors.toList());
+ return cluster.getNodeInfos().stream().
+ filter(n -> effectiveActivatedStateVersion(n, bundle) < version).
+ map(NodeInfo::getNode).
+ collect(Collectors.toList());
}
private static <E> String stringifyListWithLimits(List<E> list, int limit) {
@@ -939,7 +946,7 @@ public class FleetController implements NodeStateOrHostInfoChangeHandler, NodeAd
.stateDeriver(createBucketSpaceStateDeriver())
.deferredActivation(options.enableTwoPhaseClusterStateActivation)
.feedBlock(createResourceExhaustionCalculator()
- .inferContentClusterFeedBlockOrNull(cluster.getNodeInfo()))
+ .inferContentClusterFeedBlockOrNull(cluster.getNodeInfos()))
.deriveAndBuild();
stateVersionTracker.updateLatestCandidateStateBundle(candidateBundle);
invokeCandidateStateListeners(candidateBundle);
@@ -1095,7 +1102,7 @@ public class FleetController implements NodeStateOrHostInfoChangeHandler, NodeAd
didWork = true;
}
if (wantedStateChanged) {
- database.saveWantedStates(databaseContext);
+ didWork |= database.saveWantedStates(databaseContext);
wantedStateChanged = false;
}
} else {
@@ -1150,9 +1157,9 @@ public class FleetController implements NodeStateOrHostInfoChangeHandler, NodeAd
@Override
public FleetController getFleetController() { return FleetController.this; }
@Override
- public NodeAddedOrRemovedListener getNodeAddedOrRemovedListener() { return FleetController.this; }
+ public SlobrokListener getNodeAddedOrRemovedListener() { return FleetController.this; }
@Override
- public NodeStateOrHostInfoChangeHandler getNodeStateUpdateListener() { return FleetController.this; }
+ public NodeListener getNodeStateUpdateListener() { return FleetController.this; }
};
public void waitForCompleteCycle(long timeoutMS) {
@@ -1183,7 +1190,7 @@ public class FleetController implements NodeStateOrHostInfoChangeHandler, NodeAd
synchronized (monitor) {
while (true) {
int ackedNodes = 0;
- for (NodeInfo node : cluster.getNodeInfo()) {
+ for (NodeInfo node : cluster.getNodeInfos()) {
if (node.getClusterStateVersionBundleAcknowledged() >= version) {
++ackedNodes;
}
@@ -1206,7 +1213,7 @@ public class FleetController implements NodeStateOrHostInfoChangeHandler, NodeAd
synchronized (monitor) {
while (true) {
int distCount = 0, storCount = 0;
- for (NodeInfo info : cluster.getNodeInfo()) {
+ for (NodeInfo info : cluster.getNodeInfos()) {
if (!info.isRpcAddressOutdated()) {
if (info.isDistributor()) ++distCount;
else ++storCount;
diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/NodeLookup.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/NodeLookup.java
index cdf8b24e72d..882ae8894fa 100644
--- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/NodeLookup.java
+++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/NodeLookup.java
@@ -1,7 +1,7 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.clustercontroller.core;
-import com.yahoo.vespa.clustercontroller.core.listeners.NodeAddedOrRemovedListener;
+import com.yahoo.vespa.clustercontroller.core.listeners.SlobrokListener;
/**
* Interface for a node lookup service, such as slobrok, config, or tier controller.
@@ -10,7 +10,7 @@ public interface NodeLookup {
void shutdown();
- boolean updateCluster(ContentCluster cluster, NodeAddedOrRemovedListener listener);
+ boolean updateCluster(ContentCluster cluster, SlobrokListener listener);
/**
* Returns whether the lookup instance has been able to bootstrap itself with information about nodes.
diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/NodeStateChangeChecker.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/NodeStateChangeChecker.java
index eb0368749f0..3ed03e94fda 100644
--- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/NodeStateChangeChecker.java
+++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/NodeStateChangeChecker.java
@@ -359,7 +359,7 @@ public class NodeStateChangeChecker {
// This method verifies both storage nodes and distributors are up (or retired).
// The complicated part is making a summary error message.
- for (NodeInfo storageNodeInfo : clusterInfo.getStorageNodeInfo()) {
+ for (NodeInfo storageNodeInfo : clusterInfo.getStorageNodeInfos()) {
State wantedState = storageNodeInfo.getUserWantedState().getState();
if (wantedState != State.UP && wantedState != State.RETIRED) {
return Result.createDisallowed("Another storage node wants state " +
@@ -373,7 +373,7 @@ public class NodeStateChangeChecker {
}
}
- for (NodeInfo distributorNodeInfo : clusterInfo.getDistributorNodeInfo()) {
+ for (NodeInfo distributorNodeInfo : clusterInfo.getDistributorNodeInfos()) {
State wantedState = distributorNodeInfo.getUserWantedState().getState();
if (wantedState != State.UP && wantedState != State.RETIRED) {
return Result.createDisallowed("Another distributor wants state " + wantedState.toString().toUpperCase() +
@@ -418,10 +418,10 @@ public class NodeStateChangeChecker {
* @param clusterStateVersion the cluster state we expect distributors to have
*/
private Result checkDistributors(Node node, int clusterStateVersion) {
- if (clusterInfo.getDistributorNodeInfo().isEmpty()) {
+ if (clusterInfo.getDistributorNodeInfos().isEmpty()) {
return Result.createDisallowed("Not aware of any distributors, probably not safe to upgrade?");
}
- for (DistributorNodeInfo distributorNodeInfo : clusterInfo.getDistributorNodeInfo()) {
+ for (DistributorNodeInfo distributorNodeInfo : clusterInfo.getDistributorNodeInfos()) {
Integer distributorClusterStateVersion = distributorNodeInfo.getHostInfo().getClusterStateVersionOrNull();
if (distributorClusterStateVersion == null) {
return Result.createDisallowed("Distributor node " + distributorNodeInfo.getNodeIndex()
diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/NodeStateGatherer.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/NodeStateGatherer.java
index e3fe371c05e..69e97de84f9 100644
--- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/NodeStateGatherer.java
+++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/NodeStateGatherer.java
@@ -7,7 +7,7 @@ import java.util.logging.Level;
import com.yahoo.vdslib.state.NodeState;
import com.yahoo.vdslib.state.State;
import com.yahoo.vespa.clustercontroller.core.hostinfo.HostInfo;
-import com.yahoo.vespa.clustercontroller.core.listeners.NodeStateOrHostInfoChangeHandler;
+import com.yahoo.vespa.clustercontroller.core.listeners.NodeListener;
import java.util.LinkedList;
import java.util.List;
@@ -54,10 +54,10 @@ public class NodeStateGatherer {
* Sends state requests to nodes that does not have one pending and is due
* for another attempt.
*/
- public boolean sendMessages(ContentCluster cluster, Communicator communicator, NodeStateOrHostInfoChangeHandler listener) {
+ public boolean sendMessages(ContentCluster cluster, Communicator communicator, NodeListener listener) {
boolean sentAnyMessages = false;
long currentTime = timer.getCurrentTimeInMillis();
- for (NodeInfo info : cluster.getNodeInfo()) {
+ for (NodeInfo info : cluster.getNodeInfos()) {
Long requestTime = info.getLatestNodeStateRequestTime();
if (requestTime != null && (currentTime - requestTime < nodeStateRequestTimeoutMS)) continue; // pending request
@@ -93,7 +93,7 @@ public class NodeStateGatherer {
}
/** Reads replies to get node state requests and create events. */
- public boolean processResponses(NodeStateOrHostInfoChangeHandler listener) {
+ public boolean processResponses(NodeListener listener) {
boolean processedAnyResponses = false;
long currentTime = timer.getCurrentTimeInMillis();
synchronized(monitor) {
diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/RemoteClusterControllerTask.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/RemoteClusterControllerTask.java
index 949ad6f56a2..3c2143818e3 100644
--- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/RemoteClusterControllerTask.java
+++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/RemoteClusterControllerTask.java
@@ -2,8 +2,8 @@
package com.yahoo.vespa.clustercontroller.core;
import com.yahoo.vdslib.state.ClusterState;
-import com.yahoo.vespa.clustercontroller.core.listeners.NodeAddedOrRemovedListener;
-import com.yahoo.vespa.clustercontroller.core.listeners.NodeStateOrHostInfoChangeHandler;
+import com.yahoo.vespa.clustercontroller.core.listeners.SlobrokListener;
+import com.yahoo.vespa.clustercontroller.core.listeners.NodeListener;
import java.time.Instant;
import java.util.Optional;
@@ -15,8 +15,8 @@ public abstract class RemoteClusterControllerTask {
public ClusterState currentConsolidatedState;
public ClusterStateBundle publishedClusterStateBundle;
public MasterInterface masterInfo;
- public NodeStateOrHostInfoChangeHandler nodeStateOrHostInfoChangeHandler;
- public NodeAddedOrRemovedListener nodeAddedOrRemovedListener;
+ public NodeListener nodeListener;
+ public SlobrokListener slobrokListener;
}
private final Object monitor = new Object();
diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/StateChangeHandler.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/StateChangeHandler.java
index 46fafddfade..4c832592422 100644
--- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/StateChangeHandler.java
+++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/StateChangeHandler.java
@@ -8,7 +8,7 @@ import com.yahoo.vdslib.state.NodeState;
import com.yahoo.vdslib.state.NodeType;
import com.yahoo.vdslib.state.State;
import com.yahoo.vespa.clustercontroller.core.database.DatabaseHandler;
-import com.yahoo.vespa.clustercontroller.core.listeners.NodeStateOrHostInfoChangeHandler;
+import com.yahoo.vespa.clustercontroller.core.listeners.NodeListener;
import java.util.Map;
import java.util.Set;
@@ -113,7 +113,7 @@ public class StateChangeHandler {
public void handleNewReportedNodeState(final ClusterState currentClusterState,
final NodeInfo node,
final NodeState reportedState,
- final NodeStateOrHostInfoChangeHandler nodeListener)
+ final NodeListener nodeListener)
{
final NodeState currentState = currentClusterState.getNodeState(node.getNode());
final Level level = (currentState.equals(reportedState) && node.getVersion() == 0) ? Level.FINEST : Level.FINE;
@@ -164,7 +164,7 @@ public class StateChangeHandler {
public void handleMissingNode(final ClusterState currentClusterState,
final NodeInfo node,
- final NodeStateOrHostInfoChangeHandler nodeListener) {
+ final NodeListener nodeListener) {
final long timeNow = timer.getCurrentTimeInMillis();
if (node.getLatestNodeStateRequestTime() != null) {
@@ -241,12 +241,12 @@ public class StateChangeHandler {
// `--> this will require adding more event edges and premature crash handling to it. Which is fine.
public boolean watchTimers(final ContentCluster cluster,
final ClusterState currentClusterState,
- final NodeStateOrHostInfoChangeHandler nodeListener)
+ final NodeListener nodeListener)
{
boolean triggeredAnyTimers = false;
final long currentTime = timer.getCurrentTimeInMillis();
- for(NodeInfo node : cluster.getNodeInfo()) {
+ for(NodeInfo node : cluster.getNodeInfos()) {
triggeredAnyTimers |= handleTimeDependentOpsForNode(currentClusterState, nodeListener, currentTime, node);
}
@@ -257,7 +257,7 @@ public class StateChangeHandler {
}
private boolean handleTimeDependentOpsForNode(final ClusterState currentClusterState,
- final NodeStateOrHostInfoChangeHandler nodeListener,
+ final NodeListener nodeListener,
final long currentTime,
final NodeInfo node)
{
@@ -334,7 +334,7 @@ public class StateChangeHandler {
}
private boolean reportDownIfOutdatedSlobrokNode(ClusterState currentClusterState,
- NodeStateOrHostInfoChangeHandler nodeListener,
+ NodeListener nodeListener,
long currentTime,
NodeInfo node,
NodeState lastReportedState)
@@ -379,7 +379,7 @@ public class StateChangeHandler {
private void updateNodeInfoFromReportedState(final NodeInfo node,
final NodeState currentState,
final NodeState reportedState,
- final NodeStateOrHostInfoChangeHandler nodeListener) {
+ final NodeListener nodeListener) {
final long timeNow = timer.getCurrentTimeInMillis();
log.log(Level.FINE, () -> String.format("Finding new cluster state entry for %s switching state %s", node, currentState.getTextualDifference(reportedState)));
@@ -400,7 +400,7 @@ public class StateChangeHandler {
private void markNodeUnstableIfDownEdgeDuringInit(final NodeInfo node,
final NodeState currentState,
final NodeState reportedState,
- final NodeStateOrHostInfoChangeHandler nodeListener,
+ final NodeListener nodeListener,
final long timeNow) {
if (currentState.getState().equals(State.INITIALIZING)
&& reportedState.getState().oneOf("ds")
@@ -419,7 +419,7 @@ public class StateChangeHandler {
private boolean handleImplicitCrashEdgeFromReverseInitProgress(final NodeInfo node,
final NodeState currentState,
final NodeState reportedState,
- final NodeStateOrHostInfoChangeHandler nodeListener,
+ final NodeListener nodeListener,
final long timeNow) {
if (currentState.getState().equals(State.INITIALIZING) &&
(reportedState.getState().equals(State.INITIALIZING) && reportedState.getInitProgress() < currentState.getInitProgress()))
@@ -438,7 +438,7 @@ public class StateChangeHandler {
}
private boolean handleReportedNodeCrashEdge(NodeInfo node, NodeState currentState,
- NodeState reportedState, NodeStateOrHostInfoChangeHandler nodeListener,
+ NodeState reportedState, NodeListener nodeListener,
long timeNow) {
if (nodeUpToDownEdge(node, currentState, reportedState)) {
node.setTransitionTime(timeNow);
@@ -467,7 +467,7 @@ public class StateChangeHandler {
&& (node.getWantedState().getState().equals(State.RETIRED) || !reportedState.getState().equals(State.INITIALIZING));
}
- private boolean handlePrematureCrash(NodeInfo node, NodeStateOrHostInfoChangeHandler changeListener) {
+ private boolean handlePrematureCrash(NodeInfo node, NodeListener changeListener) {
node.setPrematureCrashCount(node.getPrematureCrashCount() + 1);
if (disableUnstableNodes && node.getPrematureCrashCount() > maxPrematureCrashes) {
NodeState wantedState = new NodeState(node.getNode().getType(), State.DOWN)
diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/SystemStateBroadcaster.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/SystemStateBroadcaster.java
index d061f7edbea..2359e4d8389 100644
--- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/SystemStateBroadcaster.java
+++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/SystemStateBroadcaster.java
@@ -188,18 +188,18 @@ public class SystemStateBroadcaster {
}
private List<NodeInfo> resolveStateVersionSendSet(DatabaseHandler.DatabaseContext dbContext) {
- return dbContext.getCluster().getNodeInfo().stream()
- .filter(this::nodeNeedsClusterStateBundle)
- .filter(node -> !newestStateBundleAlreadySentToNode(node))
- .collect(Collectors.toList());
+ return dbContext.getCluster().getNodeInfos().stream()
+ .filter(this::nodeNeedsClusterStateBundle)
+ .filter(node -> !newestStateBundleAlreadySentToNode(node))
+ .collect(Collectors.toList());
}
// Precondition: no nodes in the cluster need to receive the current cluster state version bundle
private List<NodeInfo> resolveStateActivationSendSet(DatabaseHandler.DatabaseContext dbContext) {
- return dbContext.getCluster().getNodeInfo().stream()
- .filter(this::nodeNeedsClusterStateActivation)
- .filter(node -> !newestStateActivationAlreadySentToNode(node))
- .collect(Collectors.toList());
+ return dbContext.getCluster().getNodeInfos().stream()
+ .filter(this::nodeNeedsClusterStateActivation)
+ .filter(node -> !newestStateActivationAlreadySentToNode(node))
+ .collect(Collectors.toList());
}
private boolean newestStateBundleAlreadySentToNode(NodeInfo node) {
@@ -222,9 +222,9 @@ public class SystemStateBroadcaster {
return; // Nothing to do for the current state
}
final int currentStateVersion = clusterStateBundle.getVersion();
- boolean anyDistributorsNeedStateBundle = dbContext.getCluster().getNodeInfo().stream()
- .filter(NodeInfo::isDistributor)
- .anyMatch(this::nodeNeedsClusterStateBundle);
+ boolean anyDistributorsNeedStateBundle = dbContext.getCluster().getNodeInfos().stream()
+ .filter(NodeInfo::isDistributor)
+ .anyMatch(this::nodeNeedsClusterStateBundle);
if (!anyDistributorsNeedStateBundle && (currentStateVersion > lastStateVersionBundleAcked)) {
markCurrentClusterStateBundleAsReceivedByAllDistributors();
@@ -243,9 +243,9 @@ public class SystemStateBroadcaster {
return;
}
- boolean anyDistributorsNeedActivation = dbContext.getCluster().getNodeInfo().stream()
- .filter(NodeInfo::isDistributor)
- .anyMatch(this::nodeNeedsClusterStateActivation);
+ boolean anyDistributorsNeedActivation = dbContext.getCluster().getNodeInfos().stream()
+ .filter(NodeInfo::isDistributor)
+ .anyMatch(this::nodeNeedsClusterStateActivation);
if (!anyDistributorsNeedActivation && (currentStateVersion > lastClusterStateVersionConverged)) {
markCurrentClusterStateAsConverged(database, dbContext, fleetController);
@@ -352,7 +352,7 @@ public class SystemStateBroadcaster {
private static ClusterState buildModifiedClusterState(ClusterState sourceState, DatabaseHandler.DatabaseContext dbContext) {
ClusterState newState = sourceState.clone();
- for (NodeInfo n : dbContext.getCluster().getNodeInfo()) {
+ for (NodeInfo n : dbContext.getCluster().getNodeInfos()) {
NodeState ns = newState.getNodeState(n.getNode());
if (!n.isDistributor() && ns.getStartTimestamp() == 0) {
ns.setStartTimestamp(n.getStartTimestamp());
diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/database/DatabaseFactory.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/database/DatabaseFactory.java
index 45a416fade4..31f6bbfe932 100644
--- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/database/DatabaseFactory.java
+++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/database/DatabaseFactory.java
@@ -1,8 +1,6 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.clustercontroller.core.database;
-import com.yahoo.vespa.clustercontroller.core.ContentCluster;
-
/**
* Database factory to enable test mocking of DB features. In practice, this
* will always be {@link ZooKeeperDatabase} due to rather heavy ZK feature
@@ -11,14 +9,10 @@ import com.yahoo.vespa.clustercontroller.core.ContentCluster;
public interface DatabaseFactory {
class Params {
- ContentCluster cluster;
- int nodeIndex;
String dbAddress;
int dbSessionTimeout;
Database.DatabaseListener listener;
- Params cluster(ContentCluster c) { this.cluster = c; return this; }
- Params nodeIndex(int i) { this.nodeIndex = i; return this; }
Params databaseAddress(String address) { this.dbAddress = address; return this; }
Params databaseSessionTimeout(int timeout) { this.dbSessionTimeout = timeout; return this; }
Params databaseListener(Database.DatabaseListener listener) { this.listener = listener; return this; }
diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/database/DatabaseHandler.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/database/DatabaseHandler.java
index 0c6c773a9bc..01b8ed48c80 100644
--- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/database/DatabaseHandler.java
+++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/database/DatabaseHandler.java
@@ -10,8 +10,8 @@ import com.yahoo.vespa.clustercontroller.core.FleetControllerContext;
import com.yahoo.vespa.clustercontroller.core.FleetController;
import com.yahoo.vespa.clustercontroller.core.NodeInfo;
import com.yahoo.vespa.clustercontroller.core.Timer;
-import com.yahoo.vespa.clustercontroller.core.listeners.NodeAddedOrRemovedListener;
-import com.yahoo.vespa.clustercontroller.core.listeners.NodeStateOrHostInfoChangeHandler;
+import com.yahoo.vespa.clustercontroller.core.listeners.SlobrokListener;
+import com.yahoo.vespa.clustercontroller.core.listeners.NodeListener;
import org.apache.zookeeper.KeeperException;
import java.io.PrintWriter;
@@ -32,8 +32,8 @@ public class DatabaseHandler {
public interface DatabaseContext {
ContentCluster getCluster();
FleetController getFleetController();
- NodeAddedOrRemovedListener getNodeAddedOrRemovedListener();
- NodeStateOrHostInfoChangeHandler getNodeStateUpdateListener();
+ SlobrokListener getNodeAddedOrRemovedListener();
+ NodeListener getNodeStateUpdateListener();
}
private static class Data {
@@ -191,9 +191,8 @@ public class DatabaseHandler {
// being called, but after receiving a database loss event.
clearSessionMetaData(false);
fleetControllerContext.log(logger, Level.INFO, "Setting up new ZooKeeper session at " + zooKeeperAddress);
- DatabaseFactory.Params params = new DatabaseFactory.Params()
- .cluster(cluster)
- .nodeIndex(fleetControllerContext.id().index())
+ DatabaseFactory.Params params = new DatabaseFactory
+ .Params()
.databaseAddress(zooKeeperAddress)
.databaseSessionTimeout(zooKeeperSessionTimeout)
.databaseListener(dbListener);
@@ -426,10 +425,10 @@ public class DatabaseHandler {
}
}
- public void saveWantedStates(DatabaseContext databaseContext) {
+ public boolean saveWantedStates(DatabaseContext databaseContext) {
fleetControllerContext.log(logger, Level.FINE, () -> "Checking whether wanted states have changed compared to zookeeper version.");
Map<Node, NodeState> wantedStates = new TreeMap<>();
- for (NodeInfo info : databaseContext.getCluster().getNodeInfo()) {
+ for (NodeInfo info : databaseContext.getCluster().getNodeInfos()) {
if (!info.getUserWantedState().equals(new NodeState(info.getNode().getType(), State.UP))) {
wantedStates.put(info.getNode(), info.getUserWantedState());
}
@@ -444,6 +443,9 @@ public class DatabaseHandler {
fleetControllerContext.log(logger, Level.FINE, () -> "Scheduling new wanted states to be stored into zookeeper.");
pendingStore.wantedStates = wantedStates;
doNextZooKeeperTask(databaseContext);
+ return true;
+ } else {
+ return false;
}
}
@@ -466,7 +468,11 @@ public class DatabaseHandler {
boolean altered = false;
for (Node node : wantedStates.keySet()) {
NodeInfo nodeInfo = databaseContext.getCluster().getNodeInfo(node);
- if (nodeInfo == null) continue; // ignore wanted state of nodes which doesn't exist
+ if (nodeInfo == null) {
+ databaseContext.getNodeStateUpdateListener().handleRemovedNode(node);
+ altered = true;
+ continue;
+ }
NodeState wantedState = wantedStates.get(node);
if ( ! nodeInfo.getUserWantedState().equals(wantedState)) {
nodeInfo.setWantedState(wantedState);
@@ -477,7 +483,7 @@ public class DatabaseHandler {
}
// Remove wanted state from any node having a wanted state set that is no longer valid
- for (NodeInfo info : databaseContext.getCluster().getNodeInfo()) {
+ for (NodeInfo info : databaseContext.getCluster().getNodeInfos()) {
NodeState wantedState = wantedStates.get(info.getNode());
if (wantedState == null && !info.getUserWantedState().equals(new NodeState(info.getNode().getType(), State.UP))) {
info.setWantedState(null);
diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/database/MasterDataGatherer.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/database/MasterDataGatherer.java
index 907f2e0c5e9..0c32d8ef6c2 100644
--- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/database/MasterDataGatherer.java
+++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/database/MasterDataGatherer.java
@@ -24,7 +24,7 @@ public class MasterDataGatherer {
return Integer.parseInt(nodeName.substring(lastSlash + 1));
}
- private final String zooKeeperRoot; // The root path in zookeeper, typically /vespa/fleetcontroller/<clustername>/
+ private final ZooKeeperPaths paths;
private Map<Integer, Integer> masterData = new TreeMap<>(); // The master state last reported to the fleetcontroller
private final Map<Integer, Integer> nextMasterData = new TreeMap<>(); // Temporary master state while gathering new info from zookeeper
private final AsyncCallback.ChildrenCallback childListener = new DirCallback(); // Dir change listener
@@ -46,7 +46,7 @@ public class MasterDataGatherer {
switch (watchedEvent.getType()) {
case NodeChildrenChanged: // Fleetcontrollers have either connected or disconnected to ZooKeeper
log.log(Level.INFO, "Fleetcontroller " + nodeIndex + ": A change occurred in the list of registered fleetcontrollers. Requesting new information");
- session.getChildren(zooKeeperRoot + "indexes", this, childListener, null);
+ session.getChildren(paths.indexesRoot(), this, childListener, null);
break;
case NodeDataChanged: // A fleetcontroller has changed what node it is voting for
log.log(Level.INFO, "Fleetcontroller " + nodeIndex + ": Altered data in node " + watchedEvent.getPath() + ". Requesting new vote");
@@ -54,7 +54,7 @@ public class MasterDataGatherer {
synchronized (nextMasterData) {
nextMasterData.put(index, null);
}
- session.getData(zooKeeperRoot + "indexes/" + index, this, nodeListener, null);
+ session.getData(paths.indexOf(index), this, nodeListener, null);
break;
case NodeCreated: // How can this happen? Can one leave watches on non-existing nodes?
log.log(Level.WARNING, "Fleetcontroller " + nodeIndex + ": Got unexpected ZooKeeper event NodeCreated");
@@ -85,8 +85,8 @@ public class MasterDataGatherer {
int index = Integer.parseInt(node);
nextMasterData.put(index, null);
log.log(Level.FINE, () -> "Fleetcontroller " + nodeIndex + ": Attempting to fetch data in node '"
- + zooKeeperRoot + index + "' to see vote");
- session.getData(zooKeeperRoot + "indexes/" + index, changeWatcher, nodeListener, null);
+ + paths.indexOf(index) + "' to see vote");
+ session.getData(paths.indexOf(index), changeWatcher, nodeListener, null);
// Invocation of cycleCompleted() for fully accumulated election state will happen
// as soon as all getData calls have been processed.
}
@@ -146,8 +146,8 @@ public class MasterDataGatherer {
}
/** Constructor setting up the various needed members, and initializing the first data fetch to start things up */
- public MasterDataGatherer(ZooKeeper session, String zooKeeperRoot, Database.DatabaseListener listener, int nodeIndex) {
- this.zooKeeperRoot = zooKeeperRoot;
+ public MasterDataGatherer(ZooKeeper session, ZooKeeperPaths paths, Database.DatabaseListener listener, int nodeIndex) {
+ this.paths = paths;
this.session = session;
this.listener = listener;
this.nodeIndex = nodeIndex;
@@ -161,7 +161,7 @@ public class MasterDataGatherer {
synchronized (nextMasterData) {
masterData = new TreeMap<>();
nextMasterData.clear();
- session.getChildren(zooKeeperRoot + "indexes", changeWatcher, childListener, null);
+ session.getChildren(paths.indexesRoot(), changeWatcher, childListener, null);
}
}
diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/database/ZooKeeperDatabase.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/database/ZooKeeperDatabase.java
index 72c81489351..ea745a56066 100644
--- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/database/ZooKeeperDatabase.java
+++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/database/ZooKeeperDatabase.java
@@ -6,7 +6,6 @@ import com.yahoo.vdslib.state.NodeState;
import com.yahoo.vdslib.state.State;
import com.yahoo.vespa.clustercontroller.core.AnnotatedClusterState;
import com.yahoo.vespa.clustercontroller.core.ClusterStateBundle;
-import com.yahoo.vespa.clustercontroller.core.ContentCluster;
import com.yahoo.vespa.clustercontroller.core.FleetControllerContext;
import com.yahoo.vespa.clustercontroller.core.rpc.EnvelopedClusterStateBundleCodec;
import com.yahoo.vespa.clustercontroller.core.rpc.SlimeClusterStateBundleCodec;
@@ -38,13 +37,12 @@ public class ZooKeeperDatabase extends Database {
private static final Charset utf8 = StandardCharsets.UTF_8;
private static final List<ACL> acl = ZooDefs.Ids.OPEN_ACL_UNSAFE;
- private final String zooKeeperRoot;
+ private final ZooKeeperPaths paths;
private final Database.DatabaseListener listener;
private final ZooKeeperWatcher watcher = new ZooKeeperWatcher();
private final ZooKeeper session;
private boolean sessionOpen = true;
private final FleetControllerContext context;
- private final int nodeIndex;
private final MasterDataGatherer masterDataGatherer;
// Expected ZK znode versions. Note: these are _not_ -1 as that would match anything.
// We expect the caller to invoke the load methods prior to calling any store methods.
@@ -102,31 +100,30 @@ public class ZooKeeperDatabase extends Database {
}
}
- public ZooKeeperDatabase(FleetControllerContext context, ContentCluster cluster, int nodeIndex, String address, int timeout, DatabaseListener zksl) throws IOException, KeeperException, InterruptedException {
+ public ZooKeeperDatabase(FleetControllerContext context, String address, int timeout, DatabaseListener zksl) throws IOException, KeeperException, InterruptedException {
this.context = context;
- this.nodeIndex = nodeIndex;
- zooKeeperRoot = "/vespa/fleetcontroller/" + cluster.getName() + "/";
+ this.paths = new ZooKeeperPaths(context.id());
session = new ZooKeeper(address, timeout, watcher, new ZkClientConfigBuilder().toConfig());
boolean completedOk = false;
try{
this.listener = zksl;
setupRoot();
context.log(log, Level.FINEST, "Asking for initial data on master election");
- masterDataGatherer = new MasterDataGatherer(session, zooKeeperRoot, listener, nodeIndex);
+ masterDataGatherer = new MasterDataGatherer(session, paths, listener, context.id().index());
completedOk = true;
} finally {
if (!completedOk) session.close();
}
}
- private void createNode(String prefix, String nodename, byte[] value) throws KeeperException, InterruptedException {
+ private void createNode(String path, byte[] value) throws KeeperException, InterruptedException {
try{
- if (session.exists(prefix + nodename, false) != null) {
- context.log(log, Level.FINE, () -> "Zookeeper node '" + prefix + nodename + "' already exists. Not creating it");
+ if (session.exists(path, false) != null) {
+ context.log(log, Level.FINE, () -> "Zookeeper node '" + path + "' already exists. Not creating it");
return;
}
- session.create(prefix + nodename, value, acl, CreateMode.PERSISTENT);
- context.log(log, Level.FINE, () -> "Created zookeeper node '" + prefix + nodename + "'");
+ session.create(path, value, acl, CreateMode.PERSISTENT);
+ context.log(log, Level.FINE, () -> "Created zookeeper node '" + path + "'");
} catch (KeeperException.NodeExistsException e) {
context.log(log, Level.FINE, "Node to create existed, but this is normal as other nodes " +
"may create them at the same time.");
@@ -134,21 +131,21 @@ public class ZooKeeperDatabase extends Database {
}
private void setupRoot() throws KeeperException, InterruptedException {
- String[] pathElements = zooKeeperRoot.substring(1).split("/");
+ String[] pathElements = paths.root().substring(1).split("/");
String path = "";
for (String elem : pathElements) {
path += "/" + elem;
- createNode("", path, new byte[0]);
+ createNode(path, new byte[0]);
}
- createNode(zooKeeperRoot, "indexes", new byte[0]);
- createNode(zooKeeperRoot, "wantedstates", new byte[0]);
- createNode(zooKeeperRoot, "starttimestamps", new byte[0]);
- createNode(zooKeeperRoot, "latestversion", Integer.valueOf(0).toString().getBytes(utf8));
- createNode(zooKeeperRoot, "published_state_bundle", new byte[0]); // TODO dedupe string constants
- byte[] val = String.valueOf(nodeIndex).getBytes(utf8);
- deleteNodeIfExists(getMyIndexPath());
+ createNode(paths.indexesRoot(), new byte[0]);
+ createNode(paths.wantedStates(), new byte[0]);
+ createNode(paths.startTimestamps(), new byte[0]);
+ createNode(paths.latestVersion(), Integer.valueOf(0).toString().getBytes(utf8));
+ createNode(paths.publishedStateBundle(), new byte[0]);
+ byte[] val = String.valueOf(context.id().index()).getBytes(utf8);
+ deleteNodeIfExists(paths.indexOfMe());
context.log(log, Level.INFO, "Creating ephemeral master vote node with vote to self.");
- session.create(getMyIndexPath(), val, acl, CreateMode.EPHEMERAL);
+ session.create(paths.indexOfMe(), val, acl, CreateMode.EPHEMERAL);
}
private void deleteNodeIfExists(String path) throws KeeperException, InterruptedException {
@@ -158,10 +155,6 @@ public class ZooKeeperDatabase extends Database {
}
}
- private String getMyIndexPath() {
- return zooKeeperRoot + "indexes/" + nodeIndex;
- }
-
/**
* If this is called, we assume we're in shutdown situation, or we are doing it because we need a new session.
* Thus we only need to free up resources, no need to notify anyone.
@@ -192,8 +185,8 @@ public class ZooKeeperDatabase extends Database {
public boolean storeMasterVote(int wantedMasterIndex) {
byte[] val = String.valueOf(wantedMasterIndex).getBytes(utf8);
try{
- session.setData(getMyIndexPath(), val, -1);
- context.log(log, Level.INFO, "Stored new vote in ephemeral node. " + nodeIndex + " -> " + wantedMasterIndex);
+ session.setData(paths.indexOfMe(), val, -1);
+ context.log(log, Level.INFO, "Stored new vote in ephemeral node. " + context.id().index() + " -> " + wantedMasterIndex);
return true;
} catch (InterruptedException e) {
throw new RuntimeException(e);
@@ -206,7 +199,7 @@ public class ZooKeeperDatabase extends Database {
byte[] data = Integer.toString(version).getBytes(utf8);
try{
context.log(log, Level.INFO, "Storing new cluster state version in ZooKeeper: " + version);
- var stat = session.setData(zooKeeperRoot + "latestversion", data, lastKnownStateVersionZNodeVersion);
+ var stat = session.setData(paths.latestVersion(), data, lastKnownStateVersionZNodeVersion);
lastKnownStateVersionZNodeVersion = stat.getVersion();
return true;
} catch (InterruptedException e) {
@@ -222,17 +215,17 @@ public class ZooKeeperDatabase extends Database {
public Integer retrieveLatestSystemStateVersion() {
Stat stat = new Stat();
- context.log(log, Level.FINE, "Fetching latest cluster state at '%slatestversion'", zooKeeperRoot);
+ context.log(log, Level.FINE, "Fetching latest cluster state at '%s'", paths.latestVersion());
final byte[] data;
try {
- data = session.getData(zooKeeperRoot + "latestversion", false, stat);
+ data = session.getData(paths.latestVersion(), false, stat);
} catch (KeeperException.NoNodeException e) {
// Initial condition: No latest version has ever been written (or ZK state completely wiped!)
lastKnownStateVersionZNodeVersion = 0;
maybeLogExceptionWarning(e, "No latest system state found");
return null;
} catch (InterruptedException | KeeperException e) {
- throw new RuntimeException("Failed to get " + zooKeeperRoot + "latestversion", e);
+ throw new RuntimeException("Failed to get " + paths.latestVersion(), e);
}
lastKnownStateVersionZNodeVersion = stat.getVersion();
@@ -257,8 +250,8 @@ public class ZooKeeperDatabase extends Database {
}
byte[] val = sb.toString().getBytes(utf8);
try{
- context.log(log, Level.FINE, () -> "Storing wanted states at '" + zooKeeperRoot + "wantedstates'");
- session.setData(zooKeeperRoot + "wantedstates", val, -1);
+ context.log(log, Level.FINE, () -> "Storing wanted states at '" + paths.wantedStates() + "'");
+ session.setData(paths.wantedStates(), val, -1);
return true;
} catch (InterruptedException e) {
throw new RuntimeException(e);
@@ -270,9 +263,9 @@ public class ZooKeeperDatabase extends Database {
public Map<Node, NodeState> retrieveWantedStates() {
try{
- context.log(log, Level.FINE, () -> "Fetching wanted states at '" + zooKeeperRoot + "wantedstates'");
+ context.log(log, Level.FINE, () -> "Fetching wanted states at '" + paths.wantedStates() + "'");
Stat stat = new Stat();
- byte[] data = session.getData(zooKeeperRoot + "wantedstates", false, stat);
+ byte[] data = session.getData(paths.wantedStates(), false, stat);
Map<Node, NodeState> wanted = new TreeMap<>();
if (data != null && data.length > 0) {
StringTokenizer st = new StringTokenizer(new String(data, utf8), "\n", false);
@@ -308,8 +301,8 @@ public class ZooKeeperDatabase extends Database {
}
byte val[] = sb.toString().getBytes(utf8);
try{
- context.log(log, Level.FINE, () -> "Storing start timestamps at '" + zooKeeperRoot + "starttimestamps");
- session.setData(zooKeeperRoot + "starttimestamps", val, -1);
+ context.log(log, Level.FINE, () -> "Storing start timestamps at '" + paths.startTimestamps() + "'");
+ session.setData(paths.startTimestamps(), val, -1);
return true;
} catch (InterruptedException e) {
throw new RuntimeException(e);
@@ -322,9 +315,9 @@ public class ZooKeeperDatabase extends Database {
@Override
public Map<Node, Long> retrieveStartTimestamps() {
try{
- context.log(log, Level.FINE, () -> "Fetching start timestamps at '" + zooKeeperRoot + "starttimestamps'");
+ context.log(log, Level.FINE, () -> "Fetching start timestamps at '" + paths.startTimestamps() + "'");
Stat stat = new Stat();
- byte[] data = session.getData(zooKeeperRoot + "starttimestamps", false, stat);
+ byte[] data = session.getData(paths.startTimestamps(), false, stat);
Map<Node, Long> wanted = new TreeMap<Node, Long>();
if (data != null && data.length > 0) {
StringTokenizer st = new StringTokenizer(new String(data, utf8), "\n", false);
@@ -357,10 +350,9 @@ public class ZooKeeperDatabase extends Database {
try{
context.log(log,
Level.FINE,
- () -> String.format("Storing published state bundle %s at " +
- "'%spublished_state_bundle' with expected znode version %d",
- stateBundle, zooKeeperRoot, lastKnownStateBundleZNodeVersion));
- var stat = session.setData(zooKeeperRoot + "published_state_bundle", encodedBundle, lastKnownStateBundleZNodeVersion);
+ () -> String.format("Storing published state bundle %s at '%s' with expected znode version %d",
+ stateBundle, paths.publishedStateBundle(), lastKnownStateBundleZNodeVersion));
+ var stat = session.setData(paths.publishedStateBundle(), encodedBundle, lastKnownStateBundleZNodeVersion);
lastKnownStateBundleZNodeVersion = stat.getVersion();
} catch (InterruptedException e) {
throw new RuntimeException(e);
@@ -378,7 +370,7 @@ public class ZooKeeperDatabase extends Database {
public ClusterStateBundle retrieveLastPublishedStateBundle() {
Stat stat = new Stat();
try {
- byte[] data = session.getData(zooKeeperRoot + "published_state_bundle", false, stat);
+ byte[] data = session.getData(paths.publishedStateBundle(), false, stat);
lastKnownStateBundleZNodeVersion = stat.getVersion();
if (data != null && data.length != 0) {
EnvelopedClusterStateBundleCodec envelopedBundleCodec = new SlimeClusterStateBundleCodec();
diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/database/ZooKeeperDatabaseFactory.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/database/ZooKeeperDatabaseFactory.java
index 71f39135609..3263c06a95c 100644
--- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/database/ZooKeeperDatabaseFactory.java
+++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/database/ZooKeeperDatabaseFactory.java
@@ -13,8 +13,7 @@ public class ZooKeeperDatabaseFactory implements DatabaseFactory {
@Override
public Database create(Params params) throws Exception {
- return new ZooKeeperDatabase(context, params.cluster, params.nodeIndex, params.dbAddress,
- params.dbSessionTimeout, params.listener);
+ return new ZooKeeperDatabase(context, params.dbAddress, params.dbSessionTimeout, params.listener);
}
}
diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/database/ZooKeeperPaths.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/database/ZooKeeperPaths.java
new file mode 100644
index 00000000000..06a9b240175
--- /dev/null
+++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/database/ZooKeeperPaths.java
@@ -0,0 +1,26 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.clustercontroller.core.database;
+
+import com.yahoo.vespa.clustercontroller.core.FleetControllerId;
+
+/**
+ * @author hakonhall
+ */
+public class ZooKeeperPaths {
+ private final String root;
+ private final int myIndex;
+
+ public ZooKeeperPaths(FleetControllerId id) {
+ this.root = "/vespa/fleetcontroller/" + id.clusterName();
+ this.myIndex = id.index();
+ }
+
+ public String root() { return root; }
+ public String indexesRoot() { return root + "/indexes"; }
+ public String indexOf(int index) { return indexesRoot() + "/" + index; }
+ public String indexOfMe() { return indexOf(myIndex); }
+ public String wantedStates() { return root + "/wantedstates"; }
+ public String publishedStateBundle() { return root + "/published_state_bundle"; }
+ public String latestVersion() { return root + "/latestversion"; }
+ public String startTimestamps() { return root + "/starttimestamps"; }
+}
diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/listeners/NodeListener.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/listeners/NodeListener.java
new file mode 100644
index 00000000000..351b68b3b57
--- /dev/null
+++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/listeners/NodeListener.java
@@ -0,0 +1,25 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.clustercontroller.core.listeners;
+
+import com.yahoo.vdslib.state.Node;
+import com.yahoo.vdslib.state.NodeState;
+import com.yahoo.vespa.clustercontroller.core.NodeInfo;
+import com.yahoo.vespa.clustercontroller.core.hostinfo.HostInfo;
+
+/**
+ * Implemented by classes wanting events when there are node changes.
+ */
+public interface NodeListener {
+
+ default void handleNewNodeState(NodeInfo currentInfo, NodeState newState) {}
+ default void handleNewWantedNodeState(NodeInfo node, NodeState newState) {}
+
+ /** Invoked after NodeInfo has been removed from the content cluster. */
+ default void handleRemovedNode(Node node) {}
+
+ /**
+ * For every getnodestate RPC call, handleUpdatedHostInfo() will be called with the host info JSON string.
+ */
+ default void handleUpdatedHostInfo(NodeInfo node, HostInfo newHostInfo) {}
+
+}
diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/listeners/NodeStateOrHostInfoChangeHandler.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/listeners/NodeStateOrHostInfoChangeHandler.java
deleted file mode 100644
index b76b46b216b..00000000000
--- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/listeners/NodeStateOrHostInfoChangeHandler.java
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.clustercontroller.core.listeners;
-
-import com.yahoo.vdslib.state.NodeState;
-import com.yahoo.vespa.clustercontroller.core.NodeInfo;
-import com.yahoo.vespa.clustercontroller.core.hostinfo.HostInfo;
-
-/**
- * Implemented by classes wanting events when node states changes.
- */
-public interface NodeStateOrHostInfoChangeHandler {
-
- void handleNewNodeState(NodeInfo currentInfo, NodeState newState);
- void handleNewWantedNodeState(NodeInfo node, NodeState newState);
-
- /**
- * For every getnodestate RPC call, handleUpdatedHostInfo() will be called with the host info JSON string.
- */
- void handleUpdatedHostInfo(NodeInfo node, HostInfo newHostInfo);
-
-}
diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/listeners/NodeAddedOrRemovedListener.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/listeners/SlobrokListener.java
index d811708c999..5a397cc4935 100644
--- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/listeners/NodeAddedOrRemovedListener.java
+++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/listeners/SlobrokListener.java
@@ -4,9 +4,9 @@ package com.yahoo.vespa.clustercontroller.core.listeners;
import com.yahoo.vespa.clustercontroller.core.NodeInfo;
/**
- * Listeners for new nodes detected.
+ * Implemented by classes that wants to be notified of Slobrok events.
*/
-public interface NodeAddedOrRemovedListener {
+public interface SlobrokListener {
void handleNewNode(NodeInfo node);
void handleMissingNode(NodeInfo node);
void handleNewRpcAddress(NodeInfo node);
diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/restapiv2/requests/SetNodeStateRequest.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/restapiv2/requests/SetNodeStateRequest.java
index 431c207af5c..ddbda2bf776 100644
--- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/restapiv2/requests/SetNodeStateRequest.java
+++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/restapiv2/requests/SetNodeStateRequest.java
@@ -11,7 +11,7 @@ import com.yahoo.vespa.clustercontroller.core.ContentCluster;
import com.yahoo.vespa.clustercontroller.core.NodeInfo;
import com.yahoo.vespa.clustercontroller.core.NodeStateChangeChecker;
import com.yahoo.vespa.clustercontroller.core.RemoteClusterControllerTask;
-import com.yahoo.vespa.clustercontroller.core.listeners.NodeStateOrHostInfoChangeHandler;
+import com.yahoo.vespa.clustercontroller.core.listeners.NodeListener;
import com.yahoo.vespa.clustercontroller.core.restapiv2.Id;
import com.yahoo.vespa.clustercontroller.core.restapiv2.MissingIdException;
import com.yahoo.vespa.clustercontroller.core.restapiv2.Request;
@@ -62,7 +62,7 @@ public class SetNodeStateRequest extends Request<SetResponse> {
condition,
newStates,
id.getNode(),
- context.nodeStateOrHostInfoChangeHandler,
+ context.nodeListener,
context.currentConsolidatedState,
context.masterInfo.inMasterMoratorium(),
probe);
@@ -112,7 +112,7 @@ public class SetNodeStateRequest extends Request<SetResponse> {
SetUnitStateRequest.Condition condition,
Map<String, UnitState> newStates,
Node node,
- NodeStateOrHostInfoChangeHandler stateListener,
+ NodeListener stateListener,
ClusterState currentClusterState,
boolean inMasterMoratorium,
boolean probe) throws StateRestApiException {
@@ -159,7 +159,7 @@ public class SetNodeStateRequest extends Request<SetResponse> {
SetUnitStateRequest.Condition condition,
NodeInfo nodeInfo,
ContentCluster cluster,
- NodeStateOrHostInfoChangeHandler stateListener,
+ NodeListener stateListener,
boolean probe) {
if (result.settingWantedStateIsAllowed()) {
setNewWantedState(nodeInfo, newWantedState, stateListener, probe);
@@ -186,7 +186,7 @@ public class SetNodeStateRequest extends Request<SetResponse> {
private static void setDistributorWantedState(ContentCluster cluster,
int index,
NodeState newStorageWantedState,
- NodeStateOrHostInfoChangeHandler stateListener,
+ NodeListener stateListener,
boolean probe) {
Node distributorNode = new Node(NodeType.DISTRIBUTOR, index);
NodeInfo nodeInfo = cluster.getNodeInfo(distributorNode);
@@ -224,7 +224,7 @@ public class SetNodeStateRequest extends Request<SetResponse> {
private static void setNewWantedState(NodeInfo nodeInfo,
NodeState newWantedState,
- NodeStateOrHostInfoChangeHandler stateListener,
+ NodeListener stateListener,
boolean probe) {
if (probe) return;
nodeInfo.setWantedState(newWantedState);
diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/restapiv2/requests/SetNodeStatesForClusterRequest.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/restapiv2/requests/SetNodeStatesForClusterRequest.java
index 55ac75957bc..1cc8f2860c6 100644
--- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/restapiv2/requests/SetNodeStatesForClusterRequest.java
+++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/restapiv2/requests/SetNodeStatesForClusterRequest.java
@@ -70,7 +70,7 @@ public class SetNodeStatesForClusterRequest extends Request<SetResponse> {
condition,
newStates,
node,
- context.nodeStateOrHostInfoChangeHandler,
+ context.nodeListener,
context.currentConsolidatedState,
context.masterInfo.inMasterMoratorium(),
probe);
diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/restapiv2/requests/WantedStateSetter.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/restapiv2/requests/WantedStateSetter.java
index 8095d37d641..51b2f1cfe4f 100644
--- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/restapiv2/requests/WantedStateSetter.java
+++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/restapiv2/requests/WantedStateSetter.java
@@ -4,7 +4,7 @@ package com.yahoo.vespa.clustercontroller.core.restapiv2.requests;
import com.yahoo.vdslib.state.ClusterState;
import com.yahoo.vdslib.state.Node;
import com.yahoo.vespa.clustercontroller.core.ContentCluster;
-import com.yahoo.vespa.clustercontroller.core.listeners.NodeStateOrHostInfoChangeHandler;
+import com.yahoo.vespa.clustercontroller.core.listeners.NodeListener;
import com.yahoo.vespa.clustercontroller.utils.staterestapi.errors.StateRestApiException;
import com.yahoo.vespa.clustercontroller.utils.staterestapi.requests.SetUnitStateRequest;
import com.yahoo.vespa.clustercontroller.utils.staterestapi.response.SetResponse;
@@ -21,7 +21,7 @@ public interface WantedStateSetter {
SetUnitStateRequest.Condition condition,
Map<String, UnitState> newStates,
Node node,
- NodeStateOrHostInfoChangeHandler stateListener,
+ NodeListener stateListener,
ClusterState currentClusterState,
boolean inMasterMoratorium,
boolean probe) throws StateRestApiException;
diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/rpc/RpcServer.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/rpc/RpcServer.java
index 65c8a9df28e..6e416ce4906 100644
--- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/rpc/RpcServer.java
+++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/rpc/RpcServer.java
@@ -27,8 +27,8 @@ import com.yahoo.vespa.clustercontroller.core.ContentCluster;
import com.yahoo.vespa.clustercontroller.core.MasterElectionHandler;
import com.yahoo.vespa.clustercontroller.core.NodeInfo;
import com.yahoo.vespa.clustercontroller.core.Timer;
-import com.yahoo.vespa.clustercontroller.core.listeners.NodeAddedOrRemovedListener;
-import com.yahoo.vespa.clustercontroller.core.listeners.NodeStateOrHostInfoChangeHandler;
+import com.yahoo.vespa.clustercontroller.core.listeners.SlobrokListener;
+import com.yahoo.vespa.clustercontroller.core.listeners.NodeListener;
import java.io.PrintWriter;
import java.io.StringWriter;
@@ -186,8 +186,8 @@ public class RpcServer {
}
public boolean handleRpcRequests(ContentCluster cluster, ClusterState systemState,
- NodeStateOrHostInfoChangeHandler changeListener,
- NodeAddedOrRemovedListener addedListener)
+ NodeListener changeListener,
+ SlobrokListener addedListener)
{
boolean handledAnyRequests = false;
if (!isConnected()) {
@@ -234,7 +234,7 @@ public class RpcServer {
log.log(Level.FINE, "Resolving RPC getNodeList request");
List<String> slobrok = new ArrayList<String>();
List<String> rpc = new ArrayList<String>();
- for(NodeInfo node : cluster.getNodeInfo()) {
+ for(NodeInfo node : cluster.getNodeInfos()) {
String s1 = node.getSlobrokAddress();
String s2 = node.getRpcAddress();
assert(s1 != null);
diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/rpc/SlobrokClient.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/rpc/SlobrokClient.java
index 7487f9546b7..c88bf71af09 100644
--- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/rpc/SlobrokClient.java
+++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/rpc/SlobrokClient.java
@@ -13,7 +13,7 @@ import com.yahoo.vespa.clustercontroller.core.FleetControllerContext;
import com.yahoo.vespa.clustercontroller.core.NodeInfo;
import com.yahoo.vespa.clustercontroller.core.NodeLookup;
import com.yahoo.vespa.clustercontroller.core.Timer;
-import com.yahoo.vespa.clustercontroller.core.listeners.NodeAddedOrRemovedListener;
+import com.yahoo.vespa.clustercontroller.core.listeners.SlobrokListener;
import java.util.Iterator;
import java.util.LinkedList;
@@ -78,7 +78,7 @@ public class SlobrokClient implements NodeLookup {
}
@Override
- public boolean updateCluster(ContentCluster cluster, NodeAddedOrRemovedListener listener) {
+ public boolean updateCluster(ContentCluster cluster, SlobrokListener listener) {
if (mirror == null) return false;
int mirrorVersion = mirror.updates();
if (freshMirror) {
@@ -149,7 +149,7 @@ public class SlobrokClient implements NodeLookup {
}
}
cluster.setSlobrokGenerationCount(mirrorVersion);
- for (NodeInfo nodeInfo : cluster.getNodeInfo()) {
+ for (NodeInfo nodeInfo : cluster.getNodeInfos()) {
if (slobrokNodes.containsKey(nodeInfo.getNode()) && nodeInfo.isRpcAddressOutdated()) {
context.log(log,
Level.WARNING,
@@ -174,7 +174,7 @@ public class SlobrokClient implements NodeLookup {
List<SlobrokData> alteredRpcAddress,
List<NodeInfo> returningRpcAddressNodeInfos)
{
- Iterator<NodeInfo> oldIt = oldCluster.getNodeInfo().iterator();
+ Iterator<NodeInfo> oldIt = oldCluster.getNodeInfos().iterator();
Iterator<SlobrokData> newIt = slobrokNodes.values().iterator();
NodeInfo oldNext = null;
SlobrokData newNext = null;
diff --git a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/ClusterFixture.java b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/ClusterFixture.java
index 4ce32484098..f8d41405e85 100644
--- a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/ClusterFixture.java
+++ b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/ClusterFixture.java
@@ -8,7 +8,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.clustercontroller.core.listeners.NodeStateOrHostInfoChangeHandler;
+import com.yahoo.vespa.clustercontroller.core.listeners.NodeListener;
import java.util.Collection;
import java.util.HashSet;
@@ -57,7 +57,7 @@ public class ClusterFixture {
private void doReportNodeState(final Node node, final NodeState nodeState) {
final ClusterState stateBefore = rawGeneratedClusterState();
- NodeStateOrHostInfoChangeHandler handler = mock(NodeStateOrHostInfoChangeHandler.class);
+ NodeListener handler = mock(NodeListener.class);
NodeInfo nodeInfo = cluster.getNodeInfo(node);
nodeStateChangeHandler.handleNewReportedNodeState(stateBefore, nodeInfo, nodeState, handler);
@@ -142,7 +142,7 @@ public class ClusterFixture {
}
public ClusterFixture assignDummyRpcAddresses() {
- cluster.getNodeInfo().forEach(ni -> {
+ cluster.getNodeInfos().forEach(ni -> {
ni.setRpcAddress(String.format("tcp/%s.%d.local:0",
ni.isStorage() ? "storage" : "distributor",
ni.getNodeIndex()));
@@ -169,7 +169,7 @@ public class ClusterFixture {
Set<ConfiguredNode> configuredNodes = new HashSet<>(cluster.getConfiguredNodes().values());
configuredNodes.remove(new ConfiguredNode(nodeIndex, false));
configuredNodes.add(new ConfiguredNode(nodeIndex, true));
- cluster.setNodes(configuredNodes);
+ cluster.setNodes(configuredNodes, new NodeListener() {});
return this;
}
diff --git a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/DatabaseHandlerTest.java b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/DatabaseHandlerTest.java
index a621b0f565a..1f7b9293960 100644
--- a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/DatabaseHandlerTest.java
+++ b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/DatabaseHandlerTest.java
@@ -1,23 +1,42 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.clustercontroller.core;
+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.clustercontroller.core.database.Database;
import com.yahoo.vespa.clustercontroller.core.database.DatabaseFactory;
import com.yahoo.vespa.clustercontroller.core.database.DatabaseHandler;
-import com.yahoo.vespa.clustercontroller.core.listeners.NodeAddedOrRemovedListener;
-import com.yahoo.vespa.clustercontroller.core.listeners.NodeStateOrHostInfoChangeHandler;
+import com.yahoo.vespa.clustercontroller.core.listeners.NodeListener;
+import com.yahoo.vespa.clustercontroller.core.listeners.SlobrokListener;
+import org.junit.After;
+import org.junit.Before;
import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Map;
+import java.util.TreeMap;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class DatabaseHandlerTest {
+ private AutoCloseable openMock = null;
+
+ @Captor
+ ArgumentCaptor<TreeMap<Node, NodeState>> wantedStatesArgument;
+
static class Fixture {
final ClusterFixture clusterFixture = ClusterFixture.forFlatCluster(10);
final FleetController mockController = mock(FleetController.class);
@@ -52,12 +71,12 @@ public class DatabaseHandlerTest {
}
@Override
- public NodeAddedOrRemovedListener getNodeAddedOrRemovedListener() {
+ public SlobrokListener getNodeAddedOrRemovedListener() {
return null;
}
@Override
- public NodeStateOrHostInfoChangeHandler getNodeStateUpdateListener() {
+ public NodeListener getNodeStateUpdateListener() {
return null;
}
};
@@ -70,6 +89,16 @@ public class DatabaseHandlerTest {
}
}
+ @Before
+ public void setUp() {
+ openMock = MockitoAnnotations.openMocks(this);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ openMock.close();
+ }
+
@Test
public void can_store_latest_cluster_state_bundle() throws Exception {
Fixture f = new Fixture();
@@ -104,4 +133,29 @@ public class DatabaseHandlerTest {
assertEquals(ClusterStateBundle.empty(), retrievedBundle);
}
+ @Test
+ public void save_wanted_state_of_configured_nodes() throws Exception {
+ var fixture = new Fixture();
+ DatabaseHandler handler = fixture.createHandler();
+ DatabaseHandler.DatabaseContext databaseContext = fixture.createMockContext();
+
+ // The test fixture contains 10 nodes with indices 1-10. A wanted state for
+ // an existing node (5) should be preserved. Note that it is not possible to set a
+ // wanted state outside the existing nodes.
+ Node storageNode5 = Node.ofStorage(5);
+ NodeState maintenance = new NodeState(NodeType.STORAGE, State.MAINTENANCE);
+ databaseContext.getCluster().getNodeInfo(storageNode5).setWantedState(maintenance);
+ var expectedWantedStates = new TreeMap<>(Map.of(storageNode5, maintenance));
+
+ // Ensure database is connected to ZooKeeper
+ assertTrue(handler.doNextZooKeeperTask(databaseContext));
+
+ // Verify ZooKeeperDatabase::storeWantedStates is invoked once
+ verify(fixture.mockDatabase, times(0)).storeWantedStates(any());
+ assertTrue(handler.saveWantedStates(databaseContext));
+ verify(fixture.mockDatabase, times(1)).storeWantedStates(wantedStatesArgument.capture());
+
+ // Verify ZooKeeperDatabase::storeWantedStates only saves states for existing nodes
+ assertEquals(expectedWantedStates, wantedStatesArgument.getValue());
+ }
}
diff --git a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/DummyCommunicator.java b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/DummyCommunicator.java
index 3c232a7c52b..3127201a342 100644
--- a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/DummyCommunicator.java
+++ b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/DummyCommunicator.java
@@ -6,7 +6,7 @@ import com.yahoo.vdslib.state.ClusterState;
import com.yahoo.vdslib.state.Node;
import com.yahoo.vdslib.state.NodeState;
import com.yahoo.vdslib.state.State;
-import com.yahoo.vespa.clustercontroller.core.listeners.NodeAddedOrRemovedListener;
+import com.yahoo.vespa.clustercontroller.core.listeners.SlobrokListener;
import java.util.ArrayList;
import java.util.List;
@@ -133,14 +133,14 @@ public class DummyCommunicator implements Communicator, NodeLookup {
}
@Override
- public boolean updateCluster(ContentCluster cluster, NodeAddedOrRemovedListener listener) {
+ public boolean updateCluster(ContentCluster cluster, SlobrokListener listener) {
if (newNodes != null) {
List<Node> tmp = newNodes;
for (Node node : tmp)
cluster.clusterInfo().setRpcAddress(node, "foo");
- for (NodeInfo info : cluster.getNodeInfo()) {
+ for (NodeInfo info : cluster.getNodeInfos()) {
if (!tmp.contains(info.getNode())) {
info.markRpcAddressOutdated(timer);
listener.handleMissingNode(info);
diff --git a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/GroupAutoTakedownTest.java b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/GroupAutoTakedownTest.java
index 254f863e9ea..1d4b2a73560 100644
--- a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/GroupAutoTakedownTest.java
+++ b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/GroupAutoTakedownTest.java
@@ -7,20 +7,19 @@ import com.yahoo.vdslib.state.NodeState;
import com.yahoo.vdslib.state.NodeType;
import com.yahoo.vdslib.state.State;
import com.yahoo.vespa.clustercontroller.core.database.DatabaseHandler;
-import com.yahoo.vespa.clustercontroller.core.listeners.NodeStateOrHostInfoChangeHandler;
-
-import static com.yahoo.vespa.clustercontroller.core.matchers.EventForNode.eventForNode;
-import static com.yahoo.vespa.clustercontroller.core.matchers.NodeEventWithDescription.nodeEventWithDescription;
+import com.yahoo.vespa.clustercontroller.core.listeners.NodeListener;
import org.junit.Test;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import static com.yahoo.vespa.clustercontroller.core.matchers.EventForNode.eventForNode;
+import static com.yahoo.vespa.clustercontroller.core.matchers.NodeEventWithDescription.nodeEventWithDescription;
+import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.AllOf.allOf;
import static org.hamcrest.core.IsCollectionContaining.hasItem;
import static org.junit.Assert.assertEquals;
-import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -179,7 +178,7 @@ public class GroupAutoTakedownTest {
// However, once grace period expires the group should be taken down.
fixture.timer.advanceTime(1001);
- NodeStateOrHostInfoChangeHandler changeListener = mock(NodeStateOrHostInfoChangeHandler.class);
+ NodeListener changeListener = mock(NodeListener.class);
fixture.nodeStateChangeHandler.watchTimers(
fixture.cluster, fixture.annotatedGeneratedClusterState().getClusterState(), changeListener);
@@ -253,7 +252,7 @@ public class GroupAutoTakedownTest {
nodes.add(new ConfiguredNode(5, true));
// TODO this should ideally also set the retired flag in the distribution
// config, but only the ConfiguredNodes are actually looked at currently.
- fixture.cluster.setNodes(nodes);
+ fixture.cluster.setNodes(nodes, new NodeListener() {});
assertEquals("distributor:6 storage:6 .4.s:d .5.s:r",
stateAfterStorageTransition(fixture, 5, State.UP));
diff --git a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/ResourceExhaustionCalculatorTest.java b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/ResourceExhaustionCalculatorTest.java
index 7e02f63d56e..e136ddfa72d 100644
--- a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/ResourceExhaustionCalculatorTest.java
+++ b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/ResourceExhaustionCalculatorTest.java
@@ -23,7 +23,7 @@ public class ResourceExhaustionCalculatorTest {
var calc = new ResourceExhaustionCalculator(true, mapOf(usage("disk", 0.5), usage("memory", 0.8)));
var cf = createFixtureWithReportedUsages(forNode(1, usage("disk", 0.49), usage("memory", 0.79)),
forNode(2, usage("disk", 0.4), usage("memory", 0.6)));
- var feedBlock = calc.inferContentClusterFeedBlockOrNull(cf.cluster().getNodeInfo());
+ var feedBlock = calc.inferContentClusterFeedBlockOrNull(cf.cluster().getNodeInfos());
assertNull(feedBlock);
}
@@ -32,7 +32,7 @@ public class ResourceExhaustionCalculatorTest {
var calc = new ResourceExhaustionCalculator(true, mapOf(usage("disk", 0.5), usage("memory", 0.8)));
var cf = createFixtureWithReportedUsages(forNode(1, usage("disk", 0.51), usage("memory", 0.79)),
forNode(2, usage("disk", 0.4), usage("memory", 0.6)));
- var feedBlock = calc.inferContentClusterFeedBlockOrNull(cf.cluster().getNodeInfo());
+ var feedBlock = calc.inferContentClusterFeedBlockOrNull(cf.cluster().getNodeInfos());
assertNotNull(feedBlock);
assertTrue(feedBlock.blockFeedInCluster());
assertEquals("disk on node 1 [storage.1.local] (0.510 > 0.500)", feedBlock.getDescription());
@@ -43,7 +43,7 @@ public class ResourceExhaustionCalculatorTest {
var calc = new ResourceExhaustionCalculator(true, mapOf(usage("disk", 0.5), usage("memory", 0.8)));
var cf = createFixtureWithReportedUsages(forNode(1, usage("disk", "a-fancy-disk", 0.51), usage("memory", 0.79)),
forNode(2, usage("disk", 0.4), usage("memory", 0.6)));
- var feedBlock = calc.inferContentClusterFeedBlockOrNull(cf.cluster().getNodeInfo());
+ var feedBlock = calc.inferContentClusterFeedBlockOrNull(cf.cluster().getNodeInfos());
assertNotNull(feedBlock);
assertTrue(feedBlock.blockFeedInCluster());
assertEquals("disk:a-fancy-disk on node 1 [storage.1.local] (0.510 > 0.500)", feedBlock.getDescription());
@@ -56,7 +56,7 @@ public class ResourceExhaustionCalculatorTest {
forNode(2, usage("disk", 0.4), usage("memory", 0.85)));
cf.cluster().getNodeInfo(storageNode(1)).setRpcAddress(null);
cf.cluster().getNodeInfo(storageNode(2)).setRpcAddress("max mekker");
- var feedBlock = calc.inferContentClusterFeedBlockOrNull(cf.cluster().getNodeInfo());
+ var feedBlock = calc.inferContentClusterFeedBlockOrNull(cf.cluster().getNodeInfos());
assertNotNull(feedBlock);
assertTrue(feedBlock.blockFeedInCluster());
assertEquals("disk on node 1 [unknown hostname] (0.510 > 0.500), " +
@@ -68,7 +68,7 @@ public class ResourceExhaustionCalculatorTest {
var calc = new ResourceExhaustionCalculator(true, mapOf(usage("disk", 0.4), usage("memory", 0.8)));
var cf = createFixtureWithReportedUsages(forNode(1, usage("disk", 0.51), usage("memory", 0.85)),
forNode(2, usage("disk", 0.45), usage("memory", 0.6)));
- var feedBlock = calc.inferContentClusterFeedBlockOrNull(cf.cluster().getNodeInfo());
+ var feedBlock = calc.inferContentClusterFeedBlockOrNull(cf.cluster().getNodeInfos());
assertNotNull(feedBlock);
assertTrue(feedBlock.blockFeedInCluster());
assertEquals("disk on node 1 [storage.1.local] (0.510 > 0.400), " +
@@ -83,7 +83,7 @@ public class ResourceExhaustionCalculatorTest {
var cf = createFixtureWithReportedUsages(forNode(1, usage("disk", 0.51), usage("memory", 0.85)),
forNode(2, usage("disk", 0.45), usage("memory", 0.6)),
forNode(3, usage("disk", 0.6), usage("memory", 0.9)));
- var feedBlock = calc.inferContentClusterFeedBlockOrNull(cf.cluster().getNodeInfo());
+ var feedBlock = calc.inferContentClusterFeedBlockOrNull(cf.cluster().getNodeInfos());
assertNotNull(feedBlock);
assertTrue(feedBlock.blockFeedInCluster());
assertEquals("disk on node 1 [storage.1.local] (0.510 > 0.400), " +
@@ -97,7 +97,7 @@ public class ResourceExhaustionCalculatorTest {
var calc = new ResourceExhaustionCalculator(false, mapOf(usage("disk", 0.5), usage("memory", 0.8)));
var cf = createFixtureWithReportedUsages(forNode(1, usage("disk", 0.51), usage("memory", 0.79)),
forNode(2, usage("disk", 0.4), usage("memory", 0.6)));
- var feedBlock = calc.inferContentClusterFeedBlockOrNull(cf.cluster().getNodeInfo());
+ var feedBlock = calc.inferContentClusterFeedBlockOrNull(cf.cluster().getNodeInfos());
assertNull(feedBlock);
}
@@ -109,7 +109,7 @@ public class ResourceExhaustionCalculatorTest {
// Node 2 is at 0.49 but was not previously blocked and should not be blocked now either.
var cf = createFixtureWithReportedUsages(forNode(1, usage("disk", 0.3), usage("memory", 0.49)),
forNode(2, usage("disk", 0.3), usage("memory", 0.49)));
- var feedBlock = calc.inferContentClusterFeedBlockOrNull(cf.cluster().getNodeInfo());
+ var feedBlock = calc.inferContentClusterFeedBlockOrNull(cf.cluster().getNodeInfos());
assertNotNull(feedBlock);
// TODO should we not change the limits themselves? Explicit mention of hysteresis state?
assertEquals("memory on node 1 [storage.1.local] (0.490 > 0.400)",
@@ -124,7 +124,7 @@ public class ResourceExhaustionCalculatorTest {
// Node 2 is at 0.49 but was not previously blocked and should not be blocked now either.
var cf = createFixtureWithReportedUsages(forNode(1, usage("disk", 0.3), usage("memory", 0.48)),
forNode(2, usage("disk", 0.3), usage("memory", 0.49)));
- var feedBlock = calc.inferContentClusterFeedBlockOrNull(cf.cluster().getNodeInfo());
+ var feedBlock = calc.inferContentClusterFeedBlockOrNull(cf.cluster().getNodeInfos());
assertNotNull(feedBlock);
assertEquals("memory on node 1 [storage.1.local] (0.480 > 0.400)",
feedBlock.getDescription());
@@ -138,7 +138,7 @@ public class ResourceExhaustionCalculatorTest {
// Node 2 is at 0.49 but was not previously blocked and should not be blocked now either.
var cf = createFixtureWithReportedUsages(forNode(1, usage("disk", 0.3), usage("memory", 0.39)),
forNode(2, usage("disk", 0.3), usage("memory", 0.49)));
- var feedBlock = calc.inferContentClusterFeedBlockOrNull(cf.cluster().getNodeInfo());
+ var feedBlock = calc.inferContentClusterFeedBlockOrNull(cf.cluster().getNodeInfos());
assertNull(feedBlock);
}
@@ -149,7 +149,7 @@ public class ResourceExhaustionCalculatorTest {
forNode(2, usage("disk", 0.6), usage("memory", 0.6)));
cf.reportStorageNodeState(1, State.DOWN);
cf.reportStorageNodeState(2, State.DOWN);
- var feedBlock = calc.inferContentClusterFeedBlockOrNull(cf.cluster().getNodeInfo());
+ var feedBlock = calc.inferContentClusterFeedBlockOrNull(cf.cluster().getNodeInfos());
assertNull(feedBlock);
}
@@ -160,7 +160,7 @@ public class ResourceExhaustionCalculatorTest {
forNode(2, usage("disk", 0.6), usage("memory", 0.6)));
cf.proposeStorageNodeWantedState(1, State.DOWN);
cf.proposeStorageNodeWantedState(2, State.MAINTENANCE);
- var feedBlock = calc.inferContentClusterFeedBlockOrNull(cf.cluster().getNodeInfo());
+ var feedBlock = calc.inferContentClusterFeedBlockOrNull(cf.cluster().getNodeInfos());
assertNull(feedBlock);
}
diff --git a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/ResourceUsageStatsTest.java b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/ResourceUsageStatsTest.java
index 3a5f9954a20..2eeaf7658ff 100644
--- a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/ResourceUsageStatsTest.java
+++ b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/ResourceUsageStatsTest.java
@@ -66,7 +66,7 @@ public class ResourceUsageStatsTest {
}
private static Collection<NodeInfo> createNodeInfo(FeedBlockUtil.NodeAndUsages... nodeAndUsages) {
- return createFixtureWithReportedUsages(nodeAndUsages).cluster().getNodeInfo();
+ return createFixtureWithReportedUsages(nodeAndUsages).cluster().getNodeInfos();
}
private static Map<String, Double> createFeedBlockLimits(double diskLimit, double memoryLimit) {
diff --git a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/SlobrokTest.java b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/SlobrokTest.java
index 5395048cad9..47ba7e1cb77 100644
--- a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/SlobrokTest.java
+++ b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/SlobrokTest.java
@@ -99,7 +99,7 @@ public class SlobrokTest extends FleetControllerTest {
private boolean clusterAvailable() {
boolean ok = true;
ContentCluster cluster = fleetController.getCluster();
- for (NodeInfo info : cluster.getNodeInfo()) {
+ for (NodeInfo info : cluster.getNodeInfos()) {
if (info.getConnectionAttemptCount() > 0) ok = false;
if (info.getLatestNodeStateRequestTime() == null) ok = false;
}
@@ -107,7 +107,7 @@ public class SlobrokTest extends FleetControllerTest {
}
private void assertClusterAvailable() {
ContentCluster cluster = fleetController.getCluster();
- for (NodeInfo info : cluster.getNodeInfo()) {
+ for (NodeInfo info : cluster.getNodeInfos()) {
assertEquals("Node " + info + " connection attempts.", 0, info.getConnectionAttemptCount());
assertTrue("Node " + info + " has no last request time.", info.getLatestNodeStateRequestTime() != 0);
}
diff --git a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/StateChangeHandlerTest.java b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/StateChangeHandlerTest.java
index 95c097c5920..699a35a190c 100644
--- a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/StateChangeHandlerTest.java
+++ b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/StateChangeHandlerTest.java
@@ -9,7 +9,7 @@ import com.yahoo.vdslib.state.NodeState;
import com.yahoo.vdslib.state.NodeType;
import com.yahoo.vdslib.state.State;
import com.yahoo.vespa.clustercontroller.core.hostinfo.HostInfo;
-import com.yahoo.vespa.clustercontroller.core.listeners.NodeStateOrHostInfoChangeHandler;
+import com.yahoo.vespa.clustercontroller.core.listeners.NodeListener;
import com.yahoo.vespa.clustercontroller.core.mocks.TestEventLog;
import com.yahoo.vespa.clustercontroller.core.testutils.LogFormatter;
import org.junit.Before;
@@ -34,7 +34,7 @@ public class StateChangeHandlerTest {
int maxPrematureCrashes = 3;
}
- private static class TestNodeStateOrHostInfoChangeHandler implements NodeStateOrHostInfoChangeHandler {
+ private static class TestNodeListener implements NodeListener {
LinkedList<String> events = new LinkedList<>();
@@ -49,6 +49,11 @@ public class StateChangeHandlerTest {
}
@Override
+ public void handleRemovedNode(Node node) {
+ events.add("removed: " + node);
+ }
+
+ @Override
public void handleUpdatedHostInfo(NodeInfo node, HostInfo newHostInfo) {
events.add(node + " - " + newHostInfo);
}
@@ -68,7 +73,7 @@ public class StateChangeHandlerTest {
private Config config;
private ContentCluster cluster;
private StateChangeHandler nodeStateChangeHandler;
- private TestNodeStateOrHostInfoChangeHandler nodeStateUpdateListener;
+ private TestNodeListener nodeStateUpdateListener;
private final ClusterStateGenerator.Params params = new ClusterStateGenerator.Params();
@Before
@@ -88,7 +93,7 @@ public class StateChangeHandlerTest {
.maxPrematureCrashes(config.maxPrematureCrashes)
.transitionTimes(5000)
.cluster(cluster);
- nodeStateUpdateListener = new TestNodeStateOrHostInfoChangeHandler();
+ nodeStateUpdateListener = new TestNodeListener();
}
private ClusterState currentClusterState() {
diff --git a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/StateChangeTest.java b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/StateChangeTest.java
index a5bb65e11d0..5a33414c955 100644
--- a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/StateChangeTest.java
+++ b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/StateChangeTest.java
@@ -1294,7 +1294,7 @@ public class StateChangeTest extends FleetControllerTest {
NodeState newNodeState = new NodeState(NodeType.STORAGE, State.MAINTENANCE);
NodeInfo nodeInfo = ctx.cluster.getNodeInfo(new Node(NodeType.STORAGE, 0));
nodeInfo.setWantedState(newNodeState);
- ctx.nodeStateOrHostInfoChangeHandler.handleNewWantedNodeState(nodeInfo, newNodeState);
+ ctx.nodeListener.handleNewWantedNodeState(nodeInfo, newNodeState);
invoked = true;
}
}
@@ -1312,7 +1312,7 @@ public class StateChangeTest extends FleetControllerTest {
NodeState newNodeState = new NodeState(NodeType.STORAGE, State.DOWN);
NodeInfo nodeInfo = ctx.cluster.getNodeInfo(new Node(NodeType.STORAGE, 0));
nodeInfo.setWantedState(newNodeState);
- ctx.nodeStateOrHostInfoChangeHandler.handleNewWantedNodeState(nodeInfo, newNodeState);
+ ctx.nodeListener.handleNewWantedNodeState(nodeInfo, newNodeState);
invoked = true;
}
}
diff --git a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/SystemStateBroadcasterTest.java b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/SystemStateBroadcasterTest.java
index 45593375c0b..1832f1132ac 100644
--- a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/SystemStateBroadcasterTest.java
+++ b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/SystemStateBroadcasterTest.java
@@ -6,8 +6,8 @@ import com.yahoo.vdslib.state.NodeState;
import com.yahoo.vdslib.state.NodeType;
import com.yahoo.vdslib.state.State;
import com.yahoo.vespa.clustercontroller.core.database.DatabaseHandler;
-import com.yahoo.vespa.clustercontroller.core.listeners.NodeAddedOrRemovedListener;
-import com.yahoo.vespa.clustercontroller.core.listeners.NodeStateOrHostInfoChangeHandler;
+import com.yahoo.vespa.clustercontroller.core.listeners.SlobrokListener;
+import com.yahoo.vespa.clustercontroller.core.listeners.NodeListener;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
@@ -69,12 +69,12 @@ public class SystemStateBroadcasterTest {
}
@Override
- public NodeAddedOrRemovedListener getNodeAddedOrRemovedListener() {
+ public SlobrokListener getNodeAddedOrRemovedListener() {
return null;
}
@Override
- public NodeStateOrHostInfoChangeHandler getNodeStateUpdateListener() {
+ public NodeListener getNodeStateUpdateListener() {
return null;
}
};
@@ -91,7 +91,7 @@ public class SystemStateBroadcasterTest {
ClusterFixture cf = ClusterFixture.forFlatCluster(2).bringEntireClusterUp().assignDummyRpcAddresses();
f.broadcaster.handleNewClusterStates(stateBundle);
f.broadcaster.broadcastNewStateBundleIfRequired(dbContextFrom(cf.cluster()), f.mockCommunicator, 3);
- cf.cluster().getNodeInfo().forEach(nodeInfo -> verify(f.mockCommunicator).setSystemState(eq(stateBundle), eq(nodeInfo), any()));
+ cf.cluster().getNodeInfos().forEach(nodeInfo -> verify(f.mockCommunicator).setSystemState(eq(stateBundle), eq(nodeInfo), any()));
}
@Test
@@ -121,7 +121,7 @@ public class SystemStateBroadcasterTest {
f.broadcaster.handleNewClusterStates(stateBundle);
f.broadcaster.broadcastNewStateBundleIfRequired(dbContextFrom(cf.cluster()), f.mockCommunicator, 3);
- cf.cluster().getNodeInfo().forEach(nodeInfo -> verify(f.mockCommunicator).setSystemState(eq(stateBundle), eq(nodeInfo), any()));
+ cf.cluster().getNodeInfos().forEach(nodeInfo -> verify(f.mockCommunicator).setSystemState(eq(stateBundle), eq(nodeInfo), any()));
}
@Test
@@ -153,7 +153,7 @@ public class SystemStateBroadcasterTest {
f.broadcaster.handleNewClusterStates(stateBundle);
f.broadcaster.broadcastNewStateBundleIfRequired(dbContextFrom(cf.cluster()), f.mockCommunicator, 99);
- cf.cluster().getNodeInfo().forEach(nodeInfo -> {
+ cf.cluster().getNodeInfos().forEach(nodeInfo -> {
verify(f.mockCommunicator, times(0)).setSystemState(any(), eq(nodeInfo), any());
});
}
@@ -166,7 +166,7 @@ public class SystemStateBroadcasterTest {
f.broadcaster.handleNewClusterStates(stateBundle);
f.broadcaster.broadcastNewStateBundleIfRequired(dbContextFrom(cf.cluster()), f.mockCommunicator, 100);
- cf.cluster().getNodeInfo().forEach(nodeInfo -> {
+ cf.cluster().getNodeInfos().forEach(nodeInfo -> {
verify(f.mockCommunicator, times(1)).setSystemState(any(), eq(nodeInfo), any());
});
}
@@ -276,7 +276,7 @@ public class SystemStateBroadcasterTest {
f.simulateBroadcastTick(cf, 123);
// No activations should be sent yet
- cf.cluster().getNodeInfo().forEach(nodeInfo -> {
+ cf.cluster().getNodeInfos().forEach(nodeInfo -> {
verify(f.mockCommunicator, times(0)).activateClusterStateVersion(eq(123), eq(nodeInfo), any());
});
assertNull(f.broadcaster.getLastClusterStateBundleConverged());
@@ -285,7 +285,7 @@ public class SystemStateBroadcasterTest {
f.simulateBroadcastTick(cf, 123);
// Activation should now be sent to _all_ nodes (distributor and storage)
- cf.cluster().getNodeInfo().forEach(nodeInfo -> {
+ cf.cluster().getNodeInfos().forEach(nodeInfo -> {
verify(f.mockCommunicator).activateClusterStateVersion(eq(123), eq(nodeInfo), any());
});
// But not converged yet, as activations have not been ACKed
diff --git a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/ZooKeeperDatabaseTest.java b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/ZooKeeperDatabaseTest.java
index 7d64a8f8878..1ce7586adea 100644
--- a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/ZooKeeperDatabaseTest.java
+++ b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/ZooKeeperDatabaseTest.java
@@ -37,7 +37,7 @@ public class ZooKeeperDatabaseTest {
closeDatabaseIfOpen();
var id = new FleetControllerId(clusterFixture.cluster.getName(), nodeIndex);
var context = new TestFleetControllerContext(id);
- zkDatabase = new ZooKeeperDatabase(context, clusterFixture.cluster(), nodeIndex, zkServer.getAddress(),
+ zkDatabase = new ZooKeeperDatabase(context, zkServer.getAddress(),
(int)sessionTimeout.toMillis(), mockListener);
}
diff --git a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/restapiv2/ClusterControllerMock.java b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/restapiv2/ClusterControllerMock.java
index 95071931a75..f53b2898145 100644
--- a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/restapiv2/ClusterControllerMock.java
+++ b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/restapiv2/ClusterControllerMock.java
@@ -2,11 +2,12 @@
package com.yahoo.vespa.clustercontroller.core.restapiv2;
import com.yahoo.vdslib.state.ClusterState;
+import com.yahoo.vdslib.state.Node;
import com.yahoo.vdslib.state.NodeState;
import com.yahoo.vespa.clustercontroller.core.*;
import com.yahoo.vespa.clustercontroller.core.hostinfo.HostInfo;
-import com.yahoo.vespa.clustercontroller.core.listeners.NodeAddedOrRemovedListener;
-import com.yahoo.vespa.clustercontroller.core.listeners.NodeStateOrHostInfoChangeHandler;
+import com.yahoo.vespa.clustercontroller.core.listeners.SlobrokListener;
+import com.yahoo.vespa.clustercontroller.core.listeners.NodeListener;
public class ClusterControllerMock implements RemoteClusterControllerTaskScheduler {
public RemoteClusterControllerTask.Context context = new RemoteClusterControllerTask.Context();
@@ -40,16 +41,21 @@ public class ClusterControllerMock implements RemoteClusterControllerTaskSchedul
return fleetControllerMaster;
}
};
- context.nodeStateOrHostInfoChangeHandler = new NodeStateOrHostInfoChangeHandler() {
+ context.nodeListener = new NodeListener() {
@Override
public void handleNewNodeState(NodeInfo currentInfo, NodeState newState) {
- events.append("newNodeState(").append(currentInfo.getNode()).append(": ").append(newState).append("\n");
+ events.append("newNodeState(").append(currentInfo.getNode()).append(": ").append(newState).append('\n');
}
@Override
public void handleNewWantedNodeState(NodeInfo node, NodeState newState) {
- events.append("newWantedNodeState(").append(node.getNode()).append(": ").append(newState).append("\n");
+ events.append("newWantedNodeState(").append(node.getNode()).append(": ").append(newState).append('\n');
+ }
+
+ @Override
+ public void handleRemovedNode(Node node) {
+ events.append("handleRemovedNode(").append(node).append(")\n");
}
@Override
@@ -59,7 +65,7 @@ public class ClusterControllerMock implements RemoteClusterControllerTaskSchedul
}
};
- context.nodeAddedOrRemovedListener = new NodeAddedOrRemovedListener() {
+ context.slobrokListener = new SlobrokListener() {
@Override
public void handleNewNode(NodeInfo node) {
@@ -68,12 +74,12 @@ public class ClusterControllerMock implements RemoteClusterControllerTaskSchedul
@Override
public void handleMissingNode(NodeInfo node) {
- events.append("newMissingNode(").append(node.getNode()).append("\n");
+ events.append("newMissingNode(").append(node.getNode()).append('\n');
}
@Override
public void handleNewRpcAddress(NodeInfo node) {
- events.append("newRpcAddress(").append(node.getNode()).append("\n");
+ events.append("newRpcAddress(").append(node.getNode()).append('\n');
}
@Override
diff --git a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/restapiv2/requests/SetNodeStateRequestTest.java b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/restapiv2/requests/SetNodeStateRequestTest.java
index 090e80361e5..9f14b2e71d2 100644
--- a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/restapiv2/requests/SetNodeStateRequestTest.java
+++ b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/restapiv2/requests/SetNodeStateRequestTest.java
@@ -10,7 +10,7 @@ import com.yahoo.vdslib.state.State;
import com.yahoo.vespa.clustercontroller.core.ContentCluster;
import com.yahoo.vespa.clustercontroller.core.NodeInfo;
import com.yahoo.vespa.clustercontroller.core.NodeStateChangeChecker;
-import com.yahoo.vespa.clustercontroller.core.listeners.NodeStateOrHostInfoChangeHandler;
+import com.yahoo.vespa.clustercontroller.core.listeners.NodeListener;
import com.yahoo.vespa.clustercontroller.utils.staterestapi.errors.StateRestApiException;
import com.yahoo.vespa.clustercontroller.utils.staterestapi.requests.SetUnitStateRequest;
import com.yahoo.vespa.clustercontroller.utils.staterestapi.response.SetResponse;
@@ -38,7 +38,7 @@ public class SetNodeStateRequestTest {
private final UnitState unitState = mock(UnitState.class);
private final int NODE_INDEX = 2;
private final Node storageNode = new Node(NodeType.STORAGE, NODE_INDEX);
- private final NodeStateOrHostInfoChangeHandler stateListener = mock(NodeStateOrHostInfoChangeHandler.class);
+ private final NodeListener stateListener = mock(NodeListener.class);
private final ClusterState currentClusterState = mock(ClusterState.class);
private boolean inMasterMoratorium = false;
private boolean probe = false;
diff --git a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/testutils/WaitTask.java b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/testutils/WaitTask.java
index 6362d6fe9a7..d9967381e75 100644
--- a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/testutils/WaitTask.java
+++ b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/testutils/WaitTask.java
@@ -25,7 +25,7 @@ public abstract class WaitTask {
public boolean performWaitTask() {
boolean didWork = false;
synchronized (fleetController.getMonitor()) {
- for (NodeInfo info : fleetController.getCluster().getNodeInfo()) {
+ for (NodeInfo info : fleetController.getCluster().getNodeInfos()) {
if (info.getTimeForNextStateRequestAttempt() != 0) didWork = true;
info.setNextGetStateAttemptTime(0);
}