/* Copyright (2006-2012) Schibsted ASA
* This file is part of Possom.
*
* Possom is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Possom 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 Possom. If not, see <http://www.gnu.org/licenses/>.
*/
package no.sesat.search.mode.executor;
import java.util.Collection;
import java.util.Map;
import java.util.Vector;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import no.sesat.search.mode.command.SearchCommand;
import no.sesat.search.result.ResultItem;
import no.sesat.search.result.ResultList;
/**
* A {@link no.sesat.search.executor.SearchCommandExecutor} executing a list of callables in parallel.
*
*
* @version <tt>$Id$</tt>
*/
class ParallelSearchCommandExecutor extends AbstractSearchCommandExecutor {
private final ExecutorService EXECUTOR =
new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
// Alternative to find memory leakages
//new DebugThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
private static final String DEBUG_POOL_COUNT = "Pool size: ";
/**
* Creates a new parallel EXECUTOR.
*/
public ParallelSearchCommandExecutor() {
}
@Override
public Map<Future<ResultList<ResultItem>>,SearchCommand> invokeAll(
Collection<SearchCommand> callables) throws InterruptedException {
if(LOG.isDebugEnabled()){
if( getExecutorService() instanceof ThreadPoolExecutor){
final ThreadPoolExecutor tpe = (ThreadPoolExecutor)getExecutorService();
LOG.debug(DEBUG_POOL_COUNT + tpe.getActiveCount() + '/' + tpe.getPoolSize());
if(tpe instanceof ParallelSearchCommandExecutor.DebugThreadPoolExecutor){
final ParallelSearchCommandExecutor.DebugThreadPoolExecutor dtpe
= (ParallelSearchCommandExecutor.DebugThreadPoolExecutor)tpe;
LOG.debug("Still executing...");
synchronized( dtpe.EXECUTING ){
for(Runnable r : dtpe.EXECUTING){
try {
LOG.debug(" " + ((FutureTask)r).get());
} catch (InterruptedException ex) {
LOG.debug(ex);
} catch (ExecutionException ex) {
LOG.debug(ex);
}
}
}
}
}
}
return super.invokeAll(callables);
}
/**
*
* @return
*/
@Override
protected ExecutorService getExecutorService(){
return EXECUTOR;
}
static class DebugThreadPoolExecutor extends ThreadPoolExecutor{
//final Collection<Runnable> EXECUTING = new ConcurrentSkipListSet<Runnable>(); // jdk1.6
final Collection<Runnable> EXECUTING = new Vector<Runnable>();
DebugThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
@Override
protected void beforeExecute(final Thread t, final Runnable r) {
super.beforeExecute(t, r);
EXECUTING.add(r);
}
@Override
protected void afterExecute(final Runnable r, final Throwable t) {
super.afterExecute(r, t);
EXECUTING.remove(r);
}
}
}