package org.apache.hadoop.mapred;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
/**
* Executes a JobTracker with a given tag for the Mesos JobTracker launcher
* system, maintaining the correct lease through HDFS files and potentially
* shutting down the JT after a period of inactivity.
*
* TODO: Still need to implement timeout functionality.
*/
public class MesosJobTrackerRunner {
// Date format to use in JobTracker identifiers
static DateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMddHHmm");
private static class LeaseRenewalThread extends Thread {
private final FileSystem fs;
private final Path lockPath;
private final long leaseTimeout;
private final JobTracker jt;
public LeaseRenewalThread(
FileSystem fs, Path lockPath, long leaseTimeout, JobTracker jt) {
super("LeaseRenewalThread");
this.fs = fs;
this.lockPath = lockPath;
this.leaseTimeout = leaseTimeout;
this.jt = jt;
setDaemon(true);
}
@Override
public void run() {
while (true) {
try {
fs.setTimes(lockPath, -1, System.currentTimeMillis());
} catch (IOException e) {
// If we failed to set the path, something is seriously wrong
// (for example, the lease file was deleted); stop the JT and exit
System.err.println("Fatal error: failed to setTimes on " + lockPath);
e.printStackTrace();
try {
jt.stopTracker();
} catch (IOException e2) {}
System.exit(0);
}
try {
Thread.sleep(leaseTimeout / 4);
} catch (InterruptedException e) {}
}
}
}
public static void main(String[] args) throws IOException {
if (args.length != 1) {
System.err.println("Usage: MesosJobTrackerRunner <tag>");
System.exit(1);
}
String tag = args[0];
JobConf conf = new JobConf();
FileSystem fs = FileSystem.get(conf);
// Read configuration options
String launcherDir = conf.get("mesos.launcher.dir", "/user/mesos/launcher");
long leaseTimeout = conf.getLong("mesos.launcher.lease.timeout", 30000);
Path lockPath = new Path(launcherDir, tag + ".lock");
Path jtPath = new Path(launcherDir, tag + ".jobtracker");
Path webuiPath = new Path(launcherDir, tag + ".webui");
// Delete the .lock, .jobtracker and .webui files on exit
fs.deleteOnExit(lockPath);
// Start the JobTracker
try {
// Create a new JobTracker ID - make sure to include the username
// Note: The task status server on the TT seems to break if we add an
// underscore into the JobTracker ID, so we use a dash instead
String jtId = DATE_FORMAT.format(new Date()) + "-" + tag;
// Configure the JT to bind to random ports for RPC and web UI
JobConf jtConf = new JobConf(conf);
String host = InetAddress.getLocalHost().getHostName();
jtConf.set("mapred.job.tracker", host + ":0");
jtConf.set("mapred.job.tracker.http.address", "0.0.0.0:0");
jtConf.set("mapred.jobtracker.taskScheduler",
"org.apache.hadoop.mapred.MesosScheduler");
// Start it
JobTracker jt = JobTracker.startTracker(jtConf, jtId);
// After startTracker, the JT has updated its internal variables to
// include its real RPC and HTTP addresses; write them to our files
writeTextFile(fs, jtPath, host + ":" + jt.getTrackerPort());
fs.deleteOnExit(jtPath);
writeTextFile(fs, webuiPath, host + ":" + jt.getInfoPort());
fs.deleteOnExit(webuiPath);
// Launch a daemon thread to touch the lock file and maintain our lease
new LeaseRenewalThread(fs, lockPath, leaseTimeout, jt).start();
// Run the JT
jt.offerService();
} catch (UnknownHostException e) {
fatalError("failed to get hostname of local machine");
} catch (InterruptedException e) {}
}
private static void writeTextFile(FileSystem fs, Path path, String string)
throws IOException {
Writer writer = new OutputStreamWriter(fs.create(path, true));
writer.write(string);
writer.close();
}
/**
* Print a fatal error message and exit the program.
* @param message Error to print
*/
private static void fatalError(String message) {
System.err.println("Fatal error: " + message);
System.exit(1);
}
}