Package org.hibernate.search.batchindexing.impl

Source Code of org.hibernate.search.batchindexing.impl.BatchCoordinator

/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2010, Red Hat, Inc. and/or its affiliates or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors.  All third-party contributions are
* distributed under license by Red Hat, Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA  02110-1301  USA
*/
package org.hibernate.search.batchindexing.impl;

import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;

import org.hibernate.search.engine.spi.SearchFactoryImplementor;
import org.hibernate.search.exception.ErrorHandler;
import org.hibernate.search.util.logging.impl.Log;

import org.hibernate.CacheMode;
import org.hibernate.SessionFactory;
import org.hibernate.search.backend.OptimizeLuceneWork;
import org.hibernate.search.backend.PurgeAllLuceneWork;
import org.hibernate.search.backend.impl.batch.BatchBackend;
import org.hibernate.search.batchindexing.MassIndexerProgressMonitor;
import org.hibernate.search.util.logging.impl.LoggerFactory;

/**
* Makes sure that several different BatchIndexingWorkspace(s)
* can be started concurrently, sharing the same batch-backend
* and IndexWriters.
*
* @author Sanne Grinovero
*/
public class BatchCoordinator implements Runnable {

  private static final Log log = LoggerFactory.make();

  private final Class<?>[] rootEntities; //entity types to reindex excluding all subtypes of each-other
  private final SearchFactoryImplementor searchFactoryImplementor;
  private final SessionFactory sessionFactory;
  private final int objectLoadingThreads;
  private final int collectionLoadingThreads;
  private final CacheMode cacheMode;
  private final int objectLoadingBatchSize;
  private final boolean optimizeAtEnd;
  private final boolean purgeAtStart;
  private final boolean optimizeAfterPurge;
  private final CountDownLatch endAllSignal;
  private final MassIndexerProgressMonitor monitor;
  private final long objectsLimit;
  private final ErrorHandler errorHandler;

  public BatchCoordinator(Set<Class<?>> rootEntities,
              SearchFactoryImplementor searchFactoryImplementor,
              SessionFactory sessionFactory,
              int objectLoadingThreads,
              int collectionLoadingThreads,
              CacheMode cacheMode,
              int objectLoadingBatchSize,
              long objectsLimit,
              boolean optimizeAtEnd,
              boolean purgeAtStart,
              boolean optimizeAfterPurge,
              MassIndexerProgressMonitor monitor,
              Integer writerThreads) {
    this.rootEntities = rootEntities.toArray( new Class<?>[rootEntities.size()] );
    this.searchFactoryImplementor = searchFactoryImplementor;
    this.sessionFactory = sessionFactory;
    this.objectLoadingThreads = objectLoadingThreads;
    this.collectionLoadingThreads = collectionLoadingThreads;
    this.cacheMode = cacheMode;
    this.objectLoadingBatchSize = objectLoadingBatchSize;
    this.optimizeAtEnd = optimizeAtEnd;
    this.purgeAtStart = purgeAtStart;
    this.optimizeAfterPurge = optimizeAfterPurge;
    this.monitor = monitor;
    this.objectsLimit = objectsLimit;
    this.endAllSignal = new CountDownLatch( rootEntities.size() );
    this.errorHandler = searchFactoryImplementor.getErrorHandler();
  }

  public void run() {
    try {
      final BatchBackend backend = searchFactoryImplementor.makeBatchBackend( monitor );
      try {
        beforeBatch( backend ); // purgeAll and pre-optimize activities
        doBatchWork( backend );
        afterBatch( backend );
      }
      catch ( InterruptedException e ) {
        log.interruptedBatchIndexing();
        Thread.currentThread().interrupt();
      }
      finally {
        monitor.indexingCompleted();
      }
    } catch (RuntimeException re) {
      // each batch processing stage is already supposed to properly handle any kind
      // of exception, still since this is possibly an async operation we need a safety
      // for the unexpected exceptions
      errorHandler.handleException( log.massIndexerUnexpectedErrorMessage() , re );
    }
  }

  /**
   * Will spawn a thread for each type in rootEntities, they will all re-join
   * on endAllSignal when finished.
   * @param backend
   *
   * @throws InterruptedException if interrupted while waiting for endAllSignal.
   */
  private void doBatchWork(BatchBackend backend) throws InterruptedException {
    ExecutorService executor = Executors.newFixedThreadPool( rootEntities.length, "BatchIndexingWorkspace" );
    for ( Class<?> type : rootEntities ) {
      executor.execute(
          new BatchIndexingWorkspace(
              searchFactoryImplementor, sessionFactory, type,
              objectLoadingThreads, collectionLoadingThreads,
              cacheMode, objectLoadingBatchSize,
              endAllSignal, monitor, backend, objectsLimit
          )
      );
    }
    executor.shutdown();
    endAllSignal.await(); //waits for the executor to finish
  }

  /**
   * Operations to do after all subthreads finished their work on index
   * @param backend
   */
  private void afterBatch(BatchBackend backend) {
    if ( this.optimizeAtEnd ) {
      Set<Class<?>> targetedClasses = searchFactoryImplementor.getIndexedTypesPolymorphic( rootEntities );
      optimize( backend, targetedClasses );
    }
  }

  /**
   * Optional operations to do before the multiple-threads start indexing
   * @param backend
   */
  private void beforeBatch(BatchBackend backend) {
    if ( this.purgeAtStart ) {
      //purgeAll for affected entities
      Set<Class<?>> targetedClasses = searchFactoryImplementor.getIndexedTypesPolymorphic( rootEntities );
      for ( Class<?> clazz : targetedClasses ) {
        //needs do be in-sync work to make sure we wait for the end of it.
        backend.doWorkInSync( new PurgeAllLuceneWork( clazz ) );
      }
      if ( this.optimizeAfterPurge ) {
        optimize( backend, targetedClasses );
      }
    }
  }

  private void optimize(BatchBackend backend, Set<Class<?>> targetedClasses) {
    for ( Class<?> clazz : targetedClasses ) {
      //TODO the backend should remove duplicate optimize work to the same DP (as entities might share indexes)
      backend.doWorkInSync( new OptimizeLuceneWork( clazz ) );
    }
  }
}
TOP

Related Classes of org.hibernate.search.batchindexing.impl.BatchCoordinator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.