package edu.brown.api;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import org.voltdb.utils.Pair;
import edu.brown.logging.LoggerUtil;
import edu.brown.logging.LoggerUtil.LoggerBoolean;
import edu.brown.utils.ClassUtil;
import edu.brown.utils.CollectionUtil;
import edu.brown.utils.EventObservable;
import edu.brown.utils.EventObservableExceptionHandler;
import edu.brown.utils.EventObserver;
import edu.brown.utils.ThreadUtil;
public class BenchmarkComponentSet implements Runnable {
private static final Logger LOG = Logger.getLogger(BenchmarkComponentSet.class);
private static final LoggerBoolean debug = new LoggerBoolean();
private static final LoggerBoolean trace = new LoggerBoolean();
static {
LoggerUtil.setupLogging();
LoggerUtil.attachObserver(LOG, debug, trace);
}
// ----------------------------------------------------------------------------
// INTERNAL DATA MEMBERS
// ----------------------------------------------------------------------------
private final int clientIds[];
private final Map<BenchmarkComponent, PrintWriter> components = new HashMap<BenchmarkComponent, PrintWriter>();
private final Map<BenchmarkComponent, Thread> threads = new HashMap<BenchmarkComponent, Thread>();
private final EventObservableExceptionHandler exceptionHandler = new EventObservableExceptionHandler();
private final EventObserver<Pair<Thread, Throwable>> exceptionObserver = new EventObserver<Pair<Thread,Throwable>>() {
@Override
public void update(EventObservable<Pair<Thread, Throwable>> o, Pair<Thread, Throwable> arg) {
arg.getSecond().printStackTrace();
}
};
/**
* Constructor
* @param componentClass
* @param clientIds
* @param args
* @throws Exception
*/
public BenchmarkComponentSet(final Class<? extends BenchmarkComponent> componentClass, final int clientIds[], final String args[]) throws Exception {
Thread.setDefaultUncaughtExceptionHandler(this.exceptionHandler);
Thread.currentThread().setUncaughtExceptionHandler(this.exceptionHandler);
this.exceptionHandler.addObserver(this.exceptionObserver);
this.clientIds = clientIds;
final List<Runnable> runnables = new ArrayList<Runnable>();
for (int i = 0; i < this.clientIds.length; i++) {
final int clientId = this.clientIds[i];
final PipedInputStream in = new PipedInputStream();
final PipedOutputStream out = new PipedOutputStream(in);
final PrintWriter writer = new PrintWriter(out);
runnables.add(new Runnable() {
public void run() {
Collection<String> clientArgs = CollectionUtil.addAll(new ArrayList<String>(), args);
clientArgs.add("ID=" + clientId);
BenchmarkComponent comp = BenchmarkComponent.main(componentClass,
clientArgs.toArray(new String[0]),
false);
synchronized (BenchmarkComponentSet.this.components) {
BenchmarkComponentSet.this.components.put(comp, writer);
} // SYNCH
if (debug.val) LOG.debug("Starting Client thread " + clientId);
Thread t = new Thread(comp.createControlPipe(in));
t.setDaemon(true);
t.start();
synchronized (BenchmarkComponentSet.this.threads) {
BenchmarkComponentSet.this.threads.put(comp, t);
} // SYNCH
}
});
} // FOR
ThreadUtil.runGlobalPool(runnables);
assert(runnables.size() == this.threads.size());
assert(runnables.size() == this.components.size());
}
@Override
public void run() {
String line = null;
final BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
while (true) {
if (debug.val) LOG.debug("Blocking on input stream for commands from BenchmarkController");
try {
line = in.readLine().trim();
} catch (final IOException e) {
throw new RuntimeException("Error on standard input", e);
}
if (debug.val) LOG.debug("New Command: " + line);
for (PrintWriter out : this.components.values()) {
out.println(line);
out.flush();
} // FOR
} // WHILE
}
@SuppressWarnings("unchecked")
public static void main(String[] args) throws Exception {
// First argument is the class we are going to need to invoke
// Everything else is the options that we need to pass to it
String clientClass = args[0];
assert(clientClass.isEmpty() == false);
Class<? extends BenchmarkComponent> componentClass = (Class<? extends BenchmarkComponent>)ClassUtil.getClass(clientClass);
assert(componentClass != null);
// Get the list of ClientIds that we need to start
int clientIds[] = null;
String componentArgs[] = new String[args.length - 2];
int compIdx = 0;
for (int i = 1; i < args.length; i++) {
final String arg = args[i];
final String[] parts = arg.split("=", 2);
assert(parts.length >= 1) : "Invalid parameter: " + arg;
if (parts[0].equalsIgnoreCase("ID")) {
String ids[] = parts[1].split(",");
clientIds = new int[ids.length];
for (int j = 0; j < ids.length; j++) {
clientIds[j] = Integer.parseInt(ids[j]);
} // FOR
} else {
componentArgs[compIdx++] = args[i];
}
} // FOR
if (debug.val)
LOG.info(String.format("Starting %d BenchmarkComponent threads: %s",
clientIds.length, Arrays.toString(clientIds)));
BenchmarkComponentSet bcs = new BenchmarkComponentSet(componentClass, clientIds, componentArgs);
bcs.run(); // BLOCK!
}
}