YARN-8367. Fix NPE in SingleConstraintAppPlacementAllocator when placement constraint in SchedulingRequest is null. Contributed by Weiwei Yang.

(Cherry picked from commit 6468071f13)
This commit is contained in:
Weiwei Yang 2018-05-31 20:46:39 +08:00
parent 58e7d6c3c0
commit ec4240a7fa
2 changed files with 183 additions and 90 deletions

View File

@ -19,6 +19,7 @@
package org.apache.hadoop.yarn.server.resourcemanager.scheduler.placement; package org.apache.hadoop.yarn.server.resourcemanager.scheduler.placement;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableSet;
import org.apache.commons.collections.IteratorUtils; import org.apache.commons.collections.IteratorUtils;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@ -238,14 +239,21 @@ public class SingleConstraintAppPlacementAllocator<N extends SchedulerNode>
"Only GUARANTEED execution type is supported."); "Only GUARANTEED execution type is supported.");
} }
// Node partition
String nodePartition = null;
// Target allocation tags
Set<String> targetAllocationTags = null;
PlacementConstraint constraint = PlacementConstraint constraint =
newSchedulingRequest.getPlacementConstraint(); newSchedulingRequest.getPlacementConstraint();
if (constraint != null) {
// We only accept SingleConstraint // We only accept SingleConstraint
PlacementConstraint.AbstractConstraint ac = constraint.getConstraintExpr(); PlacementConstraint.AbstractConstraint ac = constraint
.getConstraintExpr();
if (!(ac instanceof PlacementConstraint.SingleConstraint)) { if (!(ac instanceof PlacementConstraint.SingleConstraint)) {
throwExceptionWithMetaInfo( throwExceptionWithMetaInfo("Only accepts "
"Only accepts " + PlacementConstraint.SingleConstraint.class.getName() + PlacementConstraint.SingleConstraint.class.getName()
+ " as constraint-expression. Rejecting the new added " + " as constraint-expression. Rejecting the new added "
+ "constraint-expression.class=" + ac.getClass().getName()); + "constraint-expression.class=" + ac.getClass().getName());
} }
@ -277,13 +285,8 @@ public class SingleConstraintAppPlacementAllocator<N extends SchedulerNode>
"TargetExpression should not be null or empty"); "TargetExpression should not be null or empty");
} }
// Set node partition for (PlacementConstraint.TargetExpression targetExpression :
String nodePartition = null; targetExpressionSet) {
// Target allocation tags
Set<String> targetAllocationTags = null;
for (PlacementConstraint.TargetExpression targetExpression : targetExpressionSet) {
// Handle node partition // Handle node partition
if (targetExpression.getTargetType().equals( if (targetExpression.getTargetType().equals(
PlacementConstraint.TargetExpression.TargetType.NODE_ATTRIBUTE)) { PlacementConstraint.TargetExpression.TargetType.NODE_ATTRIBUTE)) {
@ -296,8 +299,8 @@ public class SingleConstraintAppPlacementAllocator<N extends SchedulerNode>
} }
if (nodePartition != null) { if (nodePartition != null) {
// This means we have duplicated node partition entry inside placement // This means we have duplicated node partition entry
// constraint, which might be set by mistake. // inside placement constraint, which might be set by mistake.
throwExceptionWithMetaInfo( throwExceptionWithMetaInfo(
"Only one node partition targetExpression is allowed"); "Only one node partition targetExpression is allowed");
} }
@ -324,8 +327,8 @@ public class SingleConstraintAppPlacementAllocator<N extends SchedulerNode>
"Only one AllocationTag targetExpression is allowed"); "Only one AllocationTag targetExpression is allowed");
} }
if (targetExpression.getTargetValues() == null || targetExpression if (targetExpression.getTargetValues() == null ||
.getTargetValues().isEmpty()) { targetExpression.getTargetValues().isEmpty()) {
throwExceptionWithMetaInfo("Failed to find allocation tags from " throwExceptionWithMetaInfo("Failed to find allocation tags from "
+ "TargetExpressions or couldn't find self-app target."); + "TargetExpressions or couldn't find self-app target.");
} }
@ -338,10 +341,16 @@ public class SingleConstraintAppPlacementAllocator<N extends SchedulerNode>
if (targetAllocationTags == null) { if (targetAllocationTags == null) {
// That means we don't have ALLOCATION_TAG specified // That means we don't have ALLOCATION_TAG specified
throwExceptionWithMetaInfo( throwExceptionWithMetaInfo(
"Couldn't find target expression with type == ALLOCATION_TAG, it is " "Couldn't find target expression with type == ALLOCATION_TAG,"
+ "required to include one and only one target expression with " + " it is required to include one and only one target"
+ "type == ALLOCATION_TAG"); + " expression with type == ALLOCATION_TAG");
}
}
// If this scheduling request doesn't contain a placement constraint,
// we set allocation tags an empty set.
if (targetAllocationTags == null) {
targetAllocationTags = ImmutableSet.of();
} }
if (nodePartition == null) { if (nodePartition == null) {

View File

@ -18,8 +18,15 @@
package org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity; package org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.yarn.api.protocolrecords.AllocateRequest;
import org.apache.hadoop.yarn.api.records.ExecutionType;
import org.apache.hadoop.yarn.api.records.ExecutionTypeRequest;
import org.apache.hadoop.yarn.api.records.SchedulingRequest;
import org.apache.hadoop.yarn.api.resource.PlacementConstraint;
import org.apache.hadoop.yarn.api.resource.PlacementConstraints;
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.constraint.TargetApplicationsNamespace; import org.apache.hadoop.yarn.server.resourcemanager.scheduler.constraint.TargetApplicationsNamespace;
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;
@ -39,6 +46,8 @@ import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import static org.apache.hadoop.yarn.api.resource.PlacementConstraints.PlacementTargets.*;
public class TestSchedulingRequestContainerAllocation { public class TestSchedulingRequestContainerAllocation {
private final int GB = 1024; private final int GB = 1024;
@ -393,4 +402,79 @@ public class TestSchedulingRequestContainerAllocation {
Assert.assertTrue(caughtException); Assert.assertTrue(caughtException);
rm1.close(); rm1.close();
} }
@Test
public void testSchedulingRequestWithNullConstraint() throws Exception {
Configuration csConf = TestUtils.getConfigurationWithMultipleQueues(
new Configuration());
csConf.set(YarnConfiguration.RM_PLACEMENT_CONSTRAINTS_HANDLER,
YarnConfiguration.SCHEDULER_RM_PLACEMENT_CONSTRAINTS_HANDLER);
// inject node label manager
MockRM rm1 = new MockRM(csConf) {
@Override
public RMNodeLabelsManager createNodeLabelManager() {
return mgr;
}
};
rm1.getRMContext().setNodeLabelManager(mgr);
rm1.start();
// 4 NMs.
MockNM[] nms = new MockNM[4];
RMNode[] rmNodes = new RMNode[4];
for (int i = 0; i < 4; i++) {
nms[i] = rm1.registerNode("192.168.0." + i + ":1234", 10 * GB);
rmNodes[i] = rm1.getRMContext().getRMNodes().get(nms[i].getNodeId());
}
// app1 -> c
RMApp app1 = rm1.submitApp(1 * GB, "app", "user", null, "c");
MockAM am1 = MockRM.launchAndRegisterAM(app1, rm1, nms[0]);
CapacityScheduler cs = (CapacityScheduler) rm1.getResourceScheduler();
PlacementConstraint constraint = PlacementConstraints
.targetNotIn("node", allocationTag("t1"))
.build();
SchedulingRequest sc = SchedulingRequest
.newInstance(0, Priority.newInstance(1),
ExecutionTypeRequest.newInstance(ExecutionType.GUARANTEED),
ImmutableSet.of("t1"),
ResourceSizing.newInstance(1, Resource.newInstance(1024, 1)),
constraint);
AllocateRequest request = AllocateRequest.newBuilder()
.schedulingRequests(ImmutableList.of(sc)).build();
am1.allocate(request);
for (int i = 0; i < 4; i++) {
cs.handle(new NodeUpdateSchedulerEvent(rmNodes[i]));
}
FiCaSchedulerApp schedApp = cs.getApplicationAttempt(
am1.getApplicationAttemptId());
Assert.assertEquals(2, schedApp.getLiveContainers().size());
// Send another request with null placement constraint,
// ensure there is no NPE while handling this request.
sc = SchedulingRequest
.newInstance(1, Priority.newInstance(1),
ExecutionTypeRequest.newInstance(ExecutionType.GUARANTEED),
ImmutableSet.of("t2"),
ResourceSizing.newInstance(2, Resource.newInstance(1024, 1)),
null);
AllocateRequest request1 = AllocateRequest.newBuilder()
.schedulingRequests(ImmutableList.of(sc)).build();
am1.allocate(request1);
for (int i = 0; i < 4; i++) {
cs.handle(new NodeUpdateSchedulerEvent(rmNodes[i]));
}
Assert.assertEquals(4, schedApp.getLiveContainers().size());
rm1.close();
}
} }