SourceForge.net Logo
Main Overview Wiki Issues Forum Build Fisheye
Issue Details (XML | Word | Printable)

Key: CMP-450
Type: Bug Bug
Status: Closed Closed
Resolution: Duplicate
Priority: Minor Minor
Assignee: Shay Banon
Reporter: Derek Clarkson
Votes: 1
Watchers: 1
Operations

If you were logged in you would be able to see more operations.
Compass

Compass triggers exception in hibernate postflush by accessing un-initialised collections for indexing

Created: 24/Aug/07 02:23 AM   Updated: 18/Sep/08 04:45 PM
Component/s: None
Affects Version/s: 1.1.1, 1.2 RC1
Fix Version/s: 2.1.0 M3

Environment: Spring 2.0.6, hibernate 3.2.1


 Description  « Hide
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 ?



 All   Comments   Change History      Sort Order: Ascending order - Click to sort in descending order
Shay Banon added a comment - 24/Aug/07 10:58 AM
Actually, this is something that was observed and discussed in the forum.

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.


Vincent Bonamy added a comment - 09/Sep/08 10:31 AM

I have the same problem,

In my case, I take the solution to "patch" Hibernate in remove the Assert in org.hibernate.engine.CollectionEntry class of Hibernate [line 205 for hibernate 3.2.5.ga], and it works ... but maybe it can be dangerous in some others cases ...

PS: I didn't find the thread/forum where you discussed about this issue, where is it ?


Shay Banon added a comment - 18/Sep/08 04:45 PM
Already fixed by CMP-704.