/*
* Hibernate Search, full-text search for your domain model
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.search.backend.impl.batch;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.hibernate.search.backend.FlushLuceneWork;
import org.hibernate.search.backend.LuceneWork;
import org.hibernate.search.backend.OptimizeLuceneWork;
import org.hibernate.search.backend.impl.StreamingOperationDispatcher;
import org.hibernate.search.backend.impl.TransactionalOperationDispatcher;
import org.hibernate.search.backend.spi.BatchBackend;
import org.hibernate.search.backend.spi.OperationDispatcher;
import org.hibernate.search.batchindexing.MassIndexerProgressMonitor;
import org.hibernate.search.engine.integration.impl.ExtendedSearchIntegrator;
import org.hibernate.search.engine.spi.EntityIndexBinding;
import org.hibernate.search.indexes.spi.IndexManager;
/**
* This is not meant to be used as a regular
* backend, only to apply batch changes to the index. Several threads
* are used to make changes to each index, so order of Work processing is not guaranteed.
*
* @author Sanne Grinovero
* @hsearch.experimental First {@code BatchBackend}
*/
public class DefaultBatchBackend implements BatchBackend {
private final ExtendedSearchIntegrator integrator;
private final MassIndexerProgressMonitor progressMonitor;
private final OperationDispatcher streamingDispatcher;
private final OperationDispatcher transactionalDispatcher;
public DefaultBatchBackend(ExtendedSearchIntegrator integrator, MassIndexerProgressMonitor progressMonitor) {
this.integrator = integrator;
this.progressMonitor = progressMonitor;
this.streamingDispatcher = new StreamingOperationDispatcher( integrator, true /* forceAsync */ );
this.transactionalDispatcher = new TransactionalOperationDispatcher( integrator );
}
@Override
public void enqueueAsyncWork(LuceneWork work) throws InterruptedException {
streamingDispatcher.dispatch( work, progressMonitor );
}
@Override
public void awaitAsyncProcessingCompletion() {
Map<Class<?>, EntityIndexBinding> indexBindings = integrator.getIndexBindings();
for ( EntityIndexBinding indexBinding : indexBindings.values() ) {
for ( IndexManager indexManager : indexBinding.getIndexManagers() ) {
indexManager.awaitAsyncProcessingCompletion();
}
}
}
@Override
public void doWorkInSync(LuceneWork work) {
//FIXME I need a "Force sync" actually for when using PurgeAll before the indexing starts
transactionalDispatcher.dispatch( work, progressMonitor );
}
@Override
public void flush(Set<Class<?>> entityTypes) {
Collection<IndexManager> uniqueIndexManagers = uniqueIndexManagerForTypes( entityTypes );
for ( IndexManager indexManager : uniqueIndexManagers ) {
indexManager.performStreamOperation( FlushLuceneWork.INSTANCE, progressMonitor, false );
}
}
@Override
public void optimize(Set<Class<?>> entityTypes) {
Collection<IndexManager> uniqueIndexManagers = uniqueIndexManagerForTypes( entityTypes );
for ( IndexManager indexManager : uniqueIndexManagers ) {
indexManager.performStreamOperation( OptimizeLuceneWork.INSTANCE, progressMonitor, false );
}
}
private Collection<IndexManager> uniqueIndexManagerForTypes(Collection<Class<?>> entityTypes) {
HashMap<String,IndexManager> uniqueBackends = new HashMap<String, IndexManager>( entityTypes.size() );
for ( Class<?> type : entityTypes ) {
EntityIndexBinding indexBindingForEntity = integrator.getIndexBinding( type );
if ( indexBindingForEntity != null ) {
IndexManager[] indexManagers = indexBindingForEntity.getIndexManagers();
for ( IndexManager im : indexManagers ) {
uniqueBackends.put( im.getIndexName(), im );
}
}
}
return uniqueBackends.values();
}
}