summaryrefslogtreecommitdiffstats
path: root/config-provisioning
diff options
context:
space:
mode:
authorJon Bratseth <bratseth@verizonmedia.com>2019-05-18 15:44:24 +0200
committerJon Bratseth <bratseth@verizonmedia.com>2019-05-18 15:44:24 +0200
commitfddfaf0d3a98b8ea389e032c8e6fc66a0404f542 (patch)
tree2455bfb8788d41e37d064ea52b501ab028bc03fb /config-provisioning
parentfac14833ab735244d67abd8114a8ca46befe292f (diff)
Take disk speed into account
Diffstat (limited to 'config-provisioning')
-rw-r--r--config-provisioning/abi-spec.json25
-rw-r--r--config-provisioning/src/main/java/com/yahoo/config/provision/AllocatedHosts.java25
-rw-r--r--config-provisioning/src/main/java/com/yahoo/config/provision/Flavor.java62
-rw-r--r--config-provisioning/src/main/java/com/yahoo/config/provision/NodeResources.java81
-rw-r--r--config-provisioning/src/test/java/com/yahoo/config/provision/AllocatedHostsTest.java4
5 files changed, 152 insertions, 45 deletions
diff --git a/config-provisioning/abi-spec.json b/config-provisioning/abi-spec.json
index fc9a3e011d9..f942ae56d64 100644
--- a/config-provisioning/abi-spec.json
+++ b/config-provisioning/abi-spec.json
@@ -384,6 +384,8 @@
"public java.lang.String name()",
"public int cost()",
"public boolean isStock()",
+ "public boolean isConfigured()",
+ "public com.yahoo.config.provision.NodeResources resources()",
"public double getMinMainMemoryAvailableGb()",
"public double getMinDiskAvailableGb()",
"public boolean hasFastDisk()",
@@ -401,8 +403,6 @@
"public boolean hasAtLeast(com.yahoo.config.provision.NodeResources)",
"public void freeze()",
"public boolean isLargerThan(com.yahoo.config.provision.Flavor)",
- "public boolean isConfigured()",
- "public com.yahoo.config.provision.NodeResources resources()",
"public int hashCode()",
"public boolean equals(java.lang.Object)",
"public java.lang.String toString()"
@@ -590,6 +590,24 @@
],
"fields": []
},
+ "com.yahoo.config.provision.NodeResources$DiskSpeed": {
+ "superClass": "java.lang.Enum",
+ "interfaces": [],
+ "attributes": [
+ "public",
+ "final",
+ "enum"
+ ],
+ "methods": [
+ "public static com.yahoo.config.provision.NodeResources$DiskSpeed[] values()",
+ "public static com.yahoo.config.provision.NodeResources$DiskSpeed valueOf(java.lang.String)"
+ ],
+ "fields": [
+ "public static final enum com.yahoo.config.provision.NodeResources$DiskSpeed fast",
+ "public static final enum com.yahoo.config.provision.NodeResources$DiskSpeed slow",
+ "public static final enum com.yahoo.config.provision.NodeResources$DiskSpeed any"
+ ]
+ },
"com.yahoo.config.provision.NodeResources": {
"superClass": "java.lang.Object",
"interfaces": [],
@@ -598,14 +616,17 @@
],
"methods": [
"public void <init>(double, double, double)",
+ "public void <init>(double, double, double, com.yahoo.config.provision.NodeResources$DiskSpeed)",
"public double vcpu()",
"public double memoryGb()",
"public double diskGb()",
+ "public com.yahoo.config.provision.NodeResources$DiskSpeed diskSpeed()",
"public boolean allocateByLegacyName()",
"public java.util.Optional legacyName()",
"public boolean equals(java.lang.Object)",
"public int hashCode()",
"public java.lang.String toString()",
+ "public boolean satisfies(com.yahoo.config.provision.NodeResources)",
"public static com.yahoo.config.provision.NodeResources fromLegacyName(java.lang.String)"
],
"fields": []
diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/AllocatedHosts.java b/config-provisioning/src/main/java/com/yahoo/config/provision/AllocatedHosts.java
index d90f52e971b..de4f3a555bd 100644
--- a/config-provisioning/src/main/java/com/yahoo/config/provision/AllocatedHosts.java
+++ b/config-provisioning/src/main/java/com/yahoo/config/provision/AllocatedHosts.java
@@ -39,6 +39,7 @@ public class AllocatedHosts {
private static final String vcpuKey = "vcpu";
private static final String memoryKey = "memory";
private static final String diskKey = "disk";
+ private static final String diskSpeedKey = "diskSpeed";
/** Wanted version */
private static final String hostSpecVespaVersionKey = "vespaVersion";
@@ -92,6 +93,7 @@ public class AllocatedHosts {
resourcesObject.setDouble(vcpuKey, resources.vcpu());
resourcesObject.setDouble(memoryKey, resources.memoryGb());
resourcesObject.setDouble(diskKey, resources.diskGb());
+ resourcesObject.setString(diskSpeedKey, diskSpeedToString(resources.diskSpeed()));
}
}
@@ -131,13 +133,34 @@ public class AllocatedHosts {
Inspector resources = object.field(resourcesKey);
return Optional.of(new Flavor(new NodeResources(resources.field(vcpuKey).asDouble(),
resources.field(memoryKey).asDouble(),
- resources.field(diskKey).asDouble())));
+ resources.field(diskKey).asDouble(),
+ diskSpeedFromSlime(resources.field(diskSpeedKey)))));
}
else {
return Optional.empty();
}
}
+ private static NodeResources.DiskSpeed diskSpeedFromSlime(Inspector diskSpeed) {
+ if ( ! diskSpeed.valid()) return NodeResources.DiskSpeed.fast; // TODO: Remove this line after June 2019
+ switch (diskSpeed.asString()) {
+ case "fast" : return NodeResources.DiskSpeed.fast;
+ case "slow" : return NodeResources.DiskSpeed.slow;
+ case "any" : return NodeResources.DiskSpeed.any;
+ default: throw new IllegalStateException("Illegal disk-speed value '" + diskSpeed.asString() + "'");
+ }
+ }
+
+ private static String diskSpeedToString(NodeResources.DiskSpeed diskSpeed) {
+ switch (diskSpeed) {
+ case fast : return "fast";
+ case slow : return "slow";
+ case any : return "any";
+ default: throw new IllegalStateException("Illegal disk-speed value '" + diskSpeed + "'");
+ }
+
+ }
+
private static ClusterMembership membershipFromSlime(Inspector object) {
return ClusterMembership.from(object.field(hostSpecMembershipKey).asString(),
com.yahoo.component.Version.fromString(object.field(hostSpecVespaVersionKey).asString()));
diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/Flavor.java b/config-provisioning/src/main/java/com/yahoo/config/provision/Flavor.java
index 74147a55a76..8667707883d 100644
--- a/config-provisioning/src/main/java/com/yahoo/config/provision/Flavor.java
+++ b/config-provisioning/src/main/java/com/yahoo/config/provision/Flavor.java
@@ -25,10 +25,6 @@ public class Flavor {
private final int cost;
private final boolean isStock;
private final Type type;
- private final double minCpuCores;
- private final double minMainMemoryAvailableGb;
- private final double minDiskAvailableGb;
- private final boolean fastDisk;
private final double bandwidth;
private final String description;
private final boolean retired;
@@ -45,16 +41,15 @@ public class Flavor {
this.cost = flavorConfig.cost();
this.isStock = flavorConfig.stock();
this.type = Type.valueOf(flavorConfig.environment());
- this.minCpuCores = flavorConfig.minCpuCores();
- this.minMainMemoryAvailableGb = flavorConfig.minMainMemoryAvailableGb();
- this.minDiskAvailableGb = flavorConfig.minDiskAvailableGb();
- this.fastDisk = flavorConfig.fastDisk();
+ this.resources = new NodeResources(flavorConfig.minCpuCores(),
+ flavorConfig.minMainMemoryAvailableGb(),
+ flavorConfig.minDiskAvailableGb(),
+ flavorConfig.fastDisk() ? NodeResources.DiskSpeed.fast : NodeResources.DiskSpeed.slow);
this.bandwidth = flavorConfig.bandwidth();
this.description = flavorConfig.description();
this.retired = flavorConfig.retired();
this.replacesFlavors = new ArrayList<>();
this.idealHeadroom = flavorConfig.idealHeadroom();
- this.resources = new NodeResources(minCpuCores, minMainMemoryAvailableGb, minDiskAvailableGb);
}
/** Creates a *node* flavor from a node resources spec */
@@ -68,10 +63,6 @@ public class Flavor {
this.cost = 0;
this.isStock = true;
this.type = Type.DOCKER_CONTAINER;
- this.minCpuCores = resources.vcpu();
- this.minMainMemoryAvailableGb = resources.memoryGb();
- this.minDiskAvailableGb = resources.diskGb();
- this.fastDisk = true;
this.bandwidth = 1;
this.description = "";
this.retired = false;
@@ -93,15 +84,23 @@ public class Flavor {
public boolean isStock() { return isStock; }
- public double getMinMainMemoryAvailableGb() { return minMainMemoryAvailableGb; }
+ /**
+ * True if this is a configured flavor used for hosts,
+ * false if it is a virtual flavor created on the fly from node resources
+ */
+ public boolean isConfigured() { return configured; }
- public double getMinDiskAvailableGb() { return minDiskAvailableGb; }
+ public NodeResources resources() { return resources; }
+
+ public double getMinMainMemoryAvailableGb() { return resources.memoryGb(); }
- public boolean hasFastDisk() { return fastDisk; }
+ public double getMinDiskAvailableGb() { return resources.diskGb(); }
+
+ public boolean hasFastDisk() { return resources.diskSpeed() == NodeResources.DiskSpeed.fast; }
public double getBandwidth() { return bandwidth; }
- public double getMinCpuCores() { return minCpuCores; }
+ public double getMinCpuCores() { return resources.vcpu(); }
public String getDescription() { return description; }
@@ -170,9 +169,7 @@ public class Flavor {
* as large as the given resources.
*/
public boolean hasAtLeast(NodeResources resources) {
- return this.minCpuCores >= resources.vcpu() &&
- this.minMainMemoryAvailableGb >= resources.memoryGb() &&
- this.minDiskAvailableGb >= resources.diskGb();
+ return this.resources.satisfies(resources);
}
/** Irreversibly freezes the content of this */
@@ -182,28 +179,21 @@ public class Flavor {
/** Returns whether this flavor has at least as much of each hardware resource as the given flavor */
public boolean isLargerThan(Flavor other) {
- return this.minCpuCores >= other.minCpuCores &&
- this.minDiskAvailableGb >= other.minDiskAvailableGb &&
- this.minMainMemoryAvailableGb >= other.minMainMemoryAvailableGb &&
- this.fastDisk || ! other.fastDisk;
+ return hasAtLeast(other.resources);
}
- /**
- * True if this is a configured flavor used for hosts,
- * false if it is a virtual flavor created on the fly from node resources
- */
- public boolean isConfigured() { return configured; }
-
- public NodeResources resources() { return resources; }
-
@Override
public int hashCode() { return name.hashCode(); }
@Override
- public boolean equals(Object other) {
- if (other == this) return true;
- if ( ! (other instanceof Flavor)) return false;
- return ((Flavor)other).name.equals(this.name);
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if ( ! (o instanceof Flavor)) return false;
+ Flavor other = (Flavor)o;
+ if (configured)
+ return other.name.equals(this.name);
+ else
+ return this.resources.equals(other.resources);
}
@Override
diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/NodeResources.java b/config-provisioning/src/main/java/com/yahoo/config/provision/NodeResources.java
index 005bfac6b5c..b5d16c35dac 100644
--- a/config-provisioning/src/main/java/com/yahoo/config/provision/NodeResources.java
+++ b/config-provisioning/src/main/java/com/yahoo/config/provision/NodeResources.java
@@ -1,6 +1,7 @@
// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.config.provision;
+import java.util.Objects;
import java.util.Optional;
/**
@@ -10,27 +11,42 @@ import java.util.Optional;
*/
public class NodeResources {
+ public enum DiskSpeed {
+ fast, // SSD disk or similar speed is needed
+ slow, // This is tuned to work with the speed of spinning disks
+ any // The performance of the cluster using this does not depend on disk speed
+ }
+
private final double vcpu;
private final double memoryGb;
private final double diskGb;
+ private final DiskSpeed diskSpeed;
private final boolean allocateByLegacyName;
/** The legacy (flavor) name of this, or null if none */
private final String legacyName;
+ /** Create node resources requiring fast disk */
public NodeResources(double vcpu, double memoryGb, double diskGb) {
+ this(vcpu, memoryGb, diskGb, DiskSpeed.fast);
+ }
+
+ public NodeResources(double vcpu, double memoryGb, double diskGb, DiskSpeed diskSpeed) {
this.vcpu = vcpu;
this.memoryGb = memoryGb;
this.diskGb = diskGb;
+ this.diskSpeed = diskSpeed;
this.allocateByLegacyName = false;
this.legacyName = null;
}
- private NodeResources(double vcpu, double memoryGb, double diskGb, boolean allocateByLegacyName, String legacyName) {
+ private NodeResources(double vcpu, double memoryGb, double diskGb, DiskSpeed diskSpeed,
+ boolean allocateByLegacyName, String legacyName) {
this.vcpu = vcpu;
this.memoryGb = memoryGb;
this.diskGb = diskGb;
+ this.diskSpeed = diskSpeed;
this.allocateByLegacyName = allocateByLegacyName;
this.legacyName = legacyName;
}
@@ -38,6 +54,25 @@ public class NodeResources {
public double vcpu() { return vcpu; }
public double memoryGb() { return memoryGb; }
public double diskGb() { return diskGb; }
+ public DiskSpeed diskSpeed() { return diskSpeed; }
+
+ public NodeResources subtract(NodeResources other) {
+ if ( ! this.isInterchangeableWith(other))
+ throw new IllegalArgumentException(this + " and " + other + " are not interchangeable");
+ return new NodeResources(vcpu - other.vcpu,
+ memoryGb - other.memoryGb,
+ diskGb - other.diskGb,
+ combine(this.diskSpeed, other.diskSpeed));
+ }
+
+ public NodeResources add(NodeResources other) {
+ if ( ! this.isInterchangeableWith(other))
+ throw new IllegalArgumentException(this + " and " + other + " are not interchangeable");
+ return new NodeResources(vcpu + other.vcpu,
+ memoryGb + other.memoryGb,
+ diskGb + other.diskGb,
+ combine(this.diskSpeed, other.diskSpeed));
+ }
/**
* If this is true, a non-docker legacy name was used to specify this and we'll respect that by mapping directly.
@@ -50,6 +85,23 @@ public class NodeResources {
return Optional.ofNullable(legacyName);
}
+ private boolean isInterchangeableWith(NodeResources other) {
+ if (this.allocateByLegacyName != other.allocateByLegacyName) return false;
+ if (this.allocateByLegacyName) return legacyName.equals(other.legacyName);
+
+ if (this.diskSpeed != DiskSpeed.any && other.diskSpeed != DiskSpeed.any && this.diskSpeed != other.diskSpeed)
+ return false;
+
+ return true;
+ }
+
+ private DiskSpeed combine(DiskSpeed a, DiskSpeed b) {
+ if (a == DiskSpeed.any) return b;
+ if (b == DiskSpeed.any) return a;
+ if (a == b) return a;
+ throw new IllegalArgumentException(a + " cannot be combined with " + b);
+ }
+
@Override
public boolean equals(Object o) {
if (o == this) return true;
@@ -62,6 +114,7 @@ public class NodeResources {
if (this.vcpu != other.vcpu) return false;
if (this.memoryGb != other.memoryGb) return false;
if (this.diskGb != other.diskGb) return false;
+ if (this.diskSpeed != other.diskSpeed) return false;
return true;
}
}
@@ -71,7 +124,7 @@ public class NodeResources {
if (allocateByLegacyName)
return legacyName.hashCode();
else
- return (int)(2503 * vcpu + 22123 * memoryGb + 26987 * diskGb);
+ return (int)(2503 * vcpu + 22123 * memoryGb + 26987 * diskGb + diskSpeed.hashCode());
}
@Override
@@ -79,7 +132,25 @@ public class NodeResources {
if (allocateByLegacyName)
return "flavor '" + legacyName + "'";
else
- return "[vcpu: " + vcpu + ", memory: " + memoryGb + " Gb, disk " + diskGb + " Gb]";
+ return "[vcpu: " + vcpu + ", memory: " + memoryGb + " Gb, disk " + diskGb + " Gb" +
+ (diskSpeed != DiskSpeed.fast ? ", disk speed: " + diskSpeed : "") + "]";
+ }
+
+ /** Returns true if all the resources of this are the same or larger than the given resources */
+ public boolean satisfies(NodeResources other) {
+ if (this.allocateByLegacyName || other.allocateByLegacyName) // resources are not available
+ return Objects.equals(this.legacyName, other.legacyName);
+
+ if (this.vcpu < other.vcpu()) return false;
+ if (this.memoryGb < other.memoryGb) return false;
+ if (this.diskGb < other.diskGb) return false;
+
+ // Why doesn't a fast disk satisfy a slow disk? Because if slow disk is explicitly specified
+ // (i.e not "any"), you should not randomly, sometimes get a faster disk as that means you may
+ // draw conclusions about performance on the basis of better resources than you think you have
+ if (other.diskSpeed != DiskSpeed.any && other.diskSpeed != this.diskSpeed) return false;
+
+ return true;
}
/**
@@ -96,10 +167,10 @@ public class NodeResources {
if (cpu == 0) cpu = 0.5;
if (cpu == 2 && mem == 8 ) cpu = 1.5;
if (cpu == 2 && mem == 12 ) cpu = 2.3;
- return new NodeResources(cpu, mem, dsk, false, flavorString);
+ return new NodeResources(cpu, mem, dsk, DiskSpeed.fast, false, flavorString);
}
else { // Another legacy flavor: Allocate by direct matching
- return new NodeResources(0, 0, 0, true, flavorString);
+ return new NodeResources(0, 0, 0, DiskSpeed.fast, true, flavorString);
}
}
diff --git a/config-provisioning/src/test/java/com/yahoo/config/provision/AllocatedHostsTest.java b/config-provisioning/src/test/java/com/yahoo/config/provision/AllocatedHostsTest.java
index 3a37c96c612..737c1047197 100644
--- a/config-provisioning/src/test/java/com/yahoo/config/provision/AllocatedHostsTest.java
+++ b/config-provisioning/src/test/java/com/yahoo/config/provision/AllocatedHostsTest.java
@@ -30,8 +30,10 @@ public class AllocatedHostsTest {
List.of("alias1", "alias2")));
hosts.add(new HostSpec("allocated",
Optional.of(ClusterMembership.from("container/test/0/0", com.yahoo.component.Version.fromString("6.73.1")))));
- hosts.add(new HostSpec("flavor-from-resources",
+ hosts.add(new HostSpec("flavor-from-resources-1",
Collections.emptyList(), new Flavor(new NodeResources(0.5, 3.1, 4))));
+ hosts.add(new HostSpec("flavor-from-resources-2",
+ Collections.emptyList(), new Flavor(new NodeResources(0.5, 3.1, 4, NodeResources.DiskSpeed.any))));
hosts.add(new HostSpec("configured-flavor",
Collections.emptyList(), configuredFlavors.getFlavorOrThrow("C/12/45/100")));
hosts.add(new HostSpec("with-version",