You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I ran the "UML2 UML Tests Standalone" test suite quite a few times now and I noticed one occasionally failing test case: Bug332057Test.testConcurrentCacheAdapterAccess()
The exceptions on the console are varying. See my attachment for a selection.
I tested only with the standalone suite (I think this is important, see below).
Bug #332057 and bug #335125 may be related.
As already stated in bug #332057, under debugger control the timing is affected such that the problem is no longer reproducible.
Here's an interesting part of one of the exceptions I saw:
Caused by: org.eclipse.emf.common.util.BasicEList$BasicIndexOutOfBoundsException: index=7, size=8
at org.eclipse.emf.common.util.BasicEList.get(BasicEList.java:346)
at org.eclipse.emf.ecore.resource.impl.URIMappingRegistryImpl.getURI(URIMappingRegistryImpl.java:109)
at org.eclipse.emf.ecore.resource.impl.ExtensibleURIConverterImpl$1.delegatedGetURI(ExtensibleURIConverterImpl.java:473)
at org.eclipse.emf.ecore.resource.impl.URIMappingRegistryImpl.getURI(URIMappingRegistryImpl.java:120)
at org.eclipse.emf.ecore.resource.impl.URIMappingRegistryImpl$URIMapImpl.getURI(URIMappingRegistryImpl.java:162)
at org.eclipse.emf.ecore.resource.impl.ExtensibleURIConverterImpl.normalize(ExtensibleURIConverterImpl.java:407)
at org.eclipse.emf.ecore.resource.impl.ExtensibleURIConverterImpl.normalize(ExtensibleURIConverterImpl.java:446)
at org.eclipse.uml2.common.util.CacheAdapter$InverseCrossReferencer.normalizeURI(CacheAdapter.java:84)
"IndexOutOfBoundsException: index=7, size=8" - This can only be caused by unsynchronized access of multiple threads. The "size" was increased after the argument check was executed but before the exception message was formed.
The other interesting part of that stack trace is "ExtensibleURIConverterImpl$1.delegatedGetURI()". Here the ResourceSet-local URIConverter delegates to some global EMF registry, i.e., URIMappingRegistryImpl.INSTANCE, which is not thread-safe.
I'm starting to think that EMF is really generally not safe in multi-threaded applications. Using separate ResourceSets for different threads probably reduces the risk for actual problems, but never to 0%. And I'm sure that EPackage.Registry.INSTANCE and Resource.Factory.Registry.INSTANCE suffer the same problem.
What makes me feel a bit better, is that modifications to these registries are normally rare and early. This also explains why we don't hear more often about the resulting problems.
In fact the test case Bug332057Test.testConcurrentCacheAdapterAccess() is especially amenable to this kind of problem, and probably even more especially when run in standalone mode. This is because of the code in Bug332057Test.createResourceSet():
if (StandaloneSupport.isStandalone()) {
// init touches some global registries, which may not be accessed
// concurrently by multiple threads, so be careful to avoid
// concurrent modifications and indices out of bounds
synchronized (this) {
StandaloneSupport.init(result);
}
}
Interestingly there is a comment about multi-threading issues! But the "synchronized (this)" there is not sufficient to work around the problem. It only limits the write accesses to a single thread. The other test threads may still read from those registries in parallel, and fail.
I'm starting to think that EMF is really generally not safe in
multi-threaded applications. Using separate ResourceSets for different
threads probably reduces the risk for actual problems, but never to 0%. And
I'm sure that EPackage.Registry.INSTANCE and
Resource.Factory.Registry.INSTANCE suffer the same problem.
EMF is not threadsafe. Full stop.
EMF is perhaps threadsafe if all global context is warmed up before a second thread gets going.
It is the application's responsibility to ensure that such warmup occurs.
This was fine for traditional EMF as a client 'library'.
However once 'live validation' was introduced, EMF became its own application; two threads both supporting org.eclipse.emf code. Some synchronization via the ResourceSet was introduced to mitigate problems. These problems were much worse where live validation of an OCL constraint could activate an OCL parser to populate a compiled constraint cache and everything that goes with it.
Further challenges occur with a concurrent builder/validator.
In this case, I suspect that a JUnit test that provokes a second thread is an invalid test.
(The latest OCL introduces a local validation registry to avoid concurrent fighting in the global validation registry.)
| --- | --- |
| Bugzilla Link | 582660 |
| Status | NEW |
| Importance | P3 normal |
| Reported | Nov 22, 2023 17:09 EDT |
| Modified | Nov 23, 2023 04:52 EDT |
| Version | 5.5.2 |
| Reporter | Eike Stepper |
Description
Created attachment 289233
Exceptions on the console
I ran the "UML2 UML Tests Standalone" test suite quite a few times now and I noticed one occasionally failing test case: Bug332057Test.testConcurrentCacheAdapterAccess()
The exceptions on the console are varying. See my attachment for a selection.
Behavior is based on commit 7601b2c.
I tested only with the standalone suite (I think this is important, see below).
Bug #332057 and bug #335125 may be related.
As already stated in bug #332057, under debugger control the timing is affected such that the problem is no longer reproducible.
Here's an interesting part of one of the exceptions I saw:
Caused by: org.eclipse.emf.common.util.BasicEList$BasicIndexOutOfBoundsException: index=7, size=8
at org.eclipse.emf.common.util.BasicEList.get(BasicEList.java:346)
at org.eclipse.emf.ecore.resource.impl.URIMappingRegistryImpl.getURI(URIMappingRegistryImpl.java:109)
at org.eclipse.emf.ecore.resource.impl.ExtensibleURIConverterImpl$1.delegatedGetURI(ExtensibleURIConverterImpl.java:473)
at org.eclipse.emf.ecore.resource.impl.URIMappingRegistryImpl.getURI(URIMappingRegistryImpl.java:120)
at org.eclipse.emf.ecore.resource.impl.URIMappingRegistryImpl$URIMapImpl.getURI(URIMappingRegistryImpl.java:162)
at org.eclipse.emf.ecore.resource.impl.ExtensibleURIConverterImpl.normalize(ExtensibleURIConverterImpl.java:407)
at org.eclipse.emf.ecore.resource.impl.ExtensibleURIConverterImpl.normalize(ExtensibleURIConverterImpl.java:446)
at org.eclipse.uml2.common.util.CacheAdapter$InverseCrossReferencer.normalizeURI(CacheAdapter.java:84)
"IndexOutOfBoundsException: index=7, size=8" - This can only be caused by unsynchronized access of multiple threads. The "size" was increased after the argument check was executed but before the exception message was formed.
The other interesting part of that stack trace is "ExtensibleURIConverterImpl$1.delegatedGetURI()". Here the ResourceSet-local URIConverter delegates to some global EMF registry, i.e., URIMappingRegistryImpl.INSTANCE, which is not thread-safe.
I'm starting to think that EMF is really generally not safe in multi-threaded applications. Using separate ResourceSets for different threads probably reduces the risk for actual problems, but never to 0%. And I'm sure that EPackage.Registry.INSTANCE and Resource.Factory.Registry.INSTANCE suffer the same problem.
What makes me feel a bit better, is that modifications to these registries are normally rare and early. This also explains why we don't hear more often about the resulting problems.
In fact the test case Bug332057Test.testConcurrentCacheAdapterAccess() is especially amenable to this kind of problem, and probably even more especially when run in standalone mode. This is because of the code in Bug332057Test.createResourceSet():
if (StandaloneSupport.isStandalone()) {
// init touches some global registries, which may not be accessed
// concurrently by multiple threads, so be careful to avoid
// concurrent modifications and indices out of bounds
synchronized (this) {
StandaloneSupport.init(result);
}
}
Interestingly there is a comment about multi-threading issues! But the "synchronized (this)" there is not sufficient to work around the problem. It only limits the write accesses to a single thread. The other test threads may still read from those registries in parallel, and fail.
:notepad_spiral: uml-test-exceptions.txt
The text was updated successfully, but these errors were encountered: