Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 324520 - [Duplicate] Race condition in PlatformResourceURIHandlerImpl.
Summary: [Duplicate] Race condition in PlatformResourceURIHandlerImpl.
Status: CLOSED FIXED
Alias: None
Product: EMF
Classification: Modeling
Component: Core (show other bugs)
Version: 2.7.0   Edit
Hardware: Macintosh Mac OS X
: P3 blocker (vote)
Target Milestone: ---   Edit
Assignee: Ed Merks CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on: 319939
Blocks:
  Show dependency tree
 
Reported: 2010-09-04 13:14 EDT by Ed Merks CLA
Modified: 2010-11-05 05:41 EDT (History)
4 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Ed Merks CLA 2010-09-04 13:14:57 EDT
+++ This bug was initially created as a clone of Bug #319939 +++

The EMF.Core PlatformResourceURIHandlerImpl has one weakness that can lead to a race condition between refreshing Eclipse resources & saving EMF Resources.

To demonstrate this, I wrote an Ant script that executes 2 tasks:
- a cleanup task that deletes ecore resources
- QVTo transformation that creates an ecore resource

When the 2 tasks execute for the first time, there's nothing to cleanup, the QVT transformation executes cleanly:


Buildfile: /Volumes/FMTools/Helios1/runtime.imce/EMF.PlatformResourceURIHandler.RaceConditionBug/build.xml

Clean:

Transform:
[qvto:transformation] QVTo Hello World
[qvto:transformation] Transformation 'platform:/resource/EMF.PlatformResourceURIHandler.RaceConditionBug/transforms/HelloWorld.qvto' has been executed

CleanAndTransform:
BUILD SUCCESSFUL
Total time: 1 second

When invoking the Ant script a second time, the cleanup task deletes the HelloWorld.ecore resource before launching the QVT transformation task.
Because Ant is running in the Eclipse environment, the Eclipse workspace may not have been refreshed between the first and second task.
This exacerbates the weakness in EMF.Core's PlatformResourceURIHandlerImpl enough to trip the following exception:

Buildfile: /Volumes/FMTools/Helios1/runtime.imce/EMF.PlatformResourceURIHandler.RaceConditionBug/build.xml

Clean:
      [delete] Deleting /Volumes/FMTools/Helios1/runtime.imce/EMF.PlatformResourceURIHandler.RaceConditionBug/models/HelloWorld.ecore

Transform:
[qvto:transformation] QVTo Hello World

BUILD FAILED
/Volumes/FMTools/Helios1/runtime.imce/EMF.PlatformResourceURIHandler.RaceConditionBug/build.xml:13: org.eclipse.m2m.internal.qvt.oml.emf.util.EmfException: Failed to save model to platform:/resource/EMF.PlatformResourceURIHandler.RaceConditionBug/models/HelloWorld.ecore 
Failed to save model to platform:/resource/EMF.PlatformResourceURIHandler.RaceConditionBug/models/HelloWorld.ecore 
Resource '/EMF.PlatformResourceURIHandler.RaceConditionBug/models/HelloWorld.ecore' does not exist.

Total time: 1 second

The error message is incorrect; to appreciate this, we need to look at the stack trace information more closely:

!SUBENTRY 1 org.eclipse.ant.core 4 1 2010-07-14 22:13:38.615
!MESSAGE /Volumes/FMTools/Helios1/runtime.imce/EMF.PlatformResourceURIHandler.RaceConditionBug/build.xml:13: org.eclipse.m2m.internal.qvt.oml.emf.util.EmfException: Failed to save model to platform:/resource/EMF.PlatformResourceURIHandler.RaceConditionBug/models/HelloWorld.ecore 
Failed to save model to platform:/resource/EMF.PlatformResourceURIHandler.RaceConditionBug/models/HelloWorld.ecore 
Resource '/EMF.PlatformResourceURIHandler.RaceConditionBug/models/HelloWorld.ecore' does not exist.
!STACK 0
/Volumes/FMTools/Helios1/runtime.imce/EMF.PlatformResourceURIHandler.RaceConditionBug/build.xml:13: org.eclipse.m2m.internal.qvt.oml.emf.util.EmfException: Failed to save model to platform:/resource/EMF.PlatformResourceURIHandler.RaceConditionBug/models/HelloWorld.ecore 
Failed to save model to platform:/resource/EMF.PlatformResourceURIHandler.RaceConditionBug/models/HelloWorld.ecore 
Resource '/EMF.PlatformResourceURIHandler.RaceConditionBug/models/HelloWorld.ecore' does not exist.
	at org.eclipse.m2m.internal.qvt.oml.runtime.ant.QvtoAntTransformationTask.execute(QvtoAntTransformationTask.java:332)
	at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:288)
	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.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
	at org.apache.tools.ant.Task.perform(Task.java:348)
	at org.apache.tools.ant.Target.execute(Target.java:357)
	at org.apache.tools.ant.Target.performTasks(Target.java:385)
	at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1337)
	at org.apache.tools.ant.Project.executeTarget(Project.java:1306)
	at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41)
	at org.eclipse.ant.internal.core.ant.EclipseDefaultExecutor.executeTargets(EclipseDefaultExecutor.java:32)
	at org.apache.tools.ant.Project.executeTargets(Project.java:1189)
	at org.eclipse.ant.internal.core.ant.InternalAntRunner.run(InternalAntRunner.java:662)
	at org.eclipse.ant.internal.core.ant.InternalAntRunner.run(InternalAntRunner.java:495)
	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.ant.core.AntRunner.run(AntRunner.java:378)
	at org.eclipse.ant.internal.launching.launchConfigurations.AntLaunchDelegate$1.run(AntLaunchDelegate.java:298)
	at java.lang.Thread.run(Thread.java:637)
Caused by: org.eclipse.m2m.internal.qvt.oml.common.MdaException: org.eclipse.m2m.internal.qvt.oml.emf.util.EmfException: Failed to save model to platform:/resource/EMF.PlatformResourceURIHandler.RaceConditionBug/models/HelloWorld.ecore 
	at org.eclipse.m2m.internal.qvt.oml.runtime.launch.QvtLaunchConfigurationDelegateBase.saveTransformationResult(QvtLaunchConfigurationDelegateBase.java:256)
	at org.eclipse.m2m.internal.qvt.oml.runtime.launch.QvtLaunchConfigurationDelegateBase.doLaunch(QvtLaunchConfigurationDelegateBase.java:202)
	at org.eclipse.m2m.internal.qvt.oml.runtime.ant.QvtoAntTransformationTask$1.run(QvtoAntTransformationTask.java:317)
	at org.eclipse.m2m.internal.qvt.oml.common.launch.SafeRunner$SameThreadRunner.run(SafeRunner.java:33)
	at org.eclipse.m2m.internal.qvt.oml.common.launch.SafeRunner$1.run(SafeRunner.java:26)
	at org.eclipse.m2m.internal.qvt.oml.runtime.ant.QvtoAntTransformationTask.execute(QvtoAntTransformationTask.java:325)
	... 23 more
Caused by: org.eclipse.m2m.internal.qvt.oml.emf.util.EmfException: Failed to save model to platform:/resource/EMF.PlatformResourceURIHandler.RaceConditionBug/models/HelloWorld.ecore 
	at org.eclipse.m2m.internal.qvt.oml.emf.util.EmfUtil.saveModel(EmfUtil.java:198)
	at org.eclipse.m2m.internal.qvt.oml.runtime.launch.QvtLaunchConfigurationDelegateBase.saveTransformationResult(QvtLaunchConfigurationDelegateBase.java:253)
	... 28 more
Caused by: org.eclipse.emf.ecore.resource.Resource$IOWrappedException: Resource '/EMF.PlatformResourceURIHandler.RaceConditionBug/models/HelloWorld.ecore' does not exist.
	at org.eclipse.emf.ecore.resource.impl.PlatformResourceURIHandlerImpl$PlatformResourceOutputStream.flush(PlatformResourceURIHandlerImpl.java:138)
	at sun.nio.cs.StreamEncoder.implFlush(StreamEncoder.java:278)
	at sun.nio.cs.StreamEncoder.flush(StreamEncoder.java:122)
	at java.io.OutputStreamWriter.flush(OutputStreamWriter.java:212)
	at org.eclipse.emf.ecore.xmi.impl.XMLSaveImpl.write(XMLSaveImpl.java:1010)
	at org.eclipse.emf.ecore.xmi.impl.XMLSaveImpl.save(XMLSaveImpl.java:266)
	at org.eclipse.emf.ecore.xmi.impl.XMLResourceImpl.doSave(XMLResourceImpl.java:206)
	at org.eclipse.emf.ecore.resource.impl.ResourceImpl.save(ResourceImpl.java:1406)
	at org.eclipse.emf.ecore.resource.impl.ResourceImpl.save(ResourceImpl.java:993)
	at org.eclipse.m2m.internal.qvt.oml.emf.util.EmfUtil.saveModel(EmfUtil.java:196)
	... 29 more
Caused by: org.eclipse.core.internal.resources.ResourceException: Resource '/EMF.PlatformResourceURIHandler.RaceConditionBug/models/HelloWorld.ecore' does not exist.
	at org.eclipse.core.internal.resources.Resource.checkExists(Resource.java:326)
	at org.eclipse.core.internal.resources.Resource.checkAccessible(Resource.java:200)
	at org.eclipse.core.internal.resources.File.setContents(File.java:361)
	at org.eclipse.core.internal.resources.File.setContents(File.java:468)
	at org.eclipse.emf.ecore.resource.impl.PlatformResourceURIHandlerImpl$PlatformResourceOutputStream.flush(PlatformResourceURIHandlerImpl.java:131)
	... 38 more
--- Nested Exception ---
org.eclipse.m2m.internal.qvt.oml.common.MdaException: org.eclipse.m2m.internal.qvt.oml.emf.util.EmfException: Failed to save model to platform:/resource/EMF.PlatformResourceURIHandler.RaceConditionBug/models/HelloWorld.ecore 
	at org.eclipse.m2m.internal.qvt.oml.runtime.launch.QvtLaunchConfigurationDelegateBase.saveTransformationResult(QvtLaunchConfigurationDelegateBase.java:256)
	at org.eclipse.m2m.internal.qvt.oml.runtime.launch.QvtLaunchConfigurationDelegateBase.doLaunch(QvtLaunchConfigurationDelegateBase.java:202)
	at org.eclipse.m2m.internal.qvt.oml.runtime.ant.QvtoAntTransformationTask$1.run(QvtoAntTransformationTask.java:317)
	at org.eclipse.m2m.internal.qvt.oml.common.launch.SafeRunner$SameThreadRunner.run(SafeRunner.java:33)
	at org.eclipse.m2m.internal.qvt.oml.common.launch.SafeRunner$1.run(SafeRunner.java:26)
	at org.eclipse.m2m.internal.qvt.oml.runtime.ant.QvtoAntTransformationTask.execute(QvtoAntTransformationTask.java:325)
	at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:288)
	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.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
	at org.apache.tools.ant.Task.perform(Task.java:348)
	at org.apache.tools.ant.Target.execute(Target.java:357)
	at org.apache.tools.ant.Target.performTasks(Target.java:385)
	at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1337)
	at org.apache.tools.ant.Project.executeTarget(Project.java:1306)
	at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41)
	at org.eclipse.ant.internal.core.ant.EclipseDefaultExecutor.executeTargets(EclipseDefaultExecutor.java:32)
	at org.apache.tools.ant.Project.executeTargets(Project.java:1189)
	at org.eclipse.ant.internal.core.ant.InternalAntRunner.run(InternalAntRunner.java:662)
	at org.eclipse.ant.internal.core.ant.InternalAntRunner.run(InternalAntRunner.java:495)
	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.ant.core.AntRunner.run(AntRunner.java:378)
	at org.eclipse.ant.internal.launching.launchConfigurations.AntLaunchDelegate$1.run(AntLaunchDelegate.java:298)
	at java.lang.Thread.run(Thread.java:637)
Caused by: org.eclipse.m2m.internal.qvt.oml.emf.util.EmfException: Failed to save model to platform:/resource/EMF.PlatformResourceURIHandler.RaceConditionBug/models/HelloWorld.ecore 
	at org.eclipse.m2m.internal.qvt.oml.emf.util.EmfUtil.saveModel(EmfUtil.java:198)
	at org.eclipse.m2m.internal.qvt.oml.runtime.launch.QvtLaunchConfigurationDelegateBase.saveTransformationResult(QvtLaunchConfigurationDelegateBase.java:253)
	... 28 more
Caused by: org.eclipse.emf.ecore.resource.Resource$IOWrappedException: Resource '/EMF.PlatformResourceURIHandler.RaceConditionBug/models/HelloWorld.ecore' does not exist.
	at org.eclipse.emf.ecore.resource.impl.PlatformResourceURIHandlerImpl$PlatformResourceOutputStream.flush(PlatformResourceURIHandlerImpl.java:138)
	at sun.nio.cs.StreamEncoder.implFlush(StreamEncoder.java:278)
	at sun.nio.cs.StreamEncoder.flush(StreamEncoder.java:122)
	at java.io.OutputStreamWriter.flush(OutputStreamWriter.java:212)
	at org.eclipse.emf.ecore.xmi.impl.XMLSaveImpl.write(XMLSaveImpl.java:1010)
	at org.eclipse.emf.ecore.xmi.impl.XMLSaveImpl.save(XMLSaveImpl.java:266)
	at org.eclipse.emf.ecore.xmi.impl.XMLResourceImpl.doSave(XMLResourceImpl.java:206)
	at org.eclipse.emf.ecore.resource.impl.ResourceImpl.save(ResourceImpl.java:1406)
	at org.eclipse.emf.ecore.resource.impl.ResourceImpl.save(ResourceImpl.java:993)
	at org.eclipse.m2m.internal.qvt.oml.emf.util.EmfUtil.saveModel(EmfUtil.java:196)
	... 29 more
Caused by: org.eclipse.core.internal.resources.ResourceException: Resource '/EMF.PlatformResourceURIHandler.RaceConditionBug/models/HelloWorld.ecore' does not exist.
	at org.eclipse.core.internal.resources.Resource.checkExists(Resource.java:326)
	at org.eclipse.core.internal.resources.Resource.checkAccessible(Resource.java:200)
	at org.eclipse.core.internal.resources.File.setContents(File.java:361)
	at org.eclipse.core.internal.resources.File.setContents(File.java:468)
	at org.eclipse.emf.ecore.resource.impl.PlatformResourceURIHandlerImpl$PlatformResourceOutputStream.flush(PlatformResourceURIHandlerImpl.java:131)
	... 38 more
	
The problem comes from: org.eclipse.emf.ecore.resource.impl.PlatformResourceURIHandlerImpl$PlatformResourceOutputStream.flush


    @Override
    public void flush() throws IOException
    {
      super.flush();

      if (previouslyFlushed)
      {
        if (count == 0)
        {
          return;
        }
      }
      else
      {
        createContainer(file.getParent());
      }

      byte[] contents = toByteArray();
      InputStream inputStream = new ByteArrayInputStream(contents, 0, contents.length);

      try
      {
        if (previouslyFlushed) // *1*
        {
          file.appendContents(inputStream, force, false, progressMonitor);
        }
        else if (!file.exists()) // *2*
        {
          file.create(inputStream, false, null);
          previouslyFlushed = true;
        }
        else
        { 
          // *3*
          if (!file.isSynchronized(IResource.DEPTH_ONE))
          {
            file.refreshLocal(IResource.DEPTH_ONE, progressMonitor);
          }
          // *4*
          file.setContents(inputStream, force, keepHistory, progressMonitor); // line 131
          previouslyFlushed = true;
        }
        reset();
      }
      catch (CoreException exception)
      {
        throw new Resource.IOWrappedException(exception);
      }
    }

The vulnerability comes from *1* where previouslyFlushed = false and the stale state of the information about files that results from the 1st Cleanup Ant task. 

This stale state results in file.exists() = true at step *2* until the code forces a refresh at step *3*.
However, at step *4*, the information about the file is no longer stale, the file has truly been deleted!
Consequently, the code will fail to execute file.setContents() at line 131 as confirmed by the exception trace:

Caused by: org.eclipse.core.internal.resources.ResourceException: Resource '/EMF.PlatformResourceURIHandler.RaceConditionBug/models/HelloWorld.ecore' does not exist.
	at org.eclipse.core.internal.resources.Resource.checkExists(Resource.java:326)
	at org.eclipse.core.internal.resources.Resource.checkAccessible(Resource.java:200)
	at org.eclipse.core.internal.resources.File.setContents(File.java:361)
	at org.eclipse.core.internal.resources.File.setContents(File.java:468)
	at org.eclipse.emf.ecore.resource.impl.PlatformResourceURIHandlerImpl$PlatformResourceOutputStream.flush(PlatformResourceURIHandlerImpl.java:131)

In this example, at *1*, previouslyFlushed = false.
at *2*, file.exists() = true because of stale information
at *3*, the refresh forces an update of the information; i.e., the file truly does not exist because the previous task deleted it!
Comment 1 Ed Merks CLA 2010-09-04 13:16:57 EDT
The fix is committed to CVS for 2.7.
Comment 2 Ed Merks CLA 2010-11-05 05:41:39 EDT
The fix is available in the latest build for the stream.