Bug 289480 - Concurrency issues in XMLParser.acquireXMLParsing()
Summary: Concurrency issues in XMLParser.acquireXMLParsing()
Status: RESOLVED FIXED
Alias: None
Product: Equinox
Classification: Eclipse Project
Component: p2 (show other bugs)
Version: 3.5   Edit
Hardware: All All
: P3 major (vote)
Target Milestone: 3.6 M3   Edit
Assignee: Simon Kaegi CLA
QA Contact:
URL:
Whiteboard:
Keywords: contributed
Depends on:
Blocks: 289670
  Show dependency tree
 
Reported: 2009-09-15 11:14 EDT by Achim Demelt CLA
Modified: 2009-09-16 21:44 EDT (History)
2 users (show)

See Also:


Attachments
Patch for synchronized creation of the ServiceTracker (1.25 KB, patch)
2009-09-16 05:14 EDT, Achim Demelt CLA
simon_kaegi: iplog+
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Achim Demelt CLA 2009-09-15 11:14:27 EDT
I am running builds with Buckminster. This uses multiple MetadataRepositoryIO instances in concurrent threads to read repository metadata from various p2 repo locations. From time to time, I run into the following exception:

org.eclipse.equinox.internal.provisional.p2.core.ProvisionException: Unable to read repository at http://svn.exxcellent.de/projects/orchideo/common/integration/trunk/site/content.jar.
         at org.eclipse.equinox.internal.p2.metadata.repository.MetadataRepositoryIO.read(MetadataRepositoryIO.java:73)
         at org.eclipse.buckminster.pde.internal.EclipseImportReaderType.getVersionFinder(EclipseImportReaderType.java:506)
        at org.eclipse.buckminster.core.rmap.model.Provider.findMatch(Provider.java:234)
         at org.eclipse.buckminster.core.rmap.model.SearchPath.getProvider(SearchPath.java:103)
         at org.eclipse.buckminster.core.rmap.model.ResourceMap.resolve(ResourceMap.java:321)
         at org.eclipse.buckminster.core.rmap.model.ResourceMap.resolve(ResourceMap.java:232)
         at org.eclipse.buckminster.core.resolver.ResourceMapResolver.innerResolve(ResourceMapResolver.java:232)
         at org.eclipse.buckminster.core.resolver.ResolverNodeWithJob.resolve(ResolverNodeWithJob.java:227)
         at org.eclipse.buckminster.core.resolver.ResolverNodeWithJob.run(ResolverNodeWithJob.java:102)
         at org.eclipse.buckminster.core.resolver.ResolverNodeWithJob$NodeResolutionJob.run(ResolverNodeWithJob.java:49)
         at org.eclipse.core.internal.jobs.Worker.run(Worker.java:55)
 Caused by: java.io.IOException: Unable to acquire a SAX parser service.
         at org.eclipse.equinox.internal.p2.metadata.repository.MetadataRepositoryIO$Parser.parse(MetadataRepositoryIO.java:206)
         at org.eclipse.equinox.internal.p2.metadata.repository.MetadataRepositoryIO.read(MetadataRepositoryIO.java:55)
         ... 10 more

The root cause of the "Unable to acquire a SAX parser service" exception is a bit obscured by the fact that the MetadataRepositoryIO$Parser.parse() method erases the original stack trace by just passing on the exception message. But anyway, it just _can't_ be that there is no SAXParserFactory in one out of 20 invocations of the exact same code.

I tracked the problem down to the call to XMLParser.acquireXMLParsing(). In the debugger, I was able to reproduce the exception by provoking a race condition between to concurrently executing threads. It goes like this:

	1 private static SAXParserFactory acquireXMLParsing(BundleContext context) {
	2 	if (xmlTracker == null) {
	3 		xmlTracker = new ServiceTracker(context, SAXParserFactory.class.getName(), null);
	4 		xmlTracker.open();
	5 	}
	6 	return (SAXParserFactory) xmlTracker.getService();
	7 }

Both threads execute line 2, which evaluates to true, and continue to line 3. Now thread 1 executes lines 3, 4, and 5. Now we switch to thread 2, execute line 3. Now back to thread 1, which executes line 6. At this point, the static xmlTracker member refers to a new ServiceTracker that has not yet been open()ed. The call to getService() thus returns null and provokes the exception I observed.

I think the initialization of the xmlTracker member must be synchronized.
Comment 1 Simon Kaegi CLA 2009-09-15 12:54:22 EDT
Looks reasonable. Can you provide a patch.
Comment 2 Achim Demelt CLA 2009-09-16 05:14:01 EDT
Created attachment 147282 [details]
Patch for synchronized creation of the ServiceTracker

I'm not overly fond of synchonizing whole methods, but in this case I think it's a viable solution. I also fixed the corresponding releaseXMLParsing() method.
Comment 3 Achim Demelt CLA 2009-09-16 05:16:29 EDT
Oh, I wanted to add that this patch can be applied to CVS HEAD as well as the 3.5 maintenance branch. I think this bugfix should also go into Galileo SR1. But that's your call, of course.
Comment 4 Simon Kaegi CLA 2009-09-16 08:38:36 EDT
Looks good. Thanks Achim.