Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 371354 - Progress view throws IAE "Comparison method violates its general contract!"
Summary: Progress view throws IAE "Comparison method violates its general contract!"
Status: VERIFIED FIXED
Alias: None
Product: Platform
Classification: Eclipse Project
Component: IDE (show other bugs)
Version: 3.8   Edit
Hardware: PC Windows 7
: P3 major (vote)
Target Milestone: 4.3 M7   Edit
Assignee: Markus Keller CLA
QA Contact:
URL:
Whiteboard:
Keywords:
: 525287 (view as bug list)
Depends on:
Blocks:
 
Reported: 2012-02-13 05:39 EST by Markus Keller CLA
Modified: 2020-04-20 07:37 EDT (History)
8 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Markus Keller CLA 2012-02-13 05:39:48 EST
eclipse.buildId=I20120207-0800
java.version=1.7.0_02
java.vendor=Oracle Corporation

I started my workspace with a new build and while it was still compiling, I pulled all my Git repositories. Progress view threw this IAE:

Error
Mon Feb 13 11:21:34 CET 2012
An internal error has occurred.

java.lang.IllegalArgumentException: Comparison method violates its general contract!
	at java.util.TimSort.mergeLo(TimSort.java:747)
	at java.util.TimSort.mergeAt(TimSort.java:483)
	at java.util.TimSort.mergeForceCollapse(TimSort.java:426)
	at java.util.TimSort.sort(TimSort.java:223)
	at java.util.TimSort.sort(TimSort.java:173)
	at java.util.Arrays.sort(Arrays.java:659)
	at org.eclipse.jface.viewers.ViewerComparator.sort(ViewerComparator.java:187)
	at org.eclipse.jface.viewers.StructuredViewer.getSortedChildren(StructuredViewer.java:1071)
	at org.eclipse.ui.internal.progress.ProgressCanvasViewer.internalRefresh(ProgressCanvasViewer.java:142)
	at org.eclipse.jface.viewers.StructuredViewer.internalRefresh(StructuredViewer.java:1299)
	at org.eclipse.jface.viewers.StructuredViewer$8.run(StructuredViewer.java:1535)
	at org.eclipse.jface.viewers.StructuredViewer.preservingSelection(StructuredViewer.java:1443)
	at org.eclipse.jface.viewers.StructuredViewer.preservingSelection(StructuredViewer.java:1404)
	at org.eclipse.jface.viewers.StructuredViewer.refresh(StructuredViewer.java:1533)
	at org.eclipse.ui.internal.progress.ProgressViewerContentProvider.refresh(ProgressViewerContentProvider.java:151)
	at org.eclipse.ui.internal.progress.ProgressViewUpdater$1.runInUIThread(ProgressViewUpdater.java:282)
	at org.eclipse.ui.progress.UIJob$1.run(UIJob.java:95)
	at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:35)
	at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:135)
	at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:4140)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3757)
	at org.eclipse.ui.internal.Workbench.runEventLoop(Workbench.java:2701)
	at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:2665)
	at org.eclipse.ui.internal.Workbench.access$4(Workbench.java:2499)
	at org.eclipse.ui.internal.Workbench$7.run(Workbench.java:679)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332)
	at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:668)
	at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:149)
	at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:124)
	at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:196)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:352)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:179)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:601)
	at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:624)
	at org.eclipse.equinox.launcher.Main.basicRun(Main.java:579)
	at org.eclipse.equinox.launcher.Main.run(Main.java:1433)
	at org.eclipse.equinox.launcher.Main.main(Main.java:1409)

Error
Mon Feb 13 11:21:34 CET 2012
Workaround for comparator violation:
	- set system property java.util.Arrays.useLegacyMergeSort=true
	- use a 1.6 JRE 
message: Comparison method violates its general contract!
this: org.eclipse.ui.internal.progress.ProgressManagerUtil$1
comparator: null
array:
	Pulling from Multiple...sitories: (0%)
	Re-indexing repository...e.jdt.core
	Re-indexing repository...e.jdt.core
	Re-indexing repository...e.jdt.core
	Re-indexing repository...e.jdt.core
	Re-indexing repositor....jdt.debug
	Re-indexing repository...e.platform
	Re-indexing repository...e.platform
	Re-indexing repositor....jdt.debug
	Re-indexing repositor....jdt.debug
	Re-indexing repositor....jdt.debug
	Re-indexing repository eclipse.jdt.ui
	Re-indexing repository eclipse.jdt.ui
	Re-indexing repository eclipse.jdt.ui
	Re-indexing repository eclipse.jdt.ui
	Re-indexing repository...e.platform
	Re-indexing repository...e.platform
	Re-indexing repository...e.platform
	Re-indexing repository...e.platform
	Re-indexing reposito...rm.common
	Re-indexing reposito...rm.common
	Re-indexing reposito...rm.common
	Re-indexing reposito...rm.common
	Re-indexing repositor...orm.debug
	Re-indexing repository...e.jdt.core
	Re-indexing repositor....jdt.debug
	Re-indexing repositor....jdt.debug
	Re-indexing repository eclipse.jdt.ui
	Re-indexing repository...e.platform
	Re-indexing repository...e.platform
	Re-indexing repository...e.platform
	Re-indexing repository...e.platform
	Re-indexing repository...e.platform
	Re-indexing repository...e.platform
	Re-indexing reposito...rm.common
	Re-indexing reposito...rm.common
	Re-indexing reposito...rm.common
	Re-indexing reposito...rm.common
	Re-indexing repositor...orm.debug
	Re-indexing repositor...orm.debug
	Re-indexing repositor...orm.releng
	Re-indexing repositor...orm.releng
	Re-indexing repositor...orm.releng
	Re-indexing repositor...orm.releng
	Re-indexing repositor...leng.maps
	Re-indexing repository...rm.runtime
	Re-indexing repository...rm.runtime
	Re-indexing repositor...latform.ua
	Re-indexing repositor...orm.releng
	Re-indexing repository...atform.swt
	Re-indexing reposito...rm.common
	Re-indexing reposito...rm.common
	Re-indexing repositor...orm.releng
	Re-indexing repositor...orm.releng
	Re-indexing repositor...orm.releng
	Re-indexing repositor...orm.releng
	Re-indexing repositor...orm.releng
	Re-indexing repositor...orm.releng
	Re-indexing repositor...orm.releng
	Re-indexing repositor...orm.releng
	Re-indexing repositor...orm.releng
	Re-indexing repositor...orm.releng
	Re-indexing repositor...orm.releng
	Re-indexing repositor...orm.releng
	Re-indexing repositor...orm.releng
	Re-indexing repositor...orm.releng
	Re-indexing repositor...leng.maps
	Re-indexing repositor...leng.maps
	Re-indexing repositor...leng.maps
	Re-indexing repositor...leng.maps
	Re-indexing repositor...leng.maps
	Re-indexing repositor...leng.maps
	Re-indexing repositor...leng.maps
	Re-indexing repository...e.jdt.core
	Re-indexing repository...e.jdt.core
	Re-indexing repository...e.jdt.core
	Re-indexing repository...e.jdt.core
	Re-indexing repository eclipse.jdt.ui
	Re-indexing repository...e.platform
	Re-indexing repository...e.platform
	Re-indexing repository...e.platform
	Re-indexing reposito...rm.common
	Re-indexing reposito...rm.common
	Re-indexing repositor...orm.debug
	Re-indexing repositor...orm.releng
	Re-indexing repositor...orm.releng
	Re-indexing repositor...leng.maps
	Re-indexing repository...rm.runtime
	Re-indexing repository...rm.runtime
	Re-indexing repository...rm.runtime
	Re-indexing repository...rm.runtime
	Re-indexing repository...rm.runtime
	Re-indexing repository...rm.runtime
	Re-indexing repository...rm.runtime
	Re-indexing repository...rm.runtime
	Re-indexing repository...rm.runtime
	Re-indexing repository...rm.runtime
	Re-indexing repository...rm.runtime
	Re-indexing repository...rm.runtime
	Re-indexing repository...rm.runtime
	Re-indexing repository...rm.runtime
	Re-indexing repository...rm.runtime
	Re-indexing repository...atform.swt
	Re-indexing repository...atform.swt
	Re-indexing repository...atform.swt
	Re-indexing repository...atform.swt
	Re-indexing repository...atform.swt
	Re-indexing repositor...latform.ua
	Re-indexing repositor...latform.ua
	Re-indexing repositor...latform.ua
	Re-indexing repositor...framework
	Re-indexing repositor...framework
	Re-indexing repositor...framework
	Re-indexing repository...rm.runtime
	Re-indexing repository...rm.runtime
	Re-indexing repository...rm.runtime
	Re-indexing repository...rm.runtime
	Re-indexing repository...rm.runtime
	Re-indexing repository...rm.runtime
	Re-indexing repository...atform.swt
	Re-indexing repository...atform.swt
	Re-indexing repository...atform.swt
	Re-indexing repositor...framework
	Re-indexing repositor...framework
	Re-indexing repositor...framework
	Re-indexing repositor...framework
	Re-indexing repositor...framework
	Re-indexing repository...e.jdt.core
	Re-indexing repository...e.jdt.core
	Re-indexing repositor....jdt.debug
	Re-indexing repositor....jdt.debug
	Re-indexing repository eclipse.jdt.ui
	Re-indexing repository...e.platform
	Re-indexing reposito...rm.common
	Re-indexing repository eclipse.jdt.ui
	Re-indexing repository eclipse.jdt.ui
	Re-indexing repository...e.platform
	Re-indexing repository...e.platform
	Re-indexing repository...e.platform
	Re-indexing repository...e.platform
	Re-indexing repository...e.platform
	Re-indexing reposito...rm.common
	Re-indexing reposito...rm.common
	Re-indexing reposito...rm.common
	Re-indexing reposito...rm.common
	Re-indexing reposito...rm.common
	Re-indexing repositor...orm.releng
	Re-indexing repositor...orm.releng
	Re-indexing repositor...orm.releng
	Re-indexing repositor...orm.releng
	Re-indexing repositor...orm.releng
	Re-indexing repositor...orm.releng
	Re-indexing repositor...leng.maps
	Re-indexing repositor...orm.releng
	Re-indexing repositor...leng.maps
	Re-indexing repository...rm.runtime
	Re-indexing repository...rm.runtime
	Re-indexing repository...rm.runtime
	Re-indexing repository...rm.runtime
	Re-indexing repository...atform.swt
	Re-indexing repository...atform.swt
	Re-indexing repositor...latform.ua
	Re-indexing repositor...framework
Comment 1 Markus Keller CLA 2012-02-29 06:16:48 EST
There's an obvious case where org.eclipse.ui.internal.progress.JobTreeElement#compareTo(Object) and its overriding methods violate the reflexivity requirement stated in the Javadoc ("The implementor must ensure sgn(x.compareTo(y)) == -sgn(y.compareTo(x)) for all x and y."):

JobInfo#compareJobs(JobInfo) must return 0 if
    job.getPriority()==job2.getPriority()

If that doesn't solve the problems, then the issue is probably jobs whose properties change while the comparison is ongoing. I don't have a good solution for that. Maybe we just have to catch the IAE and try again a few times before finally giving up.

BTW: GroupInfo#compareTo(Object) uses an unchecked cast. This method should simply be removed.
Comment 2 Markus Keller CLA 2012-02-29 06:20:24 EST
... and a second problem in JobInfo#compareTo(Object):

        //If the receiver is cancelled then it is lowest priority
        if (isCanceled() && !element.isCanceled()) {
			return 1;
	}

This needs a reverse branch:

        } else if (!isCanceled() && element.isCanceled()) {
			return -1;
	}

Then extract local variables for isCanceled() and element.isCanceled().
Comment 3 Markus Keller CLA 2012-03-01 13:08:48 EST
I'll take care of this.
Comment 4 Markus Keller CLA 2012-03-01 14:14:53 EST
First observation in comment 1 was wrong. I only saw the '>' check but bissed the existing '==' a few lines up.

But GroupInfo#compareTo(Object) is really unnecessary and there was a real issue with comparing cancelled jobs.

Fixed these problems with:
http://git.eclipse.org/c/platform/eclipse.platform.ui.git/commit/?id=0e9301014e4df28951083623d6960ca5e83c8848
http://git.eclipse.org/c/platform/eclipse.platform.ui.git/commit/?id=32c4e10c0b6e8cadba7d555e7aac21927d29e457


Closing this bug for now. If this fix doesn't help reliably, then we should catch the IAE in ProgressManagerUtil#getProgressViewerComparator() and retry it once or twice.
Comment 5 Paul Webster CLA 2012-03-01 14:17:25 EST
Thank you Markus.

PW
Comment 6 Markus Keller CLA 2012-03-13 07:07:06 EDT
Haven't seen this any more. Declaring success until proven wrong.
Comment 7 Dani Megert CLA 2013-04-17 05:18:30 EDT
(In reply to comment #6)
> Haven't seen this any more. Declaring success until proven wrong.

Sorry :-(

!ENTRY org.eclipse.jface 4 0 2013-04-17 11:12:07.847
!MESSAGE Workaround for comparator violation:
	- set system property java.util.Arrays.useLegacyMergeSort=true
	- use a 1.6 JRE 
message: Comparison method violates its general contract!
this: org.eclipse.ui.internal.progress.ProgressManagerUtil$1
comparator: null
array:
	LabelEventJob
	Re-indexing repository...e.jdt.core
	Re-indexing repository...e.jdt.core
	Re-indexing repository...e.jdt.core
	Re-indexing repository...e.jdt.core
	Re-indexing repository...e.jdt.core
	Re-indexing repository...e.jdt.core
	Re-indexing repository...e.jdt.core
	Re-indexing repository...e.jdt.core
	Re-indexing repository eclipse.jdt.ui
	Re-indexing repository eclipse.jdt.ui
	Re-indexing repository eclipse.jdt.ui
	Re-indexing repository eclipse.jdt.ui
	Re-indexing repository eclipse.jdt.ui
	Re-indexing repository eclipse.jdt.ui
	Re-indexing repository eclipse.jdt.ui
	Re-indexing repository eclipse.jdt.ui
	Re-indexing repository eclipse.jdt.ui
	Re-indexing repository eclipse.jdt.ui
	Re-indexing repository eclipse.jdt.ui
	Re-indexing repository eclipse.jdt.ui
	Re-indexing repository eclipse.jdt.ui
	Re-indexing repository eclipse.jdt.ui
	Re-indexing repository eclipse.jdt.ui
	Re-indexing repository eclipse.jdt.ui
	Re-indexing repository eclipse.jdt.ui
	Re-indexing repository eclipse.jdt.ui
	Re-indexing repository eclipse.jdt.ui
	Re-indexing repository eclipse.jdt.ui
	Re-indexing repository eclipse.jdt.ui
	Re-indexing repository eclipse.jdt.ui
	Re-indexing repository eclipse.jdt.ui
	Re-indexing repository eclipse.jdt.ui
	Re-indexing repository eclipse.jdt.ui
	Re-indexing repository eclipse.jdt.ui
	Re-indexing repository...pse.pde.ui
	Re-indexing repository...pse.pde.ui
	Re-indexing repository...pse.pde.ui
	Re-indexing repository...pse.pde.ui
	Re-indexing repository...pse.pde.ui
	Re-indexing repository...pse.pde.ui
	Re-indexing repository...pse.pde.ui
	Re-indexing repository...platform.ui
	Re-indexing repository...platform.ui
	Re-indexing repository...platform.ui
	Re-indexing repository...platform.ui
	Re-indexing repository...platform.ui
	Re-indexing repository...platform.ui
	Re-indexing repository...platform.ui
	Re-indexing repository...platform.ui
	Re-indexing repository...platform.ui
	Re-indexing repository...platform.ui
	Re-indexing repository...platform.ui
	Re-indexing repository...platform.ui
	Re-indexing repository jgit
	Re-indexing repository jgit
	Re-indexing repository jgit
	Re-indexing repository jgit
	Re-indexing repository jgit
	Re-indexing repository jgit
	Re-indexing repository jgit
Comment 8 Markus Keller CLA 2013-04-17 15:53:24 EDT
This ordering is inherently unstable, since it relies on modifiable properties of the elements: E.g. the default implementation in JobTreeElement compares getDisplayString(), many of whose implementations use getPercentDone().

Unfortunately, there's no good solution, since Java 7's new TimSort has broken this use case, and the comment on Arrays.LegacyMergeSort.userRequested doesn't make it look like the secret "java.util.Arrays.useLegacyMergeSort" is a viable long-term solution.

Options:

1) just repeat the sorting a few times until it doesn't fail
=> we haven't heard of this bug often, so this is probably the best solution
> catch the IAE in ProgressManagerUtil#getProgressViewerComparator()
=> override ViewerComparator#sort(..) and do it there

2) fix the compare methods
=> impossible, since we *want* to have e.g. running jobs on top and cancelled jobs at the end. We would have to stop the world or take a snapshot of all properties that could influence the sort order.

3) use a custom sort implementation that doesn't fail violently for "illegal" comparators
=> you know you're really screwed when you have to consider this...
Comment 9 Dani Megert CLA 2013-04-18 08:17:07 EDT
Let's got with 1).
Comment 11 Markus Keller CLA 2013-05-17 07:08:36 EDT
Verified in I20130516-2200 by code inspection.
Comment 12 Andrey Loskutov CLA 2017-09-27 16:30:37 EDT
*** Bug 525287 has been marked as a duplicate of this bug. ***