YARN-3840. Resource Manager web ui issue when sorting application by id (with application having id > 9999). Contributed by Mohammad Shahid Khan and Varun Saxena

This commit is contained in:
Jian He 2015-12-03 12:42:53 -08:00
parent 62e9348bc1
commit 9f77ccad73
12 changed files with 143 additions and 22 deletions

View File

@ -221,7 +221,7 @@ public class TaskPage extends AppView {
.append("\n{'aTargets': [ 5 ]") .append("\n{'aTargets': [ 5 ]")
.append(", 'bSearchable': false }") .append(", 'bSearchable': false }")
.append("\n, {'sType':'string', 'aTargets': [ 0 ]") .append("\n, {'sType':'natural', 'aTargets': [ 0 ]")
.append(", 'mRender': parseHadoopID }") .append(", 'mRender': parseHadoopID }")
.append("\n, {'sType':'numeric', 'aTargets': [ 6, 7") .append("\n, {'sType':'numeric', 'aTargets': [ 6, 7")

View File

@ -43,7 +43,7 @@ public class TasksPage extends AppView {
.append(", bProcessing: true") .append(", bProcessing: true")
.append("\n, aoColumnDefs: [\n") .append("\n, aoColumnDefs: [\n")
.append("{'sType':'string', 'aTargets': [0]") .append("{'sType':'natural', 'aTargets': [0]")
.append(", 'mRender': parseHadoopID }") .append(", 'mRender': parseHadoopID }")
.append("\n, {'sType':'numeric', bSearchable:false, 'aTargets': [1]") .append("\n, {'sType':'numeric', bSearchable:false, 'aTargets': [1]")

View File

@ -1126,6 +1126,10 @@ Release 2.7.3 - UNRELEASED
YARN-4398. Remove unnecessary synchronization in RMStateStore. (Ning Ding via jianhe) YARN-4398. Remove unnecessary synchronization in RMStateStore. (Ning Ding via jianhe)
YARN-3840. Resource Manager web ui issue when sorting application by id
(with application having id > 9999) Mohammad Shahid Khan & Varun Saxena
via jianhe)
Release 2.7.2 - UNRELEASED Release 2.7.2 - UNRELEASED
INCOMPATIBLE CHANGES INCOMPATIBLE CHANGES

View File

@ -65,14 +65,14 @@ public class JQueryUI extends HtmlBlock {
@Override @Override
protected void render(Block html) { protected void render(Block html) {
html. html.link(root_url("static/jquery/themes-1.9.1/base/jquery-ui.css"))
link(root_url("static/jquery/themes-1.9.1/base/jquery-ui.css")). .link(root_url("static/dt-1.9.4/css/jui-dt.css"))
link(root_url("static/dt-1.9.4/css/jui-dt.css")). .script(root_url("static/jquery/jquery-1.8.2.min.js"))
script(root_url("static/jquery/jquery-1.8.2.min.js")). .script(root_url("static/jquery/jquery-ui-1.9.1.custom.min.js"))
script(root_url("static/jquery/jquery-ui-1.9.1.custom.min.js")). .script(root_url("static/dt-1.9.4/js/jquery.dataTables.min.js"))
script(root_url("static/dt-1.9.4/js/jquery.dataTables.min.js")). .script(root_url("static/yarn.dt.plugins.js"))
script(root_url("static/yarn.dt.plugins.js")). .script(root_url("static/dt-sorting/natural.js"))
style("#jsnotice { padding: 0.2em; text-align: center; }", .style("#jsnotice { padding: 0.2em; text-align: center; }",
".ui-progressbar { height: 1em; min-width: 5em }"); // required ".ui-progressbar { height: 1em; min-width: 5em }"); // required
List<String> list = Lists.newArrayList(); List<String> list = Lists.newArrayList();
@ -82,9 +82,8 @@ public class JQueryUI extends HtmlBlock {
initProgressBars(list); initProgressBars(list);
if (!list.isEmpty()) { if (!list.isEmpty()) {
html. html.script().$type("text/javascript")._("$(function() {")
script().$type("text/javascript"). ._(list.toArray())._("});")._();
_("$(function() {")._(list.toArray())._("});")._();
} }
} }

View File

@ -0,0 +1,54 @@
/**
* 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.
*/
(function() {
function naturalSort (a, b) {
var diff = a.length - b.length;
if (diff != 0) {
var splitA = a.split("_");
var splitB = b.split("_");
if (splitA.length != splitB.length) {
return a.localeCompare(b);
}
for (var i=1; i < splitA.length; i++) {
var splitdiff = splitA[i].length - splitB[i].length;
if (splitdiff != 0) {
return splitdiff;
}
var splitCompare = splitA[i].localeCompare(splitB[i]);
if (splitCompare != 0) {
return splitCompare;
}
}
return diff;
}
return a.localeCompare(b);
}
jQuery.extend( jQuery.fn.dataTableExt.oSort, {
"natural-asc": function ( a, b ) {
return naturalSort(a,b);
},
"natural-desc": function ( a, b ) {
return naturalSort(a,b) * -1;
}
} );
}());

View File

@ -53,7 +53,7 @@ public class AppAttemptPage extends AHSView {
protected String getContainersTableColumnDefs() { protected String getContainersTableColumnDefs() {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
return sb.append("[\n").append("{'sType':'string', 'aTargets': [0]") return sb.append("[\n").append("{'sType':'natural', 'aTargets': [0]")
.append(", 'mRender': parseHadoopID }]").toString(); .append(", 'mRender': parseHadoopID }]").toString();
} }

View File

@ -55,7 +55,7 @@ public class AppPage extends AHSView {
protected String getAttemptsTableColumnDefs() { protected String getAttemptsTableColumnDefs() {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
return sb.append("[\n").append("{'sType':'string', 'aTargets': [0]") return sb.append("[\n").append("{'sType':'natural', 'aTargets': [0]")
.append(", 'mRender': parseHadoopID }") .append(", 'mRender': parseHadoopID }")
.append("\n, {'sType':'numeric', 'aTargets': [1]") .append("\n, {'sType':'numeric', 'aTargets': [1]")

View File

@ -21,7 +21,7 @@ package org.apache.hadoop.yarn.server.applicationhistoryservice.webapp;
import static org.apache.hadoop.yarn.webapp.Params.TITLE; import static org.apache.hadoop.yarn.webapp.Params.TITLE;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import org.junit.Assert; import java.util.Map;
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.yarn.api.ApplicationBaseProtocol; import org.apache.hadoop.yarn.api.ApplicationBaseProtocol;
import org.apache.hadoop.yarn.api.records.ApplicationAttemptId; import org.apache.hadoop.yarn.api.records.ApplicationAttemptId;
@ -38,6 +38,7 @@ import org.apache.hadoop.yarn.server.applicationhistoryservice.MemoryApplication
import org.apache.hadoop.yarn.util.StringHelper; import org.apache.hadoop.yarn.util.StringHelper;
import org.apache.hadoop.yarn.webapp.YarnWebParams; import org.apache.hadoop.yarn.webapp.YarnWebParams;
import org.apache.hadoop.yarn.webapp.test.WebAppTests; import org.apache.hadoop.yarn.webapp.test.WebAppTests;
import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -87,6 +88,21 @@ public class TestAHSWebApp extends ApplicationHistoryStoreTestUtils {
WebAppTests.flushOutput(injector); WebAppTests.flushOutput(injector);
} }
@Test
public void testAPPViewNaturalSortType() throws Exception {
Injector injector =
WebAppTests.createMockInjector(ApplicationBaseProtocol.class,
mockApplicationHistoryClientService(5, 1, 1));
AHSView ahsViewInstance = injector.getInstance(AHSView.class);
ahsViewInstance.render();
WebAppTests.flushOutput(injector);
Map<String, String> moreParams =
ahsViewInstance.context().requestContext().moreParams();
String appTableColumnsMeta = moreParams.get("ui.dataTables.apps.init");
Assert.assertTrue(appTableColumnsMeta.indexOf("natural") != -1);
}
@Test @Test
public void testAboutPage() throws Exception { public void testAboutPage() throws Exception {
Injector injector = Injector injector =
@ -117,6 +133,22 @@ public class TestAHSWebApp extends ApplicationHistoryStoreTestUtils {
WebAppTests.flushOutput(injector); WebAppTests.flushOutput(injector);
} }
@Test
public void testAppPageNaturalSortType() throws Exception {
Injector injector =
WebAppTests.createMockInjector(ApplicationBaseProtocol.class,
mockApplicationHistoryClientService(1, 5, 1));
AppPage appPageInstance = injector.getInstance(AppPage.class);
appPageInstance.render();
WebAppTests.flushOutput(injector);
Map<String, String> moreParams =
appPageInstance.context().requestContext().moreParams();
String attemptsTableColumnsMeta =
moreParams.get("ui.dataTables.attempts.init");
Assert.assertTrue(attemptsTableColumnsMeta.indexOf("natural") != -1);
}
@Test @Test
public void testAppAttemptPage() throws Exception { public void testAppAttemptPage() throws Exception {
Injector injector = Injector injector =
@ -135,6 +167,21 @@ public class TestAHSWebApp extends ApplicationHistoryStoreTestUtils {
WebAppTests.flushOutput(injector); WebAppTests.flushOutput(injector);
} }
@Test
public void testAppAttemptPageNaturalSortType() throws Exception {
Injector injector =
WebAppTests.createMockInjector(ApplicationBaseProtocol.class,
mockApplicationHistoryClientService(1, 1, 5));
AppAttemptPage appAttemptPageInstance =
injector.getInstance(AppAttemptPage.class);
appAttemptPageInstance.render();
WebAppTests.flushOutput(injector);
Map<String, String> moreParams =
appAttemptPageInstance.context().requestContext().moreParams();
String tableColumnsMeta = moreParams.get("ui.dataTables.containers.init");
Assert.assertTrue(tableColumnsMeta.indexOf("natural") != -1);
}
@Test @Test
public void testContainerPage() throws Exception { public void testContainerPage() throws Exception {
Injector injector = Injector injector =
@ -195,5 +242,4 @@ public class TestAHSWebApp extends ApplicationHistoryStoreTestUtils {
return store; return store;
} }
}; };
} }

View File

@ -49,7 +49,7 @@ public class WebPageUtils {
boolean isFairSchedulerPage, boolean isResourceManager) { boolean isFairSchedulerPage, boolean isResourceManager) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append("[\n") sb.append("[\n")
.append("{'sType':'string', 'aTargets': [0]") .append("{'sType':'natural', 'aTargets': [0]")
.append(", 'mRender': parseHadoopID }") .append(", 'mRender': parseHadoopID }")
.append("\n, {'sType':'numeric', 'aTargets': [6, 7]") .append("\n, {'sType':'numeric', 'aTargets': [6, 7]")
.append(", 'mRender': renderHadoopDate }") .append(", 'mRender': renderHadoopDate }")
@ -75,7 +75,7 @@ public class WebPageUtils {
private static String getAttemptsTableColumnDefs() { private static String getAttemptsTableColumnDefs() {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
return sb.append("[\n").append("{'sType':'string', 'aTargets': [0]") return sb.append("[\n").append("{'sType':'natural', 'aTargets': [0]")
.append(", 'mRender': parseHadoopID }") .append(", 'mRender': parseHadoopID }")
.append("\n, {'sType':'numeric', 'aTargets': [1]") .append("\n, {'sType':'numeric', 'aTargets': [1]")
.append(", 'mRender': renderHadoopDate }]").toString(); .append(", 'mRender': renderHadoopDate }]").toString();
@ -91,7 +91,7 @@ public class WebPageUtils {
private static String getContainersTableColumnDefs() { private static String getContainersTableColumnDefs() {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
return sb.append("[\n").append("{'sType':'string', 'aTargets': [0]") return sb.append("[\n").append("{'sType':'natural', 'aTargets': [0]")
.append(", 'mRender': parseHadoopID }]").toString(); .append(", 'mRender': parseHadoopID }]").toString();
} }

View File

@ -54,7 +54,14 @@ public class AllApplicationsPage extends NMView {
// Sort by id upon page load // Sort by id upon page load
append(", aaSorting: [[0, 'asc']]"). append(", aaSorting: [[0, 'asc']]").
// applicationid, applicationstate // applicationid, applicationstate
append(", aoColumns:[null, null]} ").toString(); append(", aoColumns:[").append(getApplicationsIdColumnDefs())
.append(", null]} ").toString();
}
private String getApplicationsIdColumnDefs() {
StringBuilder sb = new StringBuilder();
return sb.append("{'sType':'natural', 'aTargets': [0]")
.append(", 'mRender': parseHadoopID }").toString();
} }
@Override @Override

View File

@ -52,9 +52,15 @@ public class AllContainersPage extends NMView {
private String containersTableInit() { private String containersTableInit() {
return tableInit(). return tableInit().
// containerid, containerid, log-url // containerid, containerid, log-url
append(", aoColumns:[null, null, {bSearchable:false}]} ").toString(); append(", aoColumns:[").append(getContainersIdColumnDefs())
.append(", null, {bSearchable:false}]} ").toString();
} }
private String getContainersIdColumnDefs() {
StringBuilder sb = new StringBuilder();
return sb.append("{'sType':'natural', 'aTargets': [0]")
.append(", 'mRender': parseHadoopID }").toString();
}
@Override @Override
protected Class<? extends SubView> content() { protected Class<? extends SubView> content() {
return AllContainersBlock.class; return AllContainersBlock.class;

View File

@ -28,6 +28,7 @@ import static org.mockito.Mockito.when;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configuration;
@ -119,6 +120,10 @@ public class TestRMWebApp {
YarnApplicationState.RUNNING.toString())); YarnApplicationState.RUNNING.toString()));
rmViewInstance.render(); rmViewInstance.render();
WebAppTests.flushOutput(injector); WebAppTests.flushOutput(injector);
Map<String, String> moreParams =
rmViewInstance.context().requestContext().moreParams();
String appsTableColumnsMeta = moreParams.get("ui.dataTables.apps.init");
Assert.assertTrue(appsTableColumnsMeta.indexOf("natural") != -1);
} }
@Test public void testNodesPage() { @Test public void testNodesPage() {