diff options
author | Jon Bratseth <bratseth@gmail.com> | 2020-10-20 22:52:21 +0200 |
---|---|---|
committer | Jon Bratseth <bratseth@gmail.com> | 2020-10-22 15:31:33 +0200 |
commit | 53e5f06cd8e545be91a7fc1e9cf0e7eacb249aae (patch) | |
tree | c5f84be1f45ae12b77557cb9faa2778f8cd66ee8 | |
parent | 3013538d73fc9546f5d3eba7a3211e6b5c41f485 (diff) |
Make NodeTimeseries immutable
3 files changed, 20 insertions, 22 deletions
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterTimeseries.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterTimeseries.java index 49dea25f8a8..52f6a5bbabc 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterTimeseries.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterTimeseries.java @@ -93,7 +93,7 @@ public class ClusterTimeseries { private List<NodeTimeseries> filterStale(List<NodeTimeseries> timeseries, Map<String, Instant> startTimePerHost) { if (startTimePerHost.isEmpty()) return timeseries; // Map is either empty or complete - return timeseries.stream().map(m -> m.copyAfter(startTimePerHost.get(m.hostname()))).collect(Collectors.toList()); + return timeseries.stream().map(m -> m.justAfter(startTimePerHost.get(m.hostname()))).collect(Collectors.toList()); } } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/NodeMetricsDb.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/NodeMetricsDb.java index c4aacb63de6..271f8601ae2 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/NodeMetricsDb.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/NodeMetricsDb.java @@ -10,10 +10,10 @@ import java.time.Instant; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.stream.Collectors; /** * An in-memory time-series "database" of node metrics. @@ -55,7 +55,7 @@ public class NodeMetricsDb { new ArrayList<>()); db.put(hostname, timeseries); } - timeseries.add(snapshot); + db.put(hostname, timeseries.add(snapshot)); } /** Must be called intermittently (as long as any add methods are called) to gc old data */ @@ -63,11 +63,13 @@ public class NodeMetricsDb { synchronized (lock) { // Each measurement is Object + long + float = 16 + 8 + 4 = 28 bytes // 12 hours with 1k nodes and 3 resources and 1 measurement/sec is about 5Gb - for (Iterator<NodeTimeseries> i = db.values().iterator(); i.hasNext(); ) { - var snapshot = i.next(); - snapshot.removeOlderThan(clock.instant().minus(Autoscaler.scalingWindow(snapshot.type())).toEpochMilli()); - if (snapshot.isEmpty()) - i.remove(); + for (String hostname : db.keySet()) { + var timeseries = db.get(hostname); + timeseries = timeseries.justAfter(clock.instant().minus(Autoscaler.scalingWindow(timeseries.type()))); + if (timeseries.isEmpty()) + db.remove(hostname); + else + db.put(hostname, timeseries); } } } @@ -82,7 +84,7 @@ public class NodeMetricsDb { for (String hostname : hostnames) { NodeTimeseries measurements = db.get(hostname); if (measurements == null) continue; - measurements = measurements.copyAfter(startTime); + measurements = measurements.justAfter(startTime); if (measurements.isEmpty()) continue; measurementsList.add(measurements); } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/NodeTimeseries.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/NodeTimeseries.java index e6f786f55aa..778a2110d2c 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/NodeTimeseries.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/NodeTimeseries.java @@ -4,6 +4,7 @@ package com.yahoo.vespa.hosted.provision.autoscale; import com.yahoo.config.provision.ClusterSpec; import java.time.Instant; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; @@ -26,8 +27,6 @@ public class NodeTimeseries { this.snapshots = snapshots; } - // Public access - public boolean isEmpty() { return snapshots.isEmpty(); } public int size() { return snapshots.size(); } @@ -40,20 +39,17 @@ public class NodeTimeseries { public String hostname() { return hostname; } - public NodeTimeseries copyAfter(Instant oldestTime) { + public NodeTimeseries add(MetricSnapshot snapshot) { + List<MetricSnapshot> list = new ArrayList<>(snapshots); + list.add(snapshot); + return new NodeTimeseries(hostname(), type(), list); + } + + public NodeTimeseries justAfter(Instant oldestTime) { return new NodeTimeseries(hostname, type, snapshots.stream() - .filter(measurement -> measurement.at().equals(oldestTime) || measurement.at().isAfter(oldestTime)) + .filter(snapshot -> snapshot.at().equals(oldestTime) || snapshot.at().isAfter(oldestTime)) .collect(Collectors.toList())); } - // Restricted mutation - - void add(MetricSnapshot snapshot) { snapshots.add(snapshot); } - - void removeOlderThan(long oldestTimestamp) { - while (!snapshots.isEmpty() && snapshots.get(0).at().toEpochMilli() < oldestTimestamp) - snapshots.remove(0); - } - } |