| Summary: | IndexOfBoundsException during unload | ||
|---|---|---|---|
| Product: | [Modeling] MDT.UML2 | Reporter: | Rafael Chaves <eclipse> |
| Component: | Core | Assignee: | UML2 Inbox <mdt-uml2-inbox> |
| Status: | VERIFIED FIXED | QA Contact: | |
| Severity: | normal | ||
| Priority: | P3 | CC: | alex.tugarev, Kenn.Hussey |
| Version: | unspecified | ||
| Target Milestone: | --- | ||
| Hardware: | PC | ||
| OS: | Windows 7 | ||
| Whiteboard: | |||
Exception in thread "Thread-1" org.eclipse.emf.common.util.BasicEList$BasicIndexOutOfBoundsException: index=20, size=20 at org.eclipse.emf.common.util.BasicEList.remove(BasicEList.java:608) at org.eclipse.emf.ecore.util.ECrossReferenceAdapter$InverseCrossReferencer.remove(ECrossReferenceAdapter.java:216) at org.eclipse.emf.ecore.util.ECrossReferenceAdapter.unsetTarget(ECrossReferenceAdapter.java:765) at org.eclipse.uml2.common.util.CacheAdapter.unsetTarget(CacheAdapter.java:325) at org.eclipse.emf.ecore.util.ECrossReferenceAdapter.unsetTarget(ECrossReferenceAdapter.java:744) at org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1.didRemove(MinimalEObjectImpl.java:510) at org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1.didRemove(MinimalEObjectImpl.java:1) at org.eclipse.emf.common.util.ArrayDelegatingEList.remove(ArrayDelegatingEList.java:656) at org.eclipse.emf.common.util.AbstractEList.remove(AbstractEList.java:466) at org.eclipse.emf.ecore.util.ECrossReferenceAdapter.removeAdapter(ECrossReferenceAdapter.java:825) at org.eclipse.emf.ecore.util.ECrossReferenceAdapter.unsetTarget(ECrossReferenceAdapter.java:781) at org.eclipse.uml2.common.util.CacheAdapter.unsetTarget(CacheAdapter.java:325) at org.eclipse.emf.ecore.util.ECrossReferenceAdapter.unsetTarget(ECrossReferenceAdapter.java:744) at org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1.didRemove(MinimalEObjectImpl.java:510) at org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1.didRemove(MinimalEObjectImpl.java:1) at org.eclipse.emf.common.util.ArrayDelegatingEList.remove(ArrayDelegatingEList.java:656) at org.eclipse.emf.common.util.AbstractEList.remove(AbstractEList.java:466) at org.eclipse.emf.ecore.util.ECrossReferenceAdapter.removeAdapter(ECrossReferenceAdapter.java:825) at org.eclipse.emf.ecore.util.ECrossReferenceAdapter.unsetTarget(ECrossReferenceAdapter.java:781) at org.eclipse.uml2.common.util.CacheAdapter.unsetTarget(CacheAdapter.java:325) at org.eclipse.emf.ecore.util.ECrossReferenceAdapter.unsetTarget(ECrossReferenceAdapter.java:744) at org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1.didRemove(MinimalEObjectImpl.java:510) at org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1.didRemove(MinimalEObjectImpl.java:1) at org.eclipse.emf.common.util.ArrayDelegatingEList.remove(ArrayDelegatingEList.java:656) at org.eclipse.emf.common.util.AbstractEList.remove(AbstractEList.java:466) at org.eclipse.emf.ecore.util.ECrossReferenceAdapter.removeAdapter(ECrossReferenceAdapter.java:825) at org.eclipse.emf.ecore.util.ECrossReferenceAdapter.unsetTarget(ECrossReferenceAdapter.java:781) at org.eclipse.uml2.common.util.CacheAdapter.unsetTarget(CacheAdapter.java:325) at org.eclipse.emf.ecore.util.ECrossReferenceAdapter.unsetTarget(ECrossReferenceAdapter.java:744) at org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1.didRemove(MinimalEObjectImpl.java:510) at org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1.didRemove(MinimalEObjectImpl.java:1) at org.eclipse.emf.common.util.ArrayDelegatingEList.remove(ArrayDelegatingEList.java:656) at org.eclipse.emf.common.util.AbstractEList.remove(AbstractEList.java:466) at org.eclipse.emf.ecore.util.ECrossReferenceAdapter.removeAdapter(ECrossReferenceAdapter.java:825) at org.eclipse.emf.ecore.util.ECrossReferenceAdapter.unsetTarget(ECrossReferenceAdapter.java:781) at org.eclipse.uml2.common.util.CacheAdapter.unsetTarget(CacheAdapter.java:325) at org.eclipse.emf.ecore.util.ECrossReferenceAdapter.unsetTarget(ECrossReferenceAdapter.java:744) at org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1.didRemove(MinimalEObjectImpl.java:510) at org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1.didRemove(MinimalEObjectImpl.java:1) at org.eclipse.emf.common.util.AbstractEList.didClear(AbstractEList.java:172) at org.eclipse.emf.common.util.ArrayDelegatingEList.clear(ArrayDelegatingEList.java:705) at org.eclipse.emf.ecore.resource.impl.ResourceImpl.unloaded(ResourceImpl.java:1560) at org.eclipse.emf.ecore.resource.impl.ResourceImpl.doUnload(ResourceImpl.java:1619) at org.eclipse.emf.ecore.xmi.impl.XMLResourceImpl.doUnload(XMLResourceImpl.java:506) at org.eclipse.emf.ecore.resource.impl.ResourceImpl.unload(ResourceImpl.java:1634) at com.abstratt.mdd.core.util.MDDUtil.unloadResource(MDDUtil.java:464) at com.abstratt.mdd.core.util.MDDUtil.unloadResources(MDDUtil.java:460) at com.abstratt.mdd.core.util.MDDUtil.unloadResources(MDDUtil.java:455) at com.abstratt.mdd.internal.core.Repository.dispose(Repository.java:302) at com.abstratt.mdd.core.tests.LeakTest$1.run(LeakTest.java:152) at java.lang.Thread.run(Unknown Source) The NPE case: Exception in thread "Thread-18" java.lang.NullPointerException at org.eclipse.emf.ecore.util.ECrossReferenceAdapter$InverseCrossReferencer.remove(ECrossReferenceAdapter.java:208) at org.eclipse.emf.ecore.util.ECrossReferenceAdapter.unsetTarget(ECrossReferenceAdapter.java:765) at org.eclipse.uml2.common.util.CacheAdapter.unsetTarget(CacheAdapter.java:325) at org.eclipse.emf.ecore.util.ECrossReferenceAdapter.unsetTarget(ECrossReferenceAdapter.java:744) at org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1.didRemove(MinimalEObjectImpl.java:510) at org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1.didRemove(MinimalEObjectImpl.java:1) at org.eclipse.emf.common.util.ArrayDelegatingEList.remove(ArrayDelegatingEList.java:656) at org.eclipse.emf.common.util.AbstractEList.remove(AbstractEList.java:466) at org.eclipse.emf.ecore.util.ECrossReferenceAdapter.removeAdapter(ECrossReferenceAdapter.java:825) at org.eclipse.emf.ecore.util.ECrossReferenceAdapter.unsetTarget(ECrossReferenceAdapter.java:781) at org.eclipse.uml2.common.util.CacheAdapter.unsetTarget(CacheAdapter.java:325) at org.eclipse.emf.ecore.util.ECrossReferenceAdapter.unsetTarget(ECrossReferenceAdapter.java:744) at org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1.didRemove(MinimalEObjectImpl.java:510) at org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1.didRemove(MinimalEObjectImpl.java:1) at org.eclipse.emf.common.util.ArrayDelegatingEList.remove(ArrayDelegatingEList.java:656) at org.eclipse.emf.common.util.AbstractEList.remove(AbstractEList.java:466) at org.eclipse.emf.ecore.util.ECrossReferenceAdapter.removeAdapter(ECrossReferenceAdapter.java:825) at org.eclipse.emf.ecore.util.ECrossReferenceAdapter.unsetTarget(ECrossReferenceAdapter.java:781) at org.eclipse.uml2.common.util.CacheAdapter.unsetTarget(CacheAdapter.java:325) at org.eclipse.emf.ecore.util.ECrossReferenceAdapter.unsetTarget(ECrossReferenceAdapter.java:744) at org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1.didRemove(MinimalEObjectImpl.java:510) at org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1.didRemove(MinimalEObjectImpl.java:1) at org.eclipse.emf.common.util.ArrayDelegatingEList.remove(ArrayDelegatingEList.java:656) at org.eclipse.emf.common.util.AbstractEList.remove(AbstractEList.java:466) at org.eclipse.emf.ecore.util.ECrossReferenceAdapter.removeAdapter(ECrossReferenceAdapter.java:825) at org.eclipse.emf.ecore.util.ECrossReferenceAdapter.unsetTarget(ECrossReferenceAdapter.java:781) at org.eclipse.uml2.common.util.CacheAdapter.unsetTarget(CacheAdapter.java:325) at org.eclipse.emf.ecore.util.ECrossReferenceAdapter.unsetTarget(ECrossReferenceAdapter.java:744) at org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1.didRemove(MinimalEObjectImpl.java:510) at org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1.didRemove(MinimalEObjectImpl.java:1) at org.eclipse.emf.common.util.ArrayDelegatingEList.remove(ArrayDelegatingEList.java:656) at org.eclipse.emf.common.util.AbstractEList.remove(AbstractEList.java:466) at org.eclipse.emf.ecore.util.ECrossReferenceAdapter.removeAdapter(ECrossReferenceAdapter.java:825) at org.eclipse.emf.ecore.util.ECrossReferenceAdapter.unsetTarget(ECrossReferenceAdapter.java:781) at org.eclipse.uml2.common.util.CacheAdapter.unsetTarget(CacheAdapter.java:325) at org.eclipse.emf.ecore.util.ECrossReferenceAdapter.unsetTarget(ECrossReferenceAdapter.java:744) at org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1.didRemove(MinimalEObjectImpl.java:510) at org.eclipse.emf.ecore.impl.MinimalEObjectImpl$1.didRemove(MinimalEObjectImpl.java:1) at org.eclipse.emf.common.util.AbstractEList.didClear(AbstractEList.java:172) at org.eclipse.emf.common.util.ArrayDelegatingEList.clear(ArrayDelegatingEList.java:705) at org.eclipse.emf.ecore.resource.impl.ResourceImpl.unloaded(ResourceImpl.java:1560) at org.eclipse.emf.ecore.resource.impl.ResourceImpl.doUnload(ResourceImpl.java:1619) at org.eclipse.emf.ecore.xmi.impl.XMLResourceImpl.doUnload(XMLResourceImpl.java:506) at org.eclipse.emf.ecore.resource.impl.ResourceImpl.unload(ResourceImpl.java:1634) at com.abstratt.mdd.core.util.MDDUtil.unloadResource(MDDUtil.java:464) at com.abstratt.mdd.core.util.MDDUtil.unloadResources(MDDUtil.java:460) at com.abstratt.mdd.core.util.MDDUtil.unloadResources(MDDUtil.java:455) at com.abstratt.mdd.internal.core.Repository.dispose(Repository.java:302) at com.abstratt.mdd.core.tests.LeakTest$1.run(LeakTest.java:152) at java.lang.Thread.run(Unknown Source) Just found this in CacheAdapter.selfAdapt:
Object notifier = notification.getNotifier();
if (notifier instanceof Resource
&& notification.getFeatureID(Resource.class) == Resource.RESOURCE__IS_LOADED) {
if (notification.getNewBooleanValue()) {
unloadedResources.remove(notifier);
for (Notifier child : ((Resource) notifier).getContents()) {
addAdapter(child);
}
} else {
unloadedResources.add((Resource) notifier);
Note than unloadedResources is modified/read without any synchronization. That means two threads unloading resources at the same time may cause data corruption on the unloadedResources set.
Not sure this is causing the issues I am seeing, maybe a different issue, but is looks fishy nevertheless.
To be frank, the fact that CacheAdapter is a singleton and the underlying ECrossReferenceAdapter does not seem to be meant to be thread-safe makes me think the whole global CacheAdapter approach to be unworkable for any multi-threaded application.
I don't understand the code well enough, so I may be wrong and the issue may be fixable.
I did look into replacing cache adapter with a different implementation (that I would reimplement to keep data per thread - using ThreadLocal, for instance) but some of the data is kept at the level of ECrossReferenceAdapter so I wouldn't be able to ensure that data is accessed in a thread safe way.
Do the changes attached to bug 335125 address this issue? See also bug 332057 for what appears to be a related issue (and workaround). Any chance this is making it to Juno? I have been running with a modified version of UML2 for a year and a half now just because of this issue. It would be great if I could just use UML2 as is. From my point of view, these changes are pretty safe and small and address a clear issue. (In reply to comment #5) > Any chance this is making it to Juno? I have been running with a modified > version of UML2 for a year and a half now just because of this issue. It would > be great if I could just use UML2 as is. OK, so the patch attached to bug 335125 fixes this issue for you? Marking this bug as fixed now that changes for bug 335125 are available in an integration build. If you think there's something more that can be done in UML2 for this issue, please feel free to re-open it. Sorry, wasn't getting emails from Bugzilla, yes, never seen this again. |
I am seeing different failures during resource unloading deep in CacheAdapter code. Sometimes it is an infinite loop. Sometimes a NPE. Sometimes a IOBE. Sometimes a memory leak. That leads me to believe there is a thread safety issue in CacheAdapter. My code for unloading a resource set is as follows: public static void unloadResources(ResourceSet resourceSet) { for (Resource resource : resourceSet.getResources()) current.unload(); } The first resources are always: pathmap://UML_METAMODELS/UML.metamodel.uml pathmap://UML_PROFILES/Ecore.profile.uml pathmap://UML_PROFILES/Standard.profile.uml pathmap://UML_METAMODELS/Ecore.metamodel.uml pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml The rest is made of my own profiles, models etc. My test case builds a model, a profile and applies the profile to it. After persisting the model, it unloads all resources. It does that in several threads at the same time, each of their own resource set. At this point I don't have a standalone test case that would allow you to easily reproduce it. I hope the stack trace I will include soon can give you an idea of what the problem can be.