package org.playorm.nio.impl.cm.routing;
import java.util.List;
import java.util.concurrent.Executor;
import org.playorm.nio.api.channels.Channel;
import org.playorm.nio.api.libs.StartableRouterExecutor;
/**
* This is a proxy executor for a special case to prevent deadlock. Read
* the notes in the execute method for more detail
*/
public class SpecialRoutingExecutor
{
private StartableRouterExecutor executor;
private int factor;
private List<Executor> executors;
/**
* Creates an instance of ProxyExecutorService.
* @param executor
*/
public SpecialRoutingExecutor(StartableRouterExecutor executor)
{
this.executor = executor;
}
/**
* @param id
*/
public void start(Object id)
{
executor.start(id);
executors = executor.getExecutors();
factor = Integer.MAX_VALUE / executors.size();
}
/**
* @param id
*/
public void stop(Object id)
{
executor.stop(id);
executors = null;
}
/**
* @see java.util.concurrent.Executor#execute(java.lang.Runnable)
*/
public void execute(Channel channel, Runnable command)
{
//NOTE:This gets a little tricky. First a background on writes work is needed
//
//Because a write is done on the client thread(which is maybe a thread from this
//threadpool), the basic channelmanager also fires events on that thread resulting
//in this execute method being called.
//
//Now, knowing that this means all the server threads could block on the real executor
//when we call execute. Therefore, if we are on a thread that comes from that server
//pool, we MUST fire the even on that server pool thread and not call execute. Calling
//execute in that case will eventually cause deadlock when the queue fills up.
Thread t = Thread.currentThread();
if(executor.containsThread(t)) {
command.run();
return;
}
int hashCode = channel.hashCode();
int threadId = hashCode / factor;
Executor executor = executors.get(threadId);
executor.execute(command);
}
// private static final Logger log = Logger.getLogger(SpecialExecutor.class.getName());
//
// private void dumpThreads() {
// log.info("THREAD DUMP");
// Map<Thread, StackTraceElement[]> allStackTraces = Thread.getAllStackTraces();
// Set<Thread> threads = allStackTraces.keySet();
// for(Thread t : threads) {
// log.info("t name="+t.getName()+" id="+t.getId()+" t="+t+" state="+t.getState());
// StackTraceElement[] lines = allStackTraces.get(t);
// for(StackTraceElement line : lines) {
// System.err.println("\t"+line);
// }
// }
// }
}