package org.zbus.common.remoting.nio; import java.io.IOException; import java.nio.channels.SelectionKey; import java.util.concurrent.ExecutorService; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import org.zbus.common.logging.Logger; import org.zbus.common.logging.LoggerFactory; public abstract class DispatcherManager { private static final Logger log = LoggerFactory.getLogger(DispatcherManager.class); private final Codec codec; private ExecutorService executor; private final int dispatcherCount; private final Dispatcher[] dispatchers; private AtomicInteger dispactherIndex = new AtomicInteger(0); private final String dispatcherNamePrefix; protected volatile boolean started = false; public DispatcherManager( Codec codec, ExecutorService executor, int dispatcherCount, String dispatcherNamePrefix) throws IOException{ this.dispatcherCount = dispatcherCount; this.codec = codec; this.executor = executor; this.dispatcherNamePrefix = dispatcherNamePrefix; this.dispatchers = new Dispatcher[this.dispatcherCount]; for(int i=0;i<this.dispatcherCount;i++){ String dispatcherName = String.format("%s%d", dispatcherNamePrefix, i); this.dispatchers[i] = new Dispatcher(this, dispatcherName); } } public DispatcherManager( Codec codec, ExecutorService executor, int dispactherCount) throws IOException{ this(codec, executor, dispactherCount,"Dispatcher"); } public DispatcherManager(Codec codec) throws IOException{ this(codec, newDefaultExecutor(), defaultDispatcherSize()); } public Dispatcher getDispatcher(int index){ if(index <0 || index>=this.dispatcherCount){ throw new IllegalArgumentException("Dispatcher index should >=0 and <"+this.dispatcherCount); } return this.dispatchers[index]; } public Dispatcher nextDispatcher(){ return this.dispatchers[this.dispactherIndex.getAndIncrement()%this.dispatcherCount]; } public void registerSession(int ops, Session sess) throws IOException{ if(sess.dispatcherManager() != this){ throw new IOException("Unmatched DispatcherManager"); } this.nextDispatcher().registerSession(ops, sess); } public Dispatcher getDispatcher(SelectionKey key){ for(Dispatcher e : this.dispatchers){ if(key.selector() == e.selector){ return e; } } return null; } public synchronized void start() { if (this.started) { return; } this.started = true; for (Dispatcher dispatcher : this.dispatchers) { dispatcher.start(); } log.info("%s(DispatcherCount=%d) started", this.dispatcherNamePrefix, this.dispatcherCount); } public synchronized void stop() { if (!this.started) return; this.started = false; for (Dispatcher dispatcher : this.dispatchers) { dispatcher.interrupt(); } } public boolean isStarted(){ return this.started; } public Codec getCodec() { return codec; } public ExecutorService getExecutor() { return executor; } public static int defaultDispatcherSize() { int processors = Runtime.getRuntime().availableProcessors(); return processors > 8 ? 4 + (processors * 5 / 8) : processors + 1; } public static ExecutorService newDefaultExecutor(){ return new ThreadPoolExecutor(4, 256, 120, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>()); } public abstract EventAdaptor buildEventAdaptor(); }