YARN-9730. Support forcing configured partitions to be exclusive based on app node label
(cherry picked from commit 73a044a63822303f792183244e25432528ecfb1e)
This commit is contained in:
parent
a0db762206
commit
806c7b7dfb
|
@ -3624,6 +3624,12 @@ public class YarnConfiguration extends Configuration {
|
||||||
public static final String DEFAULT_NODELABEL_CONFIGURATION_TYPE =
|
public static final String DEFAULT_NODELABEL_CONFIGURATION_TYPE =
|
||||||
CENTRALIZED_NODELABEL_CONFIGURATION_TYPE;
|
CENTRALIZED_NODELABEL_CONFIGURATION_TYPE;
|
||||||
|
|
||||||
|
public static final String EXCLUSIVE_ENFORCED_PARTITIONS_SUFFIX
|
||||||
|
= "exclusive-enforced-partitions";
|
||||||
|
|
||||||
|
public static final String EXCLUSIVE_ENFORCED_PARTITIONS = NODE_LABELS_PREFIX
|
||||||
|
+ EXCLUSIVE_ENFORCED_PARTITIONS_SUFFIX;
|
||||||
|
|
||||||
public static final String MAX_CLUSTER_LEVEL_APPLICATION_PRIORITY =
|
public static final String MAX_CLUSTER_LEVEL_APPLICATION_PRIORITY =
|
||||||
YARN_PREFIX + "cluster.max-application-priority";
|
YARN_PREFIX + "cluster.max-application-priority";
|
||||||
|
|
||||||
|
|
|
@ -4103,4 +4103,13 @@
|
||||||
<value>60000</value>
|
<value>60000</value>
|
||||||
</property>
|
</property>
|
||||||
|
|
||||||
|
<property>
|
||||||
|
<description>
|
||||||
|
Comma-separated list of partitions. If a label P is in this list,
|
||||||
|
then the RM will enforce that an app has resource requests with label
|
||||||
|
P iff that app's node label expression is P.
|
||||||
|
</description>
|
||||||
|
<name>yarn.node-labels.exclusive-enforced-partitions</name>
|
||||||
|
<value></value>
|
||||||
|
</property>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|
|
@ -76,6 +76,7 @@ import org.apache.hadoop.yarn.server.resourcemanager.scheduler.Allocation;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.ContainerUpdates;
|
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.ContainerUpdates;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler
|
import org.apache.hadoop.yarn.server.resourcemanager.scheduler
|
||||||
.SchedulerNodeReport;
|
.SchedulerNodeReport;
|
||||||
|
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.SchedulerUtils;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.YarnScheduler;
|
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.YarnScheduler;
|
||||||
import org.apache.hadoop.yarn.server.utils.BuilderUtils;
|
import org.apache.hadoop.yarn.server.utils.BuilderUtils;
|
||||||
import org.apache.hadoop.yarn.util.resource.ResourceUtils;
|
import org.apache.hadoop.yarn.util.resource.ResourceUtils;
|
||||||
|
@ -235,6 +236,11 @@ final class DefaultAMSProcessor implements ApplicationMasterServiceProcessor {
|
||||||
&& ResourceRequest.ANY.equals(req.getResourceName())) {
|
&& ResourceRequest.ANY.equals(req.getResourceName())) {
|
||||||
req.setNodeLabelExpression(asc.getNodeLabelExpression());
|
req.setNodeLabelExpression(asc.getNodeLabelExpression());
|
||||||
}
|
}
|
||||||
|
if (ResourceRequest.ANY.equals(req.getResourceName())) {
|
||||||
|
SchedulerUtils.enforcePartitionExclusivity(req,
|
||||||
|
getRmContext().getExclusiveEnforcedPartitions(),
|
||||||
|
asc.getNodeLabelExpression());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Resource maximumCapacity =
|
Resource maximumCapacity =
|
||||||
|
|
|
@ -21,6 +21,7 @@ import java.util.Collections;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
|
@ -99,6 +100,7 @@ public class RMAppManager implements EventHandler<RMAppManagerEvent>,
|
||||||
private YarnAuthorizationProvider authorizer;
|
private YarnAuthorizationProvider authorizer;
|
||||||
private boolean timelineServiceV2Enabled;
|
private boolean timelineServiceV2Enabled;
|
||||||
private boolean nodeLabelsEnabled;
|
private boolean nodeLabelsEnabled;
|
||||||
|
private Set<String> exclusiveEnforcedPartitions;
|
||||||
|
|
||||||
public RMAppManager(RMContext context,
|
public RMAppManager(RMContext context,
|
||||||
YarnScheduler scheduler, ApplicationMasterService masterService,
|
YarnScheduler scheduler, ApplicationMasterService masterService,
|
||||||
|
@ -123,6 +125,7 @@ public class RMAppManager implements EventHandler<RMAppManagerEvent>,
|
||||||
timelineServiceV2Enabled(conf);
|
timelineServiceV2Enabled(conf);
|
||||||
this.nodeLabelsEnabled = YarnConfiguration
|
this.nodeLabelsEnabled = YarnConfiguration
|
||||||
.areNodeLabelsEnabled(rmContext.getYarnConfiguration());
|
.areNodeLabelsEnabled(rmContext.getYarnConfiguration());
|
||||||
|
this.exclusiveEnforcedPartitions = context.getExclusiveEnforcedPartitions();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -566,6 +569,9 @@ public class RMAppManager implements EventHandler<RMAppManagerEvent>,
|
||||||
throw new InvalidResourceRequestException("Invalid resource request, "
|
throw new InvalidResourceRequestException("Invalid resource request, "
|
||||||
+ "no resource request specified with " + ResourceRequest.ANY);
|
+ "no resource request specified with " + ResourceRequest.ANY);
|
||||||
}
|
}
|
||||||
|
SchedulerUtils.enforcePartitionExclusivity(anyReq,
|
||||||
|
exclusiveEnforcedPartitions,
|
||||||
|
submissionContext.getNodeLabelExpression());
|
||||||
|
|
||||||
// Make sure that all of the requests agree with the ANY request
|
// Make sure that all of the requests agree with the ANY request
|
||||||
// and have correct values
|
// and have correct values
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
package org.apache.hadoop.yarn.server.resourcemanager;
|
package org.apache.hadoop.yarn.server.resourcemanager;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
|
@ -188,4 +189,7 @@ public interface RMContext extends ApplicationMasterServiceContext {
|
||||||
|
|
||||||
void setMultiNodeSortingManager(
|
void setMultiNodeSortingManager(
|
||||||
MultiNodeSortingManager<SchedulerNode> multiNodeSortingManager);
|
MultiNodeSortingManager<SchedulerNode> multiNodeSortingManager);
|
||||||
|
|
||||||
|
Set<String> getExclusiveEnforcedPartitions();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,8 @@ package org.apache.hadoop.yarn.server.resourcemanager;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
|
@ -33,6 +35,7 @@ import org.apache.hadoop.yarn.LocalConfigurationProvider;
|
||||||
import org.apache.hadoop.yarn.api.records.ApplicationId;
|
import org.apache.hadoop.yarn.api.records.ApplicationId;
|
||||||
import org.apache.hadoop.yarn.api.records.NodeId;
|
import org.apache.hadoop.yarn.api.records.NodeId;
|
||||||
import org.apache.hadoop.yarn.conf.ConfigurationProvider;
|
import org.apache.hadoop.yarn.conf.ConfigurationProvider;
|
||||||
|
import org.apache.hadoop.yarn.conf.YarnConfiguration;
|
||||||
import org.apache.hadoop.yarn.event.Dispatcher;
|
import org.apache.hadoop.yarn.event.Dispatcher;
|
||||||
import org.apache.hadoop.yarn.nodelabels.NodeAttributesManager;
|
import org.apache.hadoop.yarn.nodelabels.NodeAttributesManager;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.ahs.RMApplicationHistoryWriter;
|
import org.apache.hadoop.yarn.server.resourcemanager.ahs.RMApplicationHistoryWriter;
|
||||||
|
@ -643,4 +646,16 @@ public class RMContextImpl implements RMContext {
|
||||||
public NodeAttributesManager getNodeAttributesManager() {
|
public NodeAttributesManager getNodeAttributesManager() {
|
||||||
return activeServiceContext.getNodeAttributesManager();
|
return activeServiceContext.getNodeAttributesManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<String> getExclusiveEnforcedPartitions() {
|
||||||
|
String[] configuredPartitions = getYarnConfiguration().getStrings(
|
||||||
|
YarnConfiguration.EXCLUSIVE_ENFORCED_PARTITIONS);
|
||||||
|
Set<String> exclusiveEnforcedPartitions = new HashSet<>();
|
||||||
|
if (configuredPartitions != null) {
|
||||||
|
for (String partition : configuredPartitions) {
|
||||||
|
exclusiveEnforcedPartitions.add(partition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return exclusiveEnforcedPartitions;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -205,6 +205,8 @@ public class SchedulerApplicationAttempt implements SchedulableEntity {
|
||||||
private AtomicLong unconfirmedAllocatedMem = new AtomicLong();
|
private AtomicLong unconfirmedAllocatedMem = new AtomicLong();
|
||||||
private AtomicInteger unconfirmedAllocatedVcores = new AtomicInteger();
|
private AtomicInteger unconfirmedAllocatedVcores = new AtomicInteger();
|
||||||
|
|
||||||
|
private String nodeLabelExpression;
|
||||||
|
|
||||||
public SchedulerApplicationAttempt(ApplicationAttemptId applicationAttemptId,
|
public SchedulerApplicationAttempt(ApplicationAttemptId applicationAttemptId,
|
||||||
String user, Queue queue, AbstractUsersManager abstractUsersManager,
|
String user, Queue queue, AbstractUsersManager abstractUsersManager,
|
||||||
RMContext rmContext) {
|
RMContext rmContext) {
|
||||||
|
@ -226,6 +228,8 @@ public class SchedulerApplicationAttempt implements SchedulableEntity {
|
||||||
unmanagedAM = appSubmissionContext.getUnmanagedAM();
|
unmanagedAM = appSubmissionContext.getUnmanagedAM();
|
||||||
this.logAggregationContext =
|
this.logAggregationContext =
|
||||||
appSubmissionContext.getLogAggregationContext();
|
appSubmissionContext.getLogAggregationContext();
|
||||||
|
this.nodeLabelExpression =
|
||||||
|
appSubmissionContext.getNodeLabelExpression();
|
||||||
}
|
}
|
||||||
applicationSchedulingEnvs = rmApp.getApplicationSchedulingEnvs();
|
applicationSchedulingEnvs = rmApp.getApplicationSchedulingEnvs();
|
||||||
}
|
}
|
||||||
|
@ -1468,4 +1472,9 @@ public class SchedulerApplicationAttempt implements SchedulableEntity {
|
||||||
public Map<String, String> getApplicationSchedulingEnvs() {
|
public Map<String, String> getApplicationSchedulingEnvs() {
|
||||||
return this.applicationSchedulingEnvs;
|
return this.applicationSchedulingEnvs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPartition() {
|
||||||
|
return nodeLabelExpression == null ? "" : nodeLabelExpression;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -302,6 +302,29 @@ public class SchedulerUtils {
|
||||||
rmContext, queueInfo, nodeLabelsEnabled);
|
rmContext, queueInfo, nodeLabelsEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If RM should enforce partition exclusivity for enforced partition "x":
|
||||||
|
* 1) If request is "x" and app label is not "x",
|
||||||
|
* override request to app's label.
|
||||||
|
* 2) If app label is "x", ensure request is "x".
|
||||||
|
* @param resReq resource request
|
||||||
|
* @param enforcedPartitions list of exclusive enforced partitions
|
||||||
|
* @param appLabel app's node label expression
|
||||||
|
*/
|
||||||
|
public static void enforcePartitionExclusivity(ResourceRequest resReq,
|
||||||
|
Set<String> enforcedPartitions, String appLabel) {
|
||||||
|
if (enforcedPartitions == null || enforcedPartitions.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!enforcedPartitions.contains(appLabel)
|
||||||
|
&& enforcedPartitions.contains(resReq.getNodeLabelExpression())) {
|
||||||
|
resReq.setNodeLabelExpression(appLabel);
|
||||||
|
}
|
||||||
|
if (enforcedPartitions.contains(appLabel)) {
|
||||||
|
resReq.setNodeLabelExpression(appLabel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility method to validate a resource request, by insuring that the
|
* Utility method to validate a resource request, by insuring that the
|
||||||
* requested memory/vcore is non-negative and not greater than max
|
* requested memory/vcore is non-negative and not greater than max
|
||||||
|
|
|
@ -49,6 +49,7 @@ import org.apache.hadoop.yarn.server.resourcemanager.scheduler.placement.MultiNo
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.placement.MultiNodePolicySpec;
|
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.placement.MultiNodePolicySpec;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.policy.FairOrderingPolicy;
|
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.policy.FairOrderingPolicy;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.policy.FifoOrderingPolicy;
|
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.policy.FifoOrderingPolicy;
|
||||||
|
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.policy.FifoOrderingPolicyWithExclusivePartitions;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.policy.OrderingPolicy;
|
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.policy.OrderingPolicy;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.policy.SchedulableEntity;
|
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.policy.SchedulableEntity;
|
||||||
import org.apache.hadoop.yarn.util.UnitsConversionUtil;
|
import org.apache.hadoop.yarn.util.UnitsConversionUtil;
|
||||||
|
@ -159,6 +160,9 @@ public class CapacitySchedulerConfiguration extends ReservationSchedulerConfigur
|
||||||
|
|
||||||
public static final String FAIR_APP_ORDERING_POLICY = "fair";
|
public static final String FAIR_APP_ORDERING_POLICY = "fair";
|
||||||
|
|
||||||
|
public static final String FIFO_WITH_PARTITIONS_APP_ORDERING_POLICY
|
||||||
|
= "fifo-with-partitions";
|
||||||
|
|
||||||
public static final String DEFAULT_APP_ORDERING_POLICY =
|
public static final String DEFAULT_APP_ORDERING_POLICY =
|
||||||
FIFO_APP_ORDERING_POLICY;
|
FIFO_APP_ORDERING_POLICY;
|
||||||
|
|
||||||
|
@ -555,6 +559,9 @@ public class CapacitySchedulerConfiguration extends ReservationSchedulerConfigur
|
||||||
if (policyType.trim().equals(FAIR_APP_ORDERING_POLICY)) {
|
if (policyType.trim().equals(FAIR_APP_ORDERING_POLICY)) {
|
||||||
policyType = FairOrderingPolicy.class.getName();
|
policyType = FairOrderingPolicy.class.getName();
|
||||||
}
|
}
|
||||||
|
if (policyType.trim().equals(FIFO_WITH_PARTITIONS_APP_ORDERING_POLICY)) {
|
||||||
|
policyType = FifoOrderingPolicyWithExclusivePartitions.class.getName();
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
orderingPolicy = (OrderingPolicy<S>)
|
orderingPolicy = (OrderingPolicy<S>)
|
||||||
Class.forName(policyType).newInstance();
|
Class.forName(policyType).newInstance();
|
||||||
|
|
|
@ -68,6 +68,7 @@ import org.apache.hadoop.yarn.server.resourcemanager.scheduler.common.fica.FiCaS
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.placement.CandidateNodeSet;
|
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.placement.CandidateNodeSet;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.placement.CandidateNodeSetUtils;
|
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.placement.CandidateNodeSetUtils;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.policy.FifoOrderingPolicyForPendingApps;
|
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.policy.FifoOrderingPolicyForPendingApps;
|
||||||
|
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.policy.IteratorSelector;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.policy.OrderingPolicy;
|
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.policy.OrderingPolicy;
|
||||||
import org.apache.hadoop.yarn.server.utils.Lock;
|
import org.apache.hadoop.yarn.server.utils.Lock;
|
||||||
import org.apache.hadoop.yarn.server.utils.Lock.NoLock;
|
import org.apache.hadoop.yarn.server.utils.Lock.NoLock;
|
||||||
|
@ -806,7 +807,8 @@ public class LeafQueue extends AbstractCSQueue {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Iterator<FiCaSchedulerApp> fsApp =
|
for (Iterator<FiCaSchedulerApp> fsApp =
|
||||||
getPendingAppsOrderingPolicy().getAssignmentIterator();
|
getPendingAppsOrderingPolicy()
|
||||||
|
.getAssignmentIterator(IteratorSelector.EMPTY_ITERATOR_SELECTOR);
|
||||||
fsApp.hasNext(); ) {
|
fsApp.hasNext(); ) {
|
||||||
FiCaSchedulerApp application = fsApp.next();
|
FiCaSchedulerApp application = fsApp.next();
|
||||||
ApplicationId applicationId = application.getApplicationId();
|
ApplicationId applicationId = application.getApplicationId();
|
||||||
|
@ -1103,8 +1105,10 @@ public class LeafQueue extends AbstractCSQueue {
|
||||||
|
|
||||||
Map<String, CachedUserLimit> userLimits = new HashMap<>();
|
Map<String, CachedUserLimit> userLimits = new HashMap<>();
|
||||||
boolean needAssignToQueueCheck = true;
|
boolean needAssignToQueueCheck = true;
|
||||||
|
IteratorSelector sel = new IteratorSelector();
|
||||||
|
sel.setPartition(candidates.getPartition());
|
||||||
for (Iterator<FiCaSchedulerApp> assignmentIterator =
|
for (Iterator<FiCaSchedulerApp> assignmentIterator =
|
||||||
orderingPolicy.getAssignmentIterator();
|
orderingPolicy.getAssignmentIterator(sel);
|
||||||
assignmentIterator.hasNext(); ) {
|
assignmentIterator.hasNext(); ) {
|
||||||
FiCaSchedulerApp application = assignmentIterator.next();
|
FiCaSchedulerApp application = assignmentIterator.next();
|
||||||
|
|
||||||
|
|
|
@ -46,13 +46,13 @@ public abstract class AbstractComparatorOrderingPolicy<S extends SchedulableEnti
|
||||||
public Collection<S> getSchedulableEntities() {
|
public Collection<S> getSchedulableEntities() {
|
||||||
return schedulableEntities;
|
return schedulableEntities;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Iterator<S> getAssignmentIterator() {
|
public Iterator<S> getAssignmentIterator(IteratorSelector sel) {
|
||||||
reorderScheduleEntities();
|
reorderScheduleEntities();
|
||||||
return schedulableEntities.iterator();
|
return schedulableEntities.iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Iterator<S> getPreemptionIterator() {
|
public Iterator<S> getPreemptionIterator() {
|
||||||
reorderScheduleEntities();
|
reorderScheduleEntities();
|
||||||
|
@ -137,5 +137,5 @@ public abstract class AbstractComparatorOrderingPolicy<S extends SchedulableEnti
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public abstract String getInfo();
|
public abstract String getInfo();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,144 @@
|
||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.hadoop.yarn.server.resourcemanager.scheduler.policy;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.apache.hadoop.yarn.conf.YarnConfiguration;
|
||||||
|
import org.apache.hadoop.yarn.server.resourcemanager.rmcontainer.RMContainer;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Similar to {@link FifoOrderingPolicy}, but with separate ordering policies
|
||||||
|
* for each partition in
|
||||||
|
* {@code yarn.scheduler.capacity.<queue-path>.ordering-policy.exclusive-enforced-partitions}.
|
||||||
|
*/
|
||||||
|
public class FifoOrderingPolicyWithExclusivePartitions<S extends SchedulableEntity>
|
||||||
|
implements OrderingPolicy<S> {
|
||||||
|
|
||||||
|
private static final String DEFAULT_PARTITION = "DEFAULT_PARTITION";
|
||||||
|
|
||||||
|
private Map<String, OrderingPolicy<S>> orderingPolicies;
|
||||||
|
|
||||||
|
public FifoOrderingPolicyWithExclusivePartitions() {
|
||||||
|
this.orderingPolicies = new HashMap<>();
|
||||||
|
this.orderingPolicies.put(DEFAULT_PARTITION, new FifoOrderingPolicy());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<S> getSchedulableEntities() {
|
||||||
|
return unionOrderingPolicies().getSchedulableEntities();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<S> getAssignmentIterator(IteratorSelector sel) {
|
||||||
|
// Return schedulable entities only from filtered partition
|
||||||
|
return getPartitionOrderingPolicy(sel.getPartition())
|
||||||
|
.getAssignmentIterator(sel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<S> getPreemptionIterator() {
|
||||||
|
// Entities from all partitions should be preemptible
|
||||||
|
return unionOrderingPolicies().getPreemptionIterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Union all schedulable entities from all ordering policies.
|
||||||
|
* @return ordering policy containing all schedulable entities
|
||||||
|
*/
|
||||||
|
private OrderingPolicy<S> unionOrderingPolicies() {
|
||||||
|
OrderingPolicy<S> ret = new FifoOrderingPolicy<>();
|
||||||
|
for (Map.Entry<String, OrderingPolicy<S>> entry
|
||||||
|
: orderingPolicies.entrySet()) {
|
||||||
|
ret.addAllSchedulableEntities(entry.getValue().getSchedulableEntities());
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addSchedulableEntity(S s) {
|
||||||
|
getPartitionOrderingPolicy(s.getPartition()).addSchedulableEntity(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean removeSchedulableEntity(S s) {
|
||||||
|
return getPartitionOrderingPolicy(s.getPartition())
|
||||||
|
.removeSchedulableEntity(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addAllSchedulableEntities(Collection<S> sc) {
|
||||||
|
for (S entity : sc) {
|
||||||
|
getPartitionOrderingPolicy(entity.getPartition())
|
||||||
|
.addSchedulableEntity(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumSchedulableEntities() {
|
||||||
|
// Return total number of schedulable entities, to maintain parity with
|
||||||
|
// existing FifoOrderingPolicy e.g. when determining if queue has reached
|
||||||
|
// its max app limit
|
||||||
|
int ret = 0;
|
||||||
|
for (Map.Entry<String, OrderingPolicy<S>> entry
|
||||||
|
: orderingPolicies.entrySet()) {
|
||||||
|
ret += entry.getValue().getNumSchedulableEntities();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void containerAllocated(S schedulableEntity, RMContainer r) {
|
||||||
|
getPartitionOrderingPolicy(schedulableEntity.getPartition())
|
||||||
|
.containerAllocated(schedulableEntity, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void containerReleased(S schedulableEntity, RMContainer r) {
|
||||||
|
getPartitionOrderingPolicy(schedulableEntity.getPartition())
|
||||||
|
.containerReleased(schedulableEntity, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void demandUpdated(S schedulableEntity) {
|
||||||
|
getPartitionOrderingPolicy(schedulableEntity.getPartition())
|
||||||
|
.demandUpdated(schedulableEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configure(Map<String, String> conf) {
|
||||||
|
if (conf == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String partitions =
|
||||||
|
conf.get(YarnConfiguration.EXCLUSIVE_ENFORCED_PARTITIONS_SUFFIX);
|
||||||
|
if (partitions != null) {
|
||||||
|
for (String partition : partitions.split(",")) {
|
||||||
|
partition = partition.trim();
|
||||||
|
if (!partition.isEmpty()) {
|
||||||
|
this.orderingPolicies.put(partition, new FifoOrderingPolicy());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getInfo() {
|
||||||
|
return "FifoOrderingPolicyWithExclusivePartitions";
|
||||||
|
}
|
||||||
|
|
||||||
|
private OrderingPolicy<S> getPartitionOrderingPolicy(String partition) {
|
||||||
|
String keyPartition = orderingPolicies.containsKey(partition) ?
|
||||||
|
partition : DEFAULT_PARTITION;
|
||||||
|
return orderingPolicies.get(keyPartition);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.hadoop.yarn.server.resourcemanager.scheduler.policy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IteratorSelector contains information needed to tell an
|
||||||
|
* {@link OrderingPolicy} what to return in an iterator.
|
||||||
|
*/
|
||||||
|
public class IteratorSelector {
|
||||||
|
|
||||||
|
public static final IteratorSelector EMPTY_ITERATOR_SELECTOR =
|
||||||
|
new IteratorSelector();
|
||||||
|
|
||||||
|
private String partition;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The partition for this iterator selector.
|
||||||
|
* @return partition
|
||||||
|
*/
|
||||||
|
public String getPartition() {
|
||||||
|
return this.partition;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set partition for this iterator selector.
|
||||||
|
* @param p partition
|
||||||
|
*/
|
||||||
|
public void setPartition(String p) {
|
||||||
|
this.partition = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -45,10 +45,11 @@ public interface OrderingPolicy<S extends SchedulableEntity> {
|
||||||
/**
|
/**
|
||||||
* Return an iterator over the collection of {@link SchedulableEntity}
|
* Return an iterator over the collection of {@link SchedulableEntity}
|
||||||
* objects which orders them for container assignment.
|
* objects which orders them for container assignment.
|
||||||
|
* @param sel the {@link IteratorSelector} to filter with
|
||||||
* @return an iterator over the collection of {@link SchedulableEntity}
|
* @return an iterator over the collection of {@link SchedulableEntity}
|
||||||
* objects
|
* objects
|
||||||
*/
|
*/
|
||||||
public Iterator<S> getAssignmentIterator();
|
Iterator<S> getAssignmentIterator(IteratorSelector sel);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return an iterator over the collection of {@link SchedulableEntity}
|
* Return an iterator over the collection of {@link SchedulableEntity}
|
||||||
|
|
|
@ -55,4 +55,9 @@ public interface SchedulableEntity {
|
||||||
*/
|
*/
|
||||||
public boolean isRecovering();
|
public boolean isRecovering();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get partition corresponding to this entity.
|
||||||
|
* @return partition
|
||||||
|
*/
|
||||||
|
String getPartition();
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ import java.security.PrivilegedAction;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
@ -1011,6 +1012,147 @@ public class TestSchedulerUtils {
|
||||||
System.err.println("Failed to wait scheduler application attempt stopped.");
|
System.err.println("Failed to wait scheduler application attempt stopped.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEnforcePartitionExclusivity() {
|
||||||
|
String enforcedExclusiveLabel = "x";
|
||||||
|
Set<String> enforcedExclusiveLabelSet =
|
||||||
|
Collections.singleton(enforcedExclusiveLabel);
|
||||||
|
String dummyLabel = "y";
|
||||||
|
String appLabel = "appLabel";
|
||||||
|
ResourceRequest rr = BuilderUtils.newResourceRequest(
|
||||||
|
mock(Priority.class), ResourceRequest.ANY, mock(Resource.class), 1);
|
||||||
|
|
||||||
|
// RR label unset and app label does not match. Nothing should happen.
|
||||||
|
SchedulerUtils.enforcePartitionExclusivity(rr, enforcedExclusiveLabelSet,
|
||||||
|
null);
|
||||||
|
Assert.assertNull(rr.getNodeLabelExpression());
|
||||||
|
SchedulerUtils.enforcePartitionExclusivity(rr, enforcedExclusiveLabelSet,
|
||||||
|
appLabel);
|
||||||
|
Assert.assertNull(rr.getNodeLabelExpression());
|
||||||
|
|
||||||
|
// RR label and app label do not match. Nothing should happen.
|
||||||
|
rr.setNodeLabelExpression(dummyLabel);
|
||||||
|
SchedulerUtils.enforcePartitionExclusivity(rr, enforcedExclusiveLabelSet,
|
||||||
|
null);
|
||||||
|
Assert.assertEquals(dummyLabel, rr.getNodeLabelExpression());
|
||||||
|
SchedulerUtils.enforcePartitionExclusivity(rr, enforcedExclusiveLabelSet,
|
||||||
|
appLabel);
|
||||||
|
Assert.assertEquals(dummyLabel, rr.getNodeLabelExpression());
|
||||||
|
|
||||||
|
// RR label matches but app label does not. RR label should be set
|
||||||
|
// to app label
|
||||||
|
rr.setNodeLabelExpression(enforcedExclusiveLabel);
|
||||||
|
SchedulerUtils.enforcePartitionExclusivity(rr, enforcedExclusiveLabelSet,
|
||||||
|
null);
|
||||||
|
Assert.assertNull(rr.getNodeLabelExpression());
|
||||||
|
rr.setNodeLabelExpression(enforcedExclusiveLabel);
|
||||||
|
SchedulerUtils.enforcePartitionExclusivity(rr, enforcedExclusiveLabelSet,
|
||||||
|
appLabel);
|
||||||
|
Assert.assertEquals(appLabel, rr.getNodeLabelExpression());
|
||||||
|
|
||||||
|
// RR label unset and app label matches. RR label should be set
|
||||||
|
// to app label
|
||||||
|
rr.setNodeLabelExpression(null);
|
||||||
|
SchedulerUtils.enforcePartitionExclusivity(rr, enforcedExclusiveLabelSet,
|
||||||
|
enforcedExclusiveLabel);
|
||||||
|
Assert.assertEquals(enforcedExclusiveLabel, rr.getNodeLabelExpression());
|
||||||
|
|
||||||
|
// RR label does not match and app label matches. RR label should be set
|
||||||
|
// to app label
|
||||||
|
rr.setNodeLabelExpression(dummyLabel);
|
||||||
|
SchedulerUtils.enforcePartitionExclusivity(rr, enforcedExclusiveLabelSet,
|
||||||
|
enforcedExclusiveLabel);
|
||||||
|
Assert.assertEquals(enforcedExclusiveLabel, rr.getNodeLabelExpression());
|
||||||
|
|
||||||
|
// RR label and app label matches. Nothing should happen.
|
||||||
|
rr.setNodeLabelExpression(enforcedExclusiveLabel);
|
||||||
|
SchedulerUtils.enforcePartitionExclusivity(rr, enforcedExclusiveLabelSet,
|
||||||
|
enforcedExclusiveLabel);
|
||||||
|
Assert.assertEquals(enforcedExclusiveLabel, rr.getNodeLabelExpression());
|
||||||
|
|
||||||
|
// Unconfigured label: nothing should happen.
|
||||||
|
rr.setNodeLabelExpression(null);
|
||||||
|
SchedulerUtils.enforcePartitionExclusivity(rr, null,
|
||||||
|
appLabel);
|
||||||
|
Assert.assertNull(rr.getNodeLabelExpression());
|
||||||
|
rr.setNodeLabelExpression(dummyLabel);
|
||||||
|
SchedulerUtils.enforcePartitionExclusivity(rr, null,
|
||||||
|
appLabel);
|
||||||
|
Assert.assertEquals(dummyLabel, rr.getNodeLabelExpression());
|
||||||
|
rr.setNodeLabelExpression(enforcedExclusiveLabel);
|
||||||
|
SchedulerUtils.enforcePartitionExclusivity(rr, null,
|
||||||
|
appLabel);
|
||||||
|
Assert.assertEquals(enforcedExclusiveLabel, rr.getNodeLabelExpression());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEnforcePartitionExclusivityMultipleLabels() {
|
||||||
|
String enforcedLabel1 = "x";
|
||||||
|
String enforcedLabel2 = "y";
|
||||||
|
Set<String> enforcedExclusiveLabelSet = new HashSet<>();
|
||||||
|
enforcedExclusiveLabelSet.add(enforcedLabel1);
|
||||||
|
enforcedExclusiveLabelSet.add(enforcedLabel2);
|
||||||
|
String dummyLabel = "dummyLabel";
|
||||||
|
String appLabel = "appLabel";
|
||||||
|
ResourceRequest rr = BuilderUtils.newResourceRequest(
|
||||||
|
mock(Priority.class), ResourceRequest.ANY, mock(Resource.class), 1);
|
||||||
|
|
||||||
|
// RR label unset and app label does not match. Nothing should happen.
|
||||||
|
SchedulerUtils.enforcePartitionExclusivity(rr, enforcedExclusiveLabelSet,
|
||||||
|
null);
|
||||||
|
Assert.assertNull(rr.getNodeLabelExpression());
|
||||||
|
SchedulerUtils.enforcePartitionExclusivity(rr, enforcedExclusiveLabelSet,
|
||||||
|
appLabel);
|
||||||
|
Assert.assertNull(rr.getNodeLabelExpression());
|
||||||
|
|
||||||
|
// RR label and app label do not match. Nothing should happen.
|
||||||
|
rr.setNodeLabelExpression(dummyLabel);
|
||||||
|
SchedulerUtils.enforcePartitionExclusivity(rr, enforcedExclusiveLabelSet,
|
||||||
|
null);
|
||||||
|
Assert.assertEquals(dummyLabel, rr.getNodeLabelExpression());
|
||||||
|
SchedulerUtils.enforcePartitionExclusivity(rr, enforcedExclusiveLabelSet,
|
||||||
|
appLabel);
|
||||||
|
Assert.assertEquals(dummyLabel, rr.getNodeLabelExpression());
|
||||||
|
|
||||||
|
// RR label matches but app label does not. RR label should be set
|
||||||
|
// to app label
|
||||||
|
rr.setNodeLabelExpression(enforcedLabel1);
|
||||||
|
SchedulerUtils.enforcePartitionExclusivity(rr, enforcedExclusiveLabelSet,
|
||||||
|
null);
|
||||||
|
Assert.assertNull(rr.getNodeLabelExpression());
|
||||||
|
rr.setNodeLabelExpression(enforcedLabel2);
|
||||||
|
SchedulerUtils.enforcePartitionExclusivity(rr, enforcedExclusiveLabelSet,
|
||||||
|
appLabel);
|
||||||
|
Assert.assertEquals(appLabel, rr.getNodeLabelExpression());
|
||||||
|
|
||||||
|
// RR label unset and app label matches. RR label should be set
|
||||||
|
// to app label
|
||||||
|
rr.setNodeLabelExpression(null);
|
||||||
|
SchedulerUtils.enforcePartitionExclusivity(rr, enforcedExclusiveLabelSet,
|
||||||
|
enforcedLabel1);
|
||||||
|
Assert.assertEquals(enforcedLabel1, rr.getNodeLabelExpression());
|
||||||
|
|
||||||
|
// RR label does not match and app label matches. RR label should be set
|
||||||
|
// to app label
|
||||||
|
rr.setNodeLabelExpression(dummyLabel);
|
||||||
|
SchedulerUtils.enforcePartitionExclusivity(rr, enforcedExclusiveLabelSet,
|
||||||
|
enforcedLabel2);
|
||||||
|
Assert.assertEquals(enforcedLabel2, rr.getNodeLabelExpression());
|
||||||
|
|
||||||
|
// RR label and app label matches. Nothing should happen.
|
||||||
|
rr.setNodeLabelExpression(enforcedLabel1);
|
||||||
|
SchedulerUtils.enforcePartitionExclusivity(rr, enforcedExclusiveLabelSet,
|
||||||
|
enforcedLabel1);
|
||||||
|
Assert.assertEquals(enforcedLabel1, rr.getNodeLabelExpression());
|
||||||
|
|
||||||
|
// RR label and app label don't match, but they're both enforced labels.
|
||||||
|
// RR label should be set to app label.
|
||||||
|
rr.setNodeLabelExpression(enforcedLabel2);
|
||||||
|
SchedulerUtils.enforcePartitionExclusivity(rr, enforcedExclusiveLabelSet,
|
||||||
|
enforcedLabel1);
|
||||||
|
Assert.assertEquals(enforcedLabel1, rr.getNodeLabelExpression());
|
||||||
|
}
|
||||||
|
|
||||||
public static SchedulerApplication<SchedulerApplicationAttempt>
|
public static SchedulerApplication<SchedulerApplicationAttempt>
|
||||||
verifyAppAddedAndRemovedFromScheduler(
|
verifyAppAddedAndRemovedFromScheduler(
|
||||||
Map<ApplicationId, SchedulerApplication<SchedulerApplicationAttempt>> applications,
|
Map<ApplicationId, SchedulerApplication<SchedulerApplicationAttempt>> applications,
|
||||||
|
|
|
@ -152,6 +152,7 @@ import org.apache.hadoop.yarn.server.resourcemanager.scheduler.event.NodeUpdateS
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.event.SchedulerEvent;
|
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.event.SchedulerEvent;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.placement.SimpleCandidateNodeSet;
|
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.placement.SimpleCandidateNodeSet;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.policy.FairOrderingPolicy;
|
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.policy.FairOrderingPolicy;
|
||||||
|
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.policy.IteratorSelector;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.security.ClientToAMTokenSecretManagerInRM;
|
import org.apache.hadoop.yarn.server.resourcemanager.security.ClientToAMTokenSecretManagerInRM;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.security.NMTokenSecretManagerInRM;
|
import org.apache.hadoop.yarn.server.resourcemanager.security.NMTokenSecretManagerInRM;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.security.RMContainerTokenSecretManager;
|
import org.apache.hadoop.yarn.server.resourcemanager.security.RMContainerTokenSecretManager;
|
||||||
|
@ -1288,8 +1289,9 @@ public class TestCapacityScheduler extends CapacitySchedulerTestBase {
|
||||||
//This happens because app2 has no demand/a magnitude of NaN, which
|
//This happens because app2 has no demand/a magnitude of NaN, which
|
||||||
//results in app1 and app2 being equal in the fairness comparison and
|
//results in app1 and app2 being equal in the fairness comparison and
|
||||||
//failling back to fifo (start) ordering
|
//failling back to fifo (start) ordering
|
||||||
assertEquals(q.getOrderingPolicy().getAssignmentIterator().next().getId(),
|
assertEquals(q.getOrderingPolicy().getAssignmentIterator(
|
||||||
appId1.toString());
|
IteratorSelector.EMPTY_ITERATOR_SELECTOR).next().getId(),
|
||||||
|
appId1.toString());
|
||||||
|
|
||||||
//Now, allocate for app2 (this would be the first/AM allocation)
|
//Now, allocate for app2 (this would be the first/AM allocation)
|
||||||
ResourceRequest r2 = TestUtils.createResourceRequest(ResourceRequest.ANY, 1*GB, 1, true, priority, recordFactory);
|
ResourceRequest r2 = TestUtils.createResourceRequest(ResourceRequest.ANY, 1*GB, 1, true, priority, recordFactory);
|
||||||
|
@ -1301,8 +1303,9 @@ public class TestCapacityScheduler extends CapacitySchedulerTestBase {
|
||||||
//verify re-ordering based on the allocation alone
|
//verify re-ordering based on the allocation alone
|
||||||
|
|
||||||
//Now, the first app for assignment is app2
|
//Now, the first app for assignment is app2
|
||||||
assertEquals(q.getOrderingPolicy().getAssignmentIterator().next().getId(),
|
assertEquals(q.getOrderingPolicy().getAssignmentIterator(
|
||||||
appId2.toString());
|
IteratorSelector.EMPTY_ITERATOR_SELECTOR).next().getId(),
|
||||||
|
appId2.toString());
|
||||||
|
|
||||||
rm.stop();
|
rm.stop();
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,6 +87,7 @@ import org.apache.hadoop.yarn.server.resourcemanager.scheduler.QueueResourceQuot
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.QueueStateManager;
|
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.QueueStateManager;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.ResourceLimits;
|
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.ResourceLimits;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.ResourceUsage;
|
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.ResourceUsage;
|
||||||
|
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.policy.FifoOrderingPolicyWithExclusivePartitions;
|
||||||
import org.apache.hadoop.yarn.server.scheduler.SchedulerRequestKey;
|
import org.apache.hadoop.yarn.server.scheduler.SchedulerRequestKey;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.UsersManager.User;
|
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.UsersManager.User;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.preemption.PreemptionManager;
|
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.preemption.PreemptionManager;
|
||||||
|
@ -132,6 +133,8 @@ public class TestLeafQueue {
|
||||||
final static int GB = 1024;
|
final static int GB = 1024;
|
||||||
final static String DEFAULT_RACK = "/default";
|
final static String DEFAULT_RACK = "/default";
|
||||||
|
|
||||||
|
private final static String LABEL = "test";
|
||||||
|
|
||||||
private final ResourceCalculator resourceCalculator =
|
private final ResourceCalculator resourceCalculator =
|
||||||
new DefaultResourceCalculator();
|
new DefaultResourceCalculator();
|
||||||
|
|
||||||
|
@ -140,14 +143,19 @@ public class TestLeafQueue {
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
setUpInternal(resourceCalculator);
|
setUpInternal(resourceCalculator, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setUpWithDominantResourceCalculator() throws Exception {
|
private void setUpWithDominantResourceCalculator() throws Exception {
|
||||||
setUpInternal(dominantResourceCalculator);
|
setUpInternal(dominantResourceCalculator, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setUpInternal(ResourceCalculator rC) throws Exception {
|
private void setUpWithNodeLabels() throws Exception {
|
||||||
|
setUpInternal(resourceCalculator, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setUpInternal(ResourceCalculator rC, boolean withNodeLabels)
|
||||||
|
throws Exception {
|
||||||
CapacityScheduler spyCs = new CapacityScheduler();
|
CapacityScheduler spyCs = new CapacityScheduler();
|
||||||
queues = new HashMap<String, CSQueue>();
|
queues = new HashMap<String, CSQueue>();
|
||||||
cs = spy(spyCs);
|
cs = spy(spyCs);
|
||||||
|
@ -172,7 +180,7 @@ public class TestLeafQueue {
|
||||||
csConf.setBoolean(CapacitySchedulerConfiguration.RESERVE_CONT_LOOK_ALL_NODES,
|
csConf.setBoolean(CapacitySchedulerConfiguration.RESERVE_CONT_LOOK_ALL_NODES,
|
||||||
false);
|
false);
|
||||||
final String newRoot = "root" + System.currentTimeMillis();
|
final String newRoot = "root" + System.currentTimeMillis();
|
||||||
setupQueueConfiguration(csConf, newRoot);
|
setupQueueConfiguration(csConf, newRoot, withNodeLabels);
|
||||||
YarnConfiguration conf = new YarnConfiguration();
|
YarnConfiguration conf = new YarnConfiguration();
|
||||||
cs.setConf(conf);
|
cs.setConf(conf);
|
||||||
|
|
||||||
|
@ -228,24 +236,39 @@ public class TestLeafQueue {
|
||||||
private static final String E = "e";
|
private static final String E = "e";
|
||||||
private void setupQueueConfiguration(
|
private void setupQueueConfiguration(
|
||||||
CapacitySchedulerConfiguration conf,
|
CapacitySchedulerConfiguration conf,
|
||||||
final String newRoot) {
|
final String newRoot, boolean withNodeLabels) {
|
||||||
|
|
||||||
// Define top-level queues
|
// Define top-level queues
|
||||||
conf.setQueues(ROOT, new String[] {newRoot});
|
conf.setQueues(ROOT, new String[] {newRoot});
|
||||||
conf.setMaximumCapacity(ROOT, 100);
|
conf.setMaximumCapacity(ROOT, 100);
|
||||||
conf.setAcl(ROOT,
|
conf.setAcl(ROOT,
|
||||||
QueueACL.SUBMIT_APPLICATIONS, " ");
|
QueueACL.SUBMIT_APPLICATIONS, " ");
|
||||||
|
if (withNodeLabels) {
|
||||||
|
conf.setCapacityByLabel(CapacitySchedulerConfiguration.ROOT, LABEL, 100);
|
||||||
|
conf.setMaximumCapacityByLabel(CapacitySchedulerConfiguration.ROOT,
|
||||||
|
LABEL, 100);
|
||||||
|
}
|
||||||
|
|
||||||
final String Q_newRoot = ROOT + "." + newRoot;
|
final String Q_newRoot = ROOT + "." + newRoot;
|
||||||
conf.setQueues(Q_newRoot, new String[] {A, B, C, D, E});
|
conf.setQueues(Q_newRoot, new String[] {A, B, C, D, E});
|
||||||
conf.setCapacity(Q_newRoot, 100);
|
conf.setCapacity(Q_newRoot, 100);
|
||||||
conf.setMaximumCapacity(Q_newRoot, 100);
|
conf.setMaximumCapacity(Q_newRoot, 100);
|
||||||
conf.setAcl(Q_newRoot, QueueACL.SUBMIT_APPLICATIONS, " ");
|
conf.setAcl(Q_newRoot, QueueACL.SUBMIT_APPLICATIONS, " ");
|
||||||
|
if (withNodeLabels) {
|
||||||
|
conf.setAccessibleNodeLabels(Q_newRoot, Collections.singleton(LABEL));
|
||||||
|
conf.setCapacityByLabel(Q_newRoot, LABEL, 100);
|
||||||
|
conf.setMaximumCapacityByLabel(Q_newRoot, LABEL, 100);
|
||||||
|
}
|
||||||
|
|
||||||
final String Q_A = Q_newRoot + "." + A;
|
final String Q_A = Q_newRoot + "." + A;
|
||||||
conf.setCapacity(Q_A, 8.5f);
|
conf.setCapacity(Q_A, 8.5f);
|
||||||
conf.setMaximumCapacity(Q_A, 20);
|
conf.setMaximumCapacity(Q_A, 20);
|
||||||
conf.setAcl(Q_A, QueueACL.SUBMIT_APPLICATIONS, "*");
|
conf.setAcl(Q_A, QueueACL.SUBMIT_APPLICATIONS, "*");
|
||||||
|
if (withNodeLabels) {
|
||||||
|
conf.setAccessibleNodeLabels(Q_A, Collections.singleton(LABEL));
|
||||||
|
conf.setCapacityByLabel(Q_A, LABEL, 100);
|
||||||
|
conf.setMaximumCapacityByLabel(Q_A, LABEL, 100);
|
||||||
|
}
|
||||||
|
|
||||||
final String Q_B = Q_newRoot + "." + B;
|
final String Q_B = Q_newRoot + "." + B;
|
||||||
conf.setCapacity(Q_B, 80);
|
conf.setCapacity(Q_B, 80);
|
||||||
|
@ -3097,7 +3120,7 @@ public class TestLeafQueue {
|
||||||
Map<String, CSQueue> queues = new HashMap<String, CSQueue>();
|
Map<String, CSQueue> queues = new HashMap<String, CSQueue>();
|
||||||
CapacitySchedulerConfiguration csConf = new CapacitySchedulerConfiguration();
|
CapacitySchedulerConfiguration csConf = new CapacitySchedulerConfiguration();
|
||||||
final String newRootName = "root" + System.currentTimeMillis();
|
final String newRootName = "root" + System.currentTimeMillis();
|
||||||
setupQueueConfiguration(csConf, newRootName);
|
setupQueueConfiguration(csConf, newRootName, false);
|
||||||
|
|
||||||
Resource clusterResource = Resources.createResource(100 * 16 * GB,
|
Resource clusterResource = Resources.createResource(100 * 16 * GB,
|
||||||
100 * 32);
|
100 * 32);
|
||||||
|
@ -3289,6 +3312,116 @@ public class TestLeafQueue {
|
||||||
Assert.assertEquals(3 * GB, app_0.getCurrentConsumption().getMemorySize());
|
Assert.assertEquals(3 * GB, app_0.getCurrentConsumption().getMemorySize());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFifoWithPartitionsAssignment() throws Exception {
|
||||||
|
setUpWithNodeLabels();
|
||||||
|
|
||||||
|
LeafQueue a = stubLeafQueue((LeafQueue) queues.get(A));
|
||||||
|
OrderingPolicy<FiCaSchedulerApp> policy =
|
||||||
|
new FifoOrderingPolicyWithExclusivePartitions<>();
|
||||||
|
policy.configure(Collections.singletonMap(
|
||||||
|
YarnConfiguration.EXCLUSIVE_ENFORCED_PARTITIONS_SUFFIX, LABEL));
|
||||||
|
a.setOrderingPolicy(policy);
|
||||||
|
String host00 = "127.0.0.1";
|
||||||
|
String rack0 = "rack_0";
|
||||||
|
FiCaSchedulerNode node00 = TestUtils.getMockNode(host00, rack0, 0,
|
||||||
|
16 * GB);
|
||||||
|
when(node00.getPartition()).thenReturn(LABEL);
|
||||||
|
String host01 = "127.0.0.2";
|
||||||
|
FiCaSchedulerNode node01 = TestUtils.getMockNode(host01, rack0, 0,
|
||||||
|
16 * GB);
|
||||||
|
when(node01.getPartition()).thenReturn("");
|
||||||
|
|
||||||
|
final int numNodes = 4;
|
||||||
|
Resource clusterResource = Resources.createResource(numNodes * (16 * GB),
|
||||||
|
numNodes * 16);
|
||||||
|
when(csContext.getNumClusterNodes()).thenReturn(numNodes);
|
||||||
|
|
||||||
|
String user0 = "user_0";
|
||||||
|
|
||||||
|
final ApplicationAttemptId appAttemptId0 =
|
||||||
|
TestUtils.getMockApplicationAttemptId(0, 0);
|
||||||
|
FiCaSchedulerApp app0 = spy(new FiCaSchedulerApp(appAttemptId0, user0, a,
|
||||||
|
mock(ActiveUsersManager.class), spyRMContext, Priority.newInstance(5),
|
||||||
|
false));
|
||||||
|
a.submitApplicationAttempt(app0, user0);
|
||||||
|
|
||||||
|
final ApplicationAttemptId appAttemptId1 =
|
||||||
|
TestUtils.getMockApplicationAttemptId(1, 0);
|
||||||
|
FiCaSchedulerApp app1 = spy(new FiCaSchedulerApp(appAttemptId1, user0, a,
|
||||||
|
mock(ActiveUsersManager.class), spyRMContext, Priority.newInstance(3),
|
||||||
|
false));
|
||||||
|
when(app1.getPartition()).thenReturn(LABEL);
|
||||||
|
a.submitApplicationAttempt(app1, user0);
|
||||||
|
|
||||||
|
Map<ApplicationAttemptId, FiCaSchedulerApp> apps = ImmutableMap.of(
|
||||||
|
app0.getApplicationAttemptId(), app0, app1.getApplicationAttemptId(),
|
||||||
|
app1);
|
||||||
|
Map<NodeId, FiCaSchedulerNode> nodes = ImmutableMap.of(node00.getNodeID(),
|
||||||
|
node00, node01.getNodeID(), node01);
|
||||||
|
|
||||||
|
Priority priority = TestUtils.createMockPriority(1);
|
||||||
|
List<ResourceRequest> app0Requests = new ArrayList<>();
|
||||||
|
List<ResourceRequest> app1Requests = new ArrayList<>();
|
||||||
|
|
||||||
|
app0Requests.clear();
|
||||||
|
app0Requests.add(TestUtils
|
||||||
|
.createResourceRequest(ResourceRequest.ANY, 2 * GB, 1, true, priority,
|
||||||
|
recordFactory));
|
||||||
|
app0.updateResourceRequests(app0Requests);
|
||||||
|
|
||||||
|
app1Requests.clear();
|
||||||
|
app1Requests.add(TestUtils
|
||||||
|
.createResourceRequest(ResourceRequest.ANY, 1 * GB, 1, true, priority,
|
||||||
|
recordFactory, LABEL));
|
||||||
|
app1.updateResourceRequests(app1Requests);
|
||||||
|
|
||||||
|
// app_1 will get containers since it is exclusive-enforced
|
||||||
|
applyCSAssignment(clusterResource,
|
||||||
|
a.assignContainers(clusterResource, node00,
|
||||||
|
new ResourceLimits(clusterResource),
|
||||||
|
SchedulingMode.RESPECT_PARTITION_EXCLUSIVITY), a, nodes, apps);
|
||||||
|
Assert.assertEquals(1 * GB, app1.getSchedulingResourceUsage()
|
||||||
|
.getUsed(LABEL).getMemorySize());
|
||||||
|
// app_0 should not get resources from node_0_0 since the labels
|
||||||
|
// don't match
|
||||||
|
applyCSAssignment(clusterResource,
|
||||||
|
a.assignContainers(clusterResource, node00,
|
||||||
|
new ResourceLimits(clusterResource),
|
||||||
|
SchedulingMode.RESPECT_PARTITION_EXCLUSIVITY), a, nodes, apps);
|
||||||
|
Assert.assertEquals(0 * GB, app0.getCurrentConsumption().getMemorySize());
|
||||||
|
|
||||||
|
app1Requests.clear();
|
||||||
|
app1Requests.add(TestUtils
|
||||||
|
.createResourceRequest(ResourceRequest.ANY, 1 * GB, 1, true, priority,
|
||||||
|
recordFactory, LABEL));
|
||||||
|
app1.updateResourceRequests(app1Requests);
|
||||||
|
|
||||||
|
// When node_0_1 heartbeats, app_0 should get containers
|
||||||
|
applyCSAssignment(clusterResource,
|
||||||
|
a.assignContainers(clusterResource, node01,
|
||||||
|
new ResourceLimits(clusterResource),
|
||||||
|
SchedulingMode.RESPECT_PARTITION_EXCLUSIVITY), a, nodes, apps);
|
||||||
|
Assert.assertEquals(2 * GB, app0.getCurrentConsumption().getMemorySize());
|
||||||
|
Assert.assertEquals(1 * GB, app1.getSchedulingResourceUsage()
|
||||||
|
.getUsed(LABEL).getMemorySize());
|
||||||
|
|
||||||
|
app0Requests.clear();
|
||||||
|
app0Requests.add(TestUtils
|
||||||
|
.createResourceRequest(ResourceRequest.ANY, 1 * GB, 1, true, priority,
|
||||||
|
recordFactory));
|
||||||
|
app0.updateResourceRequests(app0Requests);
|
||||||
|
|
||||||
|
// When node_0_0 heartbeats, app_1 should get containers again
|
||||||
|
applyCSAssignment(clusterResource,
|
||||||
|
a.assignContainers(clusterResource, node00,
|
||||||
|
new ResourceLimits(clusterResource),
|
||||||
|
SchedulingMode.RESPECT_PARTITION_EXCLUSIVITY), a, nodes, apps);
|
||||||
|
Assert.assertEquals(2 * GB, app0.getCurrentConsumption().getMemorySize());
|
||||||
|
Assert.assertEquals(2 * GB, app1.getSchedulingResourceUsage()
|
||||||
|
.getUsed(LABEL).getMemorySize());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testConcurrentAccess() throws Exception {
|
public void testConcurrentAccess() throws Exception {
|
||||||
YarnConfiguration conf = new YarnConfiguration();
|
YarnConfiguration conf = new YarnConfiguration();
|
||||||
|
|
|
@ -18,21 +18,19 @@
|
||||||
|
|
||||||
package org.apache.hadoop.yarn.server.resourcemanager.scheduler.policy;
|
package org.apache.hadoop.yarn.server.resourcemanager.scheduler.policy;
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import org.apache.hadoop.yarn.api.records.Priority;
|
import org.apache.hadoop.yarn.api.records.Priority;
|
||||||
import org.apache.hadoop.yarn.api.records.Resource;
|
import org.apache.hadoop.yarn.api.records.Resource;
|
||||||
import org.apache.hadoop.yarn.util.resource.Resources;
|
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.ResourceUsage;
|
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.ResourceUsage;
|
||||||
import org.apache.hadoop.yarn.nodelabels.CommonNodeLabelsManager;
|
import org.apache.hadoop.yarn.nodelabels.CommonNodeLabelsManager;
|
||||||
|
|
||||||
|
|
||||||
public class MockSchedulableEntity implements SchedulableEntity {
|
public class MockSchedulableEntity implements SchedulableEntity {
|
||||||
|
|
||||||
private String id;
|
private String id;
|
||||||
private long serial = 0;
|
private long serial = 0;
|
||||||
private Priority priority;
|
private Priority priority;
|
||||||
private boolean isRecovering;
|
private boolean isRecovering;
|
||||||
|
private String partition = "";
|
||||||
|
|
||||||
public MockSchedulableEntity() { }
|
public MockSchedulableEntity() { }
|
||||||
|
|
||||||
|
@ -101,4 +99,13 @@ public class MockSchedulableEntity implements SchedulableEntity {
|
||||||
protected void setRecovering(boolean entityRecovering) {
|
protected void setRecovering(boolean entityRecovering) {
|
||||||
this.isRecovering = entityRecovering;
|
this.isRecovering = entityRecovering;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPartition() {
|
||||||
|
return partition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPartition(String partition) {
|
||||||
|
this.partition = partition;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,19 +126,25 @@ public class TestFairOrderingPolicy {
|
||||||
|
|
||||||
|
|
||||||
//Assignment, least to greatest consumption
|
//Assignment, least to greatest consumption
|
||||||
checkIds(schedOrder.getAssignmentIterator(), new String[]{"3", "2", "1"});
|
checkIds(schedOrder.getAssignmentIterator(
|
||||||
|
IteratorSelector.EMPTY_ITERATOR_SELECTOR),
|
||||||
|
new String[]{"3", "2", "1"});
|
||||||
|
|
||||||
//Preemption, greatest to least
|
//Preemption, greatest to least
|
||||||
checkIds(schedOrder.getPreemptionIterator(), new String[]{"1", "2", "3"});
|
checkIds(schedOrder.getPreemptionIterator(), new String[]{"1", "2", "3"});
|
||||||
|
|
||||||
//Change value without inform, should see no change
|
//Change value without inform, should see no change
|
||||||
msp2.setUsed(Resources.createResource(6));
|
msp2.setUsed(Resources.createResource(6));
|
||||||
checkIds(schedOrder.getAssignmentIterator(), new String[]{"3", "2", "1"});
|
checkIds(schedOrder.getAssignmentIterator(
|
||||||
|
IteratorSelector.EMPTY_ITERATOR_SELECTOR),
|
||||||
|
new String[]{"3", "2", "1"});
|
||||||
checkIds(schedOrder.getPreemptionIterator(), new String[]{"1", "2", "3"});
|
checkIds(schedOrder.getPreemptionIterator(), new String[]{"1", "2", "3"});
|
||||||
|
|
||||||
//Do inform, will reorder
|
//Do inform, will reorder
|
||||||
schedOrder.containerAllocated(msp2, null);
|
schedOrder.containerAllocated(msp2, null);
|
||||||
checkIds(schedOrder.getAssignmentIterator(), new String[]{"3", "1", "2"});
|
checkIds(schedOrder.getAssignmentIterator(
|
||||||
|
IteratorSelector.EMPTY_ITERATOR_SELECTOR),
|
||||||
|
new String[]{"3", "1", "2"});
|
||||||
checkIds(schedOrder.getPreemptionIterator(), new String[]{"2", "1", "3"});
|
checkIds(schedOrder.getPreemptionIterator(), new String[]{"2", "1", "3"});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,7 @@ public class TestFifoOrderingPolicy {
|
||||||
schedOrder.addSchedulableEntity(msp3);
|
schedOrder.addSchedulableEntity(msp3);
|
||||||
|
|
||||||
//Assignment, oldest to youngest
|
//Assignment, oldest to youngest
|
||||||
checkSerials(schedOrder.getAssignmentIterator(), new long[]{1, 2, 3});
|
checkSerials(schedOrder.getAssignmentIterator(IteratorSelector.EMPTY_ITERATOR_SELECTOR), new long[]{1, 2, 3});
|
||||||
|
|
||||||
//Preemption, youngest to oldest
|
//Preemption, youngest to oldest
|
||||||
checkSerials(schedOrder.getPreemptionIterator(), new long[]{3, 2, 1});
|
checkSerials(schedOrder.getPreemptionIterator(), new long[]{3, 2, 1});
|
||||||
|
|
|
@ -72,8 +72,9 @@ public class TestFifoOrderingPolicyForPendingApps {
|
||||||
schedOrder.addSchedulableEntity(msp7);
|
schedOrder.addSchedulableEntity(msp7);
|
||||||
|
|
||||||
// Assignment with serial id's are 3,2,4,1,6,5,7
|
// Assignment with serial id's are 3,2,4,1,6,5,7
|
||||||
checkSerials(schedOrder.getAssignmentIterator(), new long[] { 3, 2, 4, 1,
|
checkSerials(schedOrder.getAssignmentIterator(
|
||||||
6, 5, 7 });
|
IteratorSelector.EMPTY_ITERATOR_SELECTOR), new long[] {3, 2, 4, 1,
|
||||||
|
6, 5, 7});
|
||||||
|
|
||||||
//Preemption, youngest to oldest
|
//Preemption, youngest to oldest
|
||||||
checkSerials(schedOrder.getPreemptionIterator(), new long[] { 7, 5, 6, 1,
|
checkSerials(schedOrder.getPreemptionIterator(), new long[] { 7, 5, 6, 1,
|
||||||
|
|
|
@ -0,0 +1,244 @@
|
||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.hadoop.yarn.server.resourcemanager.scheduler.policy;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import org.apache.hadoop.yarn.conf.YarnConfiguration;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests {@link FifoOrderingPolicyWithExclusivePartitions} ordering policy.
|
||||||
|
*/
|
||||||
|
public class TestFifoOrderingPolicyWithExclusivePartitions {
|
||||||
|
|
||||||
|
private static final String PARTITION = "test";
|
||||||
|
private static final String PARTITION2 = "test2";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoConfiguredExclusiveEnforcedPartitions() {
|
||||||
|
FifoOrderingPolicyWithExclusivePartitions<MockSchedulableEntity> policy =
|
||||||
|
new FifoOrderingPolicyWithExclusivePartitions<>();
|
||||||
|
policy.configure(Collections.EMPTY_MAP);
|
||||||
|
|
||||||
|
MockSchedulableEntity p1 = new MockSchedulableEntity(4, 0, false);
|
||||||
|
p1.setPartition(PARTITION);
|
||||||
|
p1.setId("p1");
|
||||||
|
MockSchedulableEntity p2 = new MockSchedulableEntity(3, 1, false);
|
||||||
|
p2.setPartition(PARTITION);
|
||||||
|
p2.setId("p2");
|
||||||
|
|
||||||
|
MockSchedulableEntity r1 = new MockSchedulableEntity(2, 0, false);
|
||||||
|
r1.setId("r1");
|
||||||
|
MockSchedulableEntity r2 = new MockSchedulableEntity(1, 0, false);
|
||||||
|
r2.setId("r2");
|
||||||
|
|
||||||
|
policy.addSchedulableEntity(p1);
|
||||||
|
policy.addAllSchedulableEntities(Arrays.asList(p2, r1, r2));
|
||||||
|
Assert.assertEquals(4, policy.getNumSchedulableEntities());
|
||||||
|
Assert.assertEquals(4, policy.getSchedulableEntities().size());
|
||||||
|
IteratorSelector sel = new IteratorSelector();
|
||||||
|
// Should behave like FifoOrderingPolicy, regardless of partition
|
||||||
|
verifyAssignmentIteratorOrder(policy,
|
||||||
|
IteratorSelector.EMPTY_ITERATOR_SELECTOR, "p2", "r2", "r1", "p1");
|
||||||
|
verifyPreemptionIteratorOrder(policy, "p1", "r1", "r2", "p2");
|
||||||
|
sel.setPartition(PARTITION);
|
||||||
|
verifyAssignmentIteratorOrder(policy, sel, "p2", "r2", "r1", "p1");
|
||||||
|
verifyPreemptionIteratorOrder(policy, "p1", "r1", "r2", "p2");
|
||||||
|
|
||||||
|
policy.removeSchedulableEntity(p2);
|
||||||
|
policy.removeSchedulableEntity(r2);
|
||||||
|
Assert.assertEquals(2, policy.getNumSchedulableEntities());
|
||||||
|
Assert.assertEquals(2, policy.getSchedulableEntities().size());
|
||||||
|
verifyAssignmentIteratorOrder(policy,
|
||||||
|
IteratorSelector.EMPTY_ITERATOR_SELECTOR, "r1", "p1");
|
||||||
|
verifyPreemptionIteratorOrder(policy, "p1", "r1");
|
||||||
|
sel.setPartition(PARTITION);
|
||||||
|
verifyAssignmentIteratorOrder(policy, sel, "r1", "p1");
|
||||||
|
verifyPreemptionIteratorOrder(policy, "p1", "r1");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSingleExclusiveEnforcedPartition() {
|
||||||
|
FifoOrderingPolicyWithExclusivePartitions<MockSchedulableEntity> policy =
|
||||||
|
new FifoOrderingPolicyWithExclusivePartitions<>();
|
||||||
|
policy.configure(Collections.singletonMap(
|
||||||
|
YarnConfiguration.EXCLUSIVE_ENFORCED_PARTITIONS_SUFFIX, PARTITION));
|
||||||
|
|
||||||
|
// PARTITION iterator should return p2, p1, p3
|
||||||
|
MockSchedulableEntity p1 = new MockSchedulableEntity(1, 0, false);
|
||||||
|
p1.setPartition(PARTITION);
|
||||||
|
p1.setId("p1");
|
||||||
|
MockSchedulableEntity p2 = new MockSchedulableEntity(5, 1, false);
|
||||||
|
p2.setPartition(PARTITION);
|
||||||
|
p2.setId("p2");
|
||||||
|
MockSchedulableEntity p3 = new MockSchedulableEntity(3, 0, false);
|
||||||
|
p3.setPartition(PARTITION);
|
||||||
|
p3.setId("p3");
|
||||||
|
|
||||||
|
// non-PARTITION iterator should return r3, r2, r1
|
||||||
|
MockSchedulableEntity r1 = new MockSchedulableEntity(6, 0, false);
|
||||||
|
r1.setId("r1");
|
||||||
|
MockSchedulableEntity r2 = new MockSchedulableEntity(4, 0, false);
|
||||||
|
r2.setId("r2");
|
||||||
|
MockSchedulableEntity r3 = new MockSchedulableEntity(2, 1, false);
|
||||||
|
r3.setId("r3");
|
||||||
|
|
||||||
|
policy.addSchedulableEntity(r1);
|
||||||
|
Assert.assertEquals(1, policy.getNumSchedulableEntities());
|
||||||
|
Assert.assertEquals("r1", policy.getSchedulableEntities()
|
||||||
|
.iterator().next().getId());
|
||||||
|
verifyAssignmentIteratorOrder(policy,
|
||||||
|
IteratorSelector.EMPTY_ITERATOR_SELECTOR, "r1");
|
||||||
|
verifyPreemptionIteratorOrder(policy, "r1");
|
||||||
|
|
||||||
|
List<MockSchedulableEntity> entities = Arrays.asList(r2, r3, p1, p2);
|
||||||
|
policy.addAllSchedulableEntities(entities);
|
||||||
|
policy.addSchedulableEntity(p3);
|
||||||
|
Assert.assertEquals(6, policy.getNumSchedulableEntities());
|
||||||
|
Assert.assertEquals(6, policy.getSchedulableEntities().size());
|
||||||
|
// Assignment iterator should return non-PARTITION entities,
|
||||||
|
// in order based on FifoOrderingPolicy
|
||||||
|
verifyAssignmentIteratorOrder(policy,
|
||||||
|
IteratorSelector.EMPTY_ITERATOR_SELECTOR, "r3", "r2", "r1");
|
||||||
|
// Preemption iterator should return all entities, in global order
|
||||||
|
verifyPreemptionIteratorOrder(policy, "r1", "r2", "p3", "p1", "p2", "r3");
|
||||||
|
// Same thing as above, but with a non-empty partition
|
||||||
|
IteratorSelector sel = new IteratorSelector();
|
||||||
|
sel.setPartition("dummy");
|
||||||
|
verifyAssignmentIteratorOrder(policy, sel, "r3", "r2", "r1");
|
||||||
|
verifyPreemptionIteratorOrder(policy, "r1", "r2", "p3", "p1", "p2", "r3");
|
||||||
|
// Should return PARTITION entities, in order based on FifoOrderingPolicy
|
||||||
|
sel.setPartition(PARTITION);
|
||||||
|
verifyAssignmentIteratorOrder(policy, sel, "p2", "p1", "p3");
|
||||||
|
verifyPreemptionIteratorOrder(policy, "r1", "r2", "p3", "p1", "p2", "r3");
|
||||||
|
|
||||||
|
policy.removeSchedulableEntity(p2);
|
||||||
|
policy.removeSchedulableEntity(r2);
|
||||||
|
Assert.assertEquals(4, policy.getNumSchedulableEntities());
|
||||||
|
Assert.assertEquals(4, policy.getSchedulableEntities().size());
|
||||||
|
verifyAssignmentIteratorOrder(policy,
|
||||||
|
IteratorSelector.EMPTY_ITERATOR_SELECTOR, "r3", "r1");
|
||||||
|
verifyPreemptionIteratorOrder(policy, "r1", "p3", "p1", "r3");
|
||||||
|
sel.setPartition(PARTITION);
|
||||||
|
verifyAssignmentIteratorOrder(policy, sel, "p1", "p3");
|
||||||
|
verifyPreemptionIteratorOrder(policy, "r1", "p3", "p1", "r3");
|
||||||
|
|
||||||
|
policy.removeSchedulableEntity(p1);
|
||||||
|
policy.removeSchedulableEntity(p3);
|
||||||
|
Assert.assertEquals(2, policy.getNumSchedulableEntities());
|
||||||
|
Assert.assertEquals(2, policy.getSchedulableEntities().size());
|
||||||
|
verifyAssignmentIteratorOrder(policy,
|
||||||
|
IteratorSelector.EMPTY_ITERATOR_SELECTOR, "r3", "r1");
|
||||||
|
verifyPreemptionIteratorOrder(policy, "r1", "r3");
|
||||||
|
sel.setPartition(PARTITION);
|
||||||
|
verifyAssignmentIteratorOrder(policy, sel);
|
||||||
|
verifyPreemptionIteratorOrder(policy, "r1", "r3");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMultipleExclusiveEnforcedPartitions() {
|
||||||
|
FifoOrderingPolicyWithExclusivePartitions<MockSchedulableEntity> policy =
|
||||||
|
new FifoOrderingPolicyWithExclusivePartitions<>();
|
||||||
|
policy.configure(Collections.singletonMap(
|
||||||
|
YarnConfiguration.EXCLUSIVE_ENFORCED_PARTITIONS_SUFFIX,
|
||||||
|
PARTITION + "," + PARTITION2));
|
||||||
|
|
||||||
|
// PARTITION iterator should return p2, p1
|
||||||
|
MockSchedulableEntity p1 = new MockSchedulableEntity(1, 0, false);
|
||||||
|
p1.setPartition(PARTITION);
|
||||||
|
p1.setId("p1");
|
||||||
|
MockSchedulableEntity p2 = new MockSchedulableEntity(5, 1, false);
|
||||||
|
p2.setPartition(PARTITION);
|
||||||
|
p2.setId("p2");
|
||||||
|
|
||||||
|
// PARTITION2 iterator should return r1, r2
|
||||||
|
MockSchedulableEntity r1 = new MockSchedulableEntity(3, 0, false);
|
||||||
|
r1.setPartition(PARTITION2);
|
||||||
|
r1.setId("r1");
|
||||||
|
MockSchedulableEntity r2 = new MockSchedulableEntity(4, 0, false);
|
||||||
|
r2.setPartition(PARTITION2);
|
||||||
|
r2.setId("r2");
|
||||||
|
|
||||||
|
// default iterator should return s2, s1
|
||||||
|
MockSchedulableEntity s1 = new MockSchedulableEntity(6, 0, false);
|
||||||
|
s1.setId("s1");
|
||||||
|
MockSchedulableEntity s2 = new MockSchedulableEntity(2, 0, false);
|
||||||
|
s2.setId("s2");
|
||||||
|
|
||||||
|
policy.addAllSchedulableEntities(Arrays.asList(s1, s2, r1));
|
||||||
|
Assert.assertEquals(3, policy.getNumSchedulableEntities());
|
||||||
|
Assert.assertEquals(3, policy.getSchedulableEntities().size());
|
||||||
|
IteratorSelector sel = new IteratorSelector();
|
||||||
|
// assignment iterator returns only default (non-partitioned) entities
|
||||||
|
verifyAssignmentIteratorOrder(policy,
|
||||||
|
IteratorSelector.EMPTY_ITERATOR_SELECTOR, "s2", "s1");
|
||||||
|
verifyPreemptionIteratorOrder(policy, "s1", "r1", "s2");
|
||||||
|
sel.setPartition(PARTITION2);
|
||||||
|
verifyAssignmentIteratorOrder(policy, sel, "r1");
|
||||||
|
|
||||||
|
policy.addAllSchedulableEntities(Arrays.asList(r2, p1, p2));
|
||||||
|
Assert.assertEquals(6, policy.getNumSchedulableEntities());
|
||||||
|
Assert.assertEquals(6, policy.getSchedulableEntities().size());
|
||||||
|
verifyAssignmentIteratorOrder(policy,
|
||||||
|
IteratorSelector.EMPTY_ITERATOR_SELECTOR, "s2", "s1");
|
||||||
|
sel.setPartition(PARTITION);
|
||||||
|
verifyAssignmentIteratorOrder(policy, sel, "p2", "p1");
|
||||||
|
sel.setPartition(PARTITION2);
|
||||||
|
verifyAssignmentIteratorOrder(policy, sel, "r1", "r2");
|
||||||
|
verifyPreemptionIteratorOrder(policy, "s1", "r2", "r1", "s2", "p1", "p2");
|
||||||
|
|
||||||
|
policy.removeSchedulableEntity(p2);
|
||||||
|
policy.removeSchedulableEntity(r1);
|
||||||
|
policy.removeSchedulableEntity(r2);
|
||||||
|
Assert.assertEquals(3, policy.getNumSchedulableEntities());
|
||||||
|
Assert.assertEquals(3, policy.getSchedulableEntities().size());
|
||||||
|
verifyAssignmentIteratorOrder(policy,
|
||||||
|
IteratorSelector.EMPTY_ITERATOR_SELECTOR, "s2", "s1");
|
||||||
|
sel.setPartition(PARTITION);
|
||||||
|
verifyAssignmentIteratorOrder(policy, sel, "p1");
|
||||||
|
sel.setPartition(PARTITION2);
|
||||||
|
verifyAssignmentIteratorOrder(policy, sel);
|
||||||
|
verifyPreemptionIteratorOrder(policy, "s1", "s2", "p1");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void verifyAssignmentIteratorOrder(
|
||||||
|
FifoOrderingPolicyWithExclusivePartitions<MockSchedulableEntity> policy,
|
||||||
|
IteratorSelector sel, String... ids) {
|
||||||
|
verifyIteratorOrder(policy.getAssignmentIterator(sel), ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void verifyPreemptionIteratorOrder(
|
||||||
|
FifoOrderingPolicyWithExclusivePartitions<MockSchedulableEntity> policy,
|
||||||
|
String... ids) {
|
||||||
|
verifyIteratorOrder(policy.getPreemptionIterator(), ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void verifyIteratorOrder(Iterator<MockSchedulableEntity> itr,
|
||||||
|
String... ids) {
|
||||||
|
for (String id : ids) {
|
||||||
|
Assert.assertEquals(id, itr.next().getId());
|
||||||
|
}
|
||||||
|
Assert.assertFalse(itr.hasNext());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue