Uploaded image for project: 'Confluence Server'
  1. Confluence Server
  2. CONFSERVER-45910

Confluence throws "Comparison method violates its general contract!" when trying to sort multiple long-running tasks

    XMLWordPrintable

    Details

    • Symptom Severity:
      Severity 2 - Major
    • Support reference count:
      4
    • Sprint:
      grasshopper, honeybee
    • Occurrence Factor:
      50%
    • QA Demo Status:
      Not Done
    • QA Kickoff Status:
      Not Done

      Description

      Code to reproduce

      Use a unit test below to reproduce this by running the comparator:

              Collections.sort(fullList, (o1, o2) -> {
                  // Sorting by name is not as good as sorting by start time (unavailable) but better than anything
                  // else we can think of this iteration. Changing this order later is unable to raise any blockers
                  // in production.
                  Message o1Name = o1.getName();
                  if (o1Name == null || o1Name.getKey() == null)
                      return 1;  // push o1 to bottom
      
                  Message o2Name = o2.getName();
                  if (o2Name == null || o2Name.getKey() == null)
                      return -1;  // push o2 to bottom
      
                  return o1Name.getKey().compareTo(o2Name.getKey());
              });
      

      Which is copied from Confluence code.

      Confluence will throw the following error message:

      Comparison method violates its general contract!
      

      That basically means that the comparator is not written correctly.

      Environments

      Attached a test class to reproduce the error: ContractViolationTest.java

      • on Windows 10,
      • java version "1.8.0_111" Java(TM) SE Runtime Environment (build 1.8.0_111-b14), Java HotSpot(TM) Client VM (build 25.111-b14, mixed mode)
      • Important: it only breaks if collection size is >= 32

      A possible fix in Confluence

      Switching the +1 and -1 return values in the comparator's two if blocks fixes the problem.
      Note that this change makes "null key" cases appear before "not-null key" cases in the sorted list. It does not affect the original order of objects where the key is not-null.

      Workaround

      Adding this JVM system property fixes the issue:
      -Djava.util.Arrays.useLegacyMergeSort=true

      References

        Attachments

          Issue Links

            Activity

              People

              • Votes:
                6 Vote for this issue
                Watchers:
                8 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved:
                  Last commented:
                  1 year, 51 weeks, 4 days ago