summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTor Brede Vekterli <vekterli@oath.com>2018-02-20 14:48:13 +0100
committerGitHub <noreply@github.com>2018-02-20 14:48:13 +0100
commit2be3d3348b515a54240ee7b8860e86a1281f4ecb (patch)
treef642a8c8088cf87da4a506691024db056d64bec2
parent1d3a2857ce8e303b12db740b7ce1045f0e9b89c9 (diff)
parentf82aafe77ecd18ddf8031ab7366949c98c13d52f (diff)
Merge pull request #5069 from vespa-engine/geirst/initial-handling-of-bucket-spaces-stats-in-clustercontroller
Geirst/initial handling of bucket spaces stats in clustercontroller
-rw-r--r--clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/ClusterStateView.java27
-rw-r--r--clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/ClusterStatsAggregator.java99
-rw-r--r--clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/ContentClusterStats.java58
-rw-r--r--clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/ContentNodeStats.java139
-rw-r--r--clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/FleetController.java2
-rw-r--r--clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/MetricUpdater.java3
-rw-r--r--clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/NodeMergeStats.java151
-rw-r--r--clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/StateVersionTracker.java8
-rw-r--r--clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/StorageMergeStats.java63
-rw-r--r--clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/hostinfo/StorageNode.java62
-rw-r--r--clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/hostinfo/StorageNodeStatsBridge.java14
-rw-r--r--clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/ClusterStateViewTest.java13
-rw-r--r--clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/ClusterStatsAggregatorTest.java261
-rw-r--r--clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/StateVersionTrackerTest.java5
-rw-r--r--clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/hostinfo/StorageNodeStatsBridgeTest.java39
-rw-r--r--protocols/getnodestate/host_info.json47
16 files changed, 424 insertions, 567 deletions
diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/ClusterStateView.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/ClusterStateView.java
index a0e93c2a9ad..ea638010ab7 100644
--- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/ClusterStateView.java
+++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/ClusterStateView.java
@@ -29,31 +29,25 @@ public class ClusterStateView {
private static Logger log = Logger.getLogger(ClusterStateView.class.getName());
private final ClusterState clusterState;
private final ClusterStatsAggregator statsAggregator;
- private final MetricUpdater metricUpdater;
- /**
- * @param metricUpdater may be null, in which case no stats will be reported.
- */
- public static ClusterStateView create(String serializedClusterState, MetricUpdater metricUpdater)
- throws ParseException {
+ public static ClusterStateView create(String serializedClusterState) throws ParseException {
ClusterState clusterState = new ClusterState(serializedClusterState);
- return new ClusterStateView(clusterState, createNewAggregator(clusterState, metricUpdater), metricUpdater);
+ return new ClusterStateView(clusterState, createNewAggregator(clusterState));
}
- public static ClusterStateView create(final ClusterState clusterState, final MetricUpdater metricUpdater) {
- return new ClusterStateView(clusterState, createNewAggregator(clusterState, metricUpdater), metricUpdater);
+ public static ClusterStateView create(final ClusterState clusterState) {
+ return new ClusterStateView(clusterState, createNewAggregator(clusterState));
}
- private static ClusterStatsAggregator createNewAggregator(ClusterState clusterState, MetricUpdater metricUpdater) {
+ private static ClusterStatsAggregator createNewAggregator(ClusterState clusterState) {
Set<Integer> upDistributors = getIndicesOfUpNodes(clusterState, NodeType.DISTRIBUTOR);
Set<Integer> upStorageNodes = getIndicesOfUpNodes(clusterState, NodeType.STORAGE);
- return new ClusterStatsAggregator(upDistributors, upStorageNodes, metricUpdater);
+ return new ClusterStatsAggregator(upDistributors, upStorageNodes);
}
- ClusterStateView(ClusterState clusterState, ClusterStatsAggregator statsAggregator, MetricUpdater metricUpdater) {
+ ClusterStateView(ClusterState clusterState, ClusterStatsAggregator statsAggregator) {
this.clusterState = clusterState;
this.statsAggregator = statsAggregator;
- this.metricUpdater = metricUpdater;
}
/**
@@ -85,8 +79,7 @@ public class ClusterStateView {
ClusterState clonedClusterState = clusterState.clone();
return new ClusterStateView(
clonedClusterState,
- createNewAggregator(clonedClusterState, metricUpdater),
- metricUpdater);
+ createNewAggregator(clonedClusterState));
}
public ClusterState getClusterState() { return clusterState; }
@@ -115,8 +108,8 @@ public class ClusterStateView {
return;
}
- statsAggregator.updateForDistributor(
- hostnames, node.getNodeIndex(), StorageNodeStatsBridge.generate(hostInfo.getDistributor()));
+ statsAggregator.updateForDistributor(node.getNodeIndex(),
+ StorageNodeStatsBridge.generate(hostInfo.getDistributor()));
}
public String toString() {
diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/ClusterStatsAggregator.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/ClusterStatsAggregator.java
index 849a2aa23c2..3f7cd129fc1 100644
--- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/ClusterStatsAggregator.java
+++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/ClusterStatsAggregator.java
@@ -4,16 +4,13 @@ package com.yahoo.vespa.clustercontroller.core;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
-import java.util.logging.Logger;
-
-import com.yahoo.log.LogLevel;
/**
- * A class that stores stats about outstanding merge operations for
- * the current cluster state version, and exports metrics about these.
+ * Class that stores content cluster stats (with bucket space stats per node) for
+ * the current cluster state version.
*
- * Each distributor reports outstanding merge operations for the different
- * storage nodes. These reports arrive with getnodestate RPC calls,
+ * Each distributor reports bucket space stats for the different content nodes.
+ * These reports arrive with getnodestate RPC calls,
* and eventually ends up as calls to updateForDistributor().
* No assumptions are made on the sequence of getnodestate calls.
* For instance, it's perfectly fine for the calls to arrive in the
@@ -25,97 +22,55 @@ import com.yahoo.log.LogLevel;
* distributor 2
* ... etc
*
- * Whereas the metrics we want, is how many merge operations are outstanding
- * for a given storage nodes. So we need to keep track of the latest info
- * from each distributor.
- *
* @author hakonhall
*/
public class ClusterStatsAggregator {
- private static Logger log = Logger.getLogger(ClusterStatsAggregator.class.getName());
-
private final Set<Integer> distributors;
- private final MetricUpdater updater;
- // Maps the distributor node index to a map of storage node index to the
- // storage node's merge stats.
- private final Map<Integer, StorageMergeStats> distributorToStats = new HashMap<>();
+ // Maps the distributor node index to a map of content node index to the
+ // content node's stats.
+ private final Map<Integer, ContentClusterStats> distributorToStats = new HashMap<>();
- // This is only needed as an optimization. should just be the sum of distributorToStats' StorageMergeStats.
- // Maps the storage node index to the aggregate merge stats for that storage node.
+ // This is only needed as an optimization. Is just the sum of distributorToStats' ContentClusterStats.
+ // Maps the content node index to the content node stats for that node.
// This MUST be kept up-to-date with distributorToStats;
- private final StorageMergeStats aggregatedStats;
+ private final ContentClusterStats aggregatedStats;
- private int hostToStatsMapHashCode = 0;
-
- ClusterStatsAggregator(Set<Integer> distributors, Set<Integer> storageNodes, MetricUpdater updater) {
+ ClusterStatsAggregator(Set<Integer> distributors, Set<Integer> storageNodes) {
this.distributors = distributors;
- aggregatedStats = new StorageMergeStats(storageNodes);
- this.updater = updater;
+ aggregatedStats = new ContentClusterStats(storageNodes);
+ }
+
+ ContentClusterStats getAggregatedStats() {
+ return aggregatedStats;
}
/**
* Update the aggregator with the newest available stats from a distributor.
- * Will update metrics if necessary.
*/
- void updateForDistributor(Map<Integer, String> hostnames, int distributorIndex, StorageMergeStats storageStats) {
+ void updateForDistributor(int distributorIndex, ContentClusterStats clusterStats) {
if (!distributors.contains(distributorIndex)) {
return;
}
-
- addStatsFromDistributor(distributorIndex, storageStats);
-
- if (distributorToStats.size() < distributors.size()) {
- // Not all distributors have reported their merge stats through getnodestate yet.
- return;
- }
-
- Map<String, NodeMergeStats> hostToStatsMap = getHostToStatsMap(hostnames);
- if (hostToStatsMap == null) {
- return;
- }
-
- if (hostToStatsMapHashCode == 0 || hostToStatsMapHashCode != hostToStatsMap.hashCode()) {
- updater.updateMergeOpMetrics(hostToStatsMap);
- hostToStatsMapHashCode = hostToStatsMap.hashCode();
- }
- }
-
- private Map<String, NodeMergeStats> getHostToStatsMap(Map<Integer, String> hostnames) {
- Map<String, NodeMergeStats> hostToStatsMap = new HashMap<>(aggregatedStats.size());
- for (NodeMergeStats nodeStats : aggregatedStats) {
- // The hosts names are kept up-to-date from Slobrok, and MAY therefore be arbitrarily
- // different from the node set used by aggregatedStats (and typically tied to a cluster state).
- // If so, we will not pretend the returned map is complete, and will return null.
- String host = hostnames.get(nodeStats.getNodeIndex());
- if (host == null) {
- log.log(LogLevel.DEBUG, "Failed to find the host name of storage node " + nodeStats.getNodeIndex() +
- ". Skipping the report from " + ClusterStatsAggregator.class.getName());
- return null;
- }
-
- hostToStatsMap.put(host, nodeStats);
- }
-
- return hostToStatsMap;
+ addStatsFromDistributor(distributorIndex, clusterStats);
}
- private void addStatsFromDistributor(int distributorIndex, StorageMergeStats storageStatsFromDistributor) {
- StorageMergeStats previousStorageStats = distributorToStats.put(distributorIndex, storageStatsFromDistributor);
+ private void addStatsFromDistributor(int distributorIndex, ContentClusterStats clusterStats) {
+ ContentClusterStats prevClusterStats = distributorToStats.put(distributorIndex, clusterStats);
- for (NodeMergeStats storageNode : aggregatedStats) {
- Integer storageNodeIndex = storageNode.getNodeIndex();
+ for (ContentNodeStats contentNode : aggregatedStats) {
+ Integer nodeIndex = contentNode.getNodeIndex();
- NodeMergeStats statsToAdd = storageStatsFromDistributor.getStorageNode(storageNodeIndex);
+ ContentNodeStats statsToAdd = clusterStats.getContentNode(nodeIndex);
if (statsToAdd != null) {
- storageNode.add(statsToAdd);
+ contentNode.add(statsToAdd);
}
- if (previousStorageStats != null) {
- NodeMergeStats statsToSubtract = storageStatsFromDistributor.getStorageNode(storageNodeIndex);
+ if (prevClusterStats != null) {
+ ContentNodeStats statsToSubtract = prevClusterStats.getContentNode(nodeIndex);
if (statsToSubtract != null) {
- storageNode.subtract(statsToSubtract);
+ contentNode.subtract(statsToSubtract);
}
}
}
diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/ContentClusterStats.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/ContentClusterStats.java
new file mode 100644
index 00000000000..2698b079073
--- /dev/null
+++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/ContentClusterStats.java
@@ -0,0 +1,58 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.clustercontroller.core;
+
+import java.util.*;
+
+/**
+ * Class for storing pending content node stats for all content nodes in the cluster.
+ *
+ * @author hakonhall
+ */
+public class ContentClusterStats implements Iterable<ContentNodeStats> {
+
+ // Maps a content node index to the content node's stats.
+ private final Map<Integer, ContentNodeStats> mapToNodeStats;
+
+ public ContentClusterStats(Set<Integer> storageNodes) {
+ mapToNodeStats = new HashMap<>(storageNodes.size());
+ for (Integer index : storageNodes) {
+ mapToNodeStats.put(index, new ContentNodeStats(index));
+ }
+ }
+
+ public ContentClusterStats(Map<Integer, ContentNodeStats> mapToNodeStats) {
+ this.mapToNodeStats = mapToNodeStats;
+ }
+
+ @Override
+ public Iterator<ContentNodeStats> iterator() {
+ return mapToNodeStats.values().iterator();
+ }
+
+ ContentNodeStats getContentNode(Integer index) {
+ return mapToNodeStats.get(index);
+ }
+
+ int size() {
+ return mapToNodeStats.size();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ContentClusterStats that = (ContentClusterStats) o;
+ return Objects.equals(mapToNodeStats, that.mapToNodeStats);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mapToNodeStats);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("{mapToNodeStats=[%s]}",
+ Arrays.toString(mapToNodeStats.entrySet().toArray()));
+ }
+}
diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/ContentNodeStats.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/ContentNodeStats.java
new file mode 100644
index 00000000000..cefb3c3c31f
--- /dev/null
+++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/ContentNodeStats.java
@@ -0,0 +1,139 @@
+// Copyright 2018 Yahoo Holdings. 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.hostinfo.StorageNode;
+
+import java.util.*;
+
+/**
+ * @author hakonhall
+ */
+public class ContentNodeStats {
+
+ private int nodeIndex;
+ private Map<String, BucketSpaceStats> bucketSpaces = new HashMap<>();
+
+ public static class BucketSpaceStats {
+ private long bucketsTotal;
+ private long bucketsPending;
+
+ private BucketSpaceStats() {
+ this.bucketsTotal = 0;
+ this.bucketsPending = 0;
+ }
+
+ private BucketSpaceStats(long bucketsTotal, long bucketsPending) {
+ this.bucketsTotal = bucketsTotal;
+ this.bucketsPending = bucketsPending;
+ }
+
+ public static BucketSpaceStats empty() {
+ return new BucketSpaceStats();
+ }
+
+ public static BucketSpaceStats of(long bucketsTotal, long bucketsPending) {
+ return new BucketSpaceStats(bucketsTotal, bucketsPending);
+ }
+
+ public long getBucketsTotal() {
+ return bucketsTotal;
+ }
+
+ public long getBucketsPending() {
+ return bucketsPending;
+ }
+
+ public void merge(BucketSpaceStats rhs, int factor) {
+ this.bucketsTotal += (factor * rhs.bucketsTotal);
+ this.bucketsPending += (factor * rhs.bucketsPending);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ BucketSpaceStats that = (BucketSpaceStats) o;
+ return bucketsTotal == that.bucketsTotal &&
+ bucketsPending == that.bucketsPending;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(bucketsTotal, bucketsPending);
+ }
+
+ @Override
+ public String toString() {
+ return "{bucketsTotal=" + bucketsTotal + ", bucketsPending=" + bucketsPending + "}";
+ }
+ }
+
+ public ContentNodeStats(StorageNode storageNode) {
+ this.nodeIndex = storageNode.getIndex();
+ for (StorageNode.BucketSpaceStats stats : storageNode.getBucketSpacesStats()) {
+ if (stats.valid()) {
+ this.bucketSpaces.put(stats.getName(),
+ BucketSpaceStats.of(stats.getBucketStats().getTotal(),
+ stats.getBucketStats().getPending()));
+ } else {
+ this.bucketSpaces.put(stats.getName(), BucketSpaceStats.empty());
+ }
+ }
+ }
+
+ public ContentNodeStats(int index) {
+ this(index, new HashMap<>());
+ }
+
+ public ContentNodeStats(int index, Map<String, BucketSpaceStats> bucketSpaces) {
+ this.nodeIndex = index;
+ this.bucketSpaces = bucketSpaces;
+ }
+
+ public int getNodeIndex() { return nodeIndex; }
+
+ public void add(ContentNodeStats stats) {
+ merge(stats, 1);
+ }
+
+ public void subtract(ContentNodeStats stats) {
+ merge(stats, -1);
+ }
+
+ private void merge(ContentNodeStats stats, int factor) {
+ for (Map.Entry<String, BucketSpaceStats> entry : stats.bucketSpaces.entrySet()) {
+ BucketSpaceStats statsToUpdate = bucketSpaces.get(entry.getKey());
+ if (statsToUpdate == null && factor == 1) {
+ statsToUpdate = new BucketSpaceStats();
+ bucketSpaces.put(entry.getKey(), statsToUpdate);
+ }
+ if (statsToUpdate != null) {
+ statsToUpdate.merge(entry.getValue(), factor);
+ }
+ }
+ }
+
+ public Map<String, BucketSpaceStats> getBucketSpaces() {
+ return bucketSpaces;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ContentNodeStats that = (ContentNodeStats) o;
+ return nodeIndex == that.nodeIndex &&
+ Objects.equals(bucketSpaces, that.bucketSpaces);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(nodeIndex, bucketSpaces);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("{index=%d, bucketSpaces=[%s]}",
+ nodeIndex, Arrays.toString(bucketSpaces.entrySet().toArray()));
+ }
+}
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 a5419c64818..ba56d75ab4c 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
@@ -122,7 +122,7 @@ public class FleetController implements NodeStateOrHostInfoChangeHandler, NodeAd
this.stateGatherer = nodeStateGatherer;
this.stateChangeHandler = stateChangeHandler;
this.systemStateBroadcaster = systemStateBroadcaster;
- this.stateVersionTracker = new StateVersionTracker(metricUpdater);
+ this.stateVersionTracker = new StateVersionTracker();
this.metricUpdater = metricUpdater;
this.statusPageServer = statusPage;
diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/MetricUpdater.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/MetricUpdater.java
index b3b10e1d0d8..199e9a3169b 100644
--- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/MetricUpdater.java
+++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/MetricUpdater.java
@@ -85,7 +85,4 @@ public class MetricUpdater {
metricReporter.add("node-event", 1);
}
- public void updateMergeOpMetrics(Map<String, NodeMergeStats> storageNodeStats) {
- // TODO(hakonhall): Remove this method once we figure out how to propagate metrics to state HTTP API.
- }
}
diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/NodeMergeStats.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/NodeMergeStats.java
deleted file mode 100644
index 97112e01aed..00000000000
--- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/NodeMergeStats.java
+++ /dev/null
@@ -1,151 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.clustercontroller.core;
-
-import com.yahoo.vespa.clustercontroller.core.hostinfo.StorageNode;
-
-/**
- * @author hakonhall
- */
-public class NodeMergeStats {
-
- /**
- * Constructor that sets values to zero if not present.
- */
- public NodeMergeStats(StorageNode storageNodePojo) {
- this.nodeIndex = storageNodePojo.getIndex();
-
- StorageNode.OutstandingMergeOps mergeOps = storageNodePojo.getOutstandingMergeOpsOrNull();
- if (mergeOps == null) {
- mergeOps = new StorageNode.OutstandingMergeOps();
- }
- syncing = createAmount(mergeOps.getSyncingOrNull());
- copyingIn = createAmount(mergeOps.getCopyingInOrNull());
- movingOut = createAmount(mergeOps.getMovingOutOrNull());
- copyingOut = createAmount(mergeOps.getCopyingOutOrNull());
- }
-
- private static Amount createAmount(StorageNode.Buckets bucketOrNull) {
- if (bucketOrNull == null) {
- return new Amount();
- }
- return new Amount(bucketOrNull.getBuckets());
- }
-
- static public class Amount {
- private long buckets;
-
- Amount() { this(0); }
- Amount(long buckets) { this.buckets = buckets; }
-
- public void set(Amount other) {
- buckets = other.buckets;
- }
-
- public long getBuckets() {
- return buckets;
- }
-
- /**
- * Logically, add (factor * amount) to this object.
- */
- void scaledAdd(int factor, Amount amount) {
- buckets += factor * amount.buckets;
- }
-
- public boolean equals(Object other) {
- if (!(other instanceof Amount)) {
- return false;
- }
- Amount otherAmount = (Amount) other;
- return buckets == otherAmount.buckets;
- }
-
- public int hashCode() {
- return (int)buckets;
- }
-
- public String toString() {
- return String.format("{buckets = %d}", buckets);
- }
- }
-
- private final Amount syncing;
- private final Amount copyingIn;
- private final Amount movingOut;
- private final Amount copyingOut;
- private int nodeIndex;
-
- /**
- * An instance with all 0 amounts.
- */
- public NodeMergeStats(int index) {
- this(index, new Amount(), new Amount(), new Amount(), new Amount());
- }
-
- NodeMergeStats(int index, Amount syncing, Amount copyingIn, Amount movingOut, Amount copyingOut) {
- this.nodeIndex = index;
- this.syncing = syncing;
- this.copyingIn = copyingIn;
- this.movingOut = movingOut;
- this.copyingOut = copyingOut;
- }
-
- public void set(NodeMergeStats stats) {
- nodeIndex = stats.nodeIndex;
- syncing.set(stats.syncing);
- copyingIn.set(stats.copyingIn);
- movingOut.set(stats.movingOut);
- copyingOut.set(stats.copyingOut);
- }
-
- int getNodeIndex() { return nodeIndex; }
- public Amount getSyncing() { return syncing; }
- public Amount getCopyingIn() { return copyingIn; }
- public Amount getMovingOut() { return movingOut; }
- public Amount getCopyingOut() { return copyingOut; }
-
- void add(NodeMergeStats stats) {
- scaledAdd(1, stats);
- }
-
- void subtract(NodeMergeStats stats) {
- scaledAdd(-1, stats);
- }
-
- /**
- * Logically, adds (factor * stats) to this object. factor of 1 is normal add, -1 is subtraction.
- */
- private void scaledAdd(int factor, NodeMergeStats stats) {
- syncing.scaledAdd(factor, stats.syncing);
- copyingIn.scaledAdd(factor, stats.copyingIn);
- movingOut.scaledAdd(factor, stats.movingOut);
- copyingOut.scaledAdd(factor, stats.copyingOut);
- }
-
- @Override
- public int hashCode() {
- return (int) (syncing.buckets +
- copyingIn.buckets * 31 +
- movingOut.buckets * 17 +
- copyingOut.buckets * 7);
- }
-
- @Override
- public boolean equals(Object other) {
- if (!(other instanceof NodeMergeStats)) {
- return false;
- }
-
- NodeMergeStats otherStats = (NodeMergeStats) other;
- return nodeIndex == otherStats.nodeIndex &&
- syncing.equals(otherStats.syncing) &&
- copyingIn.equals(otherStats.copyingIn) &&
- movingOut.equals(otherStats.movingOut) &&
- copyingOut.equals(otherStats.copyingOut);
- }
-
- public String toString() {
- return String.format("{index = %d, syncing = %s, copyingIn = %s, movingOut = %s, copyingOut = %s}",
- nodeIndex, syncing, copyingIn, movingOut, copyingOut);
- }
-}
diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/StateVersionTracker.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/StateVersionTracker.java
index 518361f18fc..902189fca8b 100644
--- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/StateVersionTracker.java
+++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/StateVersionTracker.java
@@ -32,15 +32,13 @@ public class StateVersionTracker {
private AnnotatedClusterState latestCandidateState = AnnotatedClusterState.emptyState();
private AnnotatedClusterState currentClusterState = latestCandidateState;
- private final MetricUpdater metricUpdater;
private ClusterStateView clusterStateView;
private final LinkedList<ClusterStateHistoryEntry> clusterStateHistory = new LinkedList<>();
private int maxHistoryEntryCount = 50;
- StateVersionTracker(final MetricUpdater metricUpdater) {
- this.metricUpdater = metricUpdater;
- clusterStateView = ClusterStateView.create(currentUnversionedState, metricUpdater);
+ StateVersionTracker() {
+ clusterStateView = ClusterStateView.create(currentUnversionedState);
}
void setVersionRetrievedFromZooKeeper(final int version) {
@@ -121,7 +119,7 @@ public class StateVersionTracker {
lowestObservedDistributionBits,
newState.getClusterState().getDistributionBitCount());
// TODO should this take place in updateLatestCandidateState instead? I.e. does it require a consolidated state?
- clusterStateView = ClusterStateView.create(currentClusterState.getClusterState(), metricUpdater);
+ clusterStateView = ClusterStateView.create(currentClusterState.getClusterState());
}
private void recordCurrentStateInHistoryAtTime(final long currentTimeMs) {
diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/StorageMergeStats.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/StorageMergeStats.java
deleted file mode 100644
index 6a44bee8cce..00000000000
--- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/StorageMergeStats.java
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.clustercontroller.core;
-
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Class for storing the pending merge operation stats for all the storage nodes.
- *
- * @author hakonhall
- */
-public class StorageMergeStats implements Iterable<NodeMergeStats> {
-
- // Maps a storage node index to the storage node's pending merges stats.
- private final Map<Integer, NodeMergeStats> mapToNodeStats;
-
- public StorageMergeStats(Set<Integer> storageNodes) {
- mapToNodeStats = new HashMap<>(storageNodes.size());
- for (Integer index : storageNodes) {
- mapToNodeStats.put(index, new NodeMergeStats(index));
- }
- }
-
- public StorageMergeStats(Map<Integer, NodeMergeStats> mapToNodeStats) {
- this.mapToNodeStats = mapToNodeStats;
- }
-
- @Override
- public Iterator<NodeMergeStats> iterator() {
- return mapToNodeStats.values().iterator();
- }
-
- NodeMergeStats getStorageNode(Integer index) {
- return mapToNodeStats.get(index);
- }
-
- int size() {
- return mapToNodeStats.size();
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof StorageMergeStats)) {
- return false;
- }
-
- StorageMergeStats that = (StorageMergeStats) o;
-
- if (mapToNodeStats != null ? !mapToNodeStats.equals(that.mapToNodeStats) : that.mapToNodeStats != null) {
- return false;
- }
- return true;
- }
-
- @Override
- public int hashCode() {
- return mapToNodeStats != null ? mapToNodeStats.hashCode() : 0;
- }
-
-}
diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/hostinfo/StorageNode.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/hostinfo/StorageNode.java
index 9e951236c45..bf7c1fad6ca 100644
--- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/hostinfo/StorageNode.java
+++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/hostinfo/StorageNode.java
@@ -4,6 +4,9 @@ package com.yahoo.vespa.clustercontroller.core.hostinfo;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* Keeping information about a storage node seen from the distributor.
*
@@ -36,31 +39,43 @@ public class StorageNode {
public Put getPut() { return put; }
}
- static public class Buckets {
- private final long buckets;
+ static public class BucketStats {
+ private final long total;
+ private final long pending;
@JsonCreator
- public Buckets(@JsonProperty("buckets") Long buckets) {
- this.buckets = buckets;
+ public BucketStats(@JsonProperty("total") Long total, @JsonProperty("pending") Long pending) {
+ this.total = total;
+ this.pending = pending;
}
- public long getBuckets() { return buckets; }
+ public long getTotal() {
+ return total;
+ }
+ public long getPending() {
+ return pending;
+ }
}
- static public class OutstandingMergeOps {
- @JsonProperty("syncing")
- private Buckets syncing;
- @JsonProperty("copying-in")
- private Buckets copyingIn;
- @JsonProperty("moving-out")
- private Buckets movingOut;
- @JsonProperty("copying-out")
- private Buckets copyingOut;
-
- public Buckets getSyncingOrNull() { return syncing; }
- public Buckets getCopyingInOrNull() { return copyingIn; }
- public Buckets getMovingOutOrNull() { return movingOut; }
- public Buckets getCopyingOutOrNull() { return copyingOut; }
+ static public class BucketSpaceStats {
+ private final String name;
+ @JsonProperty("buckets")
+ private BucketStats bucketStats = null;
+
+ @JsonCreator
+ public BucketSpaceStats(@JsonProperty("name") String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+ public boolean valid() {
+ return bucketStats != null;
+ }
+ public BucketStats getBucketStats() {
+ return bucketStats;
+ }
}
private final Integer index;
@@ -74,8 +89,8 @@ public class StorageNode {
@JsonProperty("min-current-replication-factor")
private Integer minCurrentReplicationFactor;
- @JsonProperty("outstanding-merge-ops")
- private OutstandingMergeOps outstandingMergeOps;
+ @JsonProperty("bucket-spaces")
+ private List<BucketSpaceStats> bucketSpacesStats = new ArrayList<>();
@JsonCreator
public StorageNode(@JsonProperty("node-index") Integer index) {
@@ -95,8 +110,7 @@ public class StorageNode {
return minCurrentReplicationFactor;
}
- public OutstandingMergeOps getOutstandingMergeOpsOrNull() {
- return outstandingMergeOps;
+ public List<BucketSpaceStats> getBucketSpacesStats() {
+ return bucketSpacesStats;
}
-
}
diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/hostinfo/StorageNodeStatsBridge.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/hostinfo/StorageNodeStatsBridge.java
index 6d0da8a9fba..55b7e4bb8c1 100644
--- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/hostinfo/StorageNodeStatsBridge.java
+++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/hostinfo/StorageNodeStatsBridge.java
@@ -1,11 +1,7 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.clustercontroller.core.hostinfo;
-import com.yahoo.vespa.clustercontroller.core.LatencyStats;
-import com.yahoo.vespa.clustercontroller.core.NodeMergeStats;
-import com.yahoo.vespa.clustercontroller.core.StorageMergeStats;
-import com.yahoo.vespa.clustercontroller.core.StorageNodeStats;
-import com.yahoo.vespa.clustercontroller.core.StorageNodeStatsContainer;
+import com.yahoo.vespa.clustercontroller.core.*;
import java.util.HashMap;
import java.util.List;
@@ -45,12 +41,12 @@ public class StorageNodeStatsBridge {
return container;
}
- public static StorageMergeStats generate(Distributor distributor) {
- Map<Integer, NodeMergeStats> mapToNodeStats = new HashMap<>();
+ public static ContentClusterStats generate(Distributor distributor) {
+ Map<Integer, ContentNodeStats> mapToNodeStats = new HashMap<>();
for (StorageNode storageNode : distributor.getStorageNodes()) {
- mapToNodeStats.put(storageNode.getIndex(), new NodeMergeStats(storageNode));
+ mapToNodeStats.put(storageNode.getIndex(), new ContentNodeStats(storageNode));
}
- return new StorageMergeStats(mapToNodeStats);
+ return new ContentClusterStats(mapToNodeStats);
}
}
diff --git a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/ClusterStateViewTest.java b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/ClusterStateViewTest.java
index 3b04fec3e79..dc8a4a0d441 100644
--- a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/ClusterStateViewTest.java
+++ b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/ClusterStateViewTest.java
@@ -22,10 +22,8 @@ public class ClusterStateViewTest {
final NodeInfo nodeInfo = mock(NodeInfo.class);
final Node node = mock(Node.class);
final ClusterStatsAggregator statsAggregator = mock(ClusterStatsAggregator.class);
- final StorageMergeStats storageStats = mock(StorageMergeStats.class);
final ClusterState clusterState = mock(ClusterState.class);
- final MetricUpdater metricUpdater = mock(MetricUpdater.class);
- final ClusterStateView clusterStateView = new ClusterStateView(clusterState, statsAggregator, metricUpdater);
+ final ClusterStateView clusterStateView = new ClusterStateView(clusterState, statsAggregator);
HostInfo createHostInfo(String version) {
return HostInfo.createHostInfo("{ \"cluster-state-version\": " + version + " }");
@@ -37,7 +35,7 @@ public class ClusterStateViewTest {
clusterStateView.handleUpdatedHostInfo(hostnames, nodeInfo, createHostInfo("101"));
- verify(statsAggregator, never()).updateForDistributor(any(), anyInt(), any());
+ verify(statsAggregator, never()).updateForDistributor(anyInt(), any());
}
@@ -49,7 +47,7 @@ public class ClusterStateViewTest {
clusterStateView.handleUpdatedHostInfo(hostnames, nodeInfo, createHostInfo("22"));
- verify(statsAggregator, never()).updateForDistributor(any(), anyInt(), any());
+ verify(statsAggregator, never()).updateForDistributor(anyInt(), any());
}
@Test
@@ -59,7 +57,7 @@ public class ClusterStateViewTest {
clusterStateView.handleUpdatedHostInfo(hostnames, nodeInfo, createHostInfo("22"));
- verify(statsAggregator, never()).updateForDistributor(any(), anyInt(), any());
+ verify(statsAggregator, never()).updateForDistributor(anyInt(), any());
}
@Test
@@ -81,8 +79,7 @@ public class ClusterStateViewTest {
clusterStateView.handleUpdatedHostInfo(hostnames, nodeInfo, hostInfo);
- verify(statsAggregator).updateForDistributor(
- hostnames, 3, StorageNodeStatsBridge.generate(hostInfo.getDistributor()));
+ verify(statsAggregator).updateForDistributor(3, StorageNodeStatsBridge.generate(hostInfo.getDistributor()));
}
@Test
diff --git a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/ClusterStatsAggregatorTest.java b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/ClusterStatsAggregatorTest.java
index eb4455b9492..c92d414aac8 100644
--- a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/ClusterStatsAggregatorTest.java
+++ b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/ClusterStatsAggregatorTest.java
@@ -1,217 +1,142 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.clustercontroller.core;
+import com.google.common.collect.Sets;
import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.runners.MockitoJUnitRunner;
import java.util.*;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.*;
/**
* @author hakonhall
* @since 5.34
*/
-@RunWith(MockitoJUnitRunner.class)
public class ClusterStatsAggregatorTest {
- final Set<Integer> distributors = new HashSet<>();
- final Set<Integer> storageNodes = new HashSet<>();
- final Map<Integer, String> hostnames = new HashMap<>();
- final MetricUpdater updater = mock(MetricUpdater.class);
- StorageMergeStats storageStats;
+ private static class StatsBuilder {
+ private final Map<Integer, Map<String, ContentNodeStats.BucketSpaceStats> > stats = new HashMap<>();
- private void addDistributors(Integer... indices) {
- for (Integer i : indices) {
- distributors.add(i);
+ public StatsBuilder add(int nodeIndex, String bucketSpace, long bucketsTotal, long bucketsPending) {
+ return add(nodeIndex, bucketSpace, ContentNodeStats.BucketSpaceStats.of(bucketsTotal, bucketsPending));
}
- }
-
- private static class StorageNodeSpec {
- public StorageNodeSpec(Integer index, String hostname) {
- this.index = index;
- this.hostname = hostname;
+ public StatsBuilder add(int nodeIndex, String bucketSpace) {
+ return add(nodeIndex, bucketSpace, ContentNodeStats.BucketSpaceStats.empty());
+ }
+ public StatsBuilder add(int nodeIndex, String bucketSpace, ContentNodeStats.BucketSpaceStats bucketSpaceStats) {
+ Map<String, ContentNodeStats.BucketSpaceStats> contentNodeStats = stats.get(nodeIndex);
+ if (contentNodeStats == null) {
+ contentNodeStats = new HashMap<>();
+ stats.put(nodeIndex, contentNodeStats);
+ }
+ contentNodeStats.put(bucketSpace, bucketSpaceStats);
+ return this;
+ }
+ public StatsBuilder add(int nodeIndex) {
+ stats.put(nodeIndex, new HashMap<>());
+ return this;
+ }
+ public ContentClusterStats build() {
+ Map<Integer, ContentNodeStats> nodeToStatsMap = new HashMap<>();
+ stats.forEach((nodeIndex, bucketSpaces) ->
+ nodeToStatsMap.put(nodeIndex, new ContentNodeStats(nodeIndex, bucketSpaces)));
+ return new ContentClusterStats(nodeToStatsMap);
}
- public Integer index;
- public String hostname;
}
- private void addStorageNodes(StorageNodeSpec... specs) {
- for (StorageNodeSpec spec : specs) {
- storageNodes.add(spec.index);
- hostnames.put(spec.index, spec.hostname);
+ private static class Fixture {
+ private ClusterStatsAggregator aggregator;
+ public Fixture(Set<Integer> distributorNodes,
+ Set<Integer> contentNodes) {
+ aggregator = new ClusterStatsAggregator(distributorNodes, contentNodes);
+ }
+ public void update(int distributorIndex, StatsBuilder clusterStats) {
+ aggregator.updateForDistributor(distributorIndex, clusterStats.build());
+ }
+ public void verify(StatsBuilder expectedStats) {
+ assertEquals(expectedStats.build(), aggregator.getAggregatedStats());
}
- storageStats = new StorageMergeStats(storageNodes);
}
- private void putStorageStats(int index, int syncing, int copyingIn, int movingOut, int copyingOut) {
- storageStats.getStorageNode(index).set(createStats(index, syncing, copyingIn, movingOut, copyingOut));
+ private static Set<Integer> distributorNodes(Integer... indices) {
+ return Sets.newHashSet(indices);
}
- private static NodeMergeStats createStats(int index, int syncing, int copyingIn, int movingOut, int copyingOut) {
- return new NodeMergeStats(
- index,
- new NodeMergeStats.Amount(syncing),
- new NodeMergeStats.Amount(copyingIn),
- new NodeMergeStats.Amount(movingOut),
- new NodeMergeStats.Amount(copyingOut));
+ private static Set<Integer> contentNodes(Integer... indices) {
+ return Sets.newHashSet(indices);
}
@Test
- public void testSimple() {
- final int distributorIndex = 1;
- addDistributors(distributorIndex);
-
- final int storageNodeIndex = 11;
- addStorageNodes(new StorageNodeSpec(storageNodeIndex, "storage-node"));
-
- putStorageStats(storageNodeIndex, 5, 6, 7, 8);
-
- ClusterStatsAggregator aggregator = new ClusterStatsAggregator(distributors, storageNodes, updater);
- aggregator.updateForDistributor(hostnames, distributorIndex, storageStats);
-
- Map<String, NodeMergeStats> expectedStorageNodeStats = new HashMap<>();
- expectedStorageNodeStats.put("storage-node", createStats(storageNodeIndex, 5, 6, 7, 8));
-
- verify(updater).updateMergeOpMetrics(expectedStorageNodeStats);
+ public void aggregator_handles_updates_to_single_distributor_and_content_node() {
+ Fixture f = new Fixture(distributorNodes(1), contentNodes(3));
+ StatsBuilder stats = new StatsBuilder()
+ .add(3, "default", 10, 1)
+ .add(3, "global", 11, 2);
+ f.update(1, stats);
+ f.verify(stats);
}
@Test
- public void testComplex() {
- final int distributor1 = 1;
- final int distributor2 = 2;
- addDistributors(distributor1, distributor2);
-
- final int storageNode1 = 11;
- final int storageNode2 = 12;
- addStorageNodes(
- new StorageNodeSpec(storageNode1, "storage-node-1"),
- new StorageNodeSpec(storageNode2, "storage-node-2"));
-
- ClusterStatsAggregator aggregator = new ClusterStatsAggregator(distributors, storageNodes, updater);
-
- // Distributor 1.
- putStorageStats(storageNode1, 0, 1, 2, 3);
- putStorageStats(storageNode2, 20, 21, 22, 23);
- aggregator.updateForDistributor(hostnames, distributor1, storageStats);
-
- // Distributor 2.
- putStorageStats(storageNode1, 10, 11, 12, 13);
- putStorageStats(storageNode2, 30, 31, 32, 33);
- aggregator.updateForDistributor(hostnames, distributor2, storageStats);
-
- Map<String, NodeMergeStats> expectedStorageNodeStats = new HashMap<>();
- expectedStorageNodeStats.put("storage-node-1", createStats(storageNode1, 0 + 10, 1 + 11, 2 + 12, 3 + 13));
- expectedStorageNodeStats.put("storage-node-2", createStats(storageNode2, 20 + 30, 21 + 31, 22 + 32, 23 + 33));
-
- verify(updater, times(1)).updateMergeOpMetrics(expectedStorageNodeStats);
+ public void aggregator_handles_updates_to_multiple_distributors_and_content_nodes() {
+ Fixture f = new Fixture(distributorNodes(1, 2), contentNodes(3, 4));
+
+ f.update(1, new StatsBuilder()
+ .add(3, "default", 10, 1)
+ .add(3, "global", 11, 2)
+ .add(4, "default", 12, 3)
+ .add(4, "global", 13, 4));
+ f.update(2, new StatsBuilder()
+ .add(3, "default", 14, 5)
+ .add(3, "global", 15, 6)
+ .add(4, "default", 16, 7)
+ .add(4, "global", 17, 8));
+ f.verify(new StatsBuilder()
+ .add(3, "default", 10 + 14, 1 + 5)
+ .add(3, "global", 11 + 15, 2 + 6)
+ .add(4, "default", 12 + 16, 3 + 7)
+ .add(4, "global", 13 + 17, 4 + 8));
}
@Test
- public void testHashCodeCache() {
- final int distributor1 = 1;
- final int distributor2 = 2;
- addDistributors(distributor1, distributor2);
+ public void aggregator_handles_multiple_updates_from_same_distributor() {
+ Fixture f = new Fixture(distributorNodes(1, 2), contentNodes(3));
- final int storageNode1 = 11;
- final int storageNode2 = 12;
- addStorageNodes(
- new StorageNodeSpec(storageNode1, "storage-node-1"),
- new StorageNodeSpec(storageNode2, "storage-node-2"));
+ f.update(1, new StatsBuilder().add(3, "default"));
+ f.verify(new StatsBuilder().add(3, "default"));
- ClusterStatsAggregator aggregator = new ClusterStatsAggregator(distributors, storageNodes, updater);
+ f.update(2, new StatsBuilder().add(3, "default", 10, 1));
+ f.verify(new StatsBuilder().add(3, "default", 10, 1));
- // Distributor 1.
- putStorageStats(storageNode1, 0, 1, 2, 3);
- putStorageStats(storageNode2, 20, 21, 22, 23);
- aggregator.updateForDistributor(hostnames, distributor1, storageStats);
+ f.update(1, new StatsBuilder().add(3, "default", 11, 2));
+ f.verify(new StatsBuilder().add(3, "default", 10 + 11, 1 + 2));
- // Distributor 2.
- putStorageStats(storageNode1, 10, 11, 12, 13);
- putStorageStats(storageNode2, 30, 31, 32, 33);
- aggregator.updateForDistributor(hostnames, distributor2, storageStats);
+ f.update(2, new StatsBuilder().add(3, "default", 15, 6));
+ f.verify(new StatsBuilder().add(3, "default", 11 + 15, 2 + 6));
- // If we add call another updateForDistributor with the same arguments, updateMergeOpMetrics() should not be called.
- // See times(1) below.
- aggregator.updateForDistributor(hostnames, distributor2, storageStats);
+ f.update(1, new StatsBuilder().add(3, "default", 16, 7));
+ f.verify(new StatsBuilder().add(3, "default", 15 + 16, 6 + 7));
- Map<String, NodeMergeStats> expectedStorageNodeStats = new HashMap<>();
- expectedStorageNodeStats.put("storage-node-1", createStats(storageNode1, 0 + 10, 1 + 11, 2 + 12, 3 + 13));
- expectedStorageNodeStats.put("storage-node-2", createStats(storageNode2, 20 + 30, 21 + 31, 22 + 32, 23 + 33));
-
-
- verify(updater, times(1)).updateMergeOpMetrics(expectedStorageNodeStats);
+ f.update(2, new StatsBuilder().add(3, "default", 12, 3));
+ f.verify(new StatsBuilder().add(3, "default", 16 + 12, 7 + 3));
}
@Test
- public void testUnknownDistributor() {
- final int upDistributor = 1;
- final int DownDistributorIndex = 2;
- addDistributors(upDistributor);
-
- final int storageNodeIndex = 11;
- addStorageNodes(new StorageNodeSpec(storageNodeIndex, "storage-node"));
-
- putStorageStats(storageNodeIndex, 5, 6, 7, 8);
-
- ClusterStatsAggregator aggregator = new ClusterStatsAggregator(distributors, storageNodes, updater);
- aggregator.updateForDistributor(hostnames, DownDistributorIndex, storageStats);
-
- verify(updater, never()).updateMergeOpMetrics(any());
+ public void aggregator_handles_more_content_nodes_that_distributors() {
+ Fixture f = new Fixture(distributorNodes(1), contentNodes(3, 4));
+ StatsBuilder stats = new StatsBuilder()
+ .add(3, "default", 10, 1)
+ .add(4, "default", 11, 2);
+ f.update(1, stats);
+ f.verify(stats);
}
@Test
- public void testMoreStorageNodesThanDistributors() {
- final int distributor1 = 1;
- addDistributors(distributor1);
-
- final int storageNode1 = 11;
- final int storageNode2 = 12;
- addStorageNodes(
- new StorageNodeSpec(storageNode1, "storage-node-1"),
- new StorageNodeSpec(storageNode2, "storage-node-2"));
-
- ClusterStatsAggregator aggregator = new ClusterStatsAggregator(distributors, storageNodes, updater);
-
- // Distributor 1.
- putStorageStats(storageNode1, 0, 1, 2, 3);
- putStorageStats(storageNode2, 20, 21, 22, 23);
- aggregator.updateForDistributor(hostnames, distributor1, storageStats);
-
- Map<String, NodeMergeStats> expectedStorageNodeStats = new HashMap<>();
- expectedStorageNodeStats.put("storage-node-1", createStats(storageNode1, 0, 1, 2, 3));
- expectedStorageNodeStats.put("storage-node-2", createStats(storageNode2, 20, 21, 22, 23));
-
- verify(updater, times(1)).updateMergeOpMetrics(expectedStorageNodeStats);
+ public void aggregator_ignores_updates_to_unknown_distributor() {
+ Fixture f = new Fixture(distributorNodes(1), contentNodes(3));
+ final int downDistributorIndex = 2;
+ f.update(downDistributorIndex, new StatsBuilder()
+ .add(3, "default", 7, 3));
+ f.verify(new StatsBuilder().add(3));
}
- @Test
- public void testMoreDistributorsThanStorageNodes() {
- final int distributor1 = 1;
- final int distributor2 = 2;
- addDistributors(distributor1, distributor2);
-
- final int storageNode1 = 11;
- addStorageNodes(new StorageNodeSpec(storageNode1, "storage-node-1"));
-
- ClusterStatsAggregator aggregator = new ClusterStatsAggregator(distributors, storageNodes, updater);
-
- // Distributor 1.
- putStorageStats(storageNode1, 0, 1, 2, 3);
- aggregator.updateForDistributor(hostnames, distributor1, storageStats);
-
- // Distributor 2.
- putStorageStats(storageNode1, 10, 11, 12, 13);
- aggregator.updateForDistributor(hostnames, distributor2, storageStats);
-
- Map<String, NodeMergeStats> expectedStorageNodeStats = new HashMap<>();
- expectedStorageNodeStats.put("storage-node-1", createStats(storageNode1, 0 + 10, 1 + 11, 2 + 12, 3 + 13));
-
- verify(updater, times(1)).updateMergeOpMetrics(expectedStorageNodeStats);
- }
}
diff --git a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/StateVersionTrackerTest.java b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/StateVersionTrackerTest.java
index 0af7bcbfeaf..d27acf8bc17 100644
--- a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/StateVersionTrackerTest.java
+++ b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/StateVersionTrackerTest.java
@@ -11,14 +11,11 @@ import org.junit.Test;
import java.util.Arrays;
import java.util.Optional;
-import static org.hamcrest.CoreMatchers.hasItems;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
public class StateVersionTrackerTest {
@@ -28,7 +25,7 @@ public class StateVersionTrackerTest {
}
private static StateVersionTracker createWithMockedMetrics() {
- return new StateVersionTracker(mock(MetricUpdater.class));
+ return new StateVersionTracker();
}
private static void updateAndPromote(final StateVersionTracker versionTracker,
diff --git a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/hostinfo/StorageNodeStatsBridgeTest.java b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/hostinfo/StorageNodeStatsBridgeTest.java
index 8a17fedee86..5319d741503 100644
--- a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/hostinfo/StorageNodeStatsBridgeTest.java
+++ b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/hostinfo/StorageNodeStatsBridgeTest.java
@@ -1,8 +1,8 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.clustercontroller.core.hostinfo;
-import com.yahoo.vespa.clustercontroller.core.NodeMergeStats;
-import com.yahoo.vespa.clustercontroller.core.StorageMergeStats;
+import com.yahoo.vespa.clustercontroller.core.ContentNodeStats;
+import com.yahoo.vespa.clustercontroller.core.ContentClusterStats;
import com.yahoo.vespa.clustercontroller.core.StorageNodeStats;
import com.yahoo.vespa.clustercontroller.core.StorageNodeStatsContainer;
import org.junit.Test;
@@ -12,11 +12,11 @@ import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.Iterator;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.*;
/**
* @author hakonhall
@@ -49,19 +49,30 @@ public class StorageNodeStatsBridgeTest {
}
@Test
- public void testStorageMergeStats() throws IOException {
+ public void testContentNodeStats() throws IOException {
String data = getJsonString();
HostInfo hostInfo = HostInfo.createHostInfo(data);
- StorageMergeStats storageMergeStats = StorageNodeStatsBridge.generate(hostInfo.getDistributor());
- int size = 0;
- for (NodeMergeStats mergeStats : storageMergeStats) {
- assertThat(mergeStats.getCopyingIn().getBuckets(), is(2L));
- assertThat(mergeStats.getCopyingOut().getBuckets(), is(4L));
- assertThat(mergeStats.getSyncing().getBuckets(), is(1L));
- assertThat(mergeStats.getMovingOut().getBuckets(), is(3L));
- size++;
+ ContentClusterStats clusterStats = StorageNodeStatsBridge.generate(hostInfo.getDistributor());
+ Iterator<ContentNodeStats> itr = clusterStats.iterator();
+ { // content node 0
+ ContentNodeStats stats = itr.next();
+ assertThat(stats.getNodeIndex(), is(0));
+ assertThat(stats.getBucketSpaces().size(), is(2));
+ assertBucketSpaceStats(11, 3, stats.getBucketSpaces().get("default"));
+ assertBucketSpaceStats(13, 5, stats.getBucketSpaces().get("global"));
}
- assertThat(size, is(2));
+ { // content node 1
+ ContentNodeStats stats = itr.next();
+ assertThat(stats.getNodeIndex(), is(1));
+ assertThat(stats.getBucketSpaces().size(), is(1));
+ assertBucketSpaceStats(0, 0, stats.getBucketSpaces().get("default"));
+ }
+ assertFalse(itr.hasNext());
+ }
+
+ private static void assertBucketSpaceStats(long expBucketsTotal, long expBucketsPending, ContentNodeStats.BucketSpaceStats stats) {
+ assertThat(stats.getBucketsTotal(), is(expBucketsTotal));
+ assertThat(stats.getBucketsPending(), is(expBucketsPending));
}
}
diff --git a/protocols/getnodestate/host_info.json b/protocols/getnodestate/host_info.json
index 5ef62d1a84f..305f279c847 100644
--- a/protocols/getnodestate/host_info.json
+++ b/protocols/getnodestate/host_info.json
@@ -48,20 +48,22 @@
"count": 16
}
},
- "outstanding-merge-ops": {
- "syncing": {
- "buckets": 1
+ "bucket-spaces": [
+ {
+ "name": "default",
+ "buckets": {
+ "total": 11,
+ "pending": 3
+ }
},
- "copying-in": {
- "buckets": 2
- },
- "moving-out": {
- "buckets": 3
- },
- "copying-out": {
- "buckets": 4
+ {
+ "name": "global",
+ "buckets": {
+ "total": 13,
+ "pending": 5
+ }
}
- }
+ ]
},
{
"node-index": 1,
@@ -71,24 +73,13 @@
"latency-ms-sum": 17,
"count": 18
}
- },
- "outstanding-merge-ops": {
- "syncing": {
- "buckets": 1
- },
- "copying-in": {
- "buckets": 2
- },
- "moving-out": {
- "buckets": 3
- },
- "copying-out": {
- "buckets": 4
+ },
+ "bucket-spaces": [
+ {
+ "name": "default"
}
- }
-
+ ]
}
-
]
}
}