Skip to content

Commit 4461cfa

Browse files
YARN-11801: NPE in FifoCandidatesSelector.selectCandidates when prempting resources for an auto-created queue without child queues (#7657)
1 parent 2f0dd7c commit 4461cfa

File tree

3 files changed

+83
-38
lines changed

3 files changed

+83
-38
lines changed

hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/monitor/capacity/ProportionalCapacityPreemptionPolicy.java

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.apache.hadoop.thirdparty.com.google.common.collect.ImmutableSet;
2323
import org.apache.commons.lang3.StringUtils;
2424
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.AbstractParentQueue;
25+
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.AbstractLeafQueue;
2526
import org.slf4j.Logger;
2627
import org.slf4j.LoggerFactory;
2728
import org.apache.hadoop.classification.InterfaceStability.Unstable;
@@ -40,8 +41,6 @@
4041
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler;
4142
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacitySchedulerConfiguration;
4243

43-
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity
44-
.ManagedParentQueue;
4544
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.QueueCapacities;
4645
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.preemption.PreemptableQueue;
4746
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.event.ContainerPreemptEvent;
@@ -430,12 +429,14 @@ private void cleanupStaledPreemptionCandidates(long currentTime) {
430429
}
431430

432431
private Set<String> getLeafQueueNames(TempQueuePerPartition q) {
433-
// Also exclude ParentQueues, which might be without children
434-
if (CollectionUtils.isEmpty(q.children)
435-
&& !(q.parentQueue instanceof ManagedParentQueue)
436-
&& (q.parentQueue == null
437-
|| !q.parentQueue.isEligibleForAutoQueueCreation())) {
438-
return ImmutableSet.of(q.queueName);
432+
// Only consider this a leaf queue if:
433+
// It is a concrete leaf queue (not a childless parent)
434+
if (CollectionUtils.isEmpty(q.children)) {
435+
CSQueue queue = scheduler.getQueue(q.queueName);
436+
if (queue instanceof AbstractLeafQueue) {
437+
return ImmutableSet.of(q.queueName);
438+
}
439+
return Collections.emptySet();
439440
}
440441

441442
Set<String> leafQueueNames = new HashSet<>();

hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/AbstractParentQueue.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,15 @@ public boolean isEligibleForAutoQueueCreation() {
552552
return isDynamicQueue() || queueContext.getConfiguration().
553553
isAutoQueueCreationV2Enabled(getQueuePath());
554554
}
555+
/**
556+
* Check whether this queue supports legacy(v1) dynamic child queue creation.
557+
* @return true if queue is eligible to create child queues dynamically using
558+
* the legacy system, false otherwise
559+
*/
560+
public boolean isEligibleForLegacyAutoQueueCreation() {
561+
return isDynamicQueue() || queueContext.getConfiguration().
562+
isAutoCreateChildQueueEnabled(getQueuePath());
563+
}
555564

556565
@Override
557566
public void reinitialize(CSQueue newlyParsedQueue,

hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/monitor/capacity/TestProportionalCapacityPreemptionPolicy.java

Lines changed: 65 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,44 +1073,75 @@ public void testRefreshPreemptionProperties() throws Exception {
10731073
}
10741074

10751075
@Test
1076-
public void testLeafQueueNameExtraction() throws Exception {
1077-
ProportionalCapacityPreemptionPolicy policy =
1078-
buildPolicy(Q_DATA_FOR_IGNORE);
1076+
public void testLeafQueueNameExtractionWithFlexibleAQC() throws Exception {
1077+
ProportionalCapacityPreemptionPolicy policy = buildPolicy(Q_DATA_FOR_IGNORE);
10791078
ParentQueue root = (ParentQueue) mCS.getRootQueue();
1079+
10801080
root.addDynamicParentQueue("childlessFlexible");
1081+
ParentQueue dynamicParent = setupDynamicParentQueue("root.dynamicParent", true);
1082+
extendRootQueueWithMock(root, dynamicParent);
1083+
1084+
policy.editSchedule();
1085+
assertFalse(
1086+
"root.dynamicLegacyParent" + " should not be a LeafQueue candidate",
1087+
policy.getLeafQueueNames().contains( "root.dynamicParent"));
1088+
}
1089+
1090+
@Test
1091+
public void testLeafQueueNameExtractionWithLegacyAQC() throws Exception {
1092+
ProportionalCapacityPreemptionPolicy policy = buildPolicy(Q_DATA_FOR_IGNORE);
1093+
ParentQueue root = (ParentQueue) mCS.getRootQueue();
1094+
1095+
root.addDynamicParentQueue("childlessLegacy");
1096+
ParentQueue dynamicParent = setupDynamicParentQueue("root.dynamicLegacyParent", false);
1097+
extendRootQueueWithMock(root, dynamicParent);
1098+
1099+
policy.editSchedule();
1100+
assertFalse("root.dynamicLegacyParent" + " should not be a LeafQueue candidate",
1101+
policy.getLeafQueueNames().contains( "root.dynamicLegacyParent"));
1102+
}
1103+
1104+
private ParentQueue setupDynamicParentQueue(String queuePath, boolean isFlexible) {
1105+
ParentQueue dynamicParent = mockParentQueue(null, 0, new LinkedList<>());
1106+
mockQueueFields(dynamicParent, queuePath);
1107+
1108+
if (isFlexible) {
1109+
when(dynamicParent.isEligibleForAutoQueueCreation()).thenReturn(true);
1110+
} else {
1111+
when(dynamicParent.isEligibleForLegacyAutoQueueCreation()).thenReturn(true);
1112+
}
1113+
1114+
return dynamicParent;
1115+
}
1116+
1117+
private void extendRootQueueWithMock(ParentQueue root, ParentQueue mockQueue) {
10811118
List<CSQueue> queues = root.getChildQueues();
10821119
ArrayList<CSQueue> extendedQueues = new ArrayList<>();
1083-
LinkedList<ParentQueue> pqs = new LinkedList<>();
1084-
ParentQueue dynamicParent = mockParentQueue(
1085-
null, 0, pqs);
1086-
when(dynamicParent.getQueuePath()).thenReturn("root.dynamicParent");
1087-
when(dynamicParent.getQueueCapacities()).thenReturn(
1088-
new QueueCapacities(false));
1089-
QueueResourceQuotas dynamicParentQr = new QueueResourceQuotas();
1090-
dynamicParentQr.setEffectiveMaxResource(Resource.newInstance(1, 1));
1091-
dynamicParentQr.setEffectiveMinResource(Resources.createResource(1));
1092-
dynamicParentQr.setEffectiveMaxResource(RMNodeLabelsManager.NO_LABEL,
1093-
Resource.newInstance(1, 1));
1094-
dynamicParentQr.setEffectiveMinResource(RMNodeLabelsManager.NO_LABEL,
1095-
Resources.createResource(1));
1096-
when(dynamicParent.getQueueResourceQuotas()).thenReturn(dynamicParentQr);
1097-
when(dynamicParent.getEffectiveCapacity(RMNodeLabelsManager.NO_LABEL))
1098-
.thenReturn(Resources.createResource(1));
1099-
when(dynamicParent.getEffectiveMaxCapacity(RMNodeLabelsManager.NO_LABEL))
1100-
.thenReturn(Resource.newInstance(1, 1));
1101-
ResourceUsage resUsage = new ResourceUsage();
1102-
resUsage.setUsed(Resources.createResource(1024));
1103-
resUsage.setReserved(Resources.createResource(1024));
1104-
when(dynamicParent.getQueueResourceUsage()).thenReturn(resUsage);
1105-
when(dynamicParent.isEligibleForAutoQueueCreation()).thenReturn(true);
1106-
extendedQueues.add(dynamicParent);
1120+
extendedQueues.add(mockQueue);
11071121
extendedQueues.addAll(queues);
11081122
when(root.getChildQueues()).thenReturn(extendedQueues);
1123+
}
11091124

1110-
policy.editSchedule();
1125+
private void mockQueueFields(ParentQueue queue, String queuePath) {
1126+
when(queue.getQueuePath()).thenReturn(queuePath);
1127+
when(queue.getQueueCapacities()).thenReturn(new QueueCapacities(false));
1128+
1129+
QueueResourceQuotas qrq = new QueueResourceQuotas();
1130+
qrq.setEffectiveMaxResource(Resource.newInstance(1, 1));
1131+
qrq.setEffectiveMinResource(Resources.createResource(1));
1132+
qrq.setEffectiveMaxResource(RMNodeLabelsManager.NO_LABEL, Resource.newInstance(1, 1));
1133+
qrq.setEffectiveMinResource(RMNodeLabelsManager.NO_LABEL, Resources.createResource(1));
11111134

1112-
assertFalse("dynamicParent should not be a LeafQueue " +
1113-
"candidate", policy.getLeafQueueNames().contains("root.dynamicParent"));
1135+
when(queue.getQueueResourceQuotas()).thenReturn(qrq);
1136+
when(queue.getEffectiveCapacity(RMNodeLabelsManager.NO_LABEL))
1137+
.thenReturn(Resources.createResource(1));
1138+
when(queue.getEffectiveMaxCapacity(RMNodeLabelsManager.NO_LABEL))
1139+
.thenReturn(Resource.newInstance(1, 1));
1140+
1141+
ResourceUsage usage = new ResourceUsage();
1142+
usage.setUsed(Resources.createResource(1024));
1143+
usage.setReserved(Resources.createResource(1024));
1144+
when(queue.getQueueResourceUsage()).thenReturn(usage);
11141145
}
11151146

11161147
static class IsPreemptionRequestFor
@@ -1359,6 +1390,10 @@ LeafQueue mockLeafQueue(ParentQueue p, Resource tot, int i, Resource[] abs,
13591390
Resource[] used, Resource[] pending, Resource[] reserved, int[] apps,
13601391
Resource[] gran) {
13611392
LeafQueue lq = mock(LeafQueue.class);
1393+
1394+
String queuePath = p.getQueuePath() + ".queue" + (char)('A' + i - 1);
1395+
when(mCS.getQueue(queuePath)).thenReturn(lq);
1396+
13621397
ResourceCalculator rc = mCS.getResourceCalculator();
13631398
List<ApplicationAttemptId> appAttemptIdList =
13641399
new ArrayList<ApplicationAttemptId>();

0 commit comments

Comments
 (0)