/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.mapred;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.JspWriter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.mapred.JobHistory.JobInfo;
import org.apache.hadoop.mapred.JobTracker.RetireJobInfo;
import org.apache.hadoop.mapreduce.TaskType;
import org.apache.hadoop.util.ServletUtil;
import org.apache.hadoop.util.StringUtils;
public class JSPUtil {
private static final String PRIVATE_ACTIONS_KEY = "webinterface.private.actions";
public static final Configuration conf = new Configuration();
//LRU based cache
private static final Map<String, JobInfo> jobHistoryCache =
new LinkedHashMap<String, JobInfo>();
private static final int CACHE_SIZE =
conf.getInt("mapred.job.tracker.jobhistory.lru.cache.size", 5);
private static final Log LOG = LogFactory.getLog(JSPUtil.class);
/**
* Method used to process the request from the job page based on the
* request which it has received. For example like changing priority.
*
* @param request HTTP request Object.
* @param response HTTP response object.
* @param tracker {@link JobTracker} instance
* @throws IOException
*/
public static void processButtons(HttpServletRequest request,
HttpServletResponse response, JobTracker tracker) throws IOException {
if (conf.getBoolean(PRIVATE_ACTIONS_KEY, false)
&& request.getParameter("killJobs") != null) {
String[] jobs = request.getParameterValues("jobCheckBox");
if (jobs != null) {
for (String job : jobs) {
tracker.killJob(JobID.forName(job));
}
}
}
if (conf.getBoolean(PRIVATE_ACTIONS_KEY, false) &&
request.getParameter("changeJobPriority") != null) {
String[] jobs = request.getParameterValues("jobCheckBox");
if (jobs != null) {
JobPriority jobPri = JobPriority.valueOf(request
.getParameter("setJobPriority"));
for (String job : jobs) {
tracker.setJobPriority(JobID.forName(job), jobPri);
}
}
}
}
/**
* Method used to generate the Job table for Job pages.
*
* @param label display heading to be used in the job table.
* @param jobs vector of jobs to be displayed in table.
* @param refresh refresh interval to be used in jobdetails page.
* @param rowId beginning row id to be used in the table.
* @return
* @throws IOException
*/
public static String generateJobTable(String label, Collection<JobInProgress> jobs
, int refresh, int rowId) throws IOException {
boolean isRunning = label.equals("Running");
boolean isModifiable =
isRunning && conf.getBoolean(PRIVATE_ACTIONS_KEY, false);
StringBuffer sb = new StringBuffer();
sb.append("<table border=\"1\" cellpadding=\"5\" cellspacing=\"0\" class=\"tablesorter\">\n");
if (jobs.size() > 0) {
if (isModifiable) {
sb.append("<thead><form action=\"/jobtracker.jsp\" onsubmit=\"return confirmAction();\" method=\"POST\">");
sb.append("<tr>");
sb.append("<td><input type=\"Button\" onclick=\"selectAll()\" " +
"value=\"Select All\" id=\"checkEm\"></td>");
sb.append("<td>");
sb.append("<input type=\"submit\" name=\"killJobs\" value=\"Kill Selected Jobs\">");
sb.append("</td>");
sb.append("<td><nobr>");
sb.append("<select name=\"setJobPriority\">");
for (JobPriority prio : JobPriority.values()) {
sb.append("<option"
+ (JobPriority.NORMAL == prio ? " selected=\"selected\">" : ">")
+ prio + "</option>");
}
sb.append("</select>");
sb.append("<input type=\"submit\" name=\"changeJobPriority\" " +
"value=\"Change\">");
sb.append("</nobr></td>");
sb.append("<td colspan=\"10\"> </td>");
sb.append("</tr>");
sb.append("<th> </th>");
} else {
sb.append("<thead><tr>");
}
int totalMaps = 0;
int comMaps = 0;
int totalRunningMaps = 0;
int totalReduces = 0;
int comReduces = 0;
int totalRunningReduces = 0;
for (Iterator<JobInProgress> it = jobs.iterator(); it.hasNext(); ) {
JobInProgress job = it.next();
totalMaps += job.desiredMaps();
totalReduces += job.desiredReduces();
comMaps += job.finishedMaps();
comReduces += job.finishedReduces();
if (isRunning) {
totalRunningMaps += job.runningMaps();
totalRunningReduces += job.runningReduces();
}
}
sb.append("<th><b>Jobid</b></th><th><b>Priority" +
"</b></th><th><b>User</b></th>");
sb.append("<th><b>Name</b></th>");
sb.append("<th><b>Map % Complete</b></th>");
sb.append("<th><b>Map Total " + totalMaps + "</b></th>");
sb.append("<th><b>Maps Completed " + comMaps + "</b></th>");
if (isRunning) {
sb.append("<th><b>Maps Running " + totalRunningMaps + "</b></th>");
}
sb.append("<th><b>Reduce % Complete</b></th>");
sb.append("<th><b>Reduce Total " + totalReduces + "</b></th>");
sb.append("<th><b>Reduces Completed " + comReduces + "</b></th>");
if (isRunning) {
sb.append("<th><b>Reduces Running " + totalRunningReduces + "</b></th>");
}
sb.append("<th><b>Job Scheduling Information</b></th>");
sb.append("</tr></thead><tbody>\n");
for (Iterator<JobInProgress> it = jobs.iterator(); it.hasNext(); ++rowId) {
JobInProgress job = it.next();
JobProfile profile = job.getProfile();
JobStatus status = job.getStatus();
JobID jobid = profile.getJobID();
int desiredMaps = job.desiredMaps();
int desiredReduces = job.desiredReduces();
int completedMaps = job.finishedMaps();
int completedReduces = job.finishedReduces();
String runningMapTableData =
(isRunning) ? job.runningMaps() + "</td><td>" : "";
String runningReduceTableData =
(isRunning) ? job.runningReduces() + "</td><td>" : "";
String name = profile.getJobName();
String abbreviatedName
= (name.length() > 76 ? name.substring(0,76) + "..." : name);
String jobpri = job.getPriority().toString();
String schedulingInfo = job.getStatus().getSchedulingInfo();
if (isModifiable) {
sb.append("<tr><td><input TYPE=\"checkbox\" " +
"onclick=\"checkButtonVerbage()\" " +
"name=\"jobCheckBox\" value="
+ jobid + "></td>");
} else {
sb.append("<tr>");
}
sb.append("<td id=\"job_" + rowId
+ "\"><a href=\"jobdetails.jsp?jobid=" + jobid + "&refresh="
+ refresh + "\">" + jobid + "</a></td>" + "<td id=\"priority_"
+ rowId + "\">" + jobpri + "</td>" + "<td id=\"user_" + rowId
+ "\">" + profile.getUser() + "</td>" + "<td id=\"name_" + rowId
+ "\">" + ("".equals(abbreviatedName) ? " " : abbreviatedName)
+ "</td>" + "<td>"
+ StringUtils.formatPercent(status.mapProgress(), 2)
+ ServletUtil.percentageGraph(status.mapProgress() * 100, 80)
+ "</td><td>" + desiredMaps + "</td><td>" + completedMaps
+ "</td><td>" + runningMapTableData
+ StringUtils.formatPercent(status.reduceProgress(), 2)
+ ServletUtil.percentageGraph(status.reduceProgress() * 100, 80)
+ "</td><td>" + desiredReduces + "</td><td> " + completedReduces
+ "</td><td>" + runningReduceTableData + schedulingInfo
+ "</td></tr>\n");
}
if (isModifiable) {
sb.append("</form>\n");
}
sb.append("</tbody>");
} else {
sb.append("<tr><td align=\"center\" colspan=\"8\"><i>none</i>" +
"</td></tr>\n");
}
sb.append("</table>\n");
return sb.toString();
}
/**
* Given jobId, resolve the link to jobdetailshistory.jsp
* @param tracker JobTracker
* @param jobId JobID
* @return the link to the page jobdetailshistory.jsp for the job
*/
public static String getJobDetailsHistoryLink(JobTracker tracker,
String jobId) {
RetireJobInfo info = tracker.retireJobs.get(JobID.forName(jobId));
String historyFileUrl = getHistoryFileUrl(info);
String result = (historyFileUrl == null ? "" :
"jobdetailshistory.jsp?jobid=" + jobId + "&logFile=" +
historyFileUrl);
return result;
}
/**
* Given jobId, taskid resolve the link to taskdetailshistory.jsp
* @param tracker JobTracker
* @param jobId JobID
* @param tid String
* @return the link to the page jobdetailshistory.jsp for the job
*/
public static String getTaskDetailsHistoryLink(JobTracker tracker,
String jobId,
String tid) {
RetireJobInfo info = tracker.retireJobs.get(JobID.forName(jobId));
String historyFileUrl = getHistoryFileUrl(info);
String result = (historyFileUrl == null ? "" :
"taskdetailshistory.jsp?jobid=" + jobId + "&logFile=" +
historyFileUrl + "&taskid=" + tid);
return result;
}
/**
* Obtain history file URL from RetireJobInfo
* @param info RetireJobInfo
* @return corresponding history file url, null if cannot creat one
*/
private static String getHistoryFileUrl(RetireJobInfo info) {
String historyFile = info.getHistoryFile();
String historyFileUrl = null;
if (historyFile != null && !historyFile.equals("")) {
try {
historyFileUrl = URLEncoder.encode(info.getHistoryFile(), "UTF-8");
} catch (UnsupportedEncodingException e) {
LOG.warn("Can't create history url ", e);
}
}
return historyFileUrl;
}
@SuppressWarnings("unchecked")
public static String generateRetiredJobTable(JobTracker tracker, int rowId)
throws IOException {
StringBuffer sb = new StringBuffer();
sb.append("<table border=\"1\" cellpadding=\"5\" cellspacing=\"0\" class=\"tablesorter\">\n");
Iterator<RetireJobInfo> iterator =
tracker.retireJobs.getAll().descendingIterator();
if (!iterator.hasNext()) {
sb.append("<tr><th align=\"center\" colspan=\"8\"><i>none</i>" +
"</th></tr>\n");
} else {
sb.append("<thead><tr>");
sb.append("<th><b>Jobid</b></th>");
sb.append("<th><b>Priority</b></th>");
sb.append("<th><b>User</b></th>");
sb.append("<th><b>Name</b></th>");
sb.append("<th><b>State</b></th>");
sb.append("<th><b>Start Time</b></th>");
sb.append("<th><b>Finish Time</b></th>");
sb.append("<th><b>Map % Complete</b></th>");
sb.append("<th><b>Reduce % Complete</b></th>");
sb.append("<th><b>Job Scheduling Information</b></th>");
sb.append("</tr></thead><tbody>\n");
for (int i = 0; i < 100 && iterator.hasNext(); i++) {
RetireJobInfo info = iterator.next();
String historyFileUrl = getHistoryFileUrl(info);
sb.append("<tr>");
String name = info.profile.getJobName();
String abbreviatedName
= (name.length() > 76 ? name.substring(0,76) + "..." : name);
sb.append(
"<td id=\"job_" + rowId + "\">" +
(historyFileUrl == null ? "" :
"<a href=\"jobdetailshistory.jsp?jobid=" +
info.status.getJobId() + "&logFile=" + historyFileUrl + "\">") +
info.status.getJobId() + "</a></td>" +
"<td id=\"priority_" + rowId + "\">" +
info.status.getJobPriority().toString() + "</td>" +
"<td id=\"user_" + rowId + "\">" + info.profile.getUser()
+ "</td>" +
"<td id=\"name_" + rowId + "\">" + abbreviatedName
+ "</td>" +
"<td>" + JobStatus.getJobRunState(info.status.getRunState())
+ "</td>" +
"<td>" + new Date(info.status.getStartTime()) + "</td>" +
"<td>" + new Date(info.finishTime) + "</td>" +
"<td>" + StringUtils.formatPercent(info.status.mapProgress(), 2)
+ ServletUtil.percentageGraph(info.status.mapProgress() * 100, 80) +
"</td>" +
"<td>" + StringUtils.formatPercent(info.status.reduceProgress(), 2)
+ ServletUtil.percentageGraph(
info.status.reduceProgress() * 100, 80) +
"</td>" +
"<td>" + info.status.getSchedulingInfo() + "</td>" +
"</tr>\n");
rowId++;
}
sb.append("</tbody>");
}
sb.append("</table>\n");
return sb.toString();
}
public static JobInfo getJobInfo(HttpServletRequest request, FileSystem fs)
throws IOException {
String jobid = request.getParameter("jobid");
String logFile = request.getParameter("logFile");
synchronized(jobHistoryCache) {
JobInfo jobInfo = jobHistoryCache.remove(jobid);
if (jobInfo == null) {
jobInfo = new JobHistory.JobInfo(jobid);
LOG.info("Loading Job History file "+jobid + ". Cache size is " +
jobHistoryCache.size());
DefaultJobHistoryParser.parseJobTasks( logFile, jobInfo, fs) ;
}
jobHistoryCache.put(jobid, jobInfo);
if (jobHistoryCache.size() > CACHE_SIZE) {
Iterator<Map.Entry<String, JobInfo>> it =
jobHistoryCache.entrySet().iterator();
String removeJobId = it.next().getKey();
it.remove();
LOG.info("Job History file removed form cache "+removeJobId);
}
return jobInfo;
}
}
@SuppressWarnings("unchecked")
public static void generateRetiredJobXml(JspWriter out, JobTracker tracker, int rowId)
throws IOException {
Iterator<RetireJobInfo> iterator =
tracker.retireJobs.getAll().descendingIterator();
for (int i = 0; i < 100 && iterator.hasNext(); i++) {
RetireJobInfo info = iterator.next();
JobStatus status = info.status;
StringBuilder sb = new StringBuilder();
sb.append("<retired_job rowid=\"" + rowId + "\" jobid=\"" + status.getJobId() + "\">");
sb.append("<jobid>" + status.getJobId() + "</jobid>");
sb.append("<history_url>jobdetailshistory.jsp?jobid=" + status.getJobId()
+ "&logFile="
+ URLEncoder.encode(info.getHistoryFile().toString(), "UTF-8")
+ "</history_url>");
sb.append("<priority>" + status.getJobPriority().toString()
+ "</priority>");
sb.append("<user>" + info.profile.getUser() + "</user>");
sb.append("<name>" + info.profile.getJobName() + "</name>");
sb.append("<run_state>" + JobStatus.getJobRunState(status.getRunState())
+ "</run_state>");
sb.append("<start_time>" + new Date(status.getStartTime())
+ "</start_time>");
sb.append("<finish_time>" + new Date(info.finishTime)
+ "</finish_time>");
sb.append("<map_complete>" + StringUtils.formatPercent(
status.mapProgress(), 2) + "</map_complete>");
sb.append("<reduce_complete>" + StringUtils.formatPercent(
status.reduceProgress(), 2) + "</reduce_complete>");
sb.append("<scheduling_info>" + status.getSchedulingInfo() + "</scheduling_info>");
sb.append("</retired_job>\n");
out.write(sb.toString());
rowId++;
}
}
/**
* Method used to generate the cluster resource utilization table
*/
public static String generateClusterResTable(JobTracker tracker)
throws IOException {
ResourceReporter reporter = tracker.getResourceReporter();
if (reporter == null) {
return "";
}
StringBuffer sb = new StringBuffer();
sb.append("<table border=\"1\" cellpadding=\"5\" cellspacing=\"0\">\n");
sb.append("<tr>\n");
sb.append("<th colspan=3>CPU</th>\n");
sb.append("<th colspan=3>MEM</th>\n");
sb.append("<th rowspan=2>Reported</th>\n");
sb.append("</tr>\n");
sb.append("<tr>\n");
sb.append("<th>Total</th><th>Used</th><th>%</th>\n");
sb.append("<th>Total</th><th>Used</th><th>%</th>\n");
sb.append("</tr>\n");
sb.append("<tr>\n");
sb.append(String.format(
"<td>%.1f GHz</td><td>%.1f GHz</td><td>%.1f%%</td>\n",
reporter.getClusterCpuTotalGHz(),
reporter.getClusterCpuUsageGHz(),
Math.min(reporter.getClusterCpuUsageGHz() /
reporter.getClusterCpuTotalGHz() * 100D, 100D)));
sb.append(String.format(
"<td>%.1f GB</td><td>%.1f GB</td><td>%.1f%%</td><td>%d</td>\n",
reporter.getClusterMemTotalGB(),
reporter.getClusterMemUsageGB(),
reporter.getClusterMemUsageGB() /
reporter.getClusterMemTotalGB() * 100D,
reporter.getReportedTaskTrackers()));
sb.append("</tr>\n");
sb.append("</table>\n");
return sb.toString();
}
/**
* Method used to generate the Job table for Job pages with resource
* utilization information obtain from {@link ResourceReporter}.
*
* @param label display heading to be used in the job table.
* @param jobs vector of jobs to be displayed in table.
* @param refresh refresh interval to be used in jobdetails page.
* @param rowId beginning row id to be used in the table.
* @return
* @throws IOException
*/
public static String generateJobTableWithResourceInfo(String label,
Collection<JobInProgress> jobs, int refresh, int rowId,
JobTracker tracker) throws IOException {
ResourceReporter reporter = tracker.getResourceReporter();
if (reporter == null) {
return generateJobTable(label, jobs, refresh, rowId);
}
boolean isRunning = label.equals("Running");
boolean isModifiable =
isRunning && conf.getBoolean(PRIVATE_ACTIONS_KEY, false);
StringBuffer sb = new StringBuffer();
sb.append("<table border=\"1\" cellpadding=\"5\" cellspacing=\"0\" class=\"tablesorter\">\n");
if (jobs.size() > 0) {
if (isModifiable) {
sb.append("<form action=\"/jobtracker_hmon.jsp\" onsubmit=\"return confirmAction();\" method=\"POST\">");
sb.append("<thead><tr>");
sb.append("<td><input type=\"Button\" onclick=\"selectAll()\" " +
"value=\"Select All\" id=\"checkEm\"></td>");
sb.append("<td>");
sb.append("<input type=\"submit\" name=\"killJobs\" value=\"Kill Selected Jobs\">");
sb.append("</td>");
sb.append("<td><nobr>");
sb.append("<select name=\"setJobPriority\">");
for (JobPriority prio : JobPriority.values()) {
sb.append("<option"
+ (JobPriority.NORMAL == prio ? " selected=\"selected\">" : ">")
+ prio + "</option>");
}
sb.append("</select>");
sb.append("<input type=\"submit\" name=\"changeJobPriority\" " +
"value=\"Change\">");
sb.append("</nobr></td>");
sb.append("<td colspan=\"15\"> </td>");
sb.append("</tr>");
sb.append("<th> </th>");
} else {
sb.append("<thead><tr>");
}
int totalMaps = 0;
int comMaps = 0;
int totalRunningMaps = 0;
int totalReduces = 0;
int comReduces = 0;
int totalRunningReduces = 0;
for (Iterator<JobInProgress> it = jobs.iterator(); it.hasNext(); ) {
JobInProgress job = it.next();
totalMaps += job.desiredMaps();
totalReduces += job.desiredReduces();
comMaps += job.finishedMaps();
comReduces += job.finishedReduces();
if (isRunning) {
totalRunningMaps += job.runningMaps();
totalRunningReduces += job.runningReduces();
}
}
sb.append("<th><b>Jobid</b></th><th><b>Priority" +
"</b></th><th><b>User</b></th>");
sb.append("<th><b>Name</b></th>");
sb.append("<th><b>Map % Complete</b></th>");
sb.append("<th><b>Map Total " + totalMaps + "</b></th>");
sb.append("<th><b>Maps Completed " + comMaps + "</b></th>");
if (isRunning) {
sb.append("<th><b>Maps Running " + totalRunningMaps + "</b></th>");
}
sb.append("<th><b>Reduce % Complete</b></th>");
sb.append("<th><b>Reduce Total " + totalReduces + "</b></th>");
sb.append("<th><b>Reduces Completed " + comReduces + "</b></th>");
if (isRunning) {
sb.append("<th><b>Reduces Running " + totalRunningReduces + "</b></th>");
}
sb.append("<th><b>CPU Now</b></th>");
sb.append("<th><b>CPU Cumulated Cluster-sec</b></th>");
sb.append("<th><b>MEM Now</b></a></th>");
sb.append("<th><b>MEM Cumulated Cluster-sec</b></th>");
sb.append("<th><b>MEM Max/Node</b></th>");
sb.append("</tr></thead><tbody>\n");
for (Iterator<JobInProgress> it = jobs.iterator(); it.hasNext(); ++rowId) {
JobInProgress job = it.next();
JobProfile profile = job.getProfile();
JobStatus status = job.getStatus();
JobID jobid = profile.getJobID();
int desiredMaps = job.desiredMaps();
int desiredReduces = job.desiredReduces();
int completedMaps = job.finishedMaps();
int completedReduces = job.finishedReduces();
String runningMapTableData =
(isRunning) ? job.runningMaps() + "</td><td>" : "";
String runningReduceTableData =
(isRunning) ? "</td><td>" + job.runningReduces() : "";
String name = profile.getJobName();
String jobpri = job.getPriority().toString();
if (isModifiable) {
sb.append("<tr><td><input TYPE=\"checkbox\" " +
"onclick=\"checkButtonVerbage()\" " +
"name=\"jobCheckBox\" value="
+ jobid + "></td>");
} else {
sb.append("<tr>");
}
String cpu = "-";
String mem = "-";
String memMax = "-";
String cpuCost = "-";
String memCost = "-";
if (reporter.getJobCpuCumulatedUsageTime(jobid) !=
ResourceReporter.UNAVAILABLE) {
cpu = String.format("%.2f%%",
reporter.getJobCpuPercentageOnCluster(jobid));
if (reporter.getJobCpuPercentageOnCluster(jobid) > 50) {
cpu = "<font color=\"red\">" + cpu + "</font>";
}
mem = String.format("%.2f%%",
reporter.getJobMemPercentageOnCluster(jobid));
if (reporter.getJobMemPercentageOnCluster(jobid) > 50) {
mem = "<font color=\"red\">" + mem + "</font>";
}
cpuCost = String.format("%.2f",
reporter.getJobCpuCumulatedUsageTime(jobid) / 1000D);
memCost = String.format("%.2f",
reporter.getJobMemCumulatedUsageTime(jobid) / 1000D);
memMax = String.format("%.2f%%",
reporter.getJobMemMaxPercentageOnBox(jobid));
if (reporter.getJobMemMaxPercentageOnBox(jobid) > 50) {
memMax = "<font color=\"red\">" + memMax + "</font>";
}
}
sb.append("<td id=\"job_" + rowId
+ "\"><a href=\"jobdetails.jsp?jobid=" + jobid + "&refresh="
+ refresh + "\">" + jobid + "</a></td>" + "<td id=\"priority_"
+ rowId + "\">" + jobpri + "</td>" + "<td id=\"user_" + rowId
+ "\">" + profile.getUser() + "</td>" + "<td id=\"name_" + rowId
+ "\">" + ("".equals(name) ? " " : name) + "</td><td>"
+ StringUtils.formatPercent(status.mapProgress(), 2)
+ ServletUtil.percentageGraph(status.mapProgress() * 100, 80)
+ "</td><td>" + desiredMaps + "</td><td>" + completedMaps
+ "</td><td>" + runningMapTableData
+ StringUtils.formatPercent(status.reduceProgress(), 2)
+ ServletUtil.percentageGraph(status.reduceProgress() * 100, 80)
+ "</td><td>" + desiredReduces + "</td><td> " + completedReduces
+ runningReduceTableData
+ "</td><td id=\"cpu_" + rowId + "\">" + cpu + "</td>"
+ "<td id=\"cpuCost_" + rowId + "\">" + cpuCost + "</td>"
+ "<td id=\"mem_" + rowId + "\">" + mem + "</td>"
+ "<td id=\"memCost_" + rowId + "\">" + memCost + "</td>"
+ "<td id=\"memMax_" + rowId + "\">" + memMax + "</td></tr>\n");
}
if (isModifiable) {
sb.append("</form>\n");
}
sb.append("</tbody>");
} else {
sb.append("<tr><td align=\"center\" colspan=\"8\"><i>none</i>" +
"</td></tr>\n");
}
sb.append("</table>\n");
return sb.toString();
}
/**
* Method used to generate the txt based Job table for Job pages.
*
* @param jobs vector of jobs to be displayed in table.
* @param colSeparator the char used to separate columns
* @param rowSeparator the char used to separate records
* @return a String contains the table
* @throws IOException
*/
public static String generateTxtJobTable(Collection<JobInProgress> jobs,
JobTracker tracker) throws IOException {
char colSeparator = '\t';
char rowSeparator = '\n';
StringBuffer sb = new StringBuffer();
sb.append("01.JOBID" + colSeparator +
"02.START" + colSeparator +
"03.FINISH" + colSeparator +
"04.USER" + colSeparator +
"05.NAME" + colSeparator +
"06.BLACK_TT" + colSeparator +
"07.PRIORITY" + colSeparator +
"08.MAP_TOTAL" + colSeparator +
"09.MAP_COMPLETE" + colSeparator +
"10.MAP_RUN" + colSeparator +
"11.MAP_SPECU" + colSeparator +
"12.MAP_NONLOC" + colSeparator +
"13.MAP_KILLED" + colSeparator +
"14.MAP_FAILED" + colSeparator +
"15.RED_TOTAL" + colSeparator +
"16.RED_COMPLETE" + colSeparator +
"17.RED_RUN" + colSeparator +
"18.RED_SPECU" + colSeparator +
"19.RED_KILLED" + colSeparator +
"20.RED_FAILED" + colSeparator +
"21.%MEM" + colSeparator +
"22.%MEM_MAX" + colSeparator +
"23.%MEM_PEAK" + colSeparator +
"24.MEM_MS" + colSeparator +
"25.%CPU" + colSeparator +
"26.%CPU_MAX" + colSeparator +
"27.CPU_MS" + rowSeparator);
if (jobs.size() > 0) {
for (Iterator<JobInProgress> it = jobs.iterator(); it.hasNext();) {
JobInProgress job = it.next();
JobProfile profile = job.getProfile();
String user = profile.getUser();
String name = profile.getJobName().
replace(' ', '_').replace('\t', '_').replace('\n', '_');
int desiredMaps = job.desiredMaps();
int desiredReduces = job.desiredReduces();
int runningMaps = 0;
int failedMaps = 0;
int killedMaps = 0;
for (TaskInProgress tip: job.getTasks(TaskType.MAP)) {
if (tip.isRunning()) {
runningMaps += tip.getActiveTasks().size();
tip.numKilledTasks();
failedMaps += tip.numTaskFailures();
killedMaps += tip.numKilledTasks();
}
}
int runningReduces = 0;
int failedReduces = 0;
int killedReduces = 0;
for (TaskInProgress tip: job.getTasks(TaskType.REDUCE)) {
if (tip.isRunning()) {
runningReduces += tip.getActiveTasks().size();
failedReduces += tip.numTaskFailures();
killedReduces += tip.numKilledTasks();
}
}
int completedMaps = job.finishedMaps();
int completedReduces = job.finishedReduces();
int nonLocalRunningMaps = job.getNonLocalRunningMaps().size();
long submitTime = job.getStartTime();
long finishTime = job.getFinishTime();
String jobpri = job.getPriority().toString();
JobID jobId = job.getJobID();
double mem = 0, memMax = 0, memMaxPeak = 0, memCost = 0;
double cpu = 0, cpuMax = 0, cpuCost = 0;
ResourceReporter reporter = tracker.getResourceReporter();
if (reporter != null) {
mem = reporter.getJobCpuPercentageOnCluster(jobId);
memMax = reporter.getJobMemMaxPercentageOnBox(jobId);
memMaxPeak = reporter.getJobMemMaxPercentageOnBoxAllTime(jobId);
memCost = reporter.getJobMemCumulatedUsageTime(jobId);
cpu = reporter.getJobCpuPercentageOnCluster(jobId);
cpuMax = reporter.getJobCpuMaxPercentageOnBox(jobId);
cpuCost = reporter.getJobCpuCumulatedUsageTime(jobId);
}
sb.append(jobId.toString() + colSeparator +
submitTime + colSeparator +
finishTime + colSeparator +
user + colSeparator +
name + colSeparator +
job.getNoOfBlackListedTrackers() + colSeparator +
jobpri + colSeparator +
desiredMaps + colSeparator +
completedMaps + colSeparator +
runningMaps + colSeparator +
job.speculativeMapTasks + colSeparator +
nonLocalRunningMaps + colSeparator +
killedMaps + colSeparator +
failedMaps + colSeparator +
desiredReduces + colSeparator +
completedReduces + colSeparator +
runningReduces + colSeparator +
job.speculativeReduceTasks + colSeparator +
killedReduces + colSeparator +
failedReduces + colSeparator +
mem + colSeparator +
memMax + colSeparator +
memMaxPeak + colSeparator +
memCost + colSeparator +
cpu + colSeparator +
cpuMax + colSeparator +
cpuCost + rowSeparator);
}
}
return sb.toString();
}
}