AMBARI-19881. Ambari Web UI is unusably irresponsive on a 1000-node perf cluster after adding AMS (restart indicator loading is too heavy). (atkach via yusaku)
(cherry picked from commit c066fa889d76c2240d2ba9b86b35ea48021e266c) Change-Id: If35ce39dbb154536f945c5954ca748eb9978a919 Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/83748a58 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/83748a58 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/83748a58 Branch: refs/heads/AMBARI-2.4.2.16 Commit: 83748a58b6a8fb35a975ee4a4c22a50a24cd9ce9 Parents: b0ccc13 Author: Yusaku Sako <[email protected]> Authored: Mon Feb 6 13:36:32 2017 -0800 Committer: Jaimin Jetly <[email protected]> Committed: Wed Mar 1 12:23:18 2017 -0800 ---------------------------------------------------------------------- ambari-web/app/controllers/main/service.js | 2 +- .../app/mappers/component_config_mapper.js | 58 ++++---------------- .../app/mappers/components_state_mapper.js | 5 +- ambari-web/app/mappers/server_data_mapper.js | 1 + ambari-web/app/models/client_component.js | 1 + ambari-web/app/models/host_component.js | 17 +++++- ambari-web/app/models/service.js | 21 ++++--- ambari-web/app/views/main/service/menu.js | 4 +- .../test/controllers/main/service_test.js | 31 +++-------- ambari-web/test/models/service_test.js | 27 +++++---- 10 files changed, 72 insertions(+), 95 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/83748a58/ambari-web/app/controllers/main/service.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers/main/service.js b/ambari-web/app/controllers/main/service.js index 7fe5b68..13db704 100644 --- a/ambari-web/app/controllers/main/service.js +++ b/ambari-web/app/controllers/main/service.js @@ -304,7 +304,7 @@ App.MainServiceController = Em.ArrayController.extend({ return App.showConfirmationPopup(function () { self.restartHostComponents(); }, Em.I18n.t('services.service.refreshAll.confirmMsg').format( - App.HostComponent.find().filterProperty('staleConfigs').mapProperty('service.displayName').uniq().join(', ')), + App.Service.find().filterProperty('isRestartRequired').mapProperty('displayName').uniq().join(', ')), null, null, Em.I18n.t('services.service.restartAll.confirmButton') http://git-wip-us.apache.org/repos/asf/ambari/blob/83748a58/ambari-web/app/mappers/component_config_mapper.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/mappers/component_config_mapper.js b/ambari-web/app/mappers/component_config_mapper.js index 866f811..c1568e0 100644 --- a/ambari-web/app/mappers/component_config_mapper.js +++ b/ambari-web/app/mappers/component_config_mapper.js @@ -36,54 +36,20 @@ App.componentConfigMapper = App.QuickDataMapper.create({ }, map: function (json) { console.time('App.componentConfigMapper execution time'); - var hostComponents = []; - var newHostComponentsMap = {}; - var cacheServices = App.cache['services']; - var currentServiceComponentsMap = this.buildServiceComponentMap(cacheServices); - var mapConfig = this.get('config'); - // We do not want to parse JSON if there is no need to - var hostComponentJsonMap = {}; - var hostComponentJsonIds = []; + var staleConfigHostsMap = App.cache.staleConfigsComponentHosts; - if (json.items.length > 0 || this.get('model').find().someProperty('staleConfigs', true)) { - json.items.forEach(function (item) { - item.host_components.forEach(function (host_component) { - host_component.id = host_component.HostRoles.component_name + '_' + host_component.HostRoles.host_name; - hostComponentJsonIds.push(host_component.id); - hostComponentJsonMap[host_component.id] = host_component; - }); - }); - this.get('model').find().forEach(function (hostComponent) { - var id = hostComponent.get('id'); - var hostComponentJson = hostComponentJsonMap[id]; - var currentStaleConfigsState = Boolean(hostComponentJson); - var stateChanged = hostComponent.get('staleConfigs') !== currentStaleConfigsState; - - if (stateChanged) { - hostComponent.set('staleConfigs', currentStaleConfigsState); - } - //delete loaded host-components, so only new ones left - delete hostComponentJsonMap[id]; - }); - hostComponentJsonIds.forEach(function (hcId) { - var newHostComponent = hostComponentJsonMap[hcId]; - if (newHostComponent) { - var serviceName = newHostComponent.HostRoles.service_name; - hostComponents.push(this.parseIt(newHostComponent, mapConfig)); - if (!newHostComponentsMap[serviceName]) { - newHostComponentsMap[serviceName] = []; - } - if (currentServiceComponentsMap[serviceName] && !currentServiceComponentsMap[serviceName][newHostComponent.id]) { - newHostComponentsMap[serviceName].push(newHostComponent.id); - } - } - }, this); - if (hostComponents.length > 0) { - App.store.commit(); - App.store.loadMany(this.get('model'), hostComponents); - this.addNewHostComponents(newHostComponentsMap, cacheServices); + json.items.forEach(function(item) { + var componentName = item.ServiceComponentInfo.component_name; + var hosts = item.host_components.mapProperty('HostRoles.host_name') || []; + staleConfigHostsMap[componentName] = hosts; + if (App.HostComponent.isMaster(componentName)) { + App.MasterComponent.find(componentName).set('staleConfigHosts', hosts); + } else if (App.HostComponent.isSlave(componentName)) { + App.SlaveComponent.find(componentName).set('staleConfigHosts', hosts); + } else if (App.HostComponent.isClient(componentName)) { + App.ClientComponent.find(componentName).set('staleConfigHosts', hosts); } - } + }); console.timeEnd('App.componentConfigMapper execution time'); }, http://git-wip-us.apache.org/repos/asf/ambari/blob/83748a58/ambari-web/app/mappers/components_state_mapper.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/mappers/components_state_mapper.js b/ambari-web/app/mappers/components_state_mapper.js index b86aee5..89d5af2 100644 --- a/ambari-web/app/mappers/components_state_mapper.js +++ b/ambari-web/app/mappers/components_state_mapper.js @@ -36,7 +36,8 @@ App.componentsStateMapper = App.QuickDataMapper.create({ unknown_count: 'ServiceComponentInfo.unknown_count', started_count: 'ServiceComponentInfo.started_count', total_count: 'ServiceComponentInfo.total_count', - host_names: 'host_names' + host_names: 'host_names', + stale_config_hosts: 'stale_config_hosts' }, slaveModel: App.SlaveComponent, @@ -171,6 +172,7 @@ App.componentsStateMapper = App.QuickDataMapper.create({ var slaves = []; var masters = []; var hasNewComponents = false; + var staleConfigHostsMap = App.cache.staleConfigsComponentHosts; if (json.items) { if (!App.isEmptyObject(Em.getWithDefault(App, 'cache.services', {}))) { @@ -184,6 +186,7 @@ App.componentsStateMapper = App.QuickDataMapper.create({ var extendedModel = this.getExtendedModel(item.ServiceComponentInfo.service_name); var cacheService = App.cache['services'].findProperty('ServiceInfo.service_name', item.ServiceComponentInfo.service_name); + item.stale_config_hosts = staleConfigHostsMap[item.ServiceComponentInfo.component_name] || []; if (item.ServiceComponentInfo.category === 'CLIENT') { item.host_names = item.host_components.mapProperty('HostRoles.host_name'); clients.push(this.parseIt(item, this.clientMap)); http://git-wip-us.apache.org/repos/asf/ambari/blob/83748a58/ambari-web/app/mappers/server_data_mapper.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/mappers/server_data_mapper.js b/ambari-web/app/mappers/server_data_mapper.js index da25212..a99d8ae 100644 --- a/ambari-web/app/mappers/server_data_mapper.js +++ b/ambari-web/app/mappers/server_data_mapper.js @@ -26,6 +26,7 @@ App.cache = { 'previousHostStatuses': {}, 'previousComponentStatuses': {}, 'previousComponentPassiveStates': {}, + 'staleConfigsComponentHosts': {}, 'services': [], 'currentConfigVersions': {} }; http://git-wip-us.apache.org/repos/asf/ambari/blob/83748a58/ambari-web/app/models/client_component.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/models/client_component.js b/ambari-web/app/models/client_component.js index 19ef7ce..dc200b0 100644 --- a/ambari-web/app/models/client_component.js +++ b/ambari-web/app/models/client_component.js @@ -31,6 +31,7 @@ App.ClientComponent = DS.Model.extend({ totalCount: DS.attr('number'), stackInfo: DS.belongsTo('App.StackServiceComponent'), hostNames: DS.attr('array'), + staleConfigHosts: DS.attr('array'), /** * Determines if component may be deleted http://git-wip-us.apache.org/repos/asf/ambari/blob/83748a58/ambari-web/app/models/host_component.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/models/host_component.js b/ambari-web/app/models/host_component.js index c6b8264..94d09ea 100644 --- a/ambari-web/app/models/host_component.js +++ b/ambari-web/app/models/host_component.js @@ -51,7 +51,7 @@ App.HostComponent = DS.Model.extend({ * @returns {bool} */ isClient: function () { - return App.get('components.clients').contains(this.get('componentName')); + return App.HostComponent.isClient(this.get('componentName')); }.property('componentName'), /** * Determine if component is running now @@ -73,7 +73,7 @@ App.HostComponent = DS.Model.extend({ * @returns {bool} */ isMaster: function () { - return App.get('components.masters').contains(this.get('componentName')); + return App.HostComponent.isMaster(this.get('componentName')); }.property('componentName', 'App.components.masters'), /** @@ -81,7 +81,7 @@ App.HostComponent = DS.Model.extend({ * @returns {bool} */ isSlave: function () { - return App.get('components.slaves').contains(this.get('componentName')); + return App.HostComponent.isSlave(this.get('componentName')); }.property('componentName'), /** * Only certain components can be deleted. @@ -164,6 +164,17 @@ App.HostComponent = DS.Model.extend({ App.HostComponent.FIXTURES = []; +App.HostComponent.isClient = function(componentName) { + return App.get('components.clients').contains(componentName); +}; + +App.HostComponent.isMaster = function(componentName) { + return App.get('components.masters').contains(componentName); +}; + +App.HostComponent.isSlave = function(componentName) { + return App.get('components.slaves').contains(componentName); +}; /** * get particular counter of host-component by name http://git-wip-us.apache.org/repos/asf/ambari/blob/83748a58/ambari-web/app/models/service.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/models/service.js b/ambari-web/app/models/service.js index c648e93..76e4437 100644 --- a/ambari-web/app/models/service.js +++ b/ambari-web/app/models/service.js @@ -108,18 +108,23 @@ App.Service = DS.Model.extend({ * actual_configs, then a restart is required. */ isRestartRequired: function () { - var rhc = this.get('hostComponents').filterProperty('staleConfigs', true); + var serviceComponents = this.get('clientComponents').toArray() + .concat(this.get('slaveComponents').toArray()) + .concat(this.get('masterComponents').toArray()); var hc = {}; - rhc.forEach(function(_rhc) { - var hostName = _rhc.get('hostName'); - if (!hc[hostName]) { - hc[hostName] = []; - } - hc[hostName].push(_rhc.get('displayName')); + serviceComponents.forEach(function(component) { + var displayName = component.get('displayName'); + component.get('staleConfigHosts').forEach(function(hostName) { + if (!hc[hostName]) { + hc[hostName] = []; + } + hc[hostName].push(displayName); + }); }); + this.set('restartRequiredHostsAndComponents', hc); - return (rhc.length > 0); + return (serviceComponents.filterProperty('staleConfigHosts.length').length > 0); }.property('serviceName'), /** http://git-wip-us.apache.org/repos/asf/ambari/blob/83748a58/ambari-web/app/views/main/service/menu.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/main/service/menu.js b/ambari-web/app/views/main/service/menu.js index 2c9ac5c..eeebc6e 100644 --- a/ambari-web/app/views/main/service/menu.js +++ b/ambari-web/app/views/main/service/menu.js @@ -63,7 +63,7 @@ App.MainServiceMenuView = Em.CollectionView.extend({ templateName:require('templates/main/service/menu_item'), restartRequiredMessage: null, - shouldBeRestarted: Em.computed.someBy('content.hostComponents', 'staleConfigs', true), + shouldBeRestarted: Em.computed.equal('content.isRestartRequired'), active:function () { return this.get('content.id') == this.get('parentView.activeServiceId') ? 'active' : ''; @@ -164,7 +164,7 @@ App.TopNavServiceMenuView = Em.CollectionView.extend({ templateName:require('templates/main/service/menu_item'), restartRequiredMessage: null, - shouldBeRestarted: Em.computed.someBy('content.hostComponents', 'staleConfigs', true), + shouldBeRestarted: Em.computed.equal('content.isRestartRequired'), active:function () { return this.get('content.id') == this.get('parentView.activeServiceId') ? 'active' : ''; http://git-wip-us.apache.org/repos/asf/ambari/blob/83748a58/ambari-web/test/controllers/main/service_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/controllers/main/service_test.js b/ambari-web/test/controllers/main/service_test.js index 06961a1..20fc82e 100644 --- a/ambari-web/test/controllers/main/service_test.js +++ b/ambari-web/test/controllers/main/service_test.js @@ -373,41 +373,26 @@ describe('App.MainServiceController', function () { beforeEach(function () { sinon.spy(App, 'showConfirmationPopup'); sinon.spy(mainServiceController, 'restartHostComponents'); - sinon.stub(App.HostComponent, 'find', function() { + sinon.stub(App.Service, 'find', function() { return [ Em.Object.create({ - componentName: 'componentName1', - hostName: 'hostName1', - service: { - serviceName: 'serviceName1', - displayName: 'displayName1' - }, - staleConfigs: true + displayName: 'displayName1', + isRestartRequired: true }), Em.Object.create({ - componentName: 'componentName2', - hostName: 'hostName2', - service: { - serviceName: 'serviceName2', - displayName: 'displayName2' - }, - staleConfigs: true + displayName: 'displayName2', + isRestartRequired: true }), Em.Object.create({ - componentName: 'componentName3', - hostName: 'hostName3', - service: { - serviceName: 'serviceName3', - displayName: 'displayName3' - }, - staleConfigs: false + displayName: 'displayName3', + isRestartRequired: false }) ]; }); }); afterEach(function () { - App.HostComponent.find.restore(); + App.Service.find.restore(); App.showConfirmationPopup.restore(); mainServiceController.restartHostComponents.restore(); }); http://git-wip-us.apache.org/repos/asf/ambari/blob/83748a58/ambari-web/test/models/service_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/models/service_test.js b/ambari-web/test/models/service_test.js index e527e1e..5bd0cf8 100644 --- a/ambari-web/test/models/service_test.js +++ b/ambari-web/test/models/service_test.js @@ -133,20 +133,25 @@ describe('App.Service', function () { beforeEach(function () { service.reopen({ serviceName: 'HDFS', - hostComponents: [] + clientComponents: [], + slaveComponents: [], + masterComponents: [] }); }); - hostComponentsDataFalse.forEach(function (item) { - it('should be false', function () { - service.set('hostComponents', item); - expect(service.get('isRestartRequired')).to.be.false; - }); + it('should be false when no component has stale configs', function () { + expect(service.get('isRestartRequired')).to.be.false; }); - hostComponentsDataTrue.forEach(function (item) { - it('should be true', function () { - service.set('hostComponents', item); - expect(service.get('isRestartRequired')).to.be.true; - }); + it('should be true when clientComponents has stale configs', function () { + service.set('clientComponents', [Em.Object.create({staleConfigHosts: ['host1']})]); + expect(service.get('isRestartRequired')).to.be.true; + }); + it('should be true when slaveComponents has stale configs', function () { + service.set('slaveComponents', [Em.Object.create({staleConfigHosts: ['host1']})]); + expect(service.get('isRestartRequired')).to.be.true; + }); + it('should be true when masterComponents has stale configs', function () { + service.set('masterComponents', [Em.Object.create({staleConfigHosts: ['host1']})]); + expect(service.get('isRestartRequired')).to.be.true; }); });
