From f97f23ad20962f0b53964942269d25a1a986efea Mon Sep 17 00:00:00 2001 From: HÃ¥kon Hallingstad Date: Fri, 10 Nov 2023 13:27:49 +0100 Subject: exclusive-provisioning and make-exclusive has rolled out --- .../src/main/java/com/yahoo/vespa/flags/Flags.java | 14 ++++----- .../maintenance/HostCapacityMaintainer.java | 23 ++++----------- .../provision/provisioning/NodeAllocation.java | 6 ++-- .../provision/provisioning/NodeCandidate.java | 10 +++---- .../provision/provisioning/NodePrioritizer.java | 10 ++----- .../hosted/provision/provisioning/Preparer.java | 34 ++++++++-------------- .../maintenance/HostCapacityMaintainerTest.java | 1 - 7 files changed, 33 insertions(+), 65 deletions(-) diff --git a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java index 06530fdc962..491b7db3c13 100644 --- a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java +++ b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java @@ -326,18 +326,16 @@ public class Flags { INSTANCE_ID); public static final UnboundBooleanFlag EXCLUSIVE_PROVISIONING = defineFeatureFlag( - "exclusive-provisioning", false, + "exclusive-provisioning", true, List.of("hakonhall"), "2023-10-12", "2023-12-20", - "Whether to provision a host exclusively to an application ID only based on exclusive=\"true\" from services.xml. " + - "Enabling this will produce hosts with exclusiveTo[ApplicationId] without provisionedToApplicationId.", - "Takes immediate effect when provisioning new hosts"); + "Unused, remove once Vespa >=8.257 has rolled out everywhere", + "no-op"); public static final UnboundBooleanFlag MAKE_EXCLUSIVE = defineFeatureFlag( - "make-exclusive", false, + "make-exclusive", true, List.of("hakonhall"), "2023-10-20", "2023-12-20", - "Allow an exclusive allocation to a non-exclusive host, but if so, make the host exclusive.", - "Takes immediate effect on any following preparation of clusters", - INSTANCE_ID, TENANT_ID, VESPA_VERSION); + "Unused, remove once Vespa >=8.257 has rolled out everywhere", + "no-op"); public static final UnboundBooleanFlag WRITE_CONFIG_SERVER_SESSION_DATA_AS_ONE_BLOB = defineFeatureFlag( "write-config-server-session-data-as-blob", false, diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/HostCapacityMaintainer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/HostCapacityMaintainer.java index 108f8d77837..226f5834b66 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/HostCapacityMaintainer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/HostCapacityMaintainer.java @@ -13,10 +13,7 @@ import com.yahoo.config.provision.NodeType; import com.yahoo.jdisc.Metric; import com.yahoo.lang.MutableInteger; import com.yahoo.transaction.Mutex; -import com.yahoo.vespa.flags.BooleanFlag; -import com.yahoo.vespa.flags.FetchVector; import com.yahoo.vespa.flags.FlagSource; -import com.yahoo.vespa.flags.Flags; import com.yahoo.vespa.flags.ListFlag; import com.yahoo.vespa.flags.PermanentFlags; import com.yahoo.vespa.flags.custom.ClusterCapacity; @@ -62,7 +59,6 @@ public class HostCapacityMaintainer extends NodeRepositoryMaintainer { private final HostProvisioner hostProvisioner; private final ListFlag preprovisionCapacityFlag; - private final BooleanFlag makeExclusiveFlag; private final ProvisioningThrottler throttler; HostCapacityMaintainer(NodeRepository nodeRepository, @@ -73,7 +69,6 @@ public class HostCapacityMaintainer extends NodeRepositoryMaintainer { super(nodeRepository, interval, metric); this.hostProvisioner = hostProvisioner; this.preprovisionCapacityFlag = PermanentFlags.PREPROVISION_CAPACITY.bindTo(flagSource); - this.makeExclusiveFlag = Flags.MAKE_EXCLUSIVE.bindTo(flagSource); this.throttler = new ProvisioningThrottler(nodeRepository, metric); } @@ -193,10 +188,6 @@ public class HostCapacityMaintainer extends NodeRepositoryMaintainer { private List provisionUntilNoDeficit(NodeList nodeList) { List preprovisionCapacity = preprovisionCapacityFlag.value(); ApplicationId application = ApplicationId.defaultId(); - boolean makeExclusive = makeExclusiveFlag.with(FetchVector.Dimension.TENANT_ID, application.tenant().value()) - .with(FetchVector.Dimension.INSTANCE_ID, application.serializedForm()) - .with(FetchVector.Dimension.VESPA_VERSION, Vtag.currentVersion.toFullString()) - .value(); // Worst-case each ClusterCapacity in preprovisionCapacity will require an allocation. int maxProvisions = preprovisionCapacity.size(); @@ -204,7 +195,7 @@ public class HostCapacityMaintainer extends NodeRepositoryMaintainer { var nodesPlusProvisioned = new ArrayList<>(nodeList.asList()); for (int numProvisions = 0;; ++numProvisions) { var nodesPlusProvisionedPlusAllocated = new ArrayList<>(nodesPlusProvisioned); - Optional deficit = allocatePreprovisionCapacity(application, preprovisionCapacity, nodesPlusProvisionedPlusAllocated, makeExclusive); + Optional deficit = allocatePreprovisionCapacity(application, preprovisionCapacity, nodesPlusProvisionedPlusAllocated); if (deficit.isEmpty()) { return nodesPlusProvisionedPlusAllocated; } @@ -265,12 +256,11 @@ public class HostCapacityMaintainer extends NodeRepositoryMaintainer { */ private Optional allocatePreprovisionCapacity(ApplicationId application, List preprovisionCapacity, - ArrayList mutableNodes, - boolean makeExclusive) { + ArrayList mutableNodes) { for (int clusterIndex = 0; clusterIndex < preprovisionCapacity.size(); ++clusterIndex) { ClusterCapacity clusterCapacity = preprovisionCapacity.get(clusterIndex); LockedNodeList allNodes = new LockedNodeList(mutableNodes, () -> {}); - List candidates = findCandidates(application, clusterCapacity, clusterIndex, allNodes, makeExclusive); + List candidates = findCandidates(application, clusterCapacity, clusterIndex, allNodes); int deficit = Math.max(0, clusterCapacity.count() - candidates.size()); if (deficit > 0) { return Optional.of(clusterCapacity.withCount(deficit)); @@ -283,7 +273,7 @@ public class HostCapacityMaintainer extends NodeRepositoryMaintainer { return Optional.empty(); } - private List findCandidates(ApplicationId application, ClusterCapacity clusterCapacity, int clusterIndex, LockedNodeList allNodes, boolean makeExclusive) { + private List findCandidates(ApplicationId application, ClusterCapacity clusterCapacity, int clusterIndex, LockedNodeList allNodes) { NodeResources nodeResources = toNodeResources(clusterCapacity); // We'll allocate each ClusterCapacity as a unique cluster in a dummy application @@ -296,7 +286,7 @@ public class HostCapacityMaintainer extends NodeRepositoryMaintainer { NodePrioritizer prioritizer = new NodePrioritizer(allNodes, application, cluster, nodeSpec, true, false, allocationContext, nodeRepository().nodes(), nodeRepository().resourcesCalculator(), nodeRepository().spareCount(), - nodeRepository().exclusiveAllocation(cluster), makeExclusive); + nodeRepository().exclusiveAllocation(cluster)); List nodeCandidates = prioritizer.collect() .stream() .filter(node -> node.violatesExclusivity(cluster, @@ -305,8 +295,7 @@ public class HostCapacityMaintainer extends NodeRepositoryMaintainer { nodeRepository().exclusiveAllocation(cluster), false, nodeRepository().zone().cloud().allowHostSharing(), - allNodes, - makeExclusive) + allNodes) != NodeCandidate.ExclusivityViolation.YES) .toList(); MutableInteger index = new MutableInteger(0); diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java index 21340baf273..ecc67681de8 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeAllocation.java @@ -84,10 +84,9 @@ class NodeAllocation { private final NodeRepository nodeRepository; private final Optional requiredHostFlavor; - private final boolean makeExclusive; NodeAllocation(NodeList allNodes, ApplicationId application, ClusterSpec cluster, NodeSpec requested, - Supplier nextIndex, NodeRepository nodeRepository, boolean makeExclusive) { + Supplier nextIndex, NodeRepository nodeRepository) { this.allNodes = allNodes; this.application = application; this.cluster = cluster; @@ -100,7 +99,6 @@ class NodeAllocation { .with(FetchVector.Dimension.CLUSTER_ID, cluster.id().value()) .value()) .filter(s -> !s.isBlank()); - this.makeExclusive = makeExclusive; } /** @@ -201,7 +199,7 @@ class NodeAllocation { nodeRepository.exclusiveClusterType(cluster), nodeRepository.exclusiveAllocation(cluster), nodeRepository.exclusiveProvisioning(cluster), - nodeRepository.zone().cloud().allowHostSharing(), allNodes, makeExclusive); + nodeRepository.zone().cloud().allowHostSharing(), allNodes); } /** diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeCandidate.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeCandidate.java index 8c29b40bc26..d4c4e86f0a3 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeCandidate.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeCandidate.java @@ -596,7 +596,7 @@ public abstract class NodeCandidate implements Nodelike, Comparable hostProvisioner; private final Optional loadBalancerProvisioner; private final ProvisioningThrottler throttler; - private final BooleanFlag makeExclusiveFlag; public Preparer(NodeRepository nodeRepository, Optional hostProvisioner, Optional loadBalancerProvisioner, Metric metric) { this.nodeRepository = nodeRepository; this.hostProvisioner = hostProvisioner; this.loadBalancerProvisioner = loadBalancerProvisioner; this.throttler = new ProvisioningThrottler(nodeRepository, metric); - this.makeExclusiveFlag = Flags.MAKE_EXCLUSIVE.bindTo(nodeRepository.flagSource()); } /** @@ -77,15 +72,11 @@ public class Preparer { loadBalancerProvisioner.ifPresent(provisioner -> provisioner.prepare(application, cluster, requested)); - boolean makeExclusive = makeExclusiveFlag.with(FetchVector.Dimension.TENANT_ID, application.tenant().value()) - .with(FetchVector.Dimension.INSTANCE_ID, application.serializedForm()) - .with(FetchVector.Dimension.VESPA_VERSION, cluster.vespaVersion().toFullString()) - .value(); // Try preparing in memory without global unallocated lock. Most of the time there should be no changes, // and we can return nodes previously allocated. LockedNodeList allNodes = nodeRepository.nodes().list(PROBE_LOCK); NodeIndices indices = new NodeIndices(cluster.id(), allNodes); - NodeAllocation probeAllocation = prepareAllocation(application, cluster, requested, indices::probeNext, allNodes, makeExclusive); + NodeAllocation probeAllocation = prepareAllocation(application, cluster, requested, indices::probeNext, allNodes); if (probeAllocation.fulfilledAndNoChanges()) { List acceptedNodes = probeAllocation.finalNodes(); indices.commitProbe(); @@ -93,25 +84,25 @@ public class Preparer { } else { // There were some changes, so re-do the allocation with locks indices.resetProbe(); - return prepareWithLocks(application, cluster, requested, indices, makeExclusive); + return prepareWithLocks(application, cluster, requested, indices); } } - private ApplicationMutex parentLockOrNull(boolean makeExclusive, NodeType type) { - return NodeCandidate.canMakeHostExclusive(makeExclusive, type, nodeRepository.zone().cloud().allowHostSharing()) ? + private ApplicationMutex parentLockOrNull(NodeType type) { + return NodeCandidate.canMakeHostExclusive(type, nodeRepository.zone().cloud().allowHostSharing()) ? nodeRepository.applications().lock(InfrastructureApplication.withNodeType(type.parentNodeType()).id()) : null; } /// Note that this will write to the node repo. - private List prepareWithLocks(ApplicationId application, ClusterSpec cluster, NodeSpec requested, NodeIndices indices, boolean makeExclusive) { + private List prepareWithLocks(ApplicationId application, ClusterSpec cluster, NodeSpec requested, NodeIndices indices) { Runnable waiter = null; List acceptedNodes; try (Mutex lock = nodeRepository.applications().lock(application); - ApplicationMutex parentLockOrNull = parentLockOrNull(makeExclusive, requested.type()); + ApplicationMutex parentLockOrNull = parentLockOrNull(requested.type()); Mutex allocationLock = nodeRepository.nodes().lockUnallocated()) { LockedNodeList allNodes = nodeRepository.nodes().list(allocationLock); - NodeAllocation allocation = prepareAllocation(application, cluster, requested, indices::next, allNodes, makeExclusive); + NodeAllocation allocation = prepareAllocation(application, cluster, requested, indices::next, allNodes); NodeType hostType = allocation.nodeType().hostType(); if (canProvisionDynamically(hostType) && allocation.hostDeficit().isPresent()) { HostSharing sharing = hostSharing(cluster, hostType); @@ -162,7 +153,7 @@ public class Preparer { // Non-dynamically provisioned zone with a deficit because we just now retired some nodes. // Try again, but without retiring indices.resetProbe(); - List accepted = prepareWithLocks(application, cluster, cns.withoutRetiring(), indices, makeExclusive); + List accepted = prepareWithLocks(application, cluster, cns.withoutRetiring(), indices); log.warning("Prepared " + application + " " + cluster.id() + " without retirement due to lack of capacity"); return accepted; } @@ -194,9 +185,9 @@ public class Preparer { } private NodeAllocation prepareAllocation(ApplicationId application, ClusterSpec cluster, NodeSpec requested, - Supplier nextIndex, LockedNodeList allNodes, boolean makeExclusive) { + Supplier nextIndex, LockedNodeList allNodes) { validateAccount(requested.cloudAccount(), application, allNodes); - NodeAllocation allocation = new NodeAllocation(allNodes, application, cluster, requested, nextIndex, nodeRepository, makeExclusive); + NodeAllocation allocation = new NodeAllocation(allNodes, application, cluster, requested, nextIndex, nodeRepository); var allocationContext = IP.Allocation.Context.from(nodeRepository.zone().cloud().name(), requested.cloudAccount().isExclave(nodeRepository.zone()), nodeRepository.nameResolver()); @@ -210,8 +201,7 @@ public class Preparer { nodeRepository.nodes(), nodeRepository.resourcesCalculator(), nodeRepository.spareCount(), - nodeRepository.exclusiveAllocation(cluster), - makeExclusive); + nodeRepository.exclusiveAllocation(cluster)); allocation.offer(prioritizer.collect()); return allocation; } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/HostCapacityMaintainerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/HostCapacityMaintainerTest.java index c804ade668c..874db8c961d 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/HostCapacityMaintainerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/HostCapacityMaintainerTest.java @@ -293,7 +293,6 @@ public class HostCapacityMaintainerTest { resources1.bandwidthGbps(), resources1.diskSpeed().name(), resources1.storageType().name(), resources1.architecture().name(), null)); - tester.flagSource.withBooleanFlag(Flags.MAKE_EXCLUSIVE.id(), true); tester.maintain(); // Hosts are provisioned -- cgit v1.2.3