Skip to content

Commit 9bf5e38

Browse files
YARN-11745: Fix TimSort contract violation in PriorityQueueComparator Class (#7278)
1 parent 06d36f5 commit 9bf5e38

File tree

2 files changed

+57
-3
lines changed

2 files changed

+57
-3
lines changed

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -91,12 +91,12 @@ public static int compare(double relativeAssigned1, double relativeAssigned2,
9191
/**
9292
* Comparator that both looks at priority and utilization
9393
*/
94-
final private class PriorityQueueComparator
94+
final public class PriorityQueueComparator
9595
implements Comparator<PriorityQueueResourcesForSorting> {
9696

9797
final private String partition;
9898

99-
private PriorityQueueComparator(String partition) {
99+
public PriorityQueueComparator(String partition) {
100100
this.partition = partition;
101101
}
102102

@@ -164,7 +164,7 @@ private int compare(PriorityQueueResourcesForSorting q1Sort,
164164
q1Sort.configuredMinResource;
165165
Resource minEffRes2 =
166166
q2Sort.configuredMinResource;
167-
if (!minEffRes1.equals(Resources.none()) && !minEffRes2.equals(
167+
if (!minEffRes1.equals(Resources.none()) || !minEffRes2.equals(
168168
Resources.none())) {
169169
return minEffRes2.compareTo(minEffRes1);
170170
}

hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/policy/TestPriorityUtilizationQueueOrderingPolicy.java

+54
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
import java.util.Iterator;
3434
import java.util.List;
3535
import java.util.Set;
36+
import java.util.Collections;
37+
3638
import java.util.concurrent.ThreadLocalRandom;
3739

3840
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
@@ -309,6 +311,58 @@ public void testComparatorDoesNotValidateGeneralContract() {
309311
assertDoesNotThrow(() -> policy.getAssignmentIterator(partition));
310312
}
311313

314+
@Test
315+
public void testComparatorClassDoesNotViolateTimSortContract() {
316+
String partition = "testPartition";
317+
318+
List<PriorityUtilizationQueueOrderingPolicy.
319+
PriorityQueueResourcesForSorting> queues = new ArrayList<>();
320+
for (int i = 0; i < 1000; i++) { // 1000 queues to have enough queues so the exception occur
321+
queues.add(createMockPriorityQueueResourcesForSorting(partition));
322+
}
323+
324+
Collections.shuffle(queues);
325+
// java.lang.IllegalArgumentException: Comparison method violates its general contract!
326+
assertDoesNotThrow(() -> queues.sort(new PriorityUtilizationQueueOrderingPolicy(true)
327+
.new PriorityQueueComparator(partition)));
328+
329+
}
330+
331+
private PriorityUtilizationQueueOrderingPolicy.
332+
PriorityQueueResourcesForSorting createMockPriorityQueueResourcesForSorting(
333+
String partition) {
334+
QueueResourceQuotas resourceQuotas = randomResourceQuotas(partition);
335+
336+
boolean isZeroResource = ThreadLocalRandom.current().nextBoolean();
337+
if (isZeroResource) {
338+
resourceQuotas.setConfiguredMinResource(partition, Resource.newInstance(0, 0));
339+
}
340+
341+
QueueCapacities mockQueueCapacities = mock(QueueCapacities.class);
342+
when(mockQueueCapacities.getAbsoluteUsedCapacity(partition))
343+
.thenReturn(4.2f); // could be any specific number, so that there are equal values
344+
when(mockQueueCapacities.getUsedCapacity(partition))
345+
.thenReturn(1.0f); // could be any specific number, so that there are equal values
346+
when(mockQueueCapacities.getAbsoluteCapacity(partition))
347+
.thenReturn(6.2f); // could be any specific number, so that there are equal values
348+
349+
CSQueue mockQueue = mock(CSQueue.class);
350+
when(mockQueue.getQueueCapacities())
351+
.thenReturn(mockQueueCapacities);
352+
when(mockQueue.getPriority())
353+
.thenReturn(Priority.newInstance(7)); // could be any specific number,
354+
// so that there are equal values
355+
when(mockQueue.getAccessibleNodeLabels())
356+
.thenReturn(Collections.singleton(partition));
357+
when(mockQueue.getQueueResourceQuotas())
358+
.thenReturn(resourceQuotas);
359+
360+
return new PriorityUtilizationQueueOrderingPolicy.PriorityQueueResourcesForSorting(
361+
mockQueue, partition
362+
);
363+
364+
}
365+
312366
private QueueCapacities randomQueueCapacities(String partition) {
313367
QueueCapacities qc = new QueueCapacities(false);
314368
qc.setAbsoluteCapacity(partition, (float) randFloat(0.0d, 100.0d));

0 commit comments

Comments
 (0)