[hibernate-commits] Hibernate SVN: r16439 - in search/trunk/src: test/java/org/hibernate/search/test/session and 1 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Sun Apr 26 17:49:47 EDT 2009


Author: sannegrinovero
Date: 2009-04-26 17:49:41 -0400 (Sun, 26 Apr 2009)
New Revision: 16439

Added:
   search/trunk/src/test/java/org/hibernate/search/test/worker/duplication/WorkSequencesTest.java
Modified:
   search/trunk/src/main/java/org/hibernate/search/engine/DocumentBuilderIndexedEntity.java
   search/trunk/src/test/java/org/hibernate/search/test/session/Domain.java
Log:
HSEARCH-353 bugfix (removing an entity and adding another with same PK (in same TX) will not add second entity to index)

Modified: search/trunk/src/main/java/org/hibernate/search/engine/DocumentBuilderIndexedEntity.java
===================================================================
--- search/trunk/src/main/java/org/hibernate/search/engine/DocumentBuilderIndexedEntity.java	2009-04-26 03:21:45 UTC (rev 16438)
+++ search/trunk/src/main/java/org/hibernate/search/engine/DocumentBuilderIndexedEntity.java	2009-04-26 21:49:41 UTC (rev 16439)
@@ -259,16 +259,22 @@
 	//TODO could we use T instead of EntityClass?
 	public void addWorkToQueue(Class<T> entityClass, T entity, Serializable id, WorkType workType, List<LuceneWork> queue, SearchFactoryImplementor searchFactoryImplementor) {
 		//TODO with the caller loop we are in a n^2: optimize it using a HashMap for work recognition
-
+		
+		boolean sameIdWasSetToBeDeleted = false;
 		List<LuceneWork> toDelete = new ArrayList<LuceneWork>();
 		boolean duplicateDelete = false;
 		for ( LuceneWork luceneWork : queue ) {
-			//avoid unecessary duplicated work
-			if ( luceneWork.getEntityClass() == entityClass
-					) {
+			if ( luceneWork.getEntityClass() == entityClass ) {
 				Serializable currentId = luceneWork.getId();
-				//currentId != null => either ADD or Delete work
 				if ( currentId != null && currentId.equals( id ) ) { //find a way to use Type.equals(x,y)
+					if ( luceneWork instanceof DeleteLuceneWork ) {
+						//flag this work as related to a to-be-deleted entity
+						sameIdWasSetToBeDeleted = true;
+					}
+					else if ( luceneWork instanceof AddLuceneWork ) {
+						//if a later work in the queue is adding it back, undo deletion flag:
+						sameIdWasSetToBeDeleted = false;
+					}
 					if ( workType == WorkType.DELETE ) { //TODO add PURGE?
 						//DELETE should have precedence over any update before (HSEARCH-257)
 						//if an Add work is here, remove it
@@ -280,14 +286,23 @@
 							duplicateDelete = true;
 						}
 					}
-					else {
-						//we can safely say we are out, the other work is an ADD
-						return;
+					if ( workType == WorkType.ADD ) {
+						if ( luceneWork instanceof AddLuceneWork ) {
+							//embedded objects may issue an "UPDATE" right before the "ADD",
+							//leading to double insertions in the index
+							toDelete.add( luceneWork );
+						}
 					}
+					//TODO do something to avoid multiple PURGE ALL and OPTIMIZE
 				}
-				//TODO do something to avoid multiple PURGE ALL and OPTIMIZE
 			}
 		}
+
+		if ( sameIdWasSetToBeDeleted && workType == WorkType.COLLECTION ) {
+			//avoid updating (and thus adding) objects which are going to be deleted
+			return;
+		}
+		
 		for ( LuceneWork luceneWork : toDelete ) {
 			queue.remove( luceneWork );
 		}

Modified: search/trunk/src/test/java/org/hibernate/search/test/session/Domain.java
===================================================================
--- search/trunk/src/test/java/org/hibernate/search/test/session/Domain.java	2009-04-26 03:21:45 UTC (rev 16438)
+++ search/trunk/src/test/java/org/hibernate/search/test/session/Domain.java	2009-04-26 21:49:41 UTC (rev 16439)
@@ -19,6 +19,13 @@
 	private Integer id;
 	@Field
 	private String name;
+	
+	public Domain(){ }
+	
+	public Domain(Integer id, String name) {
+		this.id = id;
+		this.name = name;
+	}
 
 	public Integer getId() {
 		return id;

Added: search/trunk/src/test/java/org/hibernate/search/test/worker/duplication/WorkSequencesTest.java
===================================================================
--- search/trunk/src/test/java/org/hibernate/search/test/worker/duplication/WorkSequencesTest.java	                        (rev 0)
+++ search/trunk/src/test/java/org/hibernate/search/test/worker/duplication/WorkSequencesTest.java	2009-04-26 21:49:41 UTC (rev 16439)
@@ -0,0 +1,124 @@
+package org.hibernate.search.test.worker.duplication;
+
+import java.io.IOException;
+
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.TermQuery;
+import org.apache.lucene.search.TopDocs;
+import org.hibernate.Session;
+import org.hibernate.search.FullTextSession;
+import org.hibernate.search.Search;
+import org.hibernate.search.SearchFactory;
+import org.hibernate.search.reader.ReaderProvider;
+import org.hibernate.search.store.DirectoryProvider;
+import org.hibernate.search.test.SearchTestCase;
+import org.hibernate.search.test.session.Domain;
+
+/**
+ * Testcase for HSEARCH-353
+ * Verify that different kinds of work (add/delete) found in the same
+ * queue are all executed; having special care about different entities
+ * being deleted/persisted but sharing the same PK (to replace the old
+ * instance with another one).
+ * 
+ * @author Sanne Grinovero
+ */
+public class WorkSequencesTest extends SearchTestCase {
+	
+	private SearchFactory searchFactory;
+
+	public void testComplexTransactionSequence() throws IOException {
+		Session classicSession = openSession( );
+		FullTextSession session = Search.getFullTextSession( classicSession );
+		searchFactory = session.getSearchFactory();
+		
+		// create some different domains:
+		{
+			session.beginTransaction();
+			session.persist( new Domain( 1, "jboss.org" ) );
+			session.persist( new Domain( 2, "jboss.com" ) );
+			session.persist( new Domain( 3, "hibernate.org" ) );
+			session.persist( new Domain( 4, "geocities.com" ) );
+			session.getTransaction().commit();
+		}
+		assertEquals( 2, countDomainsByFullText( "jboss" ) );
+		assertEquals( 1, countDomainsByFullText( "hibernate" ) );
+		assertEquals( 1, countDomainsByFullText( "geocities" ) );
+		
+		// now create some and delete others:
+		{
+			session.beginTransaction();
+			session.persist( new Domain( 5, "sun.com" ) );
+			session.persist( new Domain( 6, "mysql.com" ) );
+			session.persist( new Domain( 7, "oracle.com" ) );
+			Domain hibernateDomain = (Domain) session.get( Domain.class, 3 );
+			session.delete( hibernateDomain );
+			Domain geocitiesDomain = (Domain) session.get( Domain.class, 4 );
+			session.delete( geocitiesDomain );
+			session.getTransaction().commit();
+		}
+		assertEquals( 0, countDomainsByFullText( "hibernate" ) );
+		assertEquals( 0, countDomainsByFullText( "geocities" ) );
+		assertEquals( 2, countDomainsByFullText( "jboss" ) );
+		assertEquals( 1, countDomainsByFullText( "sun" ) );
+		assertEquals( 1, countDomainsByFullText( "mysql" ) );
+		assertEquals( 1, countDomainsByFullText( "oracle" ) );
+		
+		// use create/update/delete:
+		{
+			session.beginTransaction();
+			session.persist( new Domain( 3, "hibernate.org" ) );
+			Domain mysqlDomain = (Domain) session.get( Domain.class, 6 );
+			session.delete( mysqlDomain );
+			//persisting a new entity having the same PK as a deleted one:
+			session.persist( new Domain( 6, "myhql.org" ) );
+			Domain sunDomain = (Domain) session.get( Domain.class, 5 );
+			sunDomain.setName( "community.oracle.com" );
+			session.getTransaction().commit();
+		}
+		assertEquals( 1, countDomainsByFullText( "hibernate" ) );
+		assertEquals( 2, countDomainsByFullText( "oracle" ) );
+		assertEquals( 1, countDomainsByFullText( "myhql" ) );
+		assertEquals( 1, countDomainsByFullText( "community" ) );
+		assertEquals( 0, countDomainsByFullText( "mysql" ) );
+		
+		// now creating and deleting the "same" (as by pk) entity several times in same transaction:
+		{
+			session.beginTransaction();
+			session.persist( new Domain( 8, "mysql.org" ) );
+			Domain mysqlDomain = (Domain) session.load( Domain.class, 8 );
+			session.delete( mysqlDomain );
+			Domain newDomain = new Domain( 8, "something.org" );
+			session.persist( newDomain );
+			session.delete( newDomain );
+			session.persist( new Domain( 8, "somethingnew.org" ) );
+			session.getTransaction().commit();
+		}
+		assertEquals( 1, countDomainsByFullText(  "somethingnew" ) );
+		
+		session.close();
+	}
+	
+	//helper method to verify how many instances are found in the index by doing a simple FT query
+	private int countDomainsByFullText(String name) throws IOException {
+		Query luceneQuery = new TermQuery( new Term( "name", name ) );
+		DirectoryProvider<?> directoryProvider = searchFactory.getDirectoryProviders( Domain.class )[0];
+		ReaderProvider readerProvider = searchFactory.getReaderProvider();
+		IndexReader reader = readerProvider.openReader( directoryProvider );
+		IndexSearcher searcher = new IndexSearcher( reader );
+		TopDocs topDocs = searcher.search( luceneQuery, null, 100 );
+		readerProvider.closeReader( reader );
+		return topDocs.totalHits;
+	}
+	
+	@Override
+	protected Class<?>[] getMappings() {
+		return new Class[] {
+				Domain.class
+		};
+	}
+	
+}
\ No newline at end of file




More information about the hibernate-commits mailing list