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
+ */
+@Entity
+@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
+ */
+@Entity
+@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;
+ }
+}