| Summary: | Split packages are not refreshed properly | ||
|---|---|---|---|
| Product: | [Eclipse Project] Platform | Reporter: | Steffen Pingel <steffen.pingel> |
| Component: | Runtime | Assignee: | Thomas Watson <tjwatson> |
| Status: | RESOLVED FIXED | QA Contact: | |
| Severity: | normal | ||
| Priority: | P3 | CC: | daniel_megert, john.arthorne, krzysztof.daniel, pascal, pwebster, remy.suen, shawn.minto, thebravoman, tjwatson |
| Version: | 4.3 | Flags: | krzysztof.daniel:
review?
(tjwatson) |
| Target Milestone: | 4.3 M7 | ||
| Hardware: | PC | ||
| OS: | Linux | ||
| Whiteboard: | |||
| Bug Depends on: | |||
| Bug Blocks: | 297912 | ||
| Attachments: | |||
Created attachment 154437 [details]
log file running on Eclipse 3.6M4
(In reply to comment #1) > Created an attachment (id=154437) [details] > log file running on Eclipse 3.6M4 Could you give me details on the steps I could use to reproduce this (what to download, what mylyn tests to check out etc.)? The java.lang.LinkageError is pretty concerning and something I would like to get to the bottom of. I can reproduce the LinkageErrors with these steps on Linux/Gtk 32-bit: 1. Extract Eclipse SDK 3.6M4 2. Unzip http://mylyn.eclipse.org/tmp/mylyn-I20091214-1100-e3x.zip to dropins/ 3. Run ./eclipse -data ws -console Also saw this exception while doing "bundle 255" in the equinox console (plugins may not have been initialized completely when I ran the command, couldn't reproduce it afterwards). java.lang.NullPointerException at org.eclipse.osgi.internal.loader.BundleLoaderProxy.addRequirers(BundleLoaderProxy.java:133) at org.eclipse.osgi.internal.loader.BundleLoaderProxy.addRequirers(BundleLoaderProxy.java:148) at org.eclipse.osgi.internal.loader.BundleLoaderProxy.getRequiringBundles(BundleLoaderProxy.java:120) at org.eclipse.osgi.framework.internal.core.FrameworkCommandProvider._bundle(FrameworkCommandProvider.java:942) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.eclipse.osgi.framework.internal.core.FrameworkCommandInterpreter.execute(FrameworkCommandInterpreter.java:155) at org.eclipse.osgi.framework.internal.core.FrameworkConsole.docommand(FrameworkConsole.java:157) at org.eclipse.osgi.framework.internal.core.FrameworkConsole.runConsole(FrameworkConsole.java:142) at org.eclipse.osgi.framework.internal.core.FrameworkConsole.run(FrameworkConsole.java:106) at java.lang.Thread.run(Thread.java:619) *** Bug 292879 has been marked as a duplicate of this bug. *** I have not been able to reproduce the error (on Mac) but I did run into another error in the dropins reconciler. The mylyn tests contain a bundle javax.servlet (version 2.4). There already exists a javax.servlet (version 2.5) in the platform. When the dropins support installs (and refreshes) the new javax.servlet (version 2.4) bundle this forces the other version 2.5 of javax.servlet from the core platform to be refreshed. This starts a whole chain reaction of refreshing of all the bundles that transitively depend on the existing javax.servlet version 2.5. In the end almost the complete platform is refreshed. My theory is that we end up with a newly refreshed org.eclipse.core.runtime and org.eclipse.equinox.registry bundle (with new class loaders) and somehow the old class loaders are still around with the old instances of the Plugin class. And this causes us to have this strange LinkageError. On a restart we should not see this error because we no longer need to install the bundles from dropins and refresh them. But since tests are always run on a fresh configuration we never can run from a cache and we always are reconciling the dropins. Is there any way you can remove the javax.servlet 2.4 bundle from your dropins? (In reply to comment #5) > Is there any way you can remove the javax.servlet 2.4 bundle from your dropins? I manually removed the javax.servlet version 2.4 from the test/plugins/ folder and from the feature.xml files for org.eclipse.mylyn.xplanner_feature and org.eclipse.mylyn.jira_feature. This seemed to work around the reconciler issue I was seeing and I was able to launch eclipse from a clean install without error. Thanks for the great explanation. I'll try removing it. I don't think we need to include the javax.servlet plug-in since it's part of platform but have been shipping it in case Mylyn is installed on platforms that don't have it, e.g. RCP application. *** Bug 273466 has been marked as a duplicate of this bug. *** Created attachment 216027 [details]
Screenshot of F17 startup
Bad News: Eclipse in Fedora is dropins based. All users will see this error if they open a Task List view on first Eclipse launch.
I'm really surprised by such a move. Eclipse has been shipping in its regular app for years on Fedora and the recent change to dropins will result in more trouble than anything. Sure one company is shipping all of its products like that but it is the worst model ever and I know of a gadzillion way to break their install leaving them without a clue on how to recover. Honestly you should really consider moving back to the normal shape. (In reply to comment #10) > I'm really surprised by such a move. Eclipse has been shipping in its regular > app for years on Fedora and the recent change to dropins will result in more > trouble than anything. Sure one company is shipping all of its products like > that but it is the worst model ever and I know of a gadzillion way to break > their install leaving them without a clue on how to recover. > Honestly you should really consider moving back to the normal shape. I wish I could. That was the first thing that I wanted to do in eclipse build, and you are aware of efforts I have taken to get things working. P2 director in its current shape is a no-go for Fedora, and logs indicate that it never was (I'll find some witness to verify that). Eclipse since 3.4 version seems to be shipped with dropins. Since I can't get P2 working with RPM I'm focusing on removing bugs from reconciler to make the installation more predictable/less error prone, but I'm open for any investigations that could make RPM and P2 working together. Krzysztof, what is the exact error stacktrace you are getting when the Task List is loaded? The stacktrace in the view is really long. The original user log was uploaded here: https://bugzilla.redhat.com/attachment.cgi?id=585995 I got hit by this again. Thomas, do you have any idea where to look for leaked classloader that holds old definition during refresh? The error is: Caused by: java.lang.LinkageError: loader constraint violation in interface itable initialization: when resolving method "org.eclipse.core.internal.plugins.PluginDescriptor.getPlugin()Lorg/eclipse/core/runtime/Plugin;" the class loader (instance of org/eclipse/osgi/internal/baseadaptor/DefaultClassLoader) of the current class, org/eclipse/core/internal/plugins/PluginDescriptor, and the class loader (instance of org/eclipse/osgi/internal/baseadaptor/DefaultClassLoader) for interface org/eclipse/core/runtime/IPluginDescriptor have different Class objects for the type or.getPlugin()Lorg/eclipse/core/runtime/Plugin; used in the signature at org.eclipse.core.internal.plugins.PluginRegistry.getPluginDescriptor(PluginRegistry.java:117) at org.eclipse.core.internal.plugins.PluginRegistry.getPluginDescriptor(PluginRegistry.java:104) at org.eclipse.core.runtime.Platform.getPlugin(Platform.java:732) at org.eclipse.core.internal.preferences.legacy.InitLegacyPreferences.init(InitLegacyPreferences.java:43) The short version of the error is: org/eclipse/core/runtime/Plugin is loaded independently twice by org.eclipse.core.internal.plugins.PluginDescriptor and org/eclipse/core/runtime/IPluginDescriptor The PluginDescriptor comes from org.eclipse.core.runtime.compatibility, but the IPluginDescriptor class is delivered twice - in org.eclipse.core.runtime.compatibility and org.eclipse.core.runtime.compatibility.registry. The Plugin class comes from org.eclipse.core.runtime, from the same bundle that calls org.eclipse.core.runtime.Platform.getPlugin. In that light, it looks like the IPluginDescriptor managed to load "other" version of the Plugin class. Any scenario that leads to that means that there is a serious bug in the Equinox classloading. More data: Those are plugins that request (in order) the Plugin class during fresh installation: org.eclipse.core.runtime:3.9.0.v20130228-2041(id=40)] org.eclipse.core.runtime.compatibility:3.2.200.v20130228-2041(id=41)] org.eclipse.core.runtime:3.9.0.v20130228-2041(id=40)] org.eclipse.core.runtime.compatibility:3.2.200.v20130228-2041(id=41)] org.eclipse.ui.workbench:3.105.0.v20130228-2041(id=176)] org.eclipse.emf.common:2.8.0.v20120911-0500(id=73)] workspace selection dialog org.eclipse.core.resources:3.8.100.v20130228-2041(id=39)] org.eclipse.core.expressions:3.4.500.v20130228-2041(id=31)] org.eclipse.help:3.6.0.v20130228-2041(id=127)] org.eclipse.jdt.core:3.9.0.v20130228-2041(id=131)] org.eclipse.team.core:3.7.0.v20130228-2041(id=154)] org.eclipse.jdt.ui:3.9.0.v20130228-2041(id=216)] org.eclipse.jdt.core.manipulation:1.5.0.v20130228-2041(id=210)] org.eclipse.core.filebuffers:3.5.300.v20130228-2041(id=33)] org.eclipse.ltk.core.refactoring:3.6.0.v20130228-2041(id=144)] org.eclipse.debug.core:3.8.0.v20130228-2041(id=45)] org.eclipse.compare.core:3.5.300.v20130228-2041(id=24)] org.eclipse.jdt.launching:3.7.0.v20130228-2041(id=215)] org.eclipse.mylyn.tasks.ui:3.9.0.I20130301-1122(id=269)] org.eclipse.jdt.apt.core:3.3.500.v20130228-2041(id=205)] org.eclipse.jdt.apt.pluggable.core:1.0.400.v20130228-2041(id=206)] org.eclipse.core.variables:3.2.600.v20130228-2041(id=43)] This is what happens during second run: org.eclipse.core.runtime:3.9.0.v20130228-2041(id=40)] org.eclipse.core.runtime.compatibility:3.2.200.v20130228-2041(id=41)] org.eclipse.ui.workbench:3.105.0.v20130228-2041(id=176)] org.eclipse.emf.common:2.8.0.v20120911-0500(id=73)] workspace selection dialog org.eclipse.core.resources:3.8.100.v20130228-2041(id=39)] org.eclipse.core.expressions:3.4.500.v20130228-2041(id=31)] org.eclipse.help:3.6.0.v20130228-2041(id=127)] org.eclipse.jdt.core:3.9.0.v20130228-2041(id=131)] org.eclipse.team.core:3.7.0.v20130228-2041(id=154)] org.eclipse.jdt.ui:3.9.0.v20130228-2041(id=216)] org.eclipse.jdt.core.manipulation:1.5.0.v20130228-2041(id=210)] org.eclipse.core.filebuffers:3.5.300.v20130228-2041(id=33)] org.eclipse.ltk.core.refactoring:3.6.0.v20130228-2041(id=144)] org.eclipse.debug.core:3.8.0.v20130228-2041(id=45)] org.eclipse.compare.core:3.5.300.v20130228-2041(id=24)] org.eclipse.jdt.launching:3.7.0.v20130228-2041(id=215)] org.eclipse.mylyn.tasks.ui:3.9.0.I20130301-1122(id=269)] org.eclipse.mylyn.commons.net:3.9.0.I20130301-1122(id=231)] org.eclipse.mylyn.commons.core:3.9.0.I20130301-1122(id=228)] org.eclipse.jdt.apt.core:3.3.500.v20130228-2041(id=205)] org.eclipse.jdt.apt.pluggable.core:1.0.400.v20130228-2041(id=206)] org.eclipse.core.variables:3.2.600.v20130228-2041(id=43)] org.eclipse.mylyn.trac.core:3.9.0.I20130301-1122(id=272)] org.eclipse.mylyn.bugzilla.core:3.9.0.I20130301-1122(id=224)] org.eclipse.mylyn.context.core:3.9.0.I20130301-1122(id=245)] org.eclipse.team.cvs.core:3.3.500.v20130228-2041(id=155)] org.eclipse.jsch.core:1.1.400.v20130228-2041(id=142)] Notable differences: org.eclipse.core.runtime and org.eclipse.core.runtime.compatibility load the Plugin twice before the workspace selection dialog is shown during first launch. Also, failures prevent proper org.eclipse.mylyn.tasks.ui and org.eclipse.team.core.ui initialization. The LinkageError comes always from at org.eclipse.core.internal.plugins.PluginRegistry.getPluginDescriptor(PluginRegistry.java:117) at org.eclipse.core.internal.plugins.PluginRegistry.getPluginDescriptor(PluginRegistry.java:104) at org.eclipse.core.runtime.Platform.getPlugin(Platform.java:732) at org.eclipse.core.internal.preferences.legacy.InitLegacyPreferences.init(InitLegacyPreferences.java:43) at org.eclipse.core.internal.preferences.PreferenceServiceRegistryHelper.applyRuntimeDefaults(PreferenceServiceRegistryHelper.java:147) So... The exception appears for the first time here:
Daemon Thread [Refresh Packages] (Suspended)
owns: Class<T> (org.eclipse.core.internal.runtime.CompatibilityHelper) (id=11937)
owns: PackageAdminImpl (id=25)
CompatibilityHelper.getPluginDescriptor(String) line: 67
CompatibilityActivator.start(BundleContext) line: 22
BundleContextImpl$1.run() line: 711
AccessController.doPrivileged(PrivilegedExceptionAction<T>) line: not available [native method]
BundleContextImpl.startActivator(BundleActivator) line: 702
BundleContextImpl.start() line: 683
BundleHost.startWorker(int) line: 381
BundleHost(AbstractBundle).start(int) line: 300
SecureAction.start(Bundle, int) line: 440
BundleLoader.setLazyTrigger() line: 263
EclipseLazyStarter.postFindLocalClass(String, Class<?>, ClasspathManager) line: 107
ClasspathManager.findLocalClass(String) line: 469
DefaultClassLoader.findLocalClass(String) line: 216
BundleLoader.findLocalClass(String) line: 395
BundleLoader.findClassInternal(String, boolean, ClassLoader) line: 464
BundleLoader.findClass(String, boolean) line: 421
BundleLoader.findClass(String) line: 412
DefaultClassLoader.loadClass(String, boolean) line: 107
DefaultClassLoader(ClassLoader).loadClass(String) line: 356
BundleLoader.loadClass(String) line: 340
BundleHost.loadClass(String, boolean) line: 229
BundleHost(AbstractBundle).loadClass(String) line: 1212
CompatibilityHelper.getPluginDescriptor(String) line: 63
PlatformActivator(Plugin).initializeDescriptor(String) line: 767
PlatformActivator(Plugin).start(BundleContext) line: 753
PlatformActivator.start(BundleContext) line: 33
BundleContextImpl$1.run() line: 711
AccessController.doPrivileged(PrivilegedExceptionAction<T>) line: not available [native method]
BundleContextImpl.startActivator(BundleActivator) line: 702
BundleContextImpl.start() line: 683
BundleHost.startWorker(int) line: 381
BundleHost(AbstractBundle).start(int) line: 300
PackageAdminImpl.resumeBundles(AbstractBundle[], boolean, int[]) line: 312
PackageAdminImpl.processDelta(BundleDelta[], boolean, State) line: 556
PackageAdminImpl.doResolveBundles(Bundle[], boolean, FrameworkListener[]) line: 251
PackageAdminImpl$1.run() line: 174
Thread.run() line: 722
But is kindly ignored by the catch:
} catch (Exception e) {
if (DEBUG) {
String msg = "Error running compatibility code"; //$NON-NLS-1$
IStatus error = new Status(IStatus.ERROR, Platform.PI_RUNTIME, 1, msg, e);
InternalPlatform.getDefault().log(error);
}
//Ignore the exceptions, return null
}
I think it may be caused by a reflection used to load internal platform, which is not aware of bundles refresh.
Yet another observation - I've put a breakpoint in DefaultClassLoader#loadClass. (A) Classloader @53d289a4 for org.eclipse.core.runtime loads: (1) org.eclipse.core.runtime.Plugin with hashcode 779219052 (2) org.eclipse.core.runtime.IPluginDescriptor with hashcode 1542960903 (B) Classloader @4db03533 for org.eclipse.core.runtime.compatibility loads: (3) org.eclipse.core.runtime.Plugin 779219052 (4) org.eclipse.core.runtime.IPluginDescriptor 1542960903 (5) org.eclipse.core.internal.plugins.PluginDescriptor 1075544259 So far, so good. hashcode match in both classloaders. But then a refresh happens, and: (C) Classloader @3d44214e for org.eclipse.core.runtime loads: (6) org.eclipse.core.runtime.Plugin with hashcode 1966508122 (D) Classloader @160113ef for org.eclipse.core.runtime.compatibility loads: (7) org.eclipse.core.runtime.Plugin 1966508122 (8) org.eclipse.core.runtime.IPluginDescriptor 1542960903 (9) org.eclipse.core.internal.plugins.PluginDescriptor 1491048155 The class D-8 is obviously wrong - it has the same code that class A-2 and B-4, but all classloader had been changed! After putting a right breakpoint in the loadClass method I got this stack responsible for loading a wrong IPluginDescriptor: java.lang.Exception: Stack trace at java.lang.Thread.dumpStack(Thread.java:1342) at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.loadClass(DefaultClassLoader.java:109) at java.lang.ClassLoader.loadClass(ClassLoader.java:356) at java.lang.Class.getDeclaredMethods0(Native Method) at java.lang.Class.privateGetDeclaredMethods(Class.java:2451) at java.lang.Class.getMethod0(Class.java:2694) at java.lang.Class.getMethod(Class.java:1622) at org.eclipse.core.internal.runtime.CompatibilityHelper.getPluginDescriptor(CompatibilityHelper.java:66) at org.eclipse.core.internal.plugins.CompatibilityActivator.start(CompatibilityActivator.java:22) at org.eclipse.osgi.framework.internal.core.BundleContextImpl$1.run(BundleContextImpl.java:711) at java.security.AccessController.doPrivileged(Native Method) at org.eclipse.osgi.framework.internal.core.BundleContextImpl.startActivator(BundleContextImpl.java:702) at org.eclipse.osgi.framework.internal.core.BundleContextImpl.start(BundleContextImpl.java:683) at org.eclipse.osgi.framework.internal.core.BundleHost.startWorker(BundleHost.java:381) at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:300) at org.eclipse.osgi.framework.util.SecureAction.start(SecureAction.java:440) at org.eclipse.osgi.internal.loader.BundleLoader.setLazyTrigger(BundleLoader.java:263) at org.eclipse.core.runtime.internal.adaptor.EclipseLazyStarter.postFindLocalClass(EclipseLazyStarter.java:107) at org.eclipse.osgi.baseadaptor.loader.ClasspathManager.findLocalClass(ClasspathManager.java:469) at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.findLocalClass(DefaultClassLoader.java:216) at org.eclipse.osgi.internal.loader.BundleLoader.findLocalClass(BundleLoader.java:395) at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:464) at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:421) at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:412) at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.loadClass(DefaultClassLoader.java:107) at java.lang.ClassLoader.loadClass(ClassLoader.java:356) at org.eclipse.osgi.internal.loader.BundleLoader.loadClass(BundleLoader.java:340) at org.eclipse.osgi.framework.internal.core.BundleHost.loadClass(BundleHost.java:229) at org.eclipse.osgi.framework.internal.core.AbstractBundle.loadClass(AbstractBundle.java:1212) at org.eclipse.core.internal.runtime.CompatibilityHelper.getPluginDescriptor(CompatibilityHelper.java:65) at org.eclipse.core.runtime.Plugin.initializeDescriptor(Plugin.java:767) at org.eclipse.core.runtime.Plugin.start(Plugin.java:753) at org.eclipse.core.internal.runtime.PlatformActivator.start(PlatformActivator.java:33) at org.eclipse.osgi.framework.internal.core.BundleContextImpl$1.run(BundleContextImpl.java:711) at java.security.AccessController.doPrivileged(Native Method) at org.eclipse.osgi.framework.internal.core.BundleContextImpl.startActivator(BundleContextImpl.java:702) at org.eclipse.osgi.framework.internal.core.BundleContextImpl.start(BundleContextImpl.java:683) at org.eclipse.osgi.framework.internal.core.BundleHost.startWorker(BundleHost.java:381) at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:300) at org.eclipse.osgi.framework.internal.core.PackageAdminImpl.resumeBundles(PackageAdminImpl.java:312) at org.eclipse.osgi.framework.internal.core.PackageAdminImpl.processDelta(PackageAdminImpl.java:556) at org.eclipse.osgi.framework.internal.core.PackageAdminImpl.doResolveBundles(PackageAdminImpl.java:251) at org.eclipse.osgi.framework.internal.core.PackageAdminImpl$1.run(PackageAdminImpl.java:174) at java.lang.Thread.run(Thread.java:722) After cutting the classloading stuff: [loading old IPluginDescriptor from classloader] at org.eclipse.core.internal.runtime.CompatibilityHelper.getPluginDescriptor(CompatibilityHelper.java:66) at org.eclipse.core.internal.plugins.CompatibilityActivator.start(CompatibilityActivator.java:22) [starting compatibility] at org.eclipse.core.internal.runtime.CompatibilityHelper.getPluginDescriptor(CompatibilityHelper.java:65) at org.eclipse.core.runtime.Plugin.initializeDescriptor(Plugin.java:767) at org.eclipse.core.runtime.Plugin.start(Plugin.java:753) at org.eclipse.core.internal.runtime.PlatformActivator.start(PlatformActivator.java:33) [processing delta - refresh] Thomas, how is it possible that Activator manages to load obsoleted class? Is it possible that at some level of platform shutdown (compatibility stop is a very nasty method) the IPluginDescriptor leaked into framework classloader? More weird things: the class org.eclipse.core.runtime.IPluginDescriptor is misloaded from org.eclipse.equinox.registry after framework refresh. (In reply to comment #18) > Thomas, > how is it possible that Activator manages to load obsoleted class? Is it > possible that at some level of platform shutdown (compatibility stop is a > very nasty method) the IPluginDescriptor leaked into framework classloader? First of all, thanks for looking into this and doing all the diagnostics. I'm still at a loss as to what is going wrong or why the old class is getting referenced after a refresh. When the refresh operation is going on do you know the list of bundles that are being requested to be refreshed? It appears that a lot of low-level bundles are getting refreshed here, such as org.eclipse.core.runtime and org.eclipse.equinox.registry but that should really refresh all the class loaders involved and start fresh. I see that org.eclipse.core.internal.plugins.InternalPlatform.getPluginDescriptor(String) from org.eclipse.core.runtime.compatibility makes a call out to a static variable 'registry' that ultimately has map of PluginDescriptors. It would be good to know if this org.eclipse.core.internal.plugins.InternalPlatform.registry variable also got refreshed and has a new hashcode after the refresh. If not then I can see how this map would have references to old objects created with the old classes. (In reply to comment #19) > More weird things: the class org.eclipse.core.runtime.IPluginDescriptor is > misloaded from org.eclipse.equinox.registry after framework refresh. What do you mean here? It sounds as if the org.eclipse.core.runtime.compatibility.registry fragment did not attach properly to org.eclipse.equinox.registry after the refresh? I put a breakpoint into InternalPlatform.getPluginRegistry - the output I got is: org.eclipse.core.runtime@1b4775ba loads Plugin 463989851 org.eclipse.core.runtime.compatibility@5e066f43 loads IPluginDescriptor 2069743059 org.eclipse.core.runtime.compatibility@5e066f43 loads PluginDescriptor 1830175993 org.eclipse.core.runtime.compatibility@5e066f43 loads Plugin 463989851 org.eclipse.core.runtime@1b4775ba loads IPluginDescriptor 2069743059 All is OK. The hashcode for the registry is 715402562. Then refresh happens - here is a list of (somewhat stripped) bundles captured in PackageAdminImpl.refreshPackages: org.eclipse.core.runtime.compatibility.auth_3.2.200.I20130301-1122 [200] org.eclipse.core.runtime_3.9.0.v20130307-0857 [40] During refresh - the registry is referred twice - still in the old version. Then something magical happens: org.eclipse.core.runtime@170e153b loads Plugin 1515158976 org.eclipse.core.runtime.compatibility@73b7122f loads IPluginDescriptor 2069743059 (OLD ONE!!!) and now registry object is accessed again and it gets a new hash code 186317623. One step forward:
It looks like the IPluginDescriptor is *never* loaded from org.eclipse.core.runtime. The *.class file is duplicated in org.eclipse.equinox.compatibility.registry, which is a fragment for org.eclipse.equinox.registry.
I found this by watching MultiSourcePackage which always provides bundles in the following order when loading IPluginDescriptor:
org.eclipse.equinox.common
org.eclipse.equinox.registry
org.eclipse.core.runtime
I guess that's why the IPluginDescriptor class is not refreshed - because it's being held in the org.eclipse.equinox.registry! What's more (and for what I have learned during debugging), this is intentional and valid behaviour - IPluginDescriptor should not be refreshed.
Now I must trust myself that my previous observation was right:
> org/eclipse/core/runtime/Plugin is loaded independently twice by org.eclipse.core.internal.plugins.PluginDescriptor and org/eclipse/core/runtime/IPluginDescriptor
IPluginDescriptor is not refreshed while PluginDescriptor is. I guess that "old" IPluginDescriptor brings "old" Plugin, which was removed during org.eclipse.core.runtime refresh.
The only mystery that is still present is how the equinox.registry is able to solve IPluginDescriptor - because there's no direct dependency to core.runtime - but I guess this is somehow resolved by using "split" packages.
And I guess this is the ultimate source of problems - refresh of a bundle that exports a split package does not cause a refresh of all other bundles that export the same split package!
Created attachment 228131 [details]
Patch proposition
By no means can I claim it's a valid patch. Probably there's better approach, but this one seems to work fine.
(In reply to comment #24) > Created attachment 228131 [details] > Patch proposition > > By no means can I claim it's a valid patch. Probably there's better > approach, but this one seems to work fine. Thanks, I will try to have a look for M6, but likely will not get into all the details until M7. *** Bug 384686 has been marked as a duplicate of this bug. *** Created attachment 228305 [details]
Express the cycle in org.eclipse.core.runtime package parts
Looking at this in more detail I am worried that a solution that involves refreshing all contributors of a split package is not the correct behavior.
I think the central issue is that the org.eclipse.core.runtime.compatibility.registry bundle introduces a very strange cycle between the different 'parts' of the split package org.eclipse.core.runtime. I am not entirely sure how this can be working at runtime, but somehow it does.
There is a class file org.eclipse.core.runtime.IPluginDescriptor that is included in a 'classes' folder of the org.eclipse.core.runtime.compatibility.registry project. The reason this is a pre-compiled class is a bit dubious. Questions come to mind about why is this not a java file that we compile like the other classes in the org.eclipse.core.runtime.compatibility.registry bundle?
The reason is that this class references types that are found in the org.eclipse.core.runtime package part contained in the bundle of the same name org.eclipse.core.runtime. Here are the types I found which it references from the org.eclipse.core.runtime bundle:
org.eclipse.core.runtime.ILibrary
org.eclipse.core.runtime.Plugin
org.eclipse.core.runtime.IPluginPrerequisite
But at runtime the org.eclipse.core.runtime.compatibility.registry host bundle org.eclipse.equinox.registry has no class space requirements on the org.eclipse.core.runtime bundle (or its split part of the org.eclipse.core.runtime package). So it is questionable how such an interface is able to be defined by the host org.eclipse.equinox.registry bundle class loader, but it seems to 'work' so I will have to brush that aside for now.
So my argument is that the org.eclipse.core.runtime.compatibility.registry introduces an invalid cycle in the different parts of the org.eclipse.core.runtime but this cycle is not expressed at runtime so we get into this inconsistent state when one of the package parts for org.eclipse.core.runtime is refreshed, but other parts involved in the cycle of the org.eclipse.core.runtime package are not refreshed.
It would be great to just drop this org.eclipse.core.runtime.compatibility.registry fragment bundle. But if that cannot be done for Kepler then we should at least try to express some runtime dependency that tells the framework there is a cycle here.
I attached a patch that add the following requirement to org.eclipse.core.runtime.compatibility.registry bundle manifest:
Require-Capability: osgi.identity; filter:="(osgi.identity=org.eclipse.core.runtime)"
This should cause the org.eclipse.core.runtime.compatibility.registry fragment (and its host org.eclipse.equinox.registry) to get pulled into a refresh operation if the org.eclipse.core.runtime bundle is refreshed for any reason. There are two concerns with this approach:
1) May get a debug log about cycles on shutdown if debug is enabled. I argue, so what! this is a cycle we just were not expressing it before!
2) May cause class path cycle issues when building the org.eclipse.core.runtime.compatibility.registry fragment with PDE-Build or CBI. In this case I hope not since the osgi.identity requirement should not contribute to the class path computation at all and hopefully is ignored, but this would need to be confirmed.
Krzysztof, are you in any position to test this change out with a CBI build? and then also test out that it fixes your failing scenario?
No such luck: Caused by: java.lang.RuntimeException: org.osgi.framework.BundleException: Bundle org.eclipse.core.runtime.compatibility.registry cannot be resolved Resolution errors: Bundle org.eclipse.core.runtime.compatibility.registry - Missing Constraint: Require-Capability: osgi.identity; filter="(osgi.identity=org.eclipse.core.runtime)" But being less subtle seems to work: + Require-Bundle: org.eclipse.core.runtime Anyway, I'm not sure where I have found this, but I have read that split packages exist in one space and can reference themselves even when they are in different bundles. That's the only reasonable explanation why current solution works - otherwise the IPluginDescriptor could not be resolved in org.eclipse.equinox.registry, which has no direct dependency on org.eclipse.core.runtime - and this is the problem, because core.runtime refresh does not cause equinox.registry refresh. I believe the right thing to do is to refresh all contributors of a split package, or at least ensure that the main one is refreshed - because when there is no direct dependency between bundles, there's still an implicit dependency. Of course the problem is how to distinguish split packages from duplicated exports - f.e. system.bundle provides javax.xml, but adding javax.xml should not cause a refresh of the system bundle... Split packages are evil :-(. (In reply to comment #29) > But being less subtle seems to work: > + Require-Bundle: org.eclipse.core.runtime > > Anyway, I'm not sure where I have found this, but I have read that split > packages exist in one space and can reference themselves even when they are > in different bundles. > > That's the only reasonable explanation why current solution works - > otherwise the IPluginDescriptor could not be resolved in > org.eclipse.equinox.registry, which has no direct dependency on > org.eclipse.core.runtime - and this is the problem, because core.runtime > refresh does not cause equinox.registry refresh. It sounds correct, but it is not. The org.eclipse.core.runtime.compatibility.registry fragment gets attached to the org.eclipse.equinox.registry host bundle. There is one class loader for the org.eclipse.equinox.registry that loads all the classes from the host bundle and all of its attached fragment bundles. Currently there is no dependency from the org.eclipse.equinox.registry to the org.eclipse.core.runtime bundle so the bundle class loader for org.eclipse.equinox.registry has no visibility to the types in the package org.eclipse.core.runtime defined in the org.eclipse.core.runtime bundle. As a test you can attempt to do Bundle.loadClass("org.eclipse.core.runtime.ILibrary") on the bundle object for the org.eclipse.equinox.registry bundle. It will not load that class! What I suspect is happening is some VM delayed verification. Basically we have a PluginDescriptor implementation in the bundle org.eclipse.core.runtime.compatibility which implements IPlugionDescriptor from the org.eclipse.core.runtime.compatibility.registry. The VM does not really do any verification of the IPlugionDescriptor when that interface is defined by the org.eclipse.equinox.registry. Instead when the PluginDescriptor from org.eclipse.core.runtime.compatibility is loaded and used then all the types are loaded from the initiating class loader perspective. That would be from the org.eclipse.core.runtime.compatibility perspective which does have visibility to all the necessary types. > > I believe the right thing to do is to refresh all contributors of a split > package, or at least ensure that the main one is refreshed - because when > there is no direct dependency between bundles, there's still an implicit > dependency. > > Of course the problem is how to distinguish split packages from duplicated > exports - f.e. system.bundle provides javax.xml, but adding javax.xml should > not cause a refresh of the system bundle... > > Split packages are evil :-(. (In reply to comment #28) > No such luck: > > Caused by: java.lang.RuntimeException: org.osgi.framework.BundleException: > Bundle org.eclipse.core.runtime.compatibility.registry cannot be resolved > Resolution errors: > Bundle org.eclipse.core.runtime.compatibility.registry - Missing > Constraint: Require-Capability: osgi.identity; > filter="(osgi.identity=org.eclipse.core.runtime)" What is this error from? A CBI build? (In reply to comment #31) > What is this error from? A CBI build? Yes. (In reply to comment #29) > But being less subtle seems to work: > + Require-Bundle: org.eclipse.core.runtime > This approach will cause strange inconsistencies for who defines the org.eclipse.core.runtime.IPluginDescriptor class. Right now we know it will be loaded from the org.eclipse.equinox.registry bundle class loader because we have a non cyclic chain: org.eclipse.core.runtime.compatibility -> org.eclipse.core.runtime -> org.eclipse.equinox.registry If you introduce a cycle back to org.eclipse.core.runtime from the org.eclipse.core.runtime.compatibility.registry fragment it will place a payload requirement on the host bundle org.eclipse.equinox.registry back to org.eclipse.core.runtime: org.eclipse.core.runtime.compatibility -> org.eclipse.core.runtime -> org.eclipse.equinox.registry -> org.eclipse.core.runtime Now we have a very evil situation: 1) org.eclipse.osgi.runtime package is split 2) org.eclipse.orgi.runtime package has a shadowed class IPluginDescriptor defined by two bundles 3) the two bundles that contain the shadowed class IPluginDescriptor are involved in a cycle. Here we have a nasty situation that leads to inconsistent class loading situations. Imagine the following call: Bundle[org.eclipse.equinox.registry].loadClass(...IPluginDescriptor) This will follow OSGi delegation for require-bundle org.eclipse.core.runtime and look for the class in the org.eclipse.core.runtime bundle and find it and define it. Now imagine we instead started with : Bundle[org.eclipse.core.runtime].loadClass(...IPluginDescriptor) This will follow OSGi delegation for require-bundle org.eclipse.equinox.registry and look for the class in the org.eclipse.equinox.registry bundle and find it and define it. I think this would be a very confusing situation at best and could lead to strange cast exceptions in the worst case. (In reply to comment #32) > (In reply to comment #31) > > What is this error from? A CBI build? > Yes. Sorry I hope it is an easy test for you, but could you change the header to: Require-Capability: osgi.identity; filter:="(osgi.identity=org.eclipse.core.runtime)"; resolution:=optional By adding the directive resolution:=optional it should make the dependency optional, but it likely is a stretch that CBI will understand this means it is an optional dependency. (In reply to comment #34) > Sorry I hope it is an easy test for you It's not. The build has passed through the resolution part - but it takes about 40 minutes up to an hour before it's completed and tested (for this issue). The build succeeded. I was able to start Eclipse, and Mylyn got loaded from the very first time properly. I think the last approach solves the problem. What is this notation of specifying the requirement? (In reply to comment #36) > The build succeeded. I was able to start Eclipse, and Mylyn got loaded from > the very first time properly. I think the last approach solves the problem. > > What is this notation of specifying the requirement? In OSGi R5 (implemented in Juno) every bundle gets an implicit capability called osgi.identity. This capability inherits its properties from the Bundle-SymbolicName and Bundle-Version header and in most respects is similar to the osgi.wiring.bundle capability (used to resolve Require-Bundle dependencies), but the osgi.identity capability has no implications on class loading delegation like Require-Bundle does. It is only a requirement that enforces that there is a resource available in the environment that has the osgi.identity with a value of org.eclipse.core.runtime. Now making that an optional dependency is the true definition of a hack here. Basically it is stating that we want to have the org.eclipse.equinox.registry bundle (through the payload requirement from one of its attached fragments) to get wired to the org.eclipse.core.runtime resource. But we make it optional so that the fragment will not fail resolution of the org.eclipse.core.runtime bundle is not available. But in reality there is no way the compatibility.registry fragment could work without the org.eclipse.core.runtime bundle present so in my mind it really is not an optional requirement, but I suggest we got with this approach for now. Why I suspect the CBI build is failing is because whatever is modeling the resources in the build likely has no idea that all OSGi resources should get assigned to provide this implicit osgi.identity capability. Created attachment 228669 [details]
Express the cycle in org.eclipse.core.runtime package parts (optionally)
Moving to Platform->Runtime where org.eclipse.core.runtime.compatibility.registry lives. |
Starting with Eclipse 3.6M3 Mylyn's automated tests have been failing to load (see log). I haven't figured out what's wrong but noticed an exception in OSGi while looking into the problem: osgi> ss org.eclipse.mylyn.tests Framework is launched. id State Bundle 271 <<LAZY>> org.eclipse.mylyn.tests_0.0.0 272 RESOLVED org.eclipse.mylyn.tests.performance_0.0.0 273 RESOLVED org.eclipse.mylyn.tests.ui_0.0.0 274 RESOLVED org.eclipse.mylyn.tests.util_0.0.0 osgi> diag org.eclipse.mylyn.tests reference:file:dropins/test/plugins/org.eclipse.mylyn.tests_0.0.0/ [271] No unresolved constraints. osgi> bundle 271 org.eclipse.mylyn.tests_0.0.0 [271] Id=271, Status=<<LAZY>> Data Root=/home/tools/mylyn/eclipse/test-3.6M4/eclipse/configuration/org.eclipse.osgi/bundles/271/data No registered services. No services in use. Exported packages org.eclipse.mylyn.tests; version="0.0.0"[exported] org.eclipse.mylyn.tests.integration; version="0.0.0"[exported] org.eclipse.mylyn.tests.misc; version="0.0.0"[exported] java.lang.NullPointerException at org.eclipse.osgi.internal.resolver.RequiresHolder.isExported(StateHelperImpl.java:525) at org.eclipse.osgi.internal.resolver.StateHelperImpl.getPackages(StateHelperImpl.java:404) at org.eclipse.osgi.internal.resolver.StateHelperImpl.getPackages(StateHelperImpl.java:410) at org.eclipse.osgi.internal.resolver.StateHelperImpl.getPackages(StateHelperImpl.java:410) at org.eclipse.osgi.internal.resolver.StateHelperImpl.getVisiblePackages(StateHelperImpl.java:355) at org.eclipse.osgi.framework.internal.core.FrameworkCommandProvider._bundle(FrameworkCommandProvider.java:845) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:585) at org.eclipse.osgi.framework.internal.core.FrameworkCommandInterpreter.execute(FrameworkCommandInterpreter.java:155) at org.eclipse.osgi.framework.internal.core.FrameworkConsole.docommand(FrameworkConsole.java:157) at org.eclipse.osgi.framework.internal.core.FrameworkConsole.runConsole(FrameworkConsole.java:142) at org.eclipse.osgi.framework.internal.core.FrameworkConsole.run(FrameworkConsole.java:106) at java.lang.Thread.run(Thread.java:595)