YARN-11745: Fix TimSort contract violation in PriorityQueueComparator Class #7309
+57
−3
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Description of PR
This PR addresses the TimSort contract violation issue in the
PriorityQueueComparator
class, which was identified when sorting queue with resource (0, 0) and queue resource(any number, any number). The comparator previously failed to maintain transitivity of TimSort, leading tojava.lang.IllegalArgumentException: Comparison method violates its general contract!
during sorting.Root Cause
The issue occurred due to inconsistent comparison logic that violated the transitivity rules required by TimSort.
Specifically, at the following code lines the AND condition that only compare the resources if both queues' resources are not none. However, when one of the queue resource is
none or (0, 0)
and the other queue resource isnot none
it skips this condition and go to compare based on theabsoluteCapacity
and when both of the queues'absoluteCapacity
are the same, it leads to both queues equal each other even though their resources are different.For more detail example of how this behaviour break the TimSort algorithm please see this attachment. ExampleZeroQueueResourceProblem
Solution
Instead of checking if both queues' resource are not none. We should only check if one of the queue's resource is not none. This way to avoid skipping the queue resource comparison when we have one queue resource is not none and the other one is none. Specifically, change from AND condition to OR condition at the following codes:
if (!minEffRes1.equals(Resources.none()) || !minEffRes2.equals( Resources.none())) { return minEffRes2.compareTo(minEffRes1); }
Testing
Added a unit test
testPriorityQueueComparatorClassDoesNotViolateTimSortContract
to verify that sorting no longer throwsjava.lang.IllegalArgumentException: Comparison method violates its general contract!
.The test includes setting resource instance (0, 0) and resource(any number, any number) then shuffle the repeated queues that were created and then sort in using the
PriorityQueueComparator
class. It also mock the necessary elements, for example,priority
label
,absoluteUsedCapacity
,usedCapacity
andabsoluteCapacity
. These elements can be of any number.Impact
TimSort
violation, ensuring stable and predictable sorting forPriorityQueueComparator
class.PriorityQueueComparator
sorting algorithm may change in some behaviour when the queue resource is (0, 0).For code changes:
LICENSE
,LICENSE-binary
,NOTICE-binary
files?