aboutsummaryrefslogtreecommitdiffstats
path: root/node-repository
diff options
context:
space:
mode:
authorJon Bratseth <bratseth@gmail.com>2023-02-15 13:52:23 +0100
committerJon Bratseth <bratseth@gmail.com>2023-02-15 13:52:23 +0100
commit4c9206d8119d1131e248419c7e1ba669c396b89b (patch)
tree414dfdc40c088e06c108e28a7f050bf375ce9d3b /node-repository
parentb9b7e3cf8529e6f7e9904c1013174e37c0460696 (diff)
Exchange BCP info WIP
Diffstat (limited to 'node-repository')
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/applications/BcpGroupInfo.java2
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Autoscaling.java35
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterModel.java22
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializer.java41
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationPatcher.java35
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationSerializer.java15
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java8
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializerTest.java6
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationPatcherTest.java67
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application1.json22
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application2.json5
11 files changed, 186 insertions, 72 deletions
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/applications/BcpGroupInfo.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/applications/BcpGroupInfo.java
index 6b0ea8532be..e9f3303c9cb 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/applications/BcpGroupInfo.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/applications/BcpGroupInfo.java
@@ -27,7 +27,7 @@ public class BcpGroupInfo {
this.cpuCostPerQuery = cpuCostPerQuery;
}
- /** Returns the average query rate (queries/second) of the other clusters in the group this belongs to. */
+ /** Returns the max peak query rate (queries/second) of the other clusters in the group this belongs to. */
public double queryRate() { return queryRate; }
/** Returns the average growth rate headroom of the other clusters in the group this belongs to. */
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Autoscaling.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Autoscaling.java
index ebab2efbaa6..fd769ec913d 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Autoscaling.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Autoscaling.java
@@ -1,6 +1,7 @@
package com.yahoo.vespa.hosted.provision.autoscale;
import com.yahoo.config.provision.ClusterResources;
+import io.questdb.Metrics;
import java.time.Instant;
import java.util.Objects;
@@ -19,15 +20,17 @@ public class Autoscaling {
private final Instant at;
private final Load peak;
private final Load ideal;
+ private final Metrics metrics;
public Autoscaling(Status status, String description, Optional<ClusterResources> resources, Instant at,
- Load peak, Load ideal) {
+ Load peak, Load ideal, Metrics metrics) {
this.status = status;
this.description = description;
this.resources = resources;
this.at = at;
this.peak = peak;
this.ideal = ideal;
+ this.metrics = metrics;
}
public Status status() { return status; }
@@ -48,8 +51,10 @@ public class Autoscaling {
/** Returns the ideal load the cluster in question should have. */
public Load ideal() { return ideal; }
+ public Metrics metrics() { return metrics; }
+
public Autoscaling with(Status status, String description) {
- return new Autoscaling(status, description, resources, at, peak, ideal);
+ return new Autoscaling(status, description, resources, at, peak, ideal, metrics);
}
/** Converts this autoscaling into an ideal one at the completion of it. */
@@ -59,7 +64,8 @@ public class Autoscaling {
Optional.empty(),
at,
peak,
- ideal);
+ ideal,
+ metrics);
}
public boolean isEmpty() { return this.equals(empty()); }
@@ -73,12 +79,13 @@ public class Autoscaling {
if ( ! this.at.equals(other.at)) return false;
if ( ! this.peak.equals(other.peak)) return false;
if ( ! this.ideal.equals(other.ideal)) return false;
+ if ( ! this.metrics.equals(other.metrics)) return false;
return true;
}
@Override
public int hashCode() {
- return Objects.hash(status, description, at, peak, ideal);
+ return Objects.hash(status, description, at, peak, ideal, metrics);
}
@Override
@@ -93,7 +100,8 @@ public class Autoscaling {
Optional.empty(),
Instant.EPOCH,
Load.zero(),
- Load.zero());
+ Load.zero(),
+ Metrics.zero());
}
/** Creates an autoscaling conclusion which does not change the current allocation for a specified reason. */
@@ -103,7 +111,8 @@ public class Autoscaling {
Optional.empty(),
clusterModel.at(),
clusterModel.peakLoad(),
- clusterModel.idealLoad());
+ clusterModel.idealLoad(),
+ clusterModel.metrics());
}
/** Creates an autoscaling conclusion to scale. */
@@ -113,7 +122,8 @@ public class Autoscaling {
Optional.of(target),
clusterModel.at(),
clusterModel.peakLoad(),
- clusterModel.idealLoad());
+ clusterModel.idealLoad(),
+ clusterModel.metrics());
}
public enum Status {
@@ -133,6 +143,15 @@ public class Autoscaling {
/** Rescaling of this cluster has been scheduled */
rescaling
- };
+ }
+
+ // Used to create BcpGroupInfo
+ public record Metrics(double queryRate, double growthRateHeadroom, double cpuCostPerQuery) {
+
+ public static Metrics zero() {
+ return new Metrics(0, 0, 0);
+ }
+
+ }
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterModel.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterModel.java
index 4edcdbd3fa5..d122f719eff 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterModel.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterModel.java
@@ -126,14 +126,6 @@ public class ClusterModel {
return adjustment;
}
- public OptionalDouble cpuCostPerQuery() {
- if (averageQueryRate().isEmpty()) return OptionalDouble.empty();
- // TODO: Query rate should generally be sampled at the time where we see the peak resource usage
- int fanOut = clusterSpec.type().isContainer() ? 1 : groupSize();
- return OptionalDouble.of(peakLoad().cpu() * queryCpuFraction() * fanOut * nodes.not().retired().first().get().resources().vcpu()
- / averageQueryRate().getAsDouble() / groupCount());
- }
-
public boolean isStable(NodeRepository nodeRepository) {
// An autoscaling decision was recently made
if (hasScaledIn(Duration.ofMinutes(5)))
@@ -216,9 +208,23 @@ public class ClusterModel {
return ideal;
}
+ public Autoscaling.Metrics metrics() {
+ return new Autoscaling.Metrics(averageQueryRate().orElse(0),
+ growthRateHeadroom(),
+ cpuCostPerQuery().orElse(0));
+ }
+
/** Returns the instant this model was created. */
public Instant at() { return at;}
+ private OptionalDouble cpuCostPerQuery() {
+ if (averageQueryRate().isEmpty()) return OptionalDouble.empty();
+ // TODO: Query rate should generally be sampled at the time where we see the peak resource usage
+ int fanOut = clusterSpec.type().isContainer() ? 1 : groupSize();
+ return OptionalDouble.of(peakLoad().cpu() * queryCpuFraction() * fanOut * nodes.not().retired().first().get().resources().vcpu()
+ / averageQueryRate().getAsDouble() / groupCount());
+ }
+
private Load adjustQueryDependentIdealLoadByBcpGroupInfo(Load ideal) {
double currentClusterTotalVcpuPerGroup = nodes.not().retired().first().get().resources().vcpu() * groupSize();
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializer.java
index 1b73dee8b6c..38675ba3758 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializer.java
@@ -64,10 +64,10 @@ public class ApplicationSerializer {
private static final String groupsKey = "groups";
private static final String nodeResourcesKey = "resources";
private static final String scalingEventsKey = "scalingEvents";
- private static final String autoscalingStatusObjectKey = "autoscalingStatusObject";
private static final String descriptionKey = "description";
private static final String peakKey = "peak";
private static final String idealKey = "ideal";
+ private static final String metricsKey = "metrics";
private static final String cpuKey = "cpu";
private static final String memoryKey = "memory";
private static final String diskKey = "disk";
@@ -146,8 +146,8 @@ public class ApplicationSerializer {
clusterResourcesFromSlime(clusterObject.field(maxResourcesKey)),
intRangeFromSlime(clusterObject.field(groupSizeKey)),
clusterObject.field(requiredKey).asBool(),
- autoscalingFromSlime(clusterObject.field(suggestedKey), clusterObject.field("nonExisting")),
- autoscalingFromSlime(clusterObject.field(targetKey), clusterObject.field(autoscalingStatusObjectKey)),
+ autoscalingFromSlime(clusterObject.field(suggestedKey)),
+ autoscalingFromSlime(clusterObject.field(targetKey)),
bcpGroupInfoFromSlime(clusterObject.field(bcpGroupInfoKey)),
scalingEventsFromSlime(clusterObject.field(scalingEventsKey)));
}
@@ -159,6 +159,7 @@ public class ApplicationSerializer {
autoscalingObject.setLong(atKey, autoscaling.at().toEpochMilli());
toSlime(autoscaling.peak(), autoscalingObject.setObject(peakKey));
toSlime(autoscaling.ideal(), autoscalingObject.setObject(idealKey));
+ toSlime(autoscaling.metrics(), autoscalingObject.setObject(metricsKey));
}
private static void toSlime(ClusterResources resources, Cursor clusterResourcesObject) {
@@ -200,34 +201,28 @@ public class ApplicationSerializer {
loadObject.field(diskKey).asDouble());
}
- private static Autoscaling autoscalingFromSlime(Inspector autoscalingObject,
- Inspector legacyAutoscalingStatusObject) {
- if ( ! autoscalingObject.valid()) return Autoscaling.empty();
+ private static void toSlime(Autoscaling.Metrics metrics, Cursor metricsObject) {
+ metricsObject.setDouble(queryRateKey, metrics.queryRate());
+ metricsObject.setDouble(growthRateHeadroomKey, metrics.growthRateHeadroom());
+ metricsObject.setDouble(cpuCostPerQueryKey, metrics.cpuCostPerQuery());
+ }
- if ( ! autoscalingObject.field(atKey).valid()) { // TODO: Remove after January 2023
- return new Autoscaling(fromAutoscalingStatusCode(legacyAutoscalingStatusObject.field(statusKey).asString()),
- legacyAutoscalingStatusObject.field(descriptionKey).asString(),
- optionalClusterResourcesFromSlime(autoscalingObject),
- Instant.EPOCH,
- Load.zero(),
- Load.zero());
- }
+ private static Autoscaling.Metrics metricsFromSlime(Inspector metricsObject) {
+ return new Autoscaling.Metrics(metricsObject.field(queryRateKey).asDouble(),
+ metricsObject.field(growthRateHeadroomKey).asDouble(),
+ metricsObject.field(cpuCostPerQueryKey).asDouble());
+ }
- if (legacyAutoscalingStatusObject.valid()) { // TODO: Remove after January 2023
- return new Autoscaling(fromAutoscalingStatusCode(legacyAutoscalingStatusObject.field(statusKey).asString()),
- legacyAutoscalingStatusObject.field(descriptionKey).asString(),
- optionalClusterResourcesFromSlime(autoscalingObject.field(resourcesKey)),
- Instant.ofEpochMilli(autoscalingObject.field(atKey).asLong()),
- loadFromSlime(autoscalingObject.field(peakKey)),
- loadFromSlime(autoscalingObject.field(idealKey)));
- }
+ private static Autoscaling autoscalingFromSlime(Inspector autoscalingObject) {
+ if ( ! autoscalingObject.valid()) return Autoscaling.empty();
return new Autoscaling(fromAutoscalingStatusCode(autoscalingObject.field(statusKey).asString()),
autoscalingObject.field(descriptionKey).asString(),
optionalClusterResourcesFromSlime(autoscalingObject.field(resourcesKey)),
Instant.ofEpochMilli(autoscalingObject.field(atKey).asLong()),
loadFromSlime(autoscalingObject.field(peakKey)),
- loadFromSlime(autoscalingObject.field(idealKey)));
+ loadFromSlime(autoscalingObject.field(idealKey)),
+ metricsFromSlime(autoscalingObject.field(metricsKey)));
}
private static void toSlime(BcpGroupInfo bcpGroupInfo, Cursor bcpGroupInfoObject) {
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationPatcher.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationPatcher.java
index 871f30570f5..f4022570a9b 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationPatcher.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationPatcher.java
@@ -2,6 +2,7 @@
package com.yahoo.vespa.hosted.provision.restapi;
import com.yahoo.config.provision.ApplicationId;
+import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.io.IOUtils;
import com.yahoo.slime.Inspector;
import com.yahoo.slime.SlimeUtils;
@@ -9,11 +10,14 @@ import com.yahoo.slime.Type;
import com.yahoo.transaction.Mutex;
import com.yahoo.vespa.hosted.provision.NodeRepository;
import com.yahoo.vespa.hosted.provision.applications.Application;
+import com.yahoo.vespa.hosted.provision.applications.BcpGroupInfo;
+import com.yahoo.vespa.hosted.provision.applications.Cluster;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.time.Duration;
+import java.util.Optional;
/**
* A class which can take a partial JSON node/v2 application JSON structure and apply it to an application object.
@@ -47,13 +51,9 @@ public class ApplicationPatcher implements AutoCloseable {
/** Applies the json to the application and returns it. */
public Application apply() {
- inspector.traverse((String name, Inspector value) -> {
- try {
- application = applyField(application, name, value);
- } catch (IllegalArgumentException e) {
- throw new IllegalArgumentException("Could not set field '" + name + "'", e);
- }
- });
+ inspector.field("currentReadShare").ifValid(v -> application = application.with(application.status().withCurrentReadShare(asDouble(v))));
+ inspector.field("maxReadShare").ifValid(v -> application = application.with(application.status().withMaxReadShare(asDouble(v))));
+ inspector.field("clusters").ifValid(cluster -> application = applyClustersField(cluster));
return application;
}
@@ -67,13 +67,20 @@ public class ApplicationPatcher implements AutoCloseable {
lock.close();
}
- private Application applyField(Application application, String name, Inspector value) {
- return switch (name) {
- case "currentReadShare" -> application.with(application.status().withCurrentReadShare(asDouble(value)));
- case "maxReadShare" -> application.with(application.status().withMaxReadShare(asDouble(value)));
- default -> throw new IllegalArgumentException("Could not apply field '" + name +
- "' on an application: No such modifiable field");
- };
+ private Application applyClustersField(Inspector clusters) {
+ clusters.traverse((String key, Inspector cluster) -> application = applyClusterField(key, cluster));
+ return application;
+ }
+
+ private Application applyClusterField(String id, Inspector clusterObject) {
+ Optional<Cluster> cluster = application.cluster(ClusterSpec.Id.from(id));
+ if (cluster.isEmpty()) return application;
+ Inspector bcpGroupInfoObject = clusterObject.field("bcpGroupInfo");
+ if ( ! bcpGroupInfoObject.valid()) return application;
+ double queryRate = bcpGroupInfoObject.field("queryRate").asDouble();
+ double growthRateHeadroom = bcpGroupInfoObject.field("growthRateHeadroom").asDouble();
+ double cpuCostPerQuery = bcpGroupInfoObject.field("cpuCostPerQuery").asDouble();
+ return application.with(cluster.get().with(new BcpGroupInfo(queryRate, growthRateHeadroom, cpuCostPerQuery)));
}
private Double asDouble(Inspector field) {
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationSerializer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationSerializer.java
index 8a82069c2b6..7cf284eca3b 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationSerializer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationSerializer.java
@@ -80,6 +80,7 @@ public class ApplicationSerializer {
autoscalingObject.setLong("at", autoscaling.at().toEpochMilli());
toSlime(autoscaling.peak(), autoscalingObject.setObject("peak"));
toSlime(autoscaling.ideal(), autoscalingObject.setObject("ideal"));
+ toSlime(autoscaling.metrics(), autoscalingObject.setObject("metrics"));
}
private static void toSlime(ClusterResources resources, Cursor clusterResourcesObject) {
@@ -93,10 +94,16 @@ public class ApplicationSerializer {
range.to().ifPresent(to -> rangeObject.setLong("to", range.to().getAsInt()));
}
- private static void toSlime(Load load, Cursor utilizationObject) {
- utilizationObject.setDouble("cpu", load.cpu());
- utilizationObject.setDouble("memory", load.memory());
- utilizationObject.setDouble("disk", load.disk());
+ private static void toSlime(Load load, Cursor loadObject) {
+ loadObject.setDouble("cpu", load.cpu());
+ loadObject.setDouble("memory", load.memory());
+ loadObject.setDouble("disk", load.disk());
+ }
+
+ private static void toSlime(Autoscaling.Metrics metrics, Cursor metricsObject) {
+ metricsObject.setDouble("queryRate", metrics.queryRate());
+ metricsObject.setDouble("growthRateHeadroom", metrics.growthRateHeadroom());
+ metricsObject.setDouble("cpuCostPerQuery", metrics.cpuCostPerQuery());
}
private static void scalingEventsToSlime(List<ScalingEvent> scalingEvents, Cursor scalingEventsArray) {
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java
index 7127cd401e8..d27bd3aea4a 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java
@@ -216,14 +216,16 @@ public class MockNodeRepository extends NodeRepository {
new NodeResources(3, 20, 100, 1))),
clock().instant(),
Load.zero(),
- Load.zero()));
+ Load.zero(),
+ Autoscaling.Metrics.zero()));
cluster1 = cluster1.withTarget(new Autoscaling(Autoscaling.Status.unavailable,
"",
Optional.of(new ClusterResources(4, 1,
new NodeResources(3, 16, 100, 1))),
clock().instant(),
- Load.zero(),
- Load.zero()));
+ new Load(0.1, 0.2, 0.3),
+ new Load(0.4, 0.5, 0.6),
+ new Autoscaling.Metrics(0.7, 0.8, 0.9)));
try (Mutex lock = applications().lock(app1Id)) {
applications().put(app1.with(cluster1), lock);
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializerTest.java
index c8dc0d97320..d04fe1bdda2 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializerTest.java
@@ -55,14 +55,16 @@ public class ApplicationSerializerTest {
new NodeResources(0.5, 4, 14, 16))),
Instant.ofEpochMilli(1234L),
new Load(0.1, 0.2, 0.3),
- new Load(0.4, 0.5, 0.6)),
+ new Load(0.4, 0.5, 0.6),
+ new Autoscaling.Metrics(0.7, 0.8, 0.9)),
new Autoscaling(Autoscaling.Status.insufficient,
"Autoscaling status",
Optional.of(new ClusterResources(10, 5,
new NodeResources(2, 4, 14, 16))),
Instant.ofEpochMilli(5678L),
Load.zero(),
- Load.one()),
+ Load.one(),
+ Autoscaling.Metrics.zero()),
new BcpGroupInfo(0.1, 0.2, 0.3),
List.of(new ScalingEvent(new ClusterResources(10, 5, minResources),
new ClusterResources(12, 6, minResources),
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationPatcherTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationPatcherTest.java
index 79722a747e2..200187ea5d6 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationPatcherTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationPatcherTest.java
@@ -2,14 +2,20 @@
package com.yahoo.vespa.hosted.provision.restapi;
import com.yahoo.config.provision.ApplicationId;
-import com.yahoo.vespa.hosted.provision.NodeRepository;
+import com.yahoo.config.provision.Capacity;
+import com.yahoo.config.provision.ClusterResources;
+import com.yahoo.config.provision.ClusterSpec;
+import com.yahoo.config.provision.NodeResources;
import com.yahoo.vespa.hosted.provision.NodeRepositoryTester;
import com.yahoo.vespa.hosted.provision.applications.Application;
+import com.yahoo.vespa.hosted.provision.applications.BcpGroupInfo;
+import com.yahoo.vespa.hosted.provision.applications.Cluster;
import org.junit.Test;
import java.io.ByteArrayInputStream;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
/**
* @author bratseth
@@ -26,8 +32,63 @@ public class ApplicationPatcherTest {
application.id(),
tester.nodeRepository());
Application patched = patcher.apply();
- assertEquals(0.4, patcher.application().status().currentReadShare(), 0.0000001);
- assertEquals(1.0, patcher.application().status().maxReadShare(), 0.0000001);
+ assertEquals(0.4, patched.status().currentReadShare(), 0.0000001);
+ assertEquals(1.0, patched.status().maxReadShare(), 0.0000001);
+ patcher.close();
+ }
+
+ @Test
+ public void testPatchingWithBcpGroupInfo() {
+ var c1 = ClusterSpec.Id.from("c1");
+ var c2 = ClusterSpec.Id.from("c2");
+ var capacity = Capacity.from(new ClusterResources(10, 1, new NodeResources(1.0, 10.0, 100.0, 3.0)));
+ NodeRepositoryTester tester = new NodeRepositoryTester();
+ Application application = Application.empty(ApplicationId.from("t1", "a1", "i1"));
+ application = application.with(Cluster.create(c1, false, capacity));
+ application = application.with(Cluster.create(c2, false, capacity));
+ tester.nodeRepository().applications().put(application, tester.nodeRepository().applications().lock(application.id()));
+
+ String patch = """
+ {
+ "currentReadShare": 0.4,
+ "maxReadShare": 1.0,
+ "clusters": {
+ "c1": {
+ "bcpGroupInfo": {
+ "queryRate": 0.1,
+ "growthRateHeadroom": 0.2,
+ "cpuCostPerQuery": 0.3
+ }
+ },
+ "c2": {
+ "bcpGroupInfo": {
+ "queryRate": 1,
+ "growthRateHeadroom": 2,
+ "cpuCostPerQuery": 3
+ }
+ },
+ "ignored": {
+ "bcpGroupInfo": {
+ "queryRate": 1,
+ "growthRateHeadroom": 2,
+ "cpuCostPerQuery": 3
+ }
+ }
+ }
+ }
+ """;
+
+ ApplicationPatcher patcher = new ApplicationPatcher(new ByteArrayInputStream(patch.getBytes()),
+ application.id(),
+ tester.nodeRepository());
+ Application patched = patcher.apply();
+ assertEquals(0.4, patched.status().currentReadShare(), 0.0000001);
+ assertEquals(1.0, patched.status().maxReadShare(), 0.0000001);
+ assertEquals(new BcpGroupInfo(0.1, 0.2, 0.3),
+ patched.cluster(c1).get().bcpGroupInfo());
+ assertEquals(new BcpGroupInfo(1.0, 2.0, 3.0),
+ patched.cluster(c2).get().bcpGroupInfo());
+ assertTrue(patched.cluster(ClusterSpec.Id.from("ignored")).isEmpty());
patcher.close();
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application1.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application1.json
index c9046998e91..4c18b614075 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application1.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application1.json
@@ -69,6 +69,11 @@
"cpu" : 0.0,
"memory" : 0.0,
"disk" : 0.0
+ },
+ "metrics" : {
+ "queryRate" : 0.0,
+ "growthRateHeadroom" : 0.0,
+ "cpuCostPerQuery" : 0.0
}
},
"target" : {
@@ -89,14 +94,19 @@
},
"at" : 123,
"peak" : {
- "cpu" : 0.0,
- "memory" : 0.0,
- "disk" : 0.0
+ "cpu" : 0.1,
+ "memory" : 0.2,
+ "disk" : 0.3
},
"ideal" : {
- "cpu" : 0.0,
- "memory" : 0.0,
- "disk" : 0.0
+ "cpu" : 0.4,
+ "memory" : 0.5,
+ "disk" : 0.6
+ },
+ "metrics" : {
+ "queryRate" : 0.7,
+ "growthRateHeadroom" : 0.8,
+ "cpuCostPerQuery" : 0.9
}
},
"scalingEvents" : [
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application2.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application2.json
index 4166d20ad8d..ea4d5e01ebc 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application2.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application2.json
@@ -56,6 +56,11 @@
"cpu" : 0.0,
"memory" : 0.0,
"disk" : 0.0
+ },
+ "metrics" : {
+ "queryRate" : 0.0,
+ "growthRateHeadroom" : 0.0,
+ "cpuCostPerQuery" : 0.0
}
},
"scalingEvents" : [