Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 330905

Summary: Problem with persisting bundles state after install when eclipse.stateSaveDelayInterval is set to 0
Product: [Eclipse Project] Equinox Reporter: Lazar Kirchev <l.kirchev>
Component: FrameworkAssignee: Thomas Watson <tjwatson>
Status: RESOLVED FIXED QA Contact:
Severity: minor    
Priority: P3 CC: jeffmcaffer, tjwatson
Version: 3.6   
Target Milestone: 3.7 M4   
Hardware: PC   
OS: Windows Vista   
Whiteboard:
Attachments:
Description Flags
Sample test bundle to reproduce the problem.
none
patch
none
patch none

Description Lazar Kirchev CLA 2010-11-23 06:40:07 EST
Created attachment 183658 [details]
Sample test bundle to reproduce the problem.

Steps to reproduce:

1. start Equinox with the property eclipse.stateSaveDelayInterval set to zero
2. install the attached test bundle 
3. exit with the exit command
4. start again Equinox and check that the ss command does not list the installed bundle

The same happens if, instead of exiting the framework, the JVM process in which runs the framework gets killed.

This problem reproduces in most cases, although sometimes the installed bundle is correctly persisted. I checked the code which installs a bundle and it seems that in this particular case of eclipse.stateSaveDelayInterval set to zero there is a bug. In Framework.installWorkerPrivileged(...) the persisting of data is performed in a call to BundleInstall.commit(...). It delegates to code in BaseStorage and finally the data for all bundles, which are in the list of installed bundles, is persisted. But the newly installed bundle is added to this list after the call to the commit() method, so when the bundles are persisted, it is not among them. This does not happen with the default value of eclipse.stateSaveDelayInterval (which is 30000 ms), because then a separate thread waits for this timeout, and during this time the newly installed bundle is added to the list of installed bundles. The persisting thread is started from BaseStorage's StateSeaver.requestSave(). Is there any reason why the new bundle is added to the list after the call to commit()?

Another strange thing is that in the state persisting logic (in requestSave()) first a check is made if  eclipse.stateSaveDelayInterval is zero. If it is zero, the state is persisted, and then the thread for persisting the state is started. If the property is not zero only the thread is started. Is it necessary to start a thread when the property is 0? In this case the state is persisted anyway.

The reason why the problem is not 100% reproducible is synchronization - when the property is 0 in most cases the code in the run() method of the thread is executed before the bundle is added to the list of bundles (it does not wait at all), but sometimes the adding happens first and then the thread saves it.

The reason for implementing delayed persisting with eclipse.stateSaveDelayInterval is to minimize the disk operations in case of lots of operations e.g. installs. But doesn't this delay violate the OSGi spec? According to the spec the installation of a bundle must be persistent – the bundle must remain installed across Framework and Java VM invocations until it is explicitly uninstalled. In the case of delayed persisting if during the wait interval the process, in which the framework runs gets killed for some reason, the newly installed bundles will not be persisted.
Comment 1 Thomas Watson CLA 2010-11-28 22:22:25 EST
Investigate for M4.
Comment 2 Thomas Watson CLA 2010-11-29 14:06:16 EST
Created attachment 184067 [details]
patch

Here is a patch that fixes the immediate issues.  There are two main issues.

1) StateSaver creates a background thread when eclipse.stateSaveDelayInterval=0.  This is not needed in that case.  I think this background thread may be what actually causes you to succeed in some cases.

2) The other issue is an ordering issue with the data structure not being updated properly before saving the state.  
 - We did not add the bundle to the bundles repo before requesting a save
 - We did not update the resolver state before requesting a save

 - I also noticed that we did not request a save on uninstall either which would cause similar issues with an uninstalled bundle not really being removed when restarting.

There is still an issue with disk usage when using eclipse.stateSaveDelayInterval=0 setting.  We never clean up old versions of the cache until we close the framework.  This leaves you with a very large set of generation files while running an instance that has lots of bundle lifecycle operations.  I opened bug331372 to track that issue.
Comment 3 Thomas Watson CLA 2010-11-29 14:29:58 EST
Created attachment 184069 [details]
patch

Last patch still had a bug in uninstall because the data being uninstalled was not being marked as dirty so the save request did not cause anything to actually be done.
Comment 4 Thomas Watson CLA 2010-11-29 14:31:48 EST
Patch released.