Author: omalley
Date: Wed Sep 3 14:23:56 2008
New Revision: 691783
URL: http://svn.apache.org/viewvc?rev=691783&view=rev
Log:
HADOOP-3866. Added sort and multi-job updates in the JobTracker web ui.
(Craig Weisenfluh via omalley)
Modified:
hadoop/core/trunk/CHANGES.txt
hadoop/core/trunk/src/webapps/job/jobtracker.jsp
hadoop/core/trunk/src/webapps/static/hadoop.css
Modified: hadoop/core/trunk/CHANGES.txt
URL:
http://svn.apache.org/viewvc/hadoop/core/trunk/CHANGES.txt?rev=691783&r1=691782&r2=691783&view=diff
==============================================================================
--- hadoop/core/trunk/CHANGES.txt (original)
+++ hadoop/core/trunk/CHANGES.txt Wed Sep 3 14:23:56 2008
@@ -120,6 +120,9 @@
HADOOP-3601. Add a new contrib module for Hive, which is a sql-like
query processing tool that uses map/reduce. (Ashish Thusoo via omalley)
+ HADOOP-3866. Added sort and multi-job updates in the JobTracker web ui.
+ (Craig Weisenfluh via omalley)
+
IMPROVEMENTS
HADOOP-3908. Fuse-dfs: better error message if llibhdfs.so doesn't exist.
Modified: hadoop/core/trunk/src/webapps/job/jobtracker.jsp
URL:
http://svn.apache.org/viewvc/hadoop/core/trunk/src/webapps/job/jobtracker.jsp?rev=691783&r1=691782&r2=691783&view=diff
==============================================================================
--- hadoop/core/trunk/src/webapps/job/jobtracker.jsp (original)
+++ hadoop/core/trunk/src/webapps/job/jobtracker.jsp Wed Sep 3 14:23:56 2008
@@ -12,56 +12,123 @@
JobTracker tracker = (JobTracker) application.getAttribute("job.tracker");
String trackerName =
StringUtils.simpleHostname(tracker.getJobTrackerMachine());
+ int rowId = 0;
%>
<%!
+ private static final String PRIVATE_ACTIONS_KEY
+ = "webinterface.private.actions";
private static DecimalFormat percentFormat = new DecimalFormat("##0.00");
+
+ public void processButtons(JspWriter out,
+ HttpServletRequest request,
+ HttpServletResponse response,
+ JobTracker tracker) throws IOException {
+
+ if (JspHelper.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 (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);
+ }
+ }
+ }
+ }
- public void generateJobTable(JspWriter out, String label, Vector jobs, int
refresh) throws IOException {
- out.print("<center>\n");
- out.print("<table border=\"2\" cellpadding=\"5\" cellspacing=\"2\">\n");
- out.print("<tr><td align=\"center\" colspan=\"9\"><b>" + label + " Jobs
</b></td></tr>\n");
- if (jobs.size() > 0) {
- out.print("<tr><td><b>Jobid</b></td><td><b>User</b></td>");
- out.print("<td><b>Name</b></td>");
- out.print("<td><b>Map % Complete</b></td>");
- out.print("<td><b>Map Total</b></td>");
- out.print("<td><b>Maps Completed</b></td>");
- out.print("<td><b>Reduce % Complete</b></td>");
- out.print("<td><b>Reduce Total</b></td>");
- out.print("<td><b>Reduces Completed</b></td></tr>\n");
- for (Iterator it = jobs.iterator(); it.hasNext(); ) {
- JobInProgress job = (JobInProgress) 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 name = profile.getJobName();
-
- out.print("<tr><td><a href=\"jobdetails.jsp?jobid=" + jobid +
- "&refresh=" + refresh + "\">" +
- jobid + "</a></td>" +
- "<td>" + profile.getUser() + "</td>"
- + "<td>" + ("".equals(name) ? " " : name) + "</td>" +
- "<td>" +
- StringUtils.formatPercent(status.mapProgress(),2) +
- JspHelper.percentageGraph(status.mapProgress() * 100, 80)
+
- "</td><td>" +
- desiredMaps + "</td><td>" + completedMaps + "</td><td>" +
- StringUtils.formatPercent(status.reduceProgress(),2) +
- JspHelper.percentageGraph(status.reduceProgress() * 100,
80) +
- "</td><td>" +
- desiredReduces + "</td><td> " + completedReduces +
- "</td></tr>\n");
+ public int generateJobTable(JspWriter out, String label, Vector jobs, int
refresh, int rowId) throws IOException {
+
+ boolean isModifiable = label.equals("Running");
+
+ out.print("<table border=\"1\" cellpadding=\"5\" cellspacing=\"0\">\n");
+
+ if (jobs.size() > 0) {
+ if (isModifiable) {
+ out.print("<tr>");
+ out.print("<td><input type=\"Button\" onclick=\"selectAll()\"
value=\"Select All\" id=\"checkEm\"></td>");
+ out.print("<td>");
+ if (JspHelper.conf.getBoolean(PRIVATE_ACTIONS_KEY, false)) {
+ out.print("<input type=\"submit\" name=\"killJobs\" value=\"Kill
Selected Jobs\">");
}
+ out.print("</td");
+ out.print("<td><nobr>");
+ out.print("<select name=\"setJobPriority\">");
+
+ for (JobPriority prio : JobPriority.values()) {
+ out.print("<option" + (JobPriority.NORMAL == prio ? "
selected=\"selected\">" : ">") + prio + "</option>");
+ }
+
+ out.print("</select>");
+ out.print("<input type=\"submit\" name=\"changeJobPriority\"
value=\"Change\">");
+ out.print("</nobr></td>");
+ out.print("<td colspan=\"8\"> </td>");
+ out.print("</tr>");
+ out.print("<td> </td>");
} else {
- out.print("<tr><td align=\"center\"
colspan=\"8\"><i>none</i></td></tr>\n");
+ out.print("<tr>");
+ }
+
+
out.print("<td><b>Jobid</b></td><td><b>Priority</b></td><td><b>User</b></td>");
+ out.print("<td><b>Name</b></td>");
+ out.print("<td><b>Map % Complete</b></td>");
+ out.print("<td><b>Map Total</b></td>");
+ out.print("<td><b>Maps Completed</b></td>");
+ out.print("<td><b>Reduce % Complete</b></td>");
+ out.print("<td><b>Reduce Total</b></td>");
+ out.print("<td><b>Reduces Completed</b></td></tr>\n");
+ for (Iterator it = jobs.iterator(); it.hasNext(); ++rowId) {
+ JobInProgress job = (JobInProgress) 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 name = profile.getJobName();
+ String jobpri = job.getPriority().toString();
+
+ if (isModifiable) {
+ out.print("<tr><td><input TYPE=\"checkbox\"
onclick=\"checkButtonVerbage()\" name=\"jobCheckBox\" value=" +
+ jobid + "></td>");
+ } else {
+ out.print("<tr>");
+ }
+
+ out.print("<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) +
+ JspHelper.percentageGraph(status.mapProgress() * 100, 80) +
+ "</td><td>" +
+ desiredMaps + "</td><td>" + completedMaps + "</td><td>" +
+ StringUtils.formatPercent(status.reduceProgress(),2) +
+ JspHelper.percentageGraph(status.reduceProgress() * 100, 80)
+
+ "</td><td>" +
+ desiredReduces + "</td><td> " + completedReduces +
+ "</td></tr>\n");
}
- out.print("</table>\n");
- out.print("</center>\n");
+ } else {
+ out.print("<tr><td align=\"center\"
colspan=\"8\"><i>none</i></td></tr>\n");
+ }
+ out.print("</table>\n");
+
+ return rowId;
}
public void generateSummaryTable(JspWriter out,
@@ -71,7 +138,7 @@
percentFormat.format(((double)(status.getMaxMapTasks() +
status.getMaxReduceTasks())) / status.getTaskTrackers()):
"-";
- out.print("<table border=\"2\" cellpadding=\"5\" cellspacing=\"2\">\n"+
+ out.print("<table border=\"1\" cellpadding=\"5\" cellspacing=\"0\">\n"+
"<tr><th>Maps</th><th>Reduces</th>" +
"<th>Total Submissions</th>" +
"<th>Nodes</th><th>Map Task Capacity</th>" +
@@ -92,10 +159,24 @@
<head>
<title><%= trackerName %> Hadoop Map/Reduce Administration</title>
<link rel="stylesheet" type="text/css" href="/static/hadoop.css">
+<script type="text/javascript" src="/static/jobtracker.js"></script>
</head>
<body>
+
+<% processButtons(out, request, response, tracker); %>
+
<h1><%= trackerName %> Hadoop Map/Reduce Administration</h1>
+<div id="quicklinks">
+ <a href="#quicklinks" onclick="toggle('quicklinks-list'); return
false;">Quick Links</a>
+ <ul id="quicklinks-list">
+ <li><a href="#running_jobs">Running Jobs</a></li>
+ <li><a href="#completed_jobs">Completed Jobs</a></li>
+ <li><a href="#failed_jobs">Failed Jobs</a></li>
+ <li><a href="#local_logs">Local Logs</a></li>
+ </ul>
+</div>
+
<b>State:</b> <%= tracker.getClusterStatus().getJobTrackerState() %><br>
<b>Started:</b> <%= new Date(tracker.getStartTime())%><br>
<b>Version:</b> <%= VersionInfo.getVersion()%>,
@@ -106,34 +187,36 @@
<hr>
<h2>Cluster Summary</h2>
-<center>
<%
- generateSummaryTable(out, tracker);
+ generateSummaryTable(out, tracker);
%>
-</center>
<hr>
-<h2>Running Jobs</h2>
+<b>Filter (Jobid, Priority, User, Name)</b> <input type="text" id="filter"
onkeyup="applyfilter()"> <br>
+<span class="small">Example: 'user:smith 3200' will filter by 'smith' only in
the user field and '3200' in all fields</span>
+<hr>
+
+<h2 id="running_jobs">Running Jobs</h2>
<%
- generateJobTable(out, "Running", tracker.runningJobs(), 30);
+ out.print("<form action=\"/jobtracker.jsp\" onsubmit=\"return
confirmAction();\" method=\"POST\">");
+ rowId = generateJobTable(out, "Running", tracker.runningJobs(), 30, rowId);
+ out.print("</form>\n");
%>
<hr>
-<h2>Completed Jobs</h2>
+<h2 id="completed_jobs">Completed Jobs</h2>
<%
- generateJobTable(out, "Completed", tracker.completedJobs(), 0);
+ rowId = generateJobTable(out, "Completed", tracker.completedJobs(), 0,
rowId);
%>
-
<hr>
-<h2>Failed Jobs</h2>
+<h2 id="failed_jobs">Failed Jobs</h2>
<%
- generateJobTable(out, "Failed", tracker.failedJobs(), 0);
+ generateJobTable(out, "Failed", tracker.failedJobs(), 0, rowId);
%>
-
<hr>
-<h2>Local logs</h2>
+<h2 id="local_logs">Local Logs</h2>
<a href="logs/">Log</a> directory, <a href="jobhistory.jsp">
Job Tracker History</a>
Modified: hadoop/core/trunk/src/webapps/static/hadoop.css
URL:
http://svn.apache.org/viewvc/hadoop/core/trunk/src/webapps/static/hadoop.css?rev=691783&r1=691782&r2=691783&view=diff
==============================================================================
--- hadoop/core/trunk/src/webapps/static/hadoop.css (original)
+++ hadoop/core/trunk/src/webapps/static/hadoop.css Wed Sep 3 14:23:56 2008
@@ -1,8 +1,29 @@
+/*
+* 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.
+*/
+
body {
background-color : #ffffff;
font-family : sans-serif;
}
+.small {
+ font-size : smaller;
+}
+
div#dfsnodetable tr#row1, div#dfstable td#col1 {
font-weight : bolder;
}
@@ -76,4 +97,33 @@
stroke-width:1;stroke-linecap:round;
}
+#quicklinks {
+ margin: 0;
+ padding: 2px 4px;
+ position: fixed;
+ top: 0;
+ right: 0;
+ text-align: right;
+ background-color: #eee;
+ font-weight: bold;
+}
+
+#quicklinks ul {
+ margin: 0;
+ padding: 0;
+ list-style-type: none;
+ font-weight: normal;
+}
+#quicklinks ul {
+ display: none;
+}
+
+#quicklinks a {
+ font-size: smaller;
+ text-decoration: none;
+}
+
+#quicklinks ul a {
+ text-decoration: underline;
+}