-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 5 posts ] 
Author Message
 Post subject: Entity with concurrent modification safe Map
PostPosted: Fri Apr 05, 2013 2:50 pm 
Newbie

Joined: Fri Apr 05, 2013 2:14 pm
Posts: 3
Hi, I'm using Hibernate 4.0.1 via JPA2 and have an Entity (portfolio) with a collection of entries as follows:

Code:
@ElementCollection (fetch = FetchType.EAGER)
@CollectionTable (name = "portfolio_entry", joinColumns = @JoinColumn (name = "portfolio_id"))
    private final Map<String, Position> positions =
        new ConcurrentHashMap<String, Position>();

I understand that when this entity is created by Hibernate, the map instance is actually a PersistentMap, and not a ConcurrentHashMap. As such, it doesn't support modification while it is being persisted (throws a ConcurrentModificationException as I believe it uses a java.util.HashMap underyling)

Is there any way to have Hibernate use a concurrent modification safe map as the underlying? My application makes rapid changes to the collection on the main application thread, while performing persistence of the entity on a background thread. Given the time taken to persist (merge actually), there are sometime new changes during persistence, which is the issue. I don't have an issue with the persistence lagging behind the live object since the persist operations are queued.

One option is to copy the collection on the background thread and persist the copy. That would work okay, but I'm just wondering if there's a more efficient solution. I'm very much a Hibernate/JPA novice so any advice would be appreciated. In case it's relevant, the entity is always detached after merge.

One thing I tried was:
- fetch the entity from the DB
- construct a new entity object explicitly (i.e. new) so that the map instance is a ConcurrentHashMap
- copy the data from the DB object to the manually created Entity
- use that object in the app and persist it

This led to a different ConcurrentModificationException, this time during commit rather than merge:
Code:
Caused by: java.util.ConcurrentModificationException
   at java.util.LinkedHashMap$LinkedHashIterator.nextEntry(LinkedHashMap.java:373)
   at java.util.LinkedHashMap$EntryIterator.next(LinkedHashMap.java:392)
   at java.util.LinkedHashMap$EntryIterator.next(LinkedHashMap.java:391)
   at org.hibernate.internal.util.collections.IdentityMap.entryArray(IdentityMap.java:164)
   at org.hibernate.internal.util.collections.IdentityMap.concurrentEntries(IdentityMap.java:76)
   at org.hibernate.event.internal.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:147)
   at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:88)
   at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)


Thanks


Top
 Profile  
 
 Post subject: Re: Entity with concurrent modification safe Map
PostPosted: Thu Apr 11, 2013 4:54 am 
Expert
Expert

Joined: Tue Jun 16, 2009 3:36 am
Posts: 990
Hi,

hibernate is as documented not thread-safe.
Working with 2 threads simultaneusly on objects which belong to the same session
usually creates race conditions with unpredictable behaviour and exceptions of various types.
Your approach is rather uncommon and dangerous.

Why do you can't do the persistence task flush/commit in your main thread?
If you can flush/commit rather rarely, then it should not influence your through-put that much.

Quote:
Is there any way to have Hibernate use a concurrent modification safe map as the underlying?


I don't believe it exist.


Quote:
One option is to copy the collection on the background thread and persist the copy.


I think that's a clean and therefore good solution.
I you still have performance problems with such approach,
then I think you have some ask yourself if you can change something in the architekture of the whole thing.


Top
 Profile  
 
 Post subject: Re: Entity with concurrent modification safe Map
PostPosted: Thu Apr 11, 2013 5:22 am 
Newbie

Joined: Fri Apr 05, 2013 2:14 pm
Posts: 3
Hi, thanks for your reply.

The issue with persisting on the main thread is latency. Total throughput isn't really an issue since writes are not that frequent, but unfortunately the main thread can't afford to be delayed by the few milliseconds it takes to persist.

The entity is not managed. For what it's worth, I ended up implementing the copy approach.

I now have a @Transient ConcurrentHashMap and a persisted HashMap. The transient map is populated in a @PostLoad method (needed to upgrade hibernate version to avoid issue HHH-6043 - https://hibernate.atlassian.net/browse/HHH-6043).
Code:
@ElementCollection (fetch = FetchType.EAGER)
@CollectionTable (name = "portfolio_entry", joinColumns = @JoinColumn (name = "portfolio_id"))
private final Map<String, Position> positions =
   new HashMap<String, Position>();

@Transient
private final Map<String, PricedPosition> livePositions =
   new ConcurrentHashMap<String, Position>();

@PostLoad
private final void populateLivePositions() {
   livePositions.putAll(positions);
}

Any changes to the livePositions map are put into a ConcurrentLinkedQueue and during persistence operations, the background thread simply processes any items in the queue to bring the positions map up to date prior to persisting.


Top
 Profile  
 
 Post subject: Re: Entity with concurrent modification safe Map
PostPosted: Thu Apr 11, 2013 5:33 am 
Expert
Expert

Joined: Tue Jun 16, 2009 3:36 am
Posts: 990
Quote:
unfortunately the main thread can't afford to be delayed by the few milliseconds it takes to persist.


Then probably you have also to configure an appropriate Garbage Collector causing only minimal pauses...


Top
 Profile  
 
 Post subject: Re: Entity with concurrent modification safe Map
PostPosted: Thu Apr 11, 2013 5:44 am 
Newbie

Joined: Fri Apr 05, 2013 2:14 pm
Posts: 3
Correct. I use the concurrent low pause collector with an optimized initial heap size and a few other tunings.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 5 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.