package org.seqcode.data.readdb;
import java.util.*;
import java.util.logging.*;
/**
* Dispatch is a thread that manages the WorkerThreads and assigns
* WorkerThreads to ServerTasks.
*/
public class Dispatch implements Runnable {
private Vector<WorkerThread> freePool, allThreads;
private Vector<ServerTask> workQueue;
private Vector<Thread> threads;
private Server server;
private int maxConnections;
private int warnedMaxConn = 0;
public Dispatch (Server s, int numThreads, int maxC) {
server = s;
workQueue = new Vector<ServerTask>();
freePool = new Vector<WorkerThread>();
allThreads = new Vector<WorkerThread>();
threads = new Vector<Thread>();
for (int i = 0; i < numThreads; i++) {
WorkerThread servthread = new WorkerThread(this);
Thread t = new Thread(servthread);
t.start();
threads.add(t);
freePool.add(servthread);
allThreads.add(servthread);
}
maxConnections = maxC;
}
/**
* Add a new ServerTask to the set of tasks that will
* be run. Called by Server when it accepts a new connection.
*/
public void addWork(ServerTask s) {
System.err.println("workqueue size is " + workQueue.size());
while (workQueue.size() > maxConnections) {
try {
if (warnedMaxConn++ % 100 == 0) {
server.getLogger().log(Level.WARNING,(String.format("Hit maxconnections (%d)",maxConnections)));
}
Thread.sleep(10);
} catch (InterruptedException e) {
}
}
warnedMaxConn = 0;
workQueue.add(s);
synchronized(this) {
notifyAll();
}
}
/**
* called by WorkerThread when it's finished with a ServerTask.
* WorkerThread has called the run method(), so getting to this
* point means that the run method returned. The run() method
* should not throw any exceptions.
*
*/
public void freeThread(WorkerThread t, ServerTask s) {
if (s.shouldClose()) {
s.close();
} else {
workQueue.add(s);
}
freePool.add(t);
synchronized(this) {
notifyAll();
}
}
/**
* our main loop. work through the tasks, seeing who appears
* to have input
*/
public void run() {
int noTasksWaiting = 0;
int noInputAvailable = 0;
int threadCheck = 0;
int sleep = server.getSleepiness();
while (server.keepRunning()) {
if (workQueue.size() > 0) {
noTasksWaiting = 0;
ServerTask s = workQueue.remove(0);
if (s.shouldClose()) {
s.close();
} else if (s.inputAvailable()) {
while (freePool.size() == 0) {
try {
synchronized(this) {
wait(2);
}
} catch (InterruptedException e) {}
}
WorkerThread w = freePool.remove(0);
w.handle(s);
noInputAvailable = 0;
} else {
noInputAvailable++;
workQueue.add(s);
if (noInputAvailable > workQueue.size() * 2) {
try {
synchronized(this) {
wait(sleep);
}
} catch (InterruptedException e) {}
noInputAvailable = 0;
}
}
} else {
noTasksWaiting++;
try {
synchronized(this) {
wait(sleep*2);
}
} catch (InterruptedException e) {}
}
if (threadCheck++ > 1000) {
threadCheck = 0;
for (int i = 0; i < threads.size(); i++) {
if (!threads.get(i).isAlive()) {
server.getLogger().log(Level.INFO,"Dispatch","run: DEAD THREAD. Adding a new one");
WorkerThread servthread = new WorkerThread(this);
Thread t = new Thread(servthread);
t.start();
threads.set(i,t);
freePool.add(servthread);
try {
allThreads.get(i).stopRunning();
} catch (Exception e) {
server.getLogger().logp(Level.INFO,"Dispatch","run: trying to stop old thread",e.toString(),e);
}
allThreads.set(i,servthread);
}
}
}
}
while (freePool.size() < allThreads.size()) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
for (WorkerThread t : freePool) {
t.stopRunning();
}
}
}