
|
If you were logged in you would be able to see more operations.
|
|
|
|
Environment:
|
Spring 2.0.6, hibernate 3.2.1
|
|
First heres the compass declaration from our configs:
<compass:compass name="compass" txManager="transactionManager">
<compass:connection>
<compass:file path="target/test-index" />
</compass:connection>
<compass:mappings>
<compass:resource location="au/com/aegeon/newyellow/model/Listing.cpm.xml"/>
<compass:resource location="au/com/aegeon/newyellow/model/ListingAddress.cpm.xml"/>
<compass:resource location="au/com/aegeon/newyellow/model/ListingCategory.cpm.xml"/>
<compass:resource location="au/com/aegeon/newyellow/model/ListingCategoryKeyword.cpm.xml"/>
</compass:mappings>
<compass:settings>
<compass:setting name="compass.transaction.factory"
value="org.compass.spring.transaction.SpringSyncTransactionFactory"/>
</compass:settings>
</compass:compass>
<bean id="hibernateGpsDevice" class="org.compass.gps.device.hibernate.HibernateGpsDevice">
<property name="name" value="hibernateDevice" />
<property name="nativeExtractor">
<bean class="org.compass.spring.device.hibernate.SpringNativeHibernateExtractor" />
</property>
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="compassGps" class="org.compass.gps.impl.SingleCompassGps" init-method="start" destroy-method="stop">
<property name="compass" ref="compass" />
<property name="gpsDevices">
<list>
<bean class="org.compass.spring.device.SpringSyncTransactionGpsDeviceWrapper">
<property name="gpsDevice" ref="hibernateGpsDevice" />
</bean>
</list>
</property>
</bean>
Our domain model is quite simple in this area, a Listing contains a set of ListingCategories and eacy ListingCategory contains a set of keywords.
We have a spring controller which through a series of calls to our service layer, triggers an update on a Listing. When the tomcat has been recently started and hibernate's caches are fairly empty we get the following error from this controller:
DEBUG - org.compass.gps.device.hibernate.lifecycle.HibernateEventListener.onPostUpdate(113) | {hibernateDevice}: Updating [au.com.aegeon.newyellow.listing.spi.ListingImpl@279]
DEBUG - org.compass.spring.transaction.SpringSyncTransaction.begin(77) | Joining Spring transaction, and starting a new compass transaction on thread [main] with isolation [null]
DEBUG - org.compass.spring.transaction.SpringSyncTransaction.join(100) | Joining an existing compass transcation on thread [main]
DEBUG - org.compass.core.lucene.engine.LuceneSettings.createTransLog(215) | Using Trans Log [org.apache.lucene.index.RAMTransLog]
DEBUG - org.compass.core.lucene.engine.LuceneSearchEngine.delete(324) | RESOURCE DELETE {listing} [stored/uncompressed,indexed,omitNorms<$/listing/id:4>]
DEBUG - org.compass.core.lucene.engine.LuceneSearchEngine.create(344) | RESOURCE CREATE {listing} [stored/uncompressed,indexed,omitNorms<alias:listing>],[stored/uncompressed,indexed,omitNorms<$/listing/id:4>],[stored/uncompressed,indexed,tokenized<name:Thai Pothong Restaurant>],[stored/uncompressed,indexed,tokenized<city:Melbourne>],[stored/uncompressed,indexed,tokenized<state:AL>],[stored/uncompressed,indexed,tokenized<postcode:3001>],[stored/uncompressed,indexed,omitNorms<$/listing/listingCategories/id:2>],[stored/uncompressed,indexed,tokenized<categoryName:Restaurants - Take Away>],[stored/uncompressed,indexed,omitNorms<$/listing/listingCategories/keywords/id:5>],[stored/uncompressed,indexed,tokenized<categoryKeywordName:delivery>],[stored/uncompressed,indexed,omitNorms<$/listing/listingCategories/keywords/id:4>],[stored/uncompressed,indexed,tokenized<categoryKeywordName:food>],[stored/uncompressed,indexed,omitNorms<$/listing/listingCategories/keywords/colSize:2>],[stored/uncompressed,indexed,omitNorms<$/listing/listingCategories/colSize:1>],[indexed,tokenized<all:alias,name,city,state,postcode,categoryName,categoryKeywordName,categoryKeywordName>]
DEBUG - org.compass.spring.transaction.SpringSyncTransaction.doCommit(107) | Not committing transaction since compass does not control it on thread [main]
ERROR - org.hibernate.AssertionFailure.<init>(22) | an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session)
org.hibernate.AssertionFailure: collection [au.com.aegeon.newyellow.listing.spi.ListingCategoryImpl.keywords] was not processed by flush()
at org.hibernate.engine.CollectionEntry.postFlush(CollectionEntry.java:205)
at org.hibernate.event.def.AbstractFlushingEventListener.postFlush(AbstractFlushingEventListener.java:333)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:28)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:575)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:662)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:632)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:314)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:117)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:166)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
at $Proxy11.save(Unknown Source)
at au.com.aegeon.newyellow.web.controller.component.RatingComponent.create(RatingComponent.java:80)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at au.com.aegeon.newyellow.web.controller.strategy.MethodDelgatingOnSubmitStrategy.onSubmit(MethodDelgatingOnSubmitStrategy.java:36)
at au.com.aegeon.newyellow.web.controller.strategy.ComponentMethodDelegatingOnSubmitStrategy.onSubmit(ComponentMethodDelegatingOnSubmitStrategy.java:34)
at au.com.aegeon.newyellow.web.controller.AbstractBaseFormController.onSubmit(AbstractBaseFormController.java:66)
at org.springframework.web.servlet.mvc.SimpleFormController.processFormSubmission(SimpleFormController.java:267)
at org.springframework.web.servlet.mvc.AbstractFormController.handleRequestInternal(AbstractFormController.java:250)
at org.springframework.web.servlet.mvc.AbstractController.handleRequest(AbstractController.java:153)
at au.com.aegeon.newyellow.web.controller.component.RatingComponentIntegrationTest.testForCompassException(RatingComponentIntegrationTest.java:117)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at junit.framework.TestCase.runTest(TestCase.java:164)
at junit.framework.TestCase.runBare(TestCase.java:130)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:120)
at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
DEBUG - org.compass.spring.transaction.SpringSyncTransaction$SpringTransactionSynchronization.afterCompletion(231) | Rolling back compass transaction using Spring synchronization afterCompletion on thread [main]
After much playing around and looking into this (with 5 developers!) we think that what is going on is that in order for compass to reindex the listings data, it is accessing collections in the listing and listing category which have not previously been accessed (due to lazy loading). This appears to be happening during hibernate's flush routine. Looking into the hibernate code, if hibernate finds a collection in the post flush method which has not be tagged by the preflush method (which will occur if compass causes a lazy load to happen) it then throws this exception.
Any thoughts ?
|
|
Description
|
First heres the compass declaration from our configs:
<compass:compass name="compass" txManager="transactionManager">
<compass:connection>
<compass:file path="target/test-index" />
</compass:connection>
<compass:mappings>
<compass:resource location="au/com/aegeon/newyellow/model/Listing.cpm.xml"/>
<compass:resource location="au/com/aegeon/newyellow/model/ListingAddress.cpm.xml"/>
<compass:resource location="au/com/aegeon/newyellow/model/ListingCategory.cpm.xml"/>
<compass:resource location="au/com/aegeon/newyellow/model/ListingCategoryKeyword.cpm.xml"/>
</compass:mappings>
<compass:settings>
<compass:setting name="compass.transaction.factory"
value="org.compass.spring.transaction.SpringSyncTransactionFactory"/>
</compass:settings>
</compass:compass>
<bean id="hibernateGpsDevice" class="org.compass.gps.device.hibernate.HibernateGpsDevice">
<property name="name" value="hibernateDevice" />
<property name="nativeExtractor">
<bean class="org.compass.spring.device.hibernate.SpringNativeHibernateExtractor" />
</property>
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="compassGps" class="org.compass.gps.impl.SingleCompassGps" init-method="start" destroy-method="stop">
<property name="compass" ref="compass" />
<property name="gpsDevices">
<list>
<bean class="org.compass.spring.device.SpringSyncTransactionGpsDeviceWrapper">
<property name="gpsDevice" ref="hibernateGpsDevice" />
</bean>
</list>
</property>
</bean>
Our domain model is quite simple in this area, a Listing contains a set of ListingCategories and eacy ListingCategory contains a set of keywords.
We have a spring controller which through a series of calls to our service layer, triggers an update on a Listing. When the tomcat has been recently started and hibernate's caches are fairly empty we get the following error from this controller:
DEBUG - org.compass.gps.device.hibernate.lifecycle.HibernateEventListener.onPostUpdate(113) | {hibernateDevice}: Updating [au.com.aegeon.newyellow.listing.spi.ListingImpl@279]
DEBUG - org.compass.spring.transaction.SpringSyncTransaction.begin(77) | Joining Spring transaction, and starting a new compass transaction on thread [main] with isolation [null]
DEBUG - org.compass.spring.transaction.SpringSyncTransaction.join(100) | Joining an existing compass transcation on thread [main]
DEBUG - org.compass.core.lucene.engine.LuceneSettings.createTransLog(215) | Using Trans Log [org.apache.lucene.index.RAMTransLog]
DEBUG - org.compass.core.lucene.engine.LuceneSearchEngine.delete(324) | RESOURCE DELETE {listing} [stored/uncompressed,indexed,omitNorms<$/listing/id:4>]
DEBUG - org.compass.core.lucene.engine.LuceneSearchEngine.create(344) | RESOURCE CREATE {listing} [stored/uncompressed,indexed,omitNorms<alias:listing>],[stored/uncompressed,indexed,omitNorms<$/listing/id:4>],[stored/uncompressed,indexed,tokenized<name:Thai Pothong Restaurant>],[stored/uncompressed,indexed,tokenized<city:Melbourne>],[stored/uncompressed,indexed,tokenized<state:AL>],[stored/uncompressed,indexed,tokenized<postcode:3001>],[stored/uncompressed,indexed,omitNorms<$/listing/listingCategories/id:2>],[stored/uncompressed,indexed,tokenized<categoryName:Restaurants - Take Away>],[stored/uncompressed,indexed,omitNorms<$/listing/listingCategories/keywords/id:5>],[stored/uncompressed,indexed,tokenized<categoryKeywordName:delivery>],[stored/uncompressed,indexed,omitNorms<$/listing/listingCategories/keywords/id:4>],[stored/uncompressed,indexed,tokenized<categoryKeywordName:food>],[stored/uncompressed,indexed,omitNorms<$/listing/listingCategories/keywords/colSize:2>],[stored/uncompressed,indexed,omitNorms<$/listing/listingCategories/colSize:1>],[indexed,tokenized<all:alias,name,city,state,postcode,categoryName,categoryKeywordName,categoryKeywordName>]
DEBUG - org.compass.spring.transaction.SpringSyncTransaction.doCommit(107) | Not committing transaction since compass does not control it on thread [main]
ERROR - org.hibernate.AssertionFailure.<init>(22) | an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session)
org.hibernate.AssertionFailure: collection [au.com.aegeon.newyellow.listing.spi.ListingCategoryImpl.keywords] was not processed by flush()
at org.hibernate.engine.CollectionEntry.postFlush(CollectionEntry.java:205)
at org.hibernate.event.def.AbstractFlushingEventListener.postFlush(AbstractFlushingEventListener.java:333)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:28)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:575)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:662)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:632)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:314)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:117)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:166)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
at $Proxy11.save(Unknown Source)
at au.com.aegeon.newyellow.web.controller.component.RatingComponent.create(RatingComponent.java:80)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at au.com.aegeon.newyellow.web.controller.strategy.MethodDelgatingOnSubmitStrategy.onSubmit(MethodDelgatingOnSubmitStrategy.java:36)
at au.com.aegeon.newyellow.web.controller.strategy.ComponentMethodDelegatingOnSubmitStrategy.onSubmit(ComponentMethodDelegatingOnSubmitStrategy.java:34)
at au.com.aegeon.newyellow.web.controller.AbstractBaseFormController.onSubmit(AbstractBaseFormController.java:66)
at org.springframework.web.servlet.mvc.SimpleFormController.processFormSubmission(SimpleFormController.java:267)
at org.springframework.web.servlet.mvc.AbstractFormController.handleRequestInternal(AbstractFormController.java:250)
at org.springframework.web.servlet.mvc.AbstractController.handleRequest(AbstractController.java:153)
at au.com.aegeon.newyellow.web.controller.component.RatingComponentIntegrationTest.testForCompassException(RatingComponentIntegrationTest.java:117)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at junit.framework.TestCase.runTest(TestCase.java:164)
at junit.framework.TestCase.runBare(TestCase.java:130)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:120)
at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
DEBUG - org.compass.spring.transaction.SpringSyncTransaction$SpringTransactionSynchronization.afterCompletion(231) | Rolling back compass transaction using Spring synchronization afterCompletion on thread [main]
After much playing around and looking into this (with 5 developers!) we think that what is going on is that in order for compass to reindex the listings data, it is accessing collections in the listing and listing category which have not previously been accessed (due to lazy loading). This appears to be happening during hibernate's flush routine. Looking into the hibernate code, if hibernate finds a collection in the post flush method which has not be tagged by the preflush method (which will occur if compass causes a lazy load to happen) it then throws this exception.
Any thoughts ?
|
Show » |
|
Ways to solve this, as you noted, is remove the lazy association, or programmatically load the collection before flush.
The question is, what Compass can do? I have opened an issue in Hibernate to maybe support this, and was ignored. At the end of the day, there isn't something that Compass can do. It relies on the Hibernate events to apply changes to the domain model into the search engine, and the timing of when they are loaded.