[hibernate-issues] [Hibernate-JIRA] Created: (HSEARCH-841) after deleting an entity lucene index updating fails due to NullPointerException

Bogdan Butnaru (JIRA) noreply at atlassian.com
Tue Aug 9 14:04:04 EDT 2011


after deleting an entity lucene index updating fails due to NullPointerException
--------------------------------------------------------------------------------

                 Key: HSEARCH-841
                 URL: http://opensource.atlassian.com/projects/hibernate/browse/HSEARCH-841
             Project: Hibernate Search
          Issue Type: Bug
          Components: engine
    Affects Versions: 3.4.0.Final
         Environment: Hibernate 3.4.0 (on MySQL 5.1.54, but any database is affected AFAIK)
            Reporter: Bogdan Butnaru


When entities are deleted, I noticed an exception with a rather large stack trace (below), which appears to be caused by the fact that Lucene is told to remove from the index a document with a null id.

After (quite) a bit of digging, I believe the source is the top of this stack trace:

DocumentBuilderIndexedEntity<T>.getId(Object) line: 662	
WorkPlan$PerClassWork<T>.extractProperId(Work<T>) line: 233	
WorkPlan$PerClassWork<T>.addWork(Work<T>) line: 205	
WorkPlan.addWork(Work<T>) line: 79	
WorkQueue.add(Work) line: 73	
BatchedQueueingProcessor.add(Work, WorkQueue) line: 115	
PostTransactionWorkQueueSynchronization.add(Work) line: 70	
TransactionalWorker.performWork(Work<?>, TransactionContext) line: 81	
FullTextIndexEventListener.processWork(T, Serializable, WorkType, AbstractEvent, boolean) line: 215	
FullTextIndexEventListener.processCollectionEvent(AbstractCollectionEvent) line: 262	
FullTextIndexEventListener.onPostRemoveCollection(PostCollectionRemoveEvent) line: 227	
CollectionRemoveAction.postRemove() line: 146	
CollectionRemoveAction.execute() line: 119	
ActionQueue.execute(Executable) line: 273	
ActionQueue.executeActions(List) line: 265	
ActionQueue.executeActions() line: 186	
EJB3FlushEventListener(AbstractFlushingEventListener).performExecutions(EventSource) line: 321	
EJB3FlushEventListener(DefaultFlushEventListener).onFlush(FlushEvent) line: 51	
SessionImpl.flush() line: 1216	
SessionImpl.managedFlush() line: 383	
JDBCTransaction.commit() line: 133
TransactionImpl.commit() line: 76
[only application-specific lines below here, omitted]

Specifically, org.hibernate.search.engine.DocumentBuilderIndexedEntity.getId(Object) does:

	Object unproxiedEntity = HibernateHelper.unproxy( entity );
	return (Serializable) ReflectionHelper.getMemberValue( unproxiedEntity, idGetter );

As far as I can tell, unproxy(entity) will return an entity with a null id if called during postRemove; the returned result is null, although the debugger says that entity.id actually contains the correct (non-null, pre-deletion) value.

org.hibernate.search.engine.WorkPlan.PerClassWork.extractProperId(Work<T>), right below the top of the stack, does:

if ( entity == null || documentBuilder.requiresProvidedId() ||
	( work.isIdentifierWasRolledBack() && documentBuilder.isIdMatchingJpaId() )) {
		return work.getId();
} else {
	return documentBuilder.getId( entity );
}

This condition fails and goes into the "else" block, which is unfortunate, because work.getId() actually contains the correct value. 

The error doesn't occur right away: org.hibernate.search.engine.WorkPlan.PerClassWork.addWork(Work<T>) (a bit below the top of the stack) calls "entityById.put( id, entityWork );", with id=null due to the above.

A while later the following happens (the bottom two items are the same as the stack trace above):

DocumentBuilderIndexedEntity<T>.addWorkToQueue(Class<T>, T, Serializable, boolean, boolean, boolean, List<LuceneWork>) line: 355	
WorkPlan$PerEntityWork<T>.enqueueLuceneWork(Class<T>, Serializable, AbstractDocumentBuilder<T>, List<LuceneWork>) line: 449	
WorkPlan$PerClassWork<T>.enqueueLuceneWork(List<LuceneWork>) line: 250	
WorkPlan.getPlannedLuceneWork() line: 150	
WorkQueue.prepareWorkPlan() line: 134	
BatchedQueueingProcessor.prepareWorks(WorkQueue) line: 124	
PostTransactionWorkQueueSynchronization.beforeCompletion() line: 89	
EventSourceTransactionContext$DelegateToSynchronizationOnBeforeTx.doBeforeTransactionCompletion(SessionImplementor) line: 172	
ActionQueue$BeforeTransactionCompletionProcessQueue.beforeTransactionCompletion() line: 543	
ActionQueue.beforeTransactionCompletion() line: 216	
SessionImpl.beforeTransactionCompletion(Transaction) line: 571	
JDBCContext.beforeTransactionCompletion(Transaction) line: 250	
JDBCTransaction.commit() line: 138	
TransactionImpl.commit() line: 76	

The entry at the top belongs to 

public void addWorkToQueue(Class<T> entityClass, T entity, Serializable id, boolean delete, boolean add, boolean batch, List<LuceneWork> queue) {
	String idInString = objectToString( idBridge, idKeywordName, id );
	if ( delete ) {
		queue.add( new DeleteLuceneWork( id, idInString, entityClass ) );
	}
	if ( add ) {
		queue.add( createAddWork( entityClass, entity, id, idInString, HibernateStatelessInitializer.INSTANCE, batch ) );
	}
}

The argument delete is true and id is null (it's the value of WorkPlan$PerClassWork<T>.enqueueLuceneWork(List<LuceneWork>) gets it from the documentBuilder.getId(entity) call mentioned above). A little while later the actual exception is triggered:


java.lang.NullPointerException
	at org.apache.lucene.index.Term.compareTo(Term.java:115)
	at org.apache.lucene.index.TermInfosReader.getIndexOffset(TermInfosReader.java:189)
	at org.apache.lucene.index.TermInfosReader.get(TermInfosReader.java:268)
	at org.apache.lucene.index.TermInfosReader.get(TermInfosReader.java:208)
	at org.apache.lucene.index.SegmentTermDocs.seek(SegmentTermDocs.java:57)
	at org.apache.lucene.index.BufferedDeletes.applyDeletes(BufferedDeletes.java:312)
	at org.apache.lucene.index.BufferedDeletes.applyDeletes(BufferedDeletes.java:289)
	at org.apache.lucene.index.BufferedDeletes.applyDeletes(BufferedDeletes.java:191)
	at org.apache.lucene.index.IndexWriter.doFlush(IndexWriter.java:3358)
	at org.apache.lucene.index.IndexWriter.flush(IndexWriter.java:3296)
	at org.apache.lucene.index.IndexWriter.closeInternal(IndexWriter.java:1836)
	at org.apache.lucene.index.IndexWriter.close(IndexWriter.java:1800)
	at org.apache.lucene.index.IndexWriter.close(IndexWriter.java:1764)
	at org.hibernate.search.backend.Workspace.closeIndexWriter(Workspace.java:244)
	at org.hibernate.search.backend.impl.lucene.PerDPQueueProcessor.run(PerDPQueueProcessor.java:113)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
	at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
	at java.util.concurrent.FutureTask.run(FutureTask.java:138)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
	at java.lang.Thread.run(Thread.java:662)
ERROR o.h.s.e.i.LogErrorHandler - Exception occurred java.lang.NullPointerException
Primary Failure:
	Entity com.dragg.server.model.Walk  Id null  Work Type  org.hibernate.search.backend.DeleteLuceneWork
Subsequent failures:
	Entity com.dragg.server.model.Walk  Id null  Work Type  org.hibernate.search.backend.AddLuceneWork
	Entity com.dragg.server.model.Walk  Id 5552  Work Type  org.hibernate.search.backend.DeleteLuceneWork

java.lang.NullPointerException
	at org.apache.lucene.index.Term.compareTo(Term.java:115)
	at org.apache.lucene.index.TermInfosReader.getIndexOffset(TermInfosReader.java:189)
	at org.apache.lucene.index.TermInfosReader.get(TermInfosReader.java:268)
	at org.apache.lucene.index.TermInfosReader.get(TermInfosReader.java:208)
	at org.apache.lucene.index.SegmentTermDocs.seek(SegmentTermDocs.java:57)
	at org.apache.lucene.index.BufferedDeletes.applyDeletes(BufferedDeletes.java:312)
	at org.apache.lucene.index.BufferedDeletes.applyDeletes(BufferedDeletes.java:289)
	at org.apache.lucene.index.BufferedDeletes.applyDeletes(BufferedDeletes.java:191)
	at org.apache.lucene.index.IndexWriter.doFlush(IndexWriter.java:3358)
	at org.apache.lucene.index.IndexWriter.flush(IndexWriter.java:3296)
	at org.apache.lucene.index.IndexWriter.closeInternal(IndexWriter.java:1836)
	at org.apache.lucene.index.IndexWriter.close(IndexWriter.java:1800)
	at org.apache.lucene.index.IndexWriter.close(IndexWriter.java:1764)
	at org.hibernate.search.backend.Workspace.closeIndexWriter(Workspace.java:244)
	at org.hibernate.search.backend.impl.lucene.PerDPQueueProcessor.run(PerDPQueueProcessor.java:113)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
	at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
	at java.util.concurrent.FutureTask.run(FutureTask.java:138)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
	at java.lang.Thread.run(Thread.java:662)

org.apache.lucene.index.Term.compareTo fails because this.id is null, having received its value a bit earlier from the null document id above. (Technically, I think this also a bug in lucene; surrounding code, for example Term.equals, does test for null, so either Term.compareTo should do it, or the Term should have been checked for null quite a while earlier. Anyway, the results would have been the same, except for easier debugging.)



--
This message is automatically generated by JIRA.
For more information on JIRA, see: http://www.atlassian.com/software/jira

        


More information about the hibernate-issues mailing list