/**
* StaffRunner.java
*/
package com.chinamobile.bcbsp.bspstaff;
import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.Vector;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.util.RunJar;
import com.chinamobile.bcbsp.BSPConfiguration;
import com.chinamobile.bcbsp.util.BSPJob;
import com.chinamobile.bcbsp.workermanager.WorkerManager;
/**
* StaffRunner
*
* Base class that runs a staff in a child process.
*
* @author
* @version
*/
public class StaffRunner extends Thread {
public static final Log LOG = LogFactory.getLog(StaffRunner.class);
boolean killed = false;
private Process process;
private Staff staff;
private BSPJob conf;
private WorkerManager workerManager;
private int faultSSStep = 0;
public StaffRunner(BSPStaff bspStaff, WorkerManager workerManager,
BSPJob conf) {
this.staff = bspStaff;
this.conf = conf;
this.workerManager = workerManager;
}
public Staff getStaff() {
return staff;
}
public int getFaultSSStep() {
return faultSSStep;
}
public void setFaultSSStep(int faultSSStep) {
this.faultSSStep = faultSSStep;
}
/**
* Called to assemble this staff's input. This method is run in the parent
* process before the child is spawned. It should not execute user code,
* only system code.
*
* @return
* @throws IOException
*/
public boolean prepare() throws IOException {
return true;
}
public void run() {
try {
String sep = System.getProperty("path.separator");
File workDir = new File(new File(staff.getJobFile()).getParent(),
"work");
boolean isCreated = workDir.mkdirs();
if (!isCreated) {
LOG.debug("StaffRunner.workDir : " + workDir);
}
StringBuffer classPath = new StringBuffer();
classPath.append(System.getProperty("java.class.path"));
classPath.append(sep);
String jar = conf.getJar();
// if jar exists, it into workDir
if (jar != null) {
RunJar.unJar(new File(jar), workDir);
File[] libs = new File(workDir, "lib").listFiles();
if (libs != null) {
for (int i = 0; i < libs.length; i++) {
// add libs from jar to classpath
classPath.append(sep);
classPath.append(libs[i]);
}
}
classPath.append(sep);
classPath.append(new File(workDir, "classes"));
classPath.append(sep);
classPath.append(workDir);
}
// Build exec child jmv args.
Vector<String> vargs = new Vector<String>();
File jvm = new File(
new File(System.getProperty("java.home"), "bin"), "java");
vargs.add(jvm.toString());
// bsp.child.java.opts
String javaOpts = conf.getConf().get("bsp.child.java.opts",
"-Xmx200m");
javaOpts = javaOpts.replace("@taskid@", staff.getStaffID()
.toString());
String[] javaOptsSplit = javaOpts.split(" ");
for (int i = 0; i < javaOptsSplit.length; i++) {
vargs.add(javaOptsSplit[i]);
}
// Add classpath.
vargs.add("-classpath");
vargs.add(classPath.toString());
// Setup the log4j prop
long logSize = StaffLog
.getStaffLogLength((( BSPConfiguration ) conf.getConf()));
vargs.add("-Dbcbsp.log.dir="
+ new File(System.getProperty("bcbsp.log.dir"))
.getAbsolutePath());
vargs.add("-Dbcbsp.root.logger=INFO,TLA");
vargs.add("-Dbcbsp.tasklog.taskid=" + staff.getStaffID());
vargs.add("-Dbcbsp.tasklog.totalLogFileSize=" + logSize);
// Add main class and its arguments
vargs.add(WorkerManager.Child.class.getName());
InetSocketAddress addr = workerManager
.getStaffTrackerReportAddress();
vargs.add(addr.getHostName());
vargs.add(Integer.toString(addr.getPort()));
vargs.add(staff.getStaffID().toString());
vargs.add(Integer.toString(getFaultSSStep()));
vargs.add(workerManager.getHostName());
// Run java
runChild(( String[] ) vargs.toArray(new String[0]), workDir);
} catch (Exception e) {
LOG.error("[run]", e);
}
}
/**
* Run the child process
*/
private void runChild(String[] args, File dir) throws Exception {
this.process = Runtime.getRuntime().exec(args, null, dir);
try {
int exit_code = process.waitFor();
if (!killed && exit_code != 0) {
throw new Exception(
"Staff process exit with nonzero status of "
+ exit_code + ".");
}
} catch (InterruptedException e) {
throw new IOException(e.toString());
} finally {
kill();
}
}
/**
* Kill the child process
*/
public void kill() {
if (process != null) {
process.destroy();
}
killed = true;
}
}