org.compass.gps.device.support.parallel.ConcurrentParallelIndexExecutor.java Source code

Java tutorial

Introduction

Here is the source code for org.compass.gps.device.support.parallel.ConcurrentParallelIndexExecutor.java

Source

/*
 * Copyright 2004-2009 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.compass.gps.device.support.parallel;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.compass.core.CompassCallbackWithoutResult;
import org.compass.core.CompassException;
import org.compass.core.CompassSession;
import org.compass.core.util.concurrent.NamedThreadFactory;
import org.compass.gps.CompassGpsException;
import org.compass.gps.spi.CompassGpsInterfaceDevice;

/**
 * <p>Executes the indexing process using sevearl threads based on the partitioned
 * list of index entities.
 *
 * <p>By default (with <code>maxThreads</code> set to <code>-1</code>) creates N threads
 * during the indexing process where N is the number of partitioned index entities
 * groups (one therad per group). If <code>maxThreads<code> is set to a positive integer
 * number, the index executor will use it as the number of threads to create, regardless
 * of the number of partitioned entities groups.
 *
 * @author kimchy
 */
public class ConcurrentParallelIndexExecutor implements ParallelIndexExecutor {

    private static final Log log = LogFactory.getLog(ConcurrentParallelIndexExecutor.class);

    private int maxThreads = -1;

    private boolean ignoreNoEtities = false;

    /**
     * Constructs a new concurrent index executor with <code>maxThreads</code>
     * defaults to -1.
     */
    public ConcurrentParallelIndexExecutor() {

    }

    /**
     * Constructs a new concurrent index executor with the given max threads.
     *
     * @param maxThreads The number of threads to use or -1 for dynamic threads
     */
    public ConcurrentParallelIndexExecutor(int maxThreads) {
        if (maxThreads < -1 || maxThreads == 0) {
            throw new IllegalArgumentException("maxThreads must either be -1 or a value greater than 0");
        }
        this.maxThreads = maxThreads;
    }

    /**
     * Allows to ignore cases where there are no entities to index.
     */
    public ConcurrentParallelIndexExecutor setIgnoreNoEntities(boolean ignoreNoEtities) {
        this.ignoreNoEtities = ignoreNoEtities;
        return this;
    }

    /**
     * Performs the indexing process using the provided index entities indexer. Creates a pool of N
     * threads (if <code>maxThreads</code> is set to -1, N is the numer of entities groups, otherwise
     * N is the number of <code>maxThreads</code>).
     *
     * @param entities             The partitioned index entities groups and index entities to index
     * @param indexEntitiesIndexer The entities indexer to use
     * @param compassGps           Compass gps interface for meta information
     */
    public void performIndex(final IndexEntity[][] entities, final IndexEntitiesIndexer indexEntitiesIndexer,
            final CompassGpsInterfaceDevice compassGps) {

        if (entities.length <= 0) {
            if (ignoreNoEtities) {
                return;
            }
            throw new IllegalArgumentException(
                    "No entities listed to be indexed, have you defined your entities correctly?");
        }
        int maxThreads = this.maxThreads;
        if (maxThreads == -1) {
            maxThreads = entities.length;
        }
        ExecutorService executorService = Executors.newFixedThreadPool(maxThreads,
                new NamedThreadFactory("Compass Gps Index", false));
        try {
            ArrayList tasks = new ArrayList();
            for (int i = 0; i < entities.length; i++) {
                final IndexEntity[] indexEntities = entities[i];
                tasks.add(new Callable() {
                    public Object call() throws Exception {
                        compassGps.executeForIndex(new CompassCallbackWithoutResult() {
                            protected void doInCompassWithoutResult(CompassSession session)
                                    throws CompassException {
                                indexEntitiesIndexer.performIndex(session, indexEntities);
                                session.flush();
                            }
                        });
                        return null;
                    }
                });
            }
            List futures;
            try {
                futures = executorService.invokeAll(tasks);
            } catch (InterruptedException e) {
                throw new CompassGpsException("Failed to index, interrupted", e);
            }

            for (Iterator it = futures.iterator(); it.hasNext();) {
                Future future = (Future) it.next();
                try {
                    future.get();
                } catch (InterruptedException e) {
                    throw new CompassGpsException("Failed to index, interrupted", e);
                } catch (ExecutionException e) {
                    throw new CompassGpsException("Failed to index, execution exception", e);
                }
            }
        } finally {
            executorService.shutdownNow();
        }
    }

}