Bug 307764 - ResourcesPlugin's activator registers a OSGI service in it's start(), triggers a declarative service activation, and then creates OSGI classloader timeouts
Summary: ResourcesPlugin's activator registers a OSGI service in it's start(), trigger...
Status: NEW
Alias: None
Product: Platform
Classification: Eclipse Project
Component: Resources (show other bugs)
Version: 3.6   Edit
Hardware: PC Windows XP
: P3 normal with 1 vote (vote)
Target Milestone: ---   Edit
Assignee: Alex Blewitt CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on: 572128
Blocks:
  Show dependency tree
 
Reported: 2010-03-31 13:18 EDT by Min Idzelis CLA
Modified: 2021-03-19 15:37 EDT (History)
6 users (show)

See Also:


Attachments
timeout test bundle (6.24 KB, application/x-zip-compressed)
2010-03-31 15:49 EDT, Min Idzelis CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Min Idzelis CLA 2010-03-31 13:18:39 EDT
Build Identifier: 

When the activator calls: 


workspaceRegistration = context.registerService(IWorkspace.SERVICE_NAME, workspace, null);

It can trigger the starting of other plugins if they have a declarative service defined. Because of that, if during the start of that other service it tries to load classes from within the ResourcesPlugin, you will get the infamous OSGI timeouts, since OSGI tries to fully start a bundle before loading classes from it. 

This causes very slow startup since very often the dependent service (on the IWorkspace service) that is being started will need classes found in ResourcesPlugin. 

--
I think a best practice would be to NOT register OSGI services from within a bundle activator. Could somebody from the Equinox team please comment? 

Reproducible: Always
Comment 1 Thomas Watson CLA 2010-03-31 15:06:16 EDT
(In reply to comment #0)
> Build Identifier: 
> 
> When the activator calls: 
> 
> 
> workspaceRegistration = context.registerService(IWorkspace.SERVICE_NAME,
> workspace, null);
> 
> It can trigger the starting of other plugins if they have a declarative service
> defined. Because of that, if during the start of that other service it tries to
> load classes from within the ResourcesPlugin, you will get the infamous OSGI
> timeouts, since OSGI tries to fully start a bundle before loading classes from
> it. 
> 
> This causes very slow startup since very often the dependent service (on the
> IWorkspace service) that is being started will need classes found in
> ResourcesPlugin. 
> 
> --
> I think a best practice would be to NOT register OSGI services from within a
> bundle activator. Could somebody from the Equinox team please comment? 
> 
> Reproducible: Always

The activator should still be a valid place to register the service.  I am a bit confused on how the declarative service components are causing class loader contention for activation.  I wrote a small test to confirm that an immediate service component which depends on the IWorkspace service is activated on the same thread as the thread trying to start the resources plugin.  This should not cause any timeouts if additional classes are loaded from the resources plugin in the components activate method.  Do you have a testcase we can use to reproduce?
Comment 2 Min Idzelis CLA 2010-03-31 15:45:22 EDT
In creating a test case bundle, I found out what was really going on. This only happens after starting an existing workspace that has not been properly shutdown. 

What I realized is that ResourcesPlugin activator spawns a RefreshJob that refreshes the workspace when it was uncleanly shutdown. It turns out that this Job starts running (on a different thread) before the ResourcesPlugin's start() method had finished. As it starts running it tries to load "org.eclipse.core.internal.resources.Rules" and locks the DefaultClassLoader for bundle: org.eclipse.core.resources. 

In the meanwhile, the activation thread continues continues constructing the services. If one of these services needs to load a class from org.eclipse.core.resources plugin, it will trigger the timeout. 

I'm going to try to see if I muddle with the timing enough to make this happen in my test case bundle.
Comment 3 Min Idzelis CLA 2010-03-31 15:49:19 EDT
Created attachment 163565 [details]
timeout test bundle
Comment 4 Min Idzelis CLA 2010-03-31 15:51:07 EDT
To reproduce. Start an Eclipse with a non-empty workspace. Shut it down by terminating it forcefully. (Don't close using the X) 

This will cause the refresh job to start the next time around. 

Then you will see this exception. 


!ENTRY org.eclipse.core.resources 2 10035 2010-03-31 15:47:57.593
!MESSAGE The workspace exited with unsaved changes in the previous session; refreshing workspace to recover changes.
Activate start

!ENTRY org.eclipse.osgi 2 0 2010-03-31 15:48:02.890
!MESSAGE While loading class "org.eclipse.core.internal.resources.Rules", thread "Thread[Worker-0,5,main]" timed out waiting (5000ms) for thread "Thread[main,6,main]" to finish starting bundle "org.eclipse.core.resources_3.6.0.v20100310-1650 [1200]". To avoid deadlock, thread "Thread[Worker-0,5,main]" is proceeding but "org.eclipse.core.internal.resources.Rules" may not be fully initialized.
!STACK 0
org.osgi.framework.BundleException: State change in progress for bundle "reference:file:/D:/dev/targets2/RAD80-2010326_0906/eclipse/plugins/org.eclipse.core.resources_3.6.0.v20100310-1650.jar" by thread "main".
	at org.eclipse.osgi.framework.internal.core.AbstractBundle.beginStateChange(AbstractBundle.java:1072)
	at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:277)
	at org.eclipse.osgi.framework.util.SecureAction.start(SecureAction.java:406)
	at org.eclipse.osgi.internal.loader.BundleLoader.setLazyTrigger(BundleLoader.java:265)
	at org.eclipse.core.runtime.internal.adaptor.EclipseLazyStarter.postFindLocalClass(EclipseLazyStarter.java:106)
	at org.eclipse.osgi.baseadaptor.loader.ClasspathManager.findLocalClass(ClasspathManager.java:453)
	at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.findLocalClass(DefaultClassLoader.java:216)
	at org.eclipse.osgi.internal.loader.BundleLoader.findLocalClass(BundleLoader.java:393)
	at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:469)
	at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:422)
	at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:410)
	at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.loadClass(DefaultClassLoader.java:107)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
	at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
	at org.eclipse.core.internal.resources.Workspace.getRuleFactory(Workspace.java:1435)
	at org.eclipse.core.internal.resources.Resource.refreshLocal(Resource.java:1653)
	at org.eclipse.core.internal.refresh.RefreshJob.runInWorkspace(RefreshJob.java:166)
	at org.eclipse.core.internal.resources.InternalWorkspaceJob.run(InternalWorkspaceJob.java:38)
	at org.eclipse.core.internal.jobs.Worker.run(Worker.java:54)
Caused by: org.eclipse.osgi.framework.internal.core.AbstractBundle$BundleStatusException
	... 19 more
Root exception:
org.eclipse.osgi.framework.internal.core.AbstractBundle$BundleStatusException
	at org.eclipse.osgi.framework.internal.core.AbstractBundle.beginStateChange(AbstractBundle.java:1072)
	at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:277)
	at org.eclipse.osgi.framework.util.SecureAction.start(SecureAction.java:406)
	at org.eclipse.osgi.internal.loader.BundleLoader.setLazyTrigger(BundleLoader.java:265)
	at org.eclipse.core.runtime.internal.adaptor.EclipseLazyStarter.postFindLocalClass(EclipseLazyStarter.java:106)
	at org.eclipse.osgi.baseadaptor.loader.ClasspathManager.findLocalClass(ClasspathManager.java:453)
	at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.findLocalClass(DefaultClassLoader.java:216)
	at org.eclipse.osgi.internal.loader.BundleLoader.findLocalClass(BundleLoader.java:393)
	at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:469)
	at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:422)
	at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:410)
	at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.loadClass(DefaultClassLoader.java:107)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
	at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
	at org.eclipse.core.internal.resources.Workspace.getRuleFactory(Workspace.java:1435)
	at org.eclipse.core.internal.resources.Resource.refreshLocal(Resource.java:1653)
	at org.eclipse.core.internal.refresh.RefreshJob.runInWorkspace(RefreshJob.java:166)
	at org.eclipse.core.internal.resources.InternalWorkspaceJob.run(InternalWorkspaceJob.java:38)
	at org.eclipse.core.internal.jobs.Worker.run(Worker.java:54)
Activate done
Comment 5 Min Idzelis CLA 2010-05-19 15:27:43 EDT
Please target this to RC2/RC3. 

It seems like you should be able to solve this simply by waiting until the last line of the start() method to schedule() the refresh job.
Comment 6 Eclipse Webmaster CLA 2019-09-06 16:14:19 EDT
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet.

If you have further information on the current state of the bug, please add it. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant.