[hibernate-issues] [Hibernate-JIRA] Updated: (HHH-2645) Synchronization bottleneck in EntityModeToTuplizerMapping
Paul Cowan (JIRA)
noreply at atlassian.com
Sun Oct 21 20:12:39 EDT 2007
[ http://opensource.atlassian.com/projects/hibernate/browse/HHH-2645?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Paul Cowan updated HHH-2645:
----------------------------
Attachment: concurrentreader.patch
Attached is a patch against 3.2.4sp1 which makes the change that Erik suggested.
Note that this isn't QUITE a 100% replacement; this will introduce 2 behavioural changes which will need to be checked; I don't see either as being a problem from my code inspection but I'm hardly an expert.
1) Previously, the code was using a SequencedHashMap; this guarantees insertion order when navigating the entries in guessEntityMode(). This means that if the same Tuplizer is added twice for two different EntityModes, then the behaviour of guessEntityMode changes from 'first-one-added wins' to 'who knows'. If the same Tuplizer cannot be added twice (it seems so, from a code inspection of ComponentEntityModeToTuplizerMapping and EntityEntityModeToTuplizerMapping, but I'm not 100% sure) then this is not an issue.
2) ConcurrentReaderHashMap, like HashTable, does NOT allow null to be used as a key or value. This is, again, a behaviour change, but again, from inspection of the above two classes it's pretty clear that no nulls are ever passed in (in fact, they're wrapped in an explicit check).
Otherwise, it's fairly straightforward.
> Synchronization bottleneck in EntityModeToTuplizerMapping
> ---------------------------------------------------------
>
> Key: HHH-2645
> URL: http://opensource.atlassian.com/projects/hibernate/browse/HHH-2645
> Project: Hibernate3
> Issue Type: Patch
> Components: core
> Affects Versions: 3.2.3, 3.2.4, 3.2.4.sp1
> Environment: Hibernate 3.2.3 (and later), Sun's JDK 1.4.2_12 (server VM) on SunOS 5.10, Oracle 10g R2
> Reporter: Erik Bergersjö
> Priority: Minor
> Attachments: concurrentreader.patch
>
>
> We have had a major performance bottleneck in EntityModeToTuplizerMapping with Hibernate version 3.2.3 and the code for that class in 3.2.4sp1 is unchanged. We have found a solution that solves the issue and would like to get it into the real version. I submitted to the user forum first and was asked to create a JIRA issue.
> The problematic line is:
> private final Map tuplizers = Collections.synchronizedMap( new SequencedHashMap() );
> We have changed it to (using util.concurrent):
> private final Map tuplizers = new EDU.oswego.cs.dl.util.concurrent.ConcurrentReaderHashMap();
> This change alone makes our use cases six times faster. The difference is that ConcurrentReaderHashMap handles concurrent readers much better, they don't have to wait for each other.
> The problem occurs when a high number of threads try to initialize sets (see mapping below). A thread dump showed a high number of threads waiting for the same monitor, see partial stack trace below.
> The code runs on Sun's JDK 1.4.2_12 (server VM) on SunOS 5.10 and the kernel spends a lot of time handling mutexes with the original implementation. That time disappears from the radar screen with the fixed version.
> Example mapping for set:
> [code]
> <set name="lines" lazy="true" inverse="true" cascade="all-delete-orphan">
> <key>
> <column name="col1" not-null="true" />
> <column name="col2" not-null="true" />
> </key>
> <one-to-many class="LineClass" />
> </set>
> [/code]
> Stack trace (partial):
> "Thread-108" prio=5 tid=0x05852e90 nid=0x103 waiting for monitor entry [0x3ed7e000..0x3ed7fc28]
> at java.util.Collections$SynchronizedMap.get(Collections.java:1942)
> - waiting to lock <0x89d30788> (a java.util.Collections$SynchronizedMap)
> at org.hibernate.tuple.EntityModeToTuplizerMapping.getTuplizerOrNull(EntityModeToTuplizerMapping.java:53)
> at org.hibernate.tuple.EntityModeToTuplizerMapping.getTuplizer(EntityModeToTuplizerMapping.java:66)
> at org.hibernate.type.ComponentType.getPropertyValues(ComponentType.java:353)
> at org.hibernate.type.ComponentType.isEqual(ComponentType.java:141)
> at org.hibernate.engine.CollectionKey.equals(CollectionKey.java:50)
> at java.util.HashMap.eq(HashMap.java:274)
> at java.util.HashMap.get(HashMap.java:323)
> at org.hibernate.engine.loading.CollectionLoadContext.getLocalLoadingCollectionEntry(CollectionLoadContext.java:163)
> at org.hibernate.engine.loading.CollectionLoadContext.locateLoadingCollectionEntry(CollectionLoadContext.java:150)
> at org.hibernate.engine.loading.CollectionLoadContext.getLoadingCollection(CollectionLoadContext.java:92)
> at org.hibernate.loader.Loader.readCollectionElement(Loader.java:1003)
> at org.hibernate.loader.Loader.readCollectionElements(Loader.java:646)
> at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:591)
> at org.hibernate.loader.Loader.doQuery(Loader.java:701)
> at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:236)
> at org.hibernate.loader.Loader.loadCollection(Loader.java:1994)
> at org.hibernate.loader.collection.CollectionLoader.initialize(CollectionLoader.java:36)
> at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:565)
> at org.hibernate.event.def.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:60)
> at org.hibernate.impl.SessionImpl.initializeCollection(SessionImpl.java:1716)
> at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:344)
> at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:86)
> at org.hibernate.collection.PersistentSet.iterator(PersistentSet.java:163)
>
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: http://opensource.atlassian.com/projects/hibernate/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira
More information about the hibernate-issues
mailing list