-->
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.  [ 2 posts ] 
Author Message
 Post subject: nested lazy batchfetch cause ConcurrentModificationException
PostPosted: Thu Feb 11, 2010 8:17 pm 
Newbie

Joined: Mon Feb 01, 2010 1:04 pm
Posts: 6
I get java.util.ConcurrentModificationException due to nested lazy batch fetching:

Analysis of Problem:

It's not a multi-threading issue.

1. MyDataObject2.toString() results in lazy loading of MyDataObject2
2. during lazy loading of MyDataObject2, a org.hibernate.util.EqualsHelper.equals() is triggering lazy loading of MyDataObject1 while still inside of loop iterating over org.hibernate.engine.BatchFetchQueue.batchLoadableEntityKeys in org.hibernate.engine.BatchFetchQueue.getEntityBatch()
3. during lazy loading of MyDataObject1, org.hibernate.engine.BatchFetchQueue.removeBatchLoadableEntityKey modifies org.hibernate.engine.BatchFetchQueue.batchLoadableEntityKeys, will result in ConcurrentModificationException as soon as loop in org.hibernate.engine.BatchFetchQueue.getEntityBatch is continued

How can I prevent that and still use lazy / batch fetching?

Hibernate 3.2.4.sp1 (coming with jboss-4.2.3.GA)

Relevant mapping used (legacy DB + code to be accomodated):
Code:
   <class name="MyDataObject1" mutable="false">
      <composite-id name="MyDataObject1PK">
         <key-property name="MyDataObject1Nr">
         </key-property>
      </composite-id>
...
      <list name="MyDataObject2s">
         <key>
            <column name="MyDataObject1Nr" not-null="true"></column>
         </key>
         <list-index base="1">
            <column name="number" not-null="true"></column>
         </list-index>
         <one-to-many entity-name="MyDataObject2"/>
      </list>
...
   </class>

   <class name="MyDataObject2" mutable="false">
      <composite-id mapped="true">
         <key-many-to-one name="myDataObject1">
            <column name="MyDataObject1Nr" not-null="true"></column>
         </key-many-to-one>
         <key-property name="number">
         </key-property>
      </composite-id>
...
   </class>


Stacktrace of modCount modification responsible for ConcurrentModificationException later on:
Code:
Daemon Thread [Thread-1581] (Suspended (modification of field modCount in org.apache.commons.collections.SequencedHashMap))   
   org.apache.commons.collections.SequencedHashMap.removeImpl(java.lang.Object) line: 472   
   org.apache.commons.collections.SequencedHashMap.remove(java.lang.Object) line: 460   
   org.hibernate.engine.BatchFetchQueue.removeBatchLoadableEntityKey(org.hibernate.engine.EntityKey) line: 130   
   org.hibernate.engine.StatefulPersistenceContext.addEntity(org.hibernate.engine.EntityKey, java.lang.Object) line: 314   
   org.hibernate.engine.StatefulPersistenceContext.addEntity(java.lang.Object, org.hibernate.engine.Status, java.lang.Object[], org.hibernate.engine.EntityKey, java.lang.Object, org.hibernate.LockMode, boolean, org.hibernate.persister.entity.EntityPersister, boolean, boolean) line: 408   
   org.hibernate.engine.TwoPhaseLoad.addUninitializedEntity(org.hibernate.engine.EntityKey, java.lang.Object, org.hibernate.persister.entity.EntityPersister, org.hibernate.LockMode, boolean, org.hibernate.engine.SessionImplementor) line: 240   
   org.hibernate.loader.entity.EntityLoader(org.hibernate.loader.Loader).loadFromResultSet(java.sql.ResultSet, int, java.lang.Object, java.lang.String, org.hibernate.engine.EntityKey, java.lang.String, org.hibernate.LockMode, org.hibernate.persister.entity.Loadable, org.hibernate.engine.SessionImplementor) line: 1366   
   org.hibernate.loader.entity.EntityLoader(org.hibernate.loader.Loader).instanceNotYetLoaded(java.sql.ResultSet, int, org.hibernate.persister.entity.Loadable, java.lang.String, org.hibernate.engine.EntityKey, org.hibernate.LockMode, org.hibernate.engine.EntityKey, java.lang.Object, java.util.List, org.hibernate.engine.SessionImplementor) line: 1308   
   org.hibernate.loader.entity.EntityLoader(org.hibernate.loader.Loader).getRow(java.sql.ResultSet, org.hibernate.persister.entity.Loadable[], org.hibernate.engine.EntityKey[], java.lang.Object, org.hibernate.engine.EntityKey, org.hibernate.LockMode[], java.util.List, org.hibernate.engine.SessionImplementor) line: 1206   
   org.hibernate.loader.entity.EntityLoader(org.hibernate.loader.Loader).getRowFromResultSet(java.sql.ResultSet, org.hibernate.engine.SessionImplementor, org.hibernate.engine.QueryParameters, org.hibernate.LockMode[], org.hibernate.engine.EntityKey, java.util.List, org.hibernate.engine.EntityKey[], boolean) line: 580   
   org.hibernate.loader.entity.EntityLoader(org.hibernate.loader.Loader).doQuery(org.hibernate.engine.SessionImplementor, org.hibernate.engine.QueryParameters, boolean) line: 701   
   org.hibernate.loader.entity.EntityLoader(org.hibernate.loader.Loader).doQueryAndInitializeNonLazyCollections(org.hibernate.engine.SessionImplementor, org.hibernate.engine.QueryParameters, boolean) line: 236   
   org.hibernate.loader.entity.EntityLoader(org.hibernate.loader.Loader).loadEntityBatch(org.hibernate.engine.SessionImplementor, java.io.Serializable[], org.hibernate.type.Type, java.lang.Object, java.lang.String, java.io.Serializable, org.hibernate.persister.entity.EntityPersister) line: 1955   
   org.hibernate.loader.entity.BatchingEntityLoader.load(java.io.Serializable, java.lang.Object, org.hibernate.engine.SessionImplementor) line: 69   
   org.hibernate.persister.entity.SingleTableEntityPersister(org.hibernate.persister.entity.AbstractEntityPersister).load(java.io.Serializable, java.lang.Object, org.hibernate.LockMode, org.hibernate.engine.SessionImplementor) line: 3044   
   org.hibernate.event.def.DefaultLoadEventListener.loadFromDatasource(org.hibernate.event.LoadEvent, org.hibernate.persister.entity.EntityPersister, org.hibernate.engine.EntityKey, org.hibernate.event.LoadEventListener$LoadType) line: 395   
   org.hibernate.event.def.DefaultLoadEventListener.doLoad(org.hibernate.event.LoadEvent, org.hibernate.persister.entity.EntityPersister, org.hibernate.engine.EntityKey, org.hibernate.event.LoadEventListener$LoadType) line: 375   
   org.hibernate.event.def.DefaultLoadEventListener.load(org.hibernate.event.LoadEvent, org.hibernate.persister.entity.EntityPersister, org.hibernate.engine.EntityKey, org.hibernate.event.LoadEventListener$LoadType) line: 139   
   org.hibernate.event.def.DefaultLoadEventListener.onLoad(org.hibernate.event.LoadEvent, org.hibernate.event.LoadEventListener$LoadType) line: 98   
   org.hibernate.impl.SessionImpl.fireLoad(org.hibernate.event.LoadEvent, org.hibernate.event.LoadEventListener$LoadType) line: 878   
   org.hibernate.impl.SessionImpl.immediateLoad(java.lang.String, java.io.Serializable) line: 836   
   org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer(org.hibernate.proxy.AbstractLazyInitializer).initialize() line: 66   
   org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer(org.hibernate.proxy.AbstractLazyInitializer).getImplementation() line: 111   
   org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(java.lang.Object, java.lang.reflect.Method, java.lang.reflect.Method, java.lang.Object[]) line: 166   
   MyDataObject1_$$_javassist_153.equals(java.lang.Object) line: not available   
   org.hibernate.util.EqualsHelper.equals(java.lang.Object, java.lang.Object) line: 10   
   org.hibernate.type.ManyToOneType(org.hibernate.type.AbstractType).isEqual(java.lang.Object, java.lang.Object, org.hibernate.EntityMode) line: 108   
   org.hibernate.type.EmbeddedComponentType(org.hibernate.type.ComponentType).isEqual(java.lang.Object, java.lang.Object, org.hibernate.EntityMode) line: 125   
   org.hibernate.engine.BatchFetchQueue.getEntityBatch(org.hibernate.persister.entity.EntityPersister, java.io.Serializable, int, org.hibernate.EntityMode) line: 226   
   org.hibernate.loader.entity.BatchingEntityLoader.load(java.io.Serializable, java.lang.Object, org.hibernate.engine.SessionImplementor) line: 60   
   org.hibernate.persister.entity.SingleTableEntityPersister(org.hibernate.persister.entity.AbstractEntityPersister).load(java.io.Serializable, java.lang.Object, org.hibernate.LockMode, org.hibernate.engine.SessionImplementor) line: 3044   
   org.hibernate.event.def.DefaultLoadEventListener.loadFromDatasource(org.hibernate.event.LoadEvent, org.hibernate.persister.entity.EntityPersister, org.hibernate.engine.EntityKey, org.hibernate.event.LoadEventListener$LoadType) line: 395   
   org.hibernate.event.def.DefaultLoadEventListener.doLoad(org.hibernate.event.LoadEvent, org.hibernate.persister.entity.EntityPersister, org.hibernate.engine.EntityKey, org.hibernate.event.LoadEventListener$LoadType) line: 375   
   org.hibernate.event.def.DefaultLoadEventListener.load(org.hibernate.event.LoadEvent, org.hibernate.persister.entity.EntityPersister, org.hibernate.engine.EntityKey, org.hibernate.event.LoadEventListener$LoadType) line: 139   
   org.hibernate.event.def.DefaultLoadEventListener.onLoad(org.hibernate.event.LoadEvent, org.hibernate.event.LoadEventListener$LoadType) line: 98   
   org.hibernate.impl.SessionImpl.fireLoad(org.hibernate.event.LoadEvent, org.hibernate.event.LoadEventListener$LoadType) line: 878   
   org.hibernate.impl.SessionImpl.immediateLoad(java.lang.String, java.io.Serializable) line: 836   
   org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer(org.hibernate.proxy.AbstractLazyInitializer).initialize() line: 66   
   org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer(org.hibernate.proxy.AbstractLazyInitializer).getImplementation() line: 111   
   org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(java.lang.Object, java.lang.reflect.Method, java.lang.reflect.Method, java.lang.Object[]) line: 166   
   MyDataObject2_$$_javassist_146.toString() line: not available   
   java.lang.String.valueOf(java.lang.Object) line: 2615   
   java.lang.StringBuilder.append(java.lang.Object) line: 116   
   MyDataObject2.toString() line: 592   
   java.lang.String.valueOf(java.lang.Object) line: 2615   
   java.lang.StringBuilder.append(java.lang.Object) line: 116   


A few steps later:
Code:
this: org.hibernate.engine.BatchFetchQueue.batchLoadableEntityKeys of currents session batch fetch queue

this   SequencedHashMap$OrderedIterator  (id=1753)   
   expectedModCount   27970   
   pos   SequencedHashMap$Entry  (id=1755)   
   returnType   0   
   this$0   SequencedHashMap  (id=1278)   
      entries   HashMap<K,V>  (id=1286)   
      modCount   27975   
      sentinel   SequencedHashMap$Entry  (id=1301)   

Daemon Thread [Thread-1581] (Suspended (exception java.util.ConcurrentModificationException))   
   org.apache.commons.collections.SequencedHashMap$OrderedIterator.next() line: 757   
   org.hibernate.engine.BatchFetchQueue.getEntityBatch(org.hibernate.persister.entity.EntityPersister, java.io.Serializable, int, org.hibernate.EntityMode) line: 220   
   org.hibernate.loader.entity.BatchingEntityLoader.load(java.io.Serializable, java.lang.Object, org.hibernate.engine.SessionImplementor) line: 60   
   org.hibernate.persister.entity.SingleTableEntityPersister(org.hibernate.persister.entity.AbstractEntityPersister).load(java.io.Serializable, java.lang.Object, org.hibernate.LockMode, org.hibernate.engine.SessionImplementor) line: 3044   
   org.hibernate.event.def.DefaultLoadEventListener.loadFromDatasource(org.hibernate.event.LoadEvent, org.hibernate.persister.entity.EntityPersister, org.hibernate.engine.EntityKey, org.hibernate.event.LoadEventListener$LoadType) line: 395   
   org.hibernate.event.def.DefaultLoadEventListener.doLoad(org.hibernate.event.LoadEvent, org.hibernate.persister.entity.EntityPersister, org.hibernate.engine.EntityKey, org.hibernate.event.LoadEventListener$LoadType) line: 375   
   org.hibernate.event.def.DefaultLoadEventListener.load(org.hibernate.event.LoadEvent, org.hibernate.persister.entity.EntityPersister, org.hibernate.engine.EntityKey, org.hibernate.event.LoadEventListener$LoadType) line: 139   
   org.hibernate.event.def.DefaultLoadEventListener.onLoad(org.hibernate.event.LoadEvent, org.hibernate.event.LoadEventListener$LoadType) line: 98   
   org.hibernate.impl.SessionImpl.fireLoad(org.hibernate.event.LoadEvent, org.hibernate.event.LoadEventListener$LoadType) line: 878   
   org.hibernate.impl.SessionImpl.immediateLoad(java.lang.String, java.io.Serializable) line: 836   
   org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer(org.hibernate.proxy.AbstractLazyInitializer).initialize() line: 66   
   org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer(org.hibernate.proxy.AbstractLazyInitializer).getImplementation() line: 111   
   org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(java.lang.Object, java.lang.reflect.Method, java.lang.reflect.Method, java.lang.Object[]) line: 166   
   MyDataObject2_$$_javassist_146.toString() line: not available   
   java.lang.String.valueOf(java.lang.Object) line: 2615   
   java.lang.StringBuilder.append(java.lang.Object) line: 116   
   MyDataObject2.toString() line: 592   


Top
 Profile  
 
 Post subject: Re: nested lazy batchfetch cause ConcurrentModificationException
PostPosted: Thu Feb 11, 2010 8:36 pm 
Newbie

Joined: Mon Feb 01, 2010 1:04 pm
Posts: 6
Ok, a simple lazy="false" prevents the ConcurrentModificationException.

But I still believe it to be a strange behaviour by Hibernate. Should react more robustly, or issue a warning or something. Or even be able to handle the lazy="true" case properly as well.

Code:
   <class name="MyDataObject2" mutable="false">
      <composite-id mapped="true">
         <key-many-to-one name="myDataObject1" lazy="false">
            <column name="MyDataObject1Nr" not-null="true"></column>
         </key-many-to-one>


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 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.