Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » EclipseLink » ConcurrentModification Exception in JPA 3.0 Followup(Migration issues from EclipseLink 2.2.0 to EclipseLink 3.0)
ConcurrentModification Exception in JPA 3.0 Followup [message #1840573] Mon, 19 April 2021 15:31 Go to next message
WARREN WEIS is currently offline WARREN WEISFriend
Messages: 8
Registered: April 2021
Junior Member
Hello Eclipselink Forum:
I posted a related topic on this a few weeks ago, and thought I had the issue behind my post fixed, but now I think I do not. This may be an EclipseLink issue, or it may be something to do with the way our application interacts with Eclipselink. Again, I am not sure.

Background:
I work on a very large, very old Swing application that uses Eclipselink as its JPA provider and H2 as its database. The application currently runs on JDK 1.7. It uses EclipseLink version 2.2.0 and H2 1.3.164. Our problem: we must upgrade the application to be JDK 11 compatible. And to do this we must update the Eclipselink version. We've tried updating to Ecipselink 2.7.7 and Eclipselink 3.0. The results are the same:
the application won't start up. It throws a ConcurrentModification exception while loading the entity classes. I have pasted an excerpt of the logs below.

The H2 driver we are using is very old, but upgrading it to the latest version of H2 did not affect the behavior I am seeing, so I do not believe the driver is the issue here.

Analysis:
Our entity classes all extend an abstract class that implements the retrieve and retrieveAll methods for selecting from the database. Both retrieve() and retrieveAll() use Eclipselink's QueryByExample to retrieve. Here is the relevant code for the retrieve() method:

log.info( "retrieve() retrieving entity of type " + getClass() );
Query query = ((JpaEntityManager) entityManager).createQueryByExample( this );
query.setHint( QueryHints.REFRESH, HintValues.TRUE );
query.setHint( QueryHints.REFRESH_CASCADE, CascadePolicy.CascadeAllParts );
result = (T) query.getSingleResult();
log.info( "retrieve() finished retrieving entity of type " + getClass() );


I have put log entries at the beginning and end of each retrieval. As you can see from the log excerpt below all seems to go well, until several retrievals of the InterfaceConfiguration entity class pile up, followed by one of the TouchScreenType class. Then we get the ConcurrentModification exception and nothing goes well after that. This ConcurrentModification exception appears to occur in EclipseLink's caching methods.
I noticed that both InterfaceConfiguration and TouchScreenType had the same annoted relation to another entity class. This leads me to believe the ConcurrentModification exception might occur because the same cache copy of the entity referenced by both TouchScreenType and InterfaceConfigurationType are being updated at the same time. Or, perhaps, TouchScreenType is attempting to get a copy of the cache while the InterfaceConfiguration retrieval is updating it.
Another thing that I tried was changing the query hint for the CASCADE_REFRESH policy. The current code implementation adds this hint to the query prior to execution:


query.setHint( QueryHints.REFRESH_CASCADE, CascadePolicy.CascadeAllParts );


Commenting this line out, does allow the application to get through the startup process. It then fails elsewhere, but not with a ConcurrentModification exception, and probably because of the way the application was written, not because of Eclipselink. So the application does really need this cascade policy query hint.

Conclusion:
The ConcurrentModification exception can be triggered by adding the above hint, or removing it. The current application implementation will not behave properly without this hint, however.
I am faced with a massive rewrite of our application so that we can run our application with EclipseLink 2.77 or above. Or perhaps there is a simple fix that can be made to our configuration of Eclipselink that fixes this.

I sincerely hope that it is the latter and there is someone on the Eclipselink team who can help me with this.


2021-04-18 07:06:50,153 | INFO  [LicenseMonitorThread.InterfaceConfigMonitor]-> com.awi.flexids.flexdb.datamodel.InterfaceConfiguration | retrieveAll() finished retrieving entity of type class com.awi.flexids.flexdb.datamodel.InterfaceConfiguration
2021-04-18 07:06:50,185 | INFO  [ApplicationInitializationThread]-> com.awi.flexids.flexdb.datamodel.InterfaceConfiguration | retrieveAll() retrieving entity of type class com.awi.flexids.flexdb.datamodel.InterfaceConfiguration
2021-04-18 07:06:50,237 | INFO  [ApplicationInitializationThread]-> com.awi.flexids.flexdb.datamodel.InterfaceConfiguration | retrieveAll() finished retrieving entity of type class com.awi.flexids.flexdb.datamodel.InterfaceConfiguration
2021-04-18 07:06:52,994 | INFO  [ASOS Interface]-> com.awi.flexids.flexdb.datamodel.InterfaceConfiguration | retrieveAll() retrieving entity of type class com.awi.flexids.flexdb.datamodel.InterfaceConfiguration
2021-04-18 07:06:52,994 | INFO  [RBDT-0 Interface]-> com.awi.flexids.flexdb.datamodel.InterfaceConfiguration | retrieveAll() retrieving entity of type class com.awi.flexids.flexdb.datamodel.InterfaceConfiguration
2021-04-18 07:06:52,994 | INFO  [RVR Interface]-> com.awi.flexids.flexdb.datamodel.InterfaceConfiguration | retrieveAll() retrieving entity of type class com.awi.flexids.flexdb.datamodel.InterfaceConfiguration
2021-04-18 07:06:52,995 | INFO  [FDIO Interface]-> com.awi.flexids.flexdb.datamodel.InterfaceConfiguration | retrieveAll() retrieving entity of type class com.awi.flexids.flexdb.datamodel.InterfaceConfiguration
2021-04-18 07:06:52,995 | INFO  [SAWS Interface]-> com.awi.flexids.flexdb.datamodel.InterfaceConfiguration | retrieveAll() retrieving entity of type class com.awi.flexids.flexdb.datamodel.InterfaceConfiguration
2021-04-18 07:06:52,996 | INFO  [AWOS Interface]-> com.awi.flexids.flexdb.datamodel.InterfaceConfiguration | retrieveAll() retrieving entity of type class com.awi.flexids.flexdb.datamodel.InterfaceConfiguration
2021-04-18 07:06:52,996 | INFO  [DASI Interface]-> com.awi.flexids.flexdb.datamodel.InterfaceConfiguration | retrieveAll() retrieving entity of type class com.awi.flexids.flexdb.datamodel.InterfaceConfiguration
2021-04-18 07:06:52,996 | INFO  [WME Interface]-> com.awi.flexids.flexdb.datamodel.InterfaceConfiguration | retrieveAll() retrieving entity of type class com.awi.flexids.flexdb.datamodel.InterfaceConfiguration
2021-04-18 07:06:53,013 | INFO  [NetworkMonitorThread]-> com.awi.flexids.flexdb.datamodel.TouchscreenType | retrieve() retrieving entity of type class com.awi.flexids.flexdb.datamodel.TouchscreenType
2021-04-18 07:06:53,270 | WARN  [RBDT-0 Interface]-> com.awi.flexids.flexdb.FlexDBLogger | 
java.util.ConcurrentModificationException: null
	at java.util.HashMap$HashIterator.nextNode(HashMap.java:1493) ~[?:?]
	at java.util.HashMap$KeyIterator.next(HashMap.java:1516) ~[?:?]
	at org.eclipse.persistence.indirection.IndirectSet$1.next(IndirectSet.java:524) ~[eclipselink-3.0.0.jar:3.0.0]
	at org.eclipse.persistence.internal.queries.InterfaceContainerPolicy.next(InterfaceContainerPolicy.java:346) ~[eclipselink-3.0.0.jar:3.0.0]
	at org.eclipse.persistence.internal.queries.ContainerPolicy.next(ContainerPolicy.java:1207) ~[eclipselink-3.0.0.jar:3.0.0]
	at org.eclipse.persistence.mappings.CollectionMapping.buildExpression(CollectionMapping.java:371) ~[eclipselink-3.0.0.jar:3.0.0]
	at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildExpressionFromExample(ObjectBuilder.java:713) ~[eclipselink-3.0.0.jar:3.0.0]
	at org.eclipse.persistence.mappings.CollectionMapping.buildExpression(CollectionMapping.java:373) ~[eclipselink-3.0.0.jar:3.0.0]
	at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildExpressionFromExample(ObjectBuilder.java:713) ~[eclipselink-3.0.0.jar:3.0.0]
Re: ConcurrentModification Exception in JPA 3.0 Followup [message #1840842 is a reply to message #1840573] Mon, 26 April 2021 14:20 Go to previous messageGo to next message
Chris Delahunt is currently offline Chris DelahuntFriend
Messages: 1389
Registered: July 2009
Senior Member
Where and how are your 'this' instance coming from? It is the query trying to go through this object that is causing the problem, which can only occur if this object is shared and accessed in different threads. The refresh query hint (or specifically, the cascade option) might factor into it because if this object is read in using the same query hint, it resets all indirection (lazy relationships) so that they get triggered when they are next accessed. Your application must be reading in these objects and then sharing them among other processes which are accessing these lazy relationships. These objects need to be fully fetched if you are going to share them, and not use the refresh query hints on shared objects, as that can cause them to be refreshed while another process is using them.
Re: ConcurrentModification Exception in JPA 3.0 Followup [message #1840909 is a reply to message #1840842] Wed, 28 April 2021 15:59 Go to previous messageGo to next message
WARREN WEIS is currently offline WARREN WEISFriend
Messages: 8
Registered: April 2021
Junior Member
Thank you so much for responding.
Where is 'this' coming from? If you are asking me where the 'this' in the code snippet above comes from, 'this' is an entity class extending an abstract class with the method this the code above comes from. In other words, something like

@Entity("SOME_TABLE")
public class SomeTable extends AbstractEntity<SomeTable> 
{
...
}

public class AbstractEntity<T extends AbstractEntity>
{
    protected T getMyData()
    {
	...
	
	log.info( "retrieve() retrieving entity of type " + getClass() );
       Query query = ((JpaEntityManager) entityManager).createQueryByExample( this );
       query.setHint( QueryHints.REFRESH, HintValues.TRUE );
       query.setHint( QueryHints.REFRESH_CASCADE, CascadePolicy.CascadeAllParts );
       result = (T) query.getSingleResult();
      log.info( "retrieve() finished retrieving entity of type " + getClass() );
      ...	
    }


I got a copy of the eclipselink3.0 release and put some more debugging in the next() method where the ConcurrentModification exception is being thrown. Here is my new log message:

java.util.ConcurrentModificationException: next() threw ConcurrentModificationException. set type: class IdsPermission, useLazyInstantiation = false
at org.eclipse.persistence.indirection.IndirectSet$1.next(IndirectSet.java:525) ~[eclipselink.jar:3.0.0]
...

IdsPermssion is an entity class with several annotated references in other entity classes, but it doesn't look like any of the references are specifically set to being LAZY fetches. My understanding of JPA is that the default behavior for the fetch of a reference to another entity class is EAGER. Is that correct?
And is it correct to assume that useLazyInstantiation property in the IndirectSet class controls whether the fetch is EAGER or LAZY? IndirectSet is pretty far down the call stack, so it is hard for me to be sure.
Re: ConcurrentModification Exception in JPA 3.0 Followup [message #1841376 is a reply to message #1840909] Thu, 13 May 2021 13:44 Go to previous message
Chris Delahunt is currently offline Chris DelahuntFriend
Messages: 1389
Registered: July 2009
Senior Member
that 'this' is a variable for an instance of SomeTable/Entity was understood - though it helps to show specifics about the entity. My questions though were on where you obtained and built it - how you read it in from the database, as it is that specific instance of the object that is involved in the concurrent modification example. As it suggests, you have more than one process using that ('this') instance and need to figure out what and where they are and stop it. I don't see how EclipseLink should be expected to query using this object as an example if parts of it is changing while it is building the query - it you are going to use these objects concurrently, it is up to the application to manage locking.

As for EAGER vs LAZY - no, that is wrong. single reference relationships (OneToOne, ManyToOne) default to EAGER if a fetchType is unspecified, while collection mappings (OneToMany, ManyToMany etc) default to LAZY. The stack trace in the exception shows you certainly have a lazy collection mapping involved in this concurrency issue.

Assuming you can't reproduce this on demand in a single threaded environment, the main issue isn't with the refresh, the lazy/eager fetching, but with the concurrency. You have an object you are passing to a findbyexample query, which requires EclipseLink to iterate though it to build a query, but you are also using that example object elsewhere in your application. How you find/lookup/build 'this' instance will help you determine how this might be happening
Previous Topic:OneToMany - org.eclipse.persistence.exceptions.DatabaseException
Next Topic:JAXB/Moxy Unmarshalling assigns all field values to Map<String,Object> rather than the specifi
Goto Forum:
  


Current Time: Fri Apr 26 07:25:24 GMT 2024

Powered by FUDForum. Page generated in 1.44241 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top