[hibernate-commits] Hibernate SVN: r11695 - in trunk/HibernateExt/search/src: java/org/hibernate/search/backend and 8 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Tue Jun 19 18:07:51 EDT 2007


Author: epbernard
Date: 2007-06-19 18:07:51 -0400 (Tue, 19 Jun 2007)
New Revision: 11695

Added:
   trunk/HibernateExt/search/src/java/org/hibernate/search/store/optimization/
   trunk/HibernateExt/search/src/java/org/hibernate/search/store/optimization/IncrementalOptimizerStrategy.java
   trunk/HibernateExt/search/src/java/org/hibernate/search/store/optimization/NoOpOptimizerStrategy.java
   trunk/HibernateExt/search/src/java/org/hibernate/search/store/optimization/OptimizerStrategy.java
   trunk/HibernateExt/search/src/test/org/hibernate/search/test/optimizer/
   trunk/HibernateExt/search/src/test/org/hibernate/search/test/optimizer/Construction.java
   trunk/HibernateExt/search/src/test/org/hibernate/search/test/optimizer/IncrementalOptimizerStrategyTest.java
   trunk/HibernateExt/search/src/test/org/hibernate/search/test/optimizer/OptimizerTestCase.java
   trunk/HibernateExt/search/src/test/org/hibernate/search/test/optimizer/Worker.java
Modified:
   trunk/HibernateExt/search/src/java/org/hibernate/search/Version.java
   trunk/HibernateExt/search/src/java/org/hibernate/search/backend/Workspace.java
   trunk/HibernateExt/search/src/java/org/hibernate/search/backend/impl/lucene/LuceneWorker.java
   trunk/HibernateExt/search/src/java/org/hibernate/search/engine/SearchFactoryImplementor.java
   trunk/HibernateExt/search/src/java/org/hibernate/search/impl/SearchFactoryImpl.java
   trunk/HibernateExt/search/src/java/org/hibernate/search/store/DirectoryProviderFactory.java
   trunk/HibernateExt/search/src/test/log4j.properties
Log:
HSEARCH-73 HSEARCH-83 OptimizerStrategy and incremental optimizer implementation

Modified: trunk/HibernateExt/search/src/java/org/hibernate/search/Version.java
===================================================================
--- trunk/HibernateExt/search/src/java/org/hibernate/search/Version.java	2007-06-19 05:44:02 UTC (rev 11694)
+++ trunk/HibernateExt/search/src/java/org/hibernate/search/Version.java	2007-06-19 22:07:51 UTC (rev 11695)
@@ -10,7 +10,7 @@
  * @author Emmanuel Bernard
  */
 public class Version {
-	public static final String VERSION = "3.0.0.Beta3"; //SNAPSHOT" + new Date();
+	public static final String VERSION = "3.0.0.Beta4SNAPSHOT" + new Date();
 	private static Log log = LogFactory.getLog( Version.class );
 
 	static {

Modified: trunk/HibernateExt/search/src/java/org/hibernate/search/backend/Workspace.java
===================================================================
--- trunk/HibernateExt/search/src/java/org/hibernate/search/backend/Workspace.java	2007-06-19 05:44:02 UTC (rev 11694)
+++ trunk/HibernateExt/search/src/java/org/hibernate/search/backend/Workspace.java	2007-06-19 22:07:51 UTC (rev 11695)
@@ -2,20 +2,23 @@
 package org.hibernate.search.backend;
 
 import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 import java.util.concurrent.locks.ReentrantLock;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.analysis.SimpleAnalyzer;
 import org.hibernate.search.engine.DocumentBuilder;
 import org.hibernate.search.engine.SearchFactoryImplementor;
 import org.hibernate.search.SearchException;
 import org.hibernate.search.store.DirectoryProvider;
+import org.hibernate.search.store.optimization.OptimizerStrategy;
 import org.hibernate.annotations.common.AssertionFailure;
 
 /**
@@ -35,7 +38,9 @@
 	private Map<DirectoryProvider, IndexReader> readers = new HashMap<DirectoryProvider, IndexReader>();
 	private Map<DirectoryProvider, IndexWriter> writers = new HashMap<DirectoryProvider, IndexWriter>();
 	private List<DirectoryProvider> lockedProviders = new ArrayList<DirectoryProvider>();
+	private Map<DirectoryProvider, DPStatistics> dpStatistics = new HashMap<DirectoryProvider, DPStatistics>();
 	private SearchFactoryImplementor searchFactoryImplementor;
+	
 
 	public Workspace(SearchFactoryImplementor searchFactoryImplementor) {
 		this.searchFactoryImplementor = searchFactoryImplementor;
@@ -46,7 +51,14 @@
 		return searchFactoryImplementor.getDocumentBuilders().get( entity );
 	}
 
-	public IndexReader getIndexReader(Class entity) {
+	/**
+	 * Retrieve an IndexWriter for a given entity
+	 *
+	 * @param entity entity processed
+	 * @param modificationOperation true if the modification is expected to be an idnex state change
+	 * @return appropriate indexWriter
+	 */
+	public IndexReader getIndexReader(Class entity, boolean modificationOperation) {
 		//TODO NPEs
 		DirectoryProvider provider = searchFactoryImplementor.getDirectoryProvider( entity );
 		//one cannot access a reader for update after a writer has been accessed
@@ -55,6 +67,7 @@
 		IndexReader reader = readers.get( provider );
 		if ( reader != null ) return reader;
 		lockProvider( provider );
+		dpStatistics.get(provider).operations++;
 		try {
 			reader = IndexReader.open( provider.getDirectory() );
 			readers.put( provider, reader );
@@ -65,8 +78,24 @@
 		return reader;
 	}
 
-	public IndexWriter getIndexWriter(Class entity) {
+	/**
+	 * Retrieve an IndexWriter for a given entity
+	 *
+	 * @param entity entity processed
+	 * @param modificationOperation true if the modification is expected to be an idnex state change
+	 * @return appropriate indexWriter
+	 */
+	public IndexWriter getIndexWriter(Class entity, boolean modificationOperation) {
 		DirectoryProvider provider = searchFactoryImplementor.getDirectoryProvider( entity );
+		return getIndexWriter( provider, entity, modificationOperation );
+	}
+
+	//for optimization
+	public IndexWriter getIndexWriter(DirectoryProvider provider) {
+		return getIndexWriter( provider, null, false );
+	}
+
+	private IndexWriter getIndexWriter(DirectoryProvider provider, Class entity, boolean modificationOperation) {
 		//one has to close a reader for update before a writer is accessed
 		IndexReader reader = readers.get( provider );
 		if ( reader != null ) {
@@ -81,14 +110,18 @@
 		IndexWriter writer = writers.get( provider );
 		if ( writer != null ) return writer;
 		lockProvider( provider );
+		dpStatistics.get(provider).operations++;
 		try {
-			writer = new IndexWriter(
-					provider.getDirectory(), searchFactoryImplementor.getDocumentBuilders().get( entity ).getAnalyzer(), false
-			); //have been created at init time
+			Analyzer analyzer = entity != null ?
+					searchFactoryImplementor.getDocumentBuilders().get( entity ).getAnalyzer() :
+					new SimpleAnalyzer(); //never used
+			writer = new IndexWriter( provider.getDirectory(), analyzer, false ); //have been created at init time
 			writers.put( provider, writer );
 		}
 		catch (IOException e) {
-			cleanUp( new SearchException( "Unable to open IndexWriter for " + entity, e ) );
+			cleanUp(
+				new SearchException( "Unable to open IndexWriter" + ( entity != null ? " for " + entity : "" ), e )
+			);
 		}
 		return writer;
 	}
@@ -100,6 +133,7 @@
 		if ( !lock.isHeldByCurrentThread() ) {
 			lock.lock();
 			lockedProviders.add( provider );
+			dpStatistics.put( provider, new DPStatistics() );
 		}
 	}
 
@@ -119,6 +153,26 @@
 				}
 			}
 		}
+		readers.clear();
+		//TODO release lock of all indexes that do not need optimization early
+		//don't optimze if there is a failure
+		if (raisedException == null) {
+			for ( DirectoryProvider provider : lockedProviders ) {
+				Workspace.DPStatistics stats = dpStatistics.get(provider);
+				if (!stats.optimizationForced) {
+					OptimizerStrategy optimizerStrategy = searchFactoryImplementor.getOptimizerStrategy( provider );
+					optimizerStrategy.addTransaction( stats.operations );
+					try {
+						optimizerStrategy.optimize( this );
+					}
+					catch( SearchException e ) {
+						raisedException = new SearchException( "Exception while optimizing directoryProvider: "
+								+ provider.getDirectory().toString(), e );
+						break; //no point in continuing
+					}
+				}
+			}
+		}
 		for ( IndexWriter writer : writers.values() ) {
 			try {
 				writer.close();
@@ -135,9 +189,9 @@
 		for ( DirectoryProvider provider : lockedProviders ) {
 			searchFactoryImplementor.getLockableDirectoryProviders().get( provider ).unlock();
 		}
-		readers.clear();
 		writers.clear();
 		lockedProviders.clear();
+		dpStatistics.clear();
 		if ( raisedException != null ) throw raisedException;
 	}
 
@@ -147,4 +201,17 @@
 	public void clean() {
 		cleanUp( null );
 	}
+
+	public void optimize(Class entity) {
+		DirectoryProvider provider = searchFactoryImplementor.getDirectoryProvider( entity );
+		OptimizerStrategy optimizerStrategy = searchFactoryImplementor.getOptimizerStrategy( provider );
+		dpStatistics.get(provider).optimizationForced = true;
+		optimizerStrategy.optimizationForced();
+	}
+
+	private class DPStatistics {
+		boolean optimizationForced = false;
+		public long operations;
+	}
+
 }

Modified: trunk/HibernateExt/search/src/java/org/hibernate/search/backend/impl/lucene/LuceneWorker.java
===================================================================
--- trunk/HibernateExt/search/src/java/org/hibernate/search/backend/impl/lucene/LuceneWorker.java	2007-06-19 05:44:02 UTC (rev 11694)
+++ trunk/HibernateExt/search/src/java/org/hibernate/search/backend/impl/lucene/LuceneWorker.java	2007-06-19 22:07:51 UTC (rev 11695)
@@ -58,7 +58,7 @@
 	private void add(Class entity, Serializable id, Document document) {
 		if ( log.isTraceEnabled() )
 			log.trace( "add to Lucene index: " + entity + "#" + id + ": " + document );
-		IndexWriter writer = workspace.getIndexWriter( entity );
+		IndexWriter writer = workspace.getIndexWriter( entity, true );
 		try {
 			writer.addDocument( document );
 		}
@@ -82,7 +82,7 @@
 		log.trace( "remove from Lucene index: " + entity + "#" + id );
 		DocumentBuilder builder = workspace.getDocumentBuilder( entity );
 		Term term = builder.getTerm( id );
-		IndexReader reader = workspace.getIndexReader( entity );
+		IndexReader reader = workspace.getIndexReader( entity, true );
 		TermDocs termDocs = null;
 		try {
 			//TODO is there a faster way?
@@ -117,9 +117,10 @@
 			log.trace( "optimize Lucene index: " + entity );
 		//TODO get a batchIndexWriter of some kind that deals with different merge factors and all
 		//TODO this one should not compete with a regular IndexWriter (ie exception from the workspace)
-		IndexWriter writer = workspace.getIndexWriter( entity );
+		IndexWriter writer = workspace.getIndexWriter( entity, false );
 		try {
 			writer.optimize();
+			workspace.optimize(entity);
 		}
 		catch (IOException e) {
 			throw new SearchException( "Unable to optimize Lucene index: " + entity, e );

Modified: trunk/HibernateExt/search/src/java/org/hibernate/search/engine/SearchFactoryImplementor.java
===================================================================
--- trunk/HibernateExt/search/src/java/org/hibernate/search/engine/SearchFactoryImplementor.java	2007-06-19 05:44:02 UTC (rev 11694)
+++ trunk/HibernateExt/search/src/java/org/hibernate/search/engine/SearchFactoryImplementor.java	2007-06-19 22:07:51 UTC (rev 11695)
@@ -6,6 +6,7 @@
 
 import org.hibernate.search.SearchFactory;
 import org.hibernate.search.store.DirectoryProvider;
+import org.hibernate.search.store.optimization.OptimizerStrategy;
 import org.hibernate.search.backend.BackendQueueProcessorFactory;
 import org.hibernate.search.backend.Worker;
 
@@ -22,4 +23,8 @@
 	Map<DirectoryProvider, ReentrantLock> getLockableDirectoryProviders();
 
 	Worker getWorker();
+
+	void addOptimizerStrategy(DirectoryProvider<?> provider, OptimizerStrategy optimizerStrategy);
+
+	public OptimizerStrategy getOptimizerStrategy(DirectoryProvider<?> provider);
 }

Modified: trunk/HibernateExt/search/src/java/org/hibernate/search/impl/SearchFactoryImpl.java
===================================================================
--- trunk/HibernateExt/search/src/java/org/hibernate/search/impl/SearchFactoryImpl.java	2007-06-19 05:44:02 UTC (rev 11694)
+++ trunk/HibernateExt/search/src/java/org/hibernate/search/impl/SearchFactoryImpl.java	2007-06-19 22:07:51 UTC (rev 11695)
@@ -32,6 +32,7 @@
 import org.hibernate.search.reader.ReaderProviderFactory;
 import org.hibernate.search.store.DirectoryProvider;
 import org.hibernate.search.store.DirectoryProviderFactory;
+import org.hibernate.search.store.optimization.OptimizerStrategy;
 import org.hibernate.util.ReflectHelper;
 
 /**
@@ -49,6 +50,8 @@
 	//keep track of the index modifiers per DirectoryProvider since multiple entity can use the same directory provider
 	private Map<DirectoryProvider, ReentrantLock> lockableDirectoryProviders =
 			new HashMap<DirectoryProvider, ReentrantLock>();
+	private Map<DirectoryProvider, OptimizerStrategy> dirProviderOptimizerStrategies =
+			new HashMap<DirectoryProvider, OptimizerStrategy>();
 	private Worker worker;
 	private ReaderProvider readerProvider;
 	private BackendQueueProcessorFactory backendQueueProcessorFactory;
@@ -104,6 +107,7 @@
 				XClass mappedXClass = reflectionManager.toXClass( mappedClass );
 				if ( mappedXClass != null && mappedXClass.isAnnotationPresent( Indexed.class ) ) {
 					DirectoryProvider provider = factory.createDirectoryProvider( mappedXClass, cfg, this );
+					//TODO move that into DirectoryProviderFactory
 					if ( !lockableDirectoryProviders.containsKey( provider ) ) {
 						lockableDirectoryProviders.put( provider, new ReentrantLock() );
 					}
@@ -154,6 +158,14 @@
 		return worker;
 	}
 
+	public void addOptimizerStrategy(DirectoryProvider<?> provider, OptimizerStrategy optimizerStrategy) {
+		dirProviderOptimizerStrategies.put( provider, optimizerStrategy );
+	}
+
+	public OptimizerStrategy getOptimizerStrategy(DirectoryProvider<?> provider) {
+		return dirProviderOptimizerStrategies.get( provider );
+	}
+
 	public ReaderProvider getReaderProvider() {
 		return readerProvider;
 	}

Modified: trunk/HibernateExt/search/src/java/org/hibernate/search/store/DirectoryProviderFactory.java
===================================================================
--- trunk/HibernateExt/search/src/java/org/hibernate/search/store/DirectoryProviderFactory.java	2007-06-19 05:44:02 UTC (rev 11694)
+++ trunk/HibernateExt/search/src/java/org/hibernate/search/store/DirectoryProviderFactory.java	2007-06-19 22:07:51 UTC (rev 11695)
@@ -11,6 +11,9 @@
 import org.hibernate.search.annotations.Indexed;
 import org.hibernate.search.impl.SearchFactoryImpl;
 import org.hibernate.search.engine.SearchFactoryImplementor;
+import org.hibernate.search.store.optimization.OptimizerStrategy;
+import org.hibernate.search.store.optimization.IncrementalOptimizerStrategy;
+import org.hibernate.search.store.optimization.NoOpOptimizerStrategy;
 import org.hibernate.mapping.PersistentClass;
 import org.hibernate.annotations.common.reflection.ReflectionManager;
 import org.hibernate.annotations.common.reflection.XClass;
@@ -74,6 +77,17 @@
 			return providers.get( index );
 		}
 		else {
+			boolean incremental = indexProps.containsKey( "optimizer.operation_limit.max" )
+					|| indexProps.containsKey( "optimizer.transaction_limit.max" );
+			OptimizerStrategy optimizerStrategy;
+			if (incremental) {
+				optimizerStrategy = new IncrementalOptimizerStrategy();
+				optimizerStrategy.initialize( provider, indexProps, searchFactoryImplementor);
+			}
+			else {
+				optimizerStrategy = new NoOpOptimizerStrategy();
+			}
+			searchFactoryImplementor.addOptimizerStrategy(provider, optimizerStrategy);
 			providers.add( provider );
 			return provider;
 		}

Added: trunk/HibernateExt/search/src/java/org/hibernate/search/store/optimization/IncrementalOptimizerStrategy.java
===================================================================
--- trunk/HibernateExt/search/src/java/org/hibernate/search/store/optimization/IncrementalOptimizerStrategy.java	                        (rev 0)
+++ trunk/HibernateExt/search/src/java/org/hibernate/search/store/optimization/IncrementalOptimizerStrategy.java	2007-06-19 22:07:51 UTC (rev 11695)
@@ -0,0 +1,75 @@
+//$Id$
+package org.hibernate.search.store.optimization;
+
+import java.util.Properties;
+import java.io.IOException;
+
+import org.hibernate.search.engine.SearchFactoryImplementor;
+import org.hibernate.search.backend.Workspace;
+import org.hibernate.search.store.DirectoryProvider;
+import org.hibernate.search.SearchException;
+import org.hibernate.annotations.common.util.StringHelper;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Optimization strategy triggered after a certain amount of operations
+ *
+ * @author Emmanuel Bernard
+ */
+public class IncrementalOptimizerStrategy implements OptimizerStrategy {
+	private int operationMax = -1;
+	private int transactionMax = -1;
+	private long operations = 0;
+	private long transactions = 0;
+	private DirectoryProvider directoryProvider;
+	private Log log = LogFactory.getLog( IncrementalOptimizerStrategy.class );
+
+	public void initialize(DirectoryProvider directoryProvider, Properties indexProperties, SearchFactoryImplementor searchFactoryImplementor) {
+		this.directoryProvider = directoryProvider;
+		String maxString = indexProperties.getProperty( "optimizer.operation_limit.max" );
+		if ( StringHelper.isNotEmpty( maxString ) ) {
+			operationMax = Integer.parseInt( maxString );
+		}
+
+		maxString = indexProperties.getProperty( "optimizer.transaction_limit.max" );
+		if ( StringHelper.isNotEmpty( maxString ) ) {
+			transactionMax = Integer.parseInt( maxString );
+		}
+	}
+
+	public void optimizationForced() {
+		operations = 0;
+		transactions = 0;
+	}
+
+	public boolean needOptimization() {
+		return (operationMax != -1 && operations >= operationMax)
+				|| (transactionMax != -1 && transactions >= transactionMax);
+	}
+
+	public void addTransaction(long operations) {
+		this.operations += operations;
+		this.transactions++;
+	}
+
+	public void optimize(Workspace workspace) {
+		if ( needOptimization() ) {
+			if ( log.isDebugEnabled() ) {
+				log.debug( "Optimize "
+				 	+ directoryProvider.getDirectory().toString()
+					+" after " + operations + " operations and " + transactions + " transactions");
+			}
+			IndexWriter writer = workspace.getIndexWriter( directoryProvider );
+			try {
+				writer.optimize();
+			}
+			catch (IOException e) {
+				throw new SearchException( "Unable to optimize directoryProvider: "
+						+ directoryProvider.getDirectory().toString(), e );
+			}
+			optimizationForced();
+		}
+	}
+}

Added: trunk/HibernateExt/search/src/java/org/hibernate/search/store/optimization/NoOpOptimizerStrategy.java
===================================================================
--- trunk/HibernateExt/search/src/java/org/hibernate/search/store/optimization/NoOpOptimizerStrategy.java	                        (rev 0)
+++ trunk/HibernateExt/search/src/java/org/hibernate/search/store/optimization/NoOpOptimizerStrategy.java	2007-06-19 22:07:51 UTC (rev 11695)
@@ -0,0 +1,29 @@
+//$Id$
+package org.hibernate.search.store.optimization;
+
+import java.util.Properties;
+
+import org.hibernate.search.store.DirectoryProvider;
+import org.hibernate.search.engine.SearchFactoryImplementor;
+import org.hibernate.search.backend.Workspace;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class NoOpOptimizerStrategy implements OptimizerStrategy {
+	public void initialize(DirectoryProvider directoryProvider, Properties indexProperties, SearchFactoryImplementor searchFactoryImplementor) {
+	}
+
+	public void optimizationForced() {
+	}
+
+	public boolean needOptimization() {
+		return false;
+	}
+
+	public void addTransaction(long operations) {
+	}
+
+	public void optimize(Workspace workspace) {
+	}
+}

Added: trunk/HibernateExt/search/src/java/org/hibernate/search/store/optimization/OptimizerStrategy.java
===================================================================
--- trunk/HibernateExt/search/src/java/org/hibernate/search/store/optimization/OptimizerStrategy.java	                        (rev 0)
+++ trunk/HibernateExt/search/src/java/org/hibernate/search/store/optimization/OptimizerStrategy.java	2007-06-19 22:07:51 UTC (rev 11695)
@@ -0,0 +1,36 @@
+//$Id$
+package org.hibernate.search.store.optimization;
+
+import java.util.Properties;
+
+import org.hibernate.search.engine.SearchFactoryImplementor;
+import org.hibernate.search.backend.Workspace;
+import org.hibernate.search.store.DirectoryProvider;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public interface OptimizerStrategy {
+	public void initialize(DirectoryProvider directoryProvider, Properties indexProperties, SearchFactoryImplementor searchFactoryImplementor);
+
+	/**
+	 * has to be called in a thread safe way
+	 */
+	void optimizationForced();
+
+	/**
+	 * has to be called in a thread safe way
+	 */
+	boolean needOptimization();
+
+	/**
+	 * has to be called in a thread safe way
+	 */
+	public void addTransaction(long operations);
+
+	/**
+	 * has to be called in a thread safe way
+	 */
+	void optimize(Workspace workspace);
+
+}

Modified: trunk/HibernateExt/search/src/test/log4j.properties
===================================================================
--- trunk/HibernateExt/search/src/test/log4j.properties	2007-06-19 05:44:02 UTC (rev 11694)
+++ trunk/HibernateExt/search/src/test/log4j.properties	2007-06-19 22:07:51 UTC (rev 11695)
@@ -18,11 +18,11 @@
 
 log4j.logger.org.hibernate=info
 
-log4j.logger.org.hibernate.search=debug
+#log4j.logger.org.hibernate.search=debug
 
 
 ### log just the SQL
-log4j.logger.org.hibernate.SQL=debug
+#log4j.logger.org.hibernate.SQL=debug
 
 #log4j.logger.org.hibernate.engine.CascadingAction=debug
 

Added: trunk/HibernateExt/search/src/test/org/hibernate/search/test/optimizer/Construction.java
===================================================================
--- trunk/HibernateExt/search/src/test/org/hibernate/search/test/optimizer/Construction.java	                        (rev 0)
+++ trunk/HibernateExt/search/src/test/org/hibernate/search/test/optimizer/Construction.java	2007-06-19 22:07:51 UTC (rev 11695)
@@ -0,0 +1,60 @@
+//$Id$
+package org.hibernate.search.test.optimizer;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.GeneratedValue;
+
+import org.hibernate.search.annotations.Indexed;
+import org.hibernate.search.annotations.DocumentId;
+import org.hibernate.search.annotations.Field;
+import org.hibernate.search.annotations.Index;
+
+/**
+ * @author Emmanuel Bernard
+ */
+ at Entity
+ at Indexed
+public class Construction {
+	@Id
+	@GeneratedValue
+	@DocumentId
+	private Integer id;
+	@Field(index = Index.TOKENIZED)
+	private String name;
+	@Field(index = Index.TOKENIZED)
+	private String address;
+
+
+	public Construction() {
+	}
+
+	public Construction(String name, String address) {
+		this.name = name;
+		this.address = address;
+	}
+
+	public Integer getId() {
+		return id;
+	}
+
+	public void setId(Integer id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public String getAddress() {
+		return address;
+	}
+
+	public void setAddress(String address) {
+		this.address = address;
+	}
+}

Added: trunk/HibernateExt/search/src/test/org/hibernate/search/test/optimizer/IncrementalOptimizerStrategyTest.java
===================================================================
--- trunk/HibernateExt/search/src/test/org/hibernate/search/test/optimizer/IncrementalOptimizerStrategyTest.java	                        (rev 0)
+++ trunk/HibernateExt/search/src/test/org/hibernate/search/test/optimizer/IncrementalOptimizerStrategyTest.java	2007-06-19 22:07:51 UTC (rev 11695)
@@ -0,0 +1,18 @@
+//$Id$
+package org.hibernate.search.test.optimizer;
+
+import java.io.File;
+
+import org.hibernate.search.store.FSDirectoryProvider;
+import org.hibernate.search.Environment;
+import org.apache.lucene.analysis.StopAnalyzer;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class IncrementalOptimizerStrategyTest extends OptimizerTestCase {
+	protected void configure(org.hibernate.cfg.Configuration cfg) {
+		super.configure( cfg );
+		cfg.setProperty( "hibernate.search.default.optimizer.transaction_limit.max", "10" );
+	}
+}

Added: trunk/HibernateExt/search/src/test/org/hibernate/search/test/optimizer/OptimizerTestCase.java
===================================================================
--- trunk/HibernateExt/search/src/test/org/hibernate/search/test/optimizer/OptimizerTestCase.java	                        (rev 0)
+++ trunk/HibernateExt/search/src/test/org/hibernate/search/test/optimizer/OptimizerTestCase.java	2007-06-19 22:07:51 UTC (rev 11695)
@@ -0,0 +1,204 @@
+//$Id$
+package org.hibernate.search.test.optimizer;
+
+import java.io.File;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.Date;
+
+import org.apache.lucene.analysis.StopAnalyzer;
+import org.apache.lucene.queryParser.ParseException;
+import org.apache.lucene.queryParser.QueryParser;
+import org.apache.lucene.search.Query;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.Transaction;
+import org.hibernate.search.Environment;
+import org.hibernate.search.FullTextSession;
+import org.hibernate.search.impl.FullTextSessionImpl;
+import org.hibernate.search.store.FSDirectoryProvider;
+import org.hibernate.search.test.SearchTestCase;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class OptimizerTestCase extends SearchTestCase {
+	protected void setUp() throws Exception {
+		File sub = getBaseIndexDir();
+		delete( sub );
+		sub.mkdir();
+		File[] files = sub.listFiles();
+		for (File file : files) {
+			if ( file.isDirectory() ) {
+				delete( file );
+			}
+		}
+		//super.setUp(); //we need a fresh session factory each time for index set up
+		buildSessionFactory( getMappings(), getAnnotatedPackages(), getXmlFiles() );
+	}
+
+	private File getBaseIndexDir() {
+		File current = new File( "." );
+		File sub = new File( current, "indextemp" );
+		return sub;
+	}
+
+	protected void tearDown() throws Exception {
+		super.tearDown();
+		File sub = getBaseIndexDir();
+		delete( sub );
+	}
+
+	private void delete(File sub) {
+		if ( sub.isDirectory() ) {
+			for (File file : sub.listFiles()) {
+				delete( file );
+			}
+			sub.delete();
+		}
+		else {
+			sub.delete();
+		}
+	}
+
+	public void testConcurrency() throws Exception {
+		int nThreads = 15;
+		ExecutorService es = Executors.newFixedThreadPool( nThreads );
+		Work work = new Work( getSessions() );
+		ReverseWork reverseWork = new ReverseWork( getSessions() );
+		long start = System.currentTimeMillis();
+		int iteration = 100;
+		for (int i = 0; i < iteration; i++) {
+			es.execute( work );
+			es.execute( reverseWork );
+		}
+		while ( work.count < iteration - 1 ) {
+			Thread.sleep( 20 );
+		}
+		System.out.println( iteration + " iterations (8 tx per iteration) in " + nThreads + " threads: " + ( System
+				.currentTimeMillis() - start ) );
+	}
+
+	protected class Work implements Runnable {
+		private SessionFactory sf;
+		public volatile int count = 0;
+
+		public Work(SessionFactory sf) {
+			this.sf = sf;
+		}
+
+		public void run() {
+			try {
+				Session s = sf.openSession();
+				Transaction tx = s.beginTransaction();
+				Worker w = new Worker( "Emmanuel", 65 );
+				s.persist( w );
+				Construction c = new Construction( "Bellagio", "Las Vagas Nevada" );
+				s.persist( c );
+				tx.commit();
+				s.close();
+
+				s = sf.openSession();
+				tx = s.beginTransaction();
+				w = (Worker) s.get( Worker.class, w.getId() );
+				w.setName( "Gavin" );
+				c = (Construction) s.get( Construction.class, c.getId() );
+				c.setName( "W Hotel" );
+				tx.commit();
+				s.close();
+
+				try {
+					Thread.sleep( 50 );
+				}
+				catch (InterruptedException e) {
+					e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
+				}
+
+				s = sf.openSession();
+				tx = s.beginTransaction();
+				FullTextSession fts = new FullTextSessionImpl( s );
+				QueryParser parser = new QueryParser( "id", new StopAnalyzer() );
+				Query query;
+				try {
+					query = parser.parse( "name:Gavin" );
+				}
+				catch (ParseException e) {
+					throw new RuntimeException( e );
+				}
+				boolean results = fts.createFullTextQuery( query ).list().size() > 0;
+				//don't test because in case of async, it query happens before actual saving
+				//if ( !results ) throw new RuntimeException( "No results!" );
+				tx.commit();
+				s.close();
+
+				s = sf.openSession();
+				tx = s.beginTransaction();
+				w = (Worker) s.get( Worker.class, w.getId() );
+				s.delete( w );
+				c = (Construction) s.get( Construction.class, c.getId() );
+				s.delete( c );
+				tx.commit();
+				s.close();
+				count++;
+			} catch (Throwable t) {
+				t.printStackTrace( );
+			}
+		}
+	}
+
+	protected class ReverseWork implements Runnable {
+		private SessionFactory sf;
+
+		public ReverseWork(SessionFactory sf) {
+			this.sf = sf;
+		}
+
+		public void run() {
+			try {
+				Session s = sf.openSession();
+				Transaction tx = s.beginTransaction();
+				Worker w = new Worker( "Mladen", 70 );
+				s.persist( w );
+				Construction c = new Construction( "Hover Dam", "Croatia" );
+				s.persist( c );
+				tx.commit();
+				s.close();
+
+				s = sf.openSession();
+				tx = s.beginTransaction();
+				w = (Worker) s.get( Worker.class, w.getId() );
+				w.setName( "Remi" );
+				c = (Construction) s.get( Construction.class, c.getId() );
+				c.setName( "Palais des festivals" );
+				tx.commit();
+				s.close();
+
+				s = sf.openSession();
+				tx = s.beginTransaction();
+				w = (Worker) s.get( Worker.class, w.getId() );
+				s.delete( w );
+				c = (Construction) s.get( Construction.class, c.getId() );
+				s.delete( c );
+				tx.commit();
+				s.close();
+			} catch (Throwable t) {
+				t.printStackTrace( );
+			}
+		}
+	}
+
+	protected void configure(org.hibernate.cfg.Configuration cfg) {
+		super.configure( cfg );
+		File sub = getBaseIndexDir();
+		cfg.setProperty( "hibernate.search.default.indexBase", sub.getAbsolutePath() );
+		cfg.setProperty( "hibernate.search.default.directory_provider", FSDirectoryProvider.class.getName() );
+		cfg.setProperty( Environment.ANALYZER_CLASS, StopAnalyzer.class.getName() );
+	}
+
+	protected Class[] getMappings() {
+		return new Class[] {
+				Worker.class,
+				Construction.class
+		};
+	}
+}

Added: trunk/HibernateExt/search/src/test/org/hibernate/search/test/optimizer/Worker.java
===================================================================
--- trunk/HibernateExt/search/src/test/org/hibernate/search/test/optimizer/Worker.java	                        (rev 0)
+++ trunk/HibernateExt/search/src/test/org/hibernate/search/test/optimizer/Worker.java	2007-06-19 22:07:51 UTC (rev 11695)
@@ -0,0 +1,60 @@
+//$Id$
+package org.hibernate.search.test.optimizer;
+
+import javax.persistence.Id;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Entity;
+
+import org.hibernate.search.annotations.Indexed;
+import org.hibernate.search.annotations.DocumentId;
+import org.hibernate.search.annotations.Field;
+import org.hibernate.search.annotations.Index;
+
+/**
+ * @author Emmanuel Bernard
+ */
+ at Entity
+ at Indexed
+public class Worker {
+	@Id
+	@GeneratedValue
+	@DocumentId
+	private Integer id;
+	@Field(index = Index.TOKENIZED)
+	private String name;
+	@Field(index = Index.UN_TOKENIZED)
+	private int workhours;
+
+
+	public Worker() {
+	}
+
+	public Worker(String name, int workhours) {
+		this.name = name;
+		this.workhours = workhours;
+	}
+
+	public Integer getId() {
+		return id;
+	}
+
+	public void setId(Integer id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public int getWorkhours() {
+		return workhours;
+	}
+
+	public void setWorkhours(int workhours) {
+		this.workhours = workhours;
+	}
+}




More information about the hibernate-commits mailing list