From 00eb6f26f6165a00d647d2bf35fb7996534cfc09 Mon Sep 17 00:00:00 2001 From: shenjiatong Date: Mon, 27 May 2019 11:26:49 +0800 Subject: [PATCH] improve dvr port update under large scale deployment update port may takes an excessive number of seconds to complete if dvr routers are running on more than 100 compute nodes. This patch tries to save some time by removing unnecessary calls inside looping through hosts. Change-Id: Ide740e0c5c43c2d2b842460a37c8ce125da12b28 Closes-Bug: #1830456 --- neutron/db/l3_dvrscheduler_db.py | 25 +++++++++++-------- .../unit/scheduler/test_l3_agent_scheduler.py | 4 +-- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/neutron/db/l3_dvrscheduler_db.py b/neutron/db/l3_dvrscheduler_db.py index 8b085283ddc..63e91b128a4 100644 --- a/neutron/db/l3_dvrscheduler_db.py +++ b/neutron/db/l3_dvrscheduler_db.py @@ -13,6 +13,8 @@ # License for the specific language governing permissions and limitations # under the License. +import collections + from neutron_lib.api.definitions import portbindings from neutron_lib.api import extensions from neutron_lib.callbacks import events @@ -141,19 +143,22 @@ class L3_DVRsch_db_mixin(l3agent_sch_db.L3AgentSchedulerDbMixin): for router_id in router_ids: hosts |= set(self.get_hosts_to_notify(context, router_id)) - for host in hosts: - updated_routers = set() - for router_id in router_ids: + host_routers = collections.defaultdict(set) + for router_id in router_ids: + # avoid calling get_ports in host loop + subnet_ids = self.get_subnet_ids_on_router( + context.elevated(), router_id) + for host in hosts: LOG.debug('DVR: Handle new service port, host %(host)s, ' 'router ids %(router_id)s', {'host': host, 'router_id': router_id}) - if self._check_for_rtr_serviceable_ports( - context.elevated(), router_id, host): - updated_routers.add(router_id) + if self._check_dvr_serviceable_ports_on_host( + context.elevated(), host, subnet_ids): + host_routers[host].add(router_id) - if updated_routers: - self.l3_rpc_notifier.routers_updated_on_host( - context, updated_routers, host) + for host, router_ids in host_routers.items(): + self.l3_rpc_notifier.routers_updated_on_host( + context, router_ids, host) def get_dvr_snat_agent_list(self, context): agent_filters = {'agent_modes': [n_const.L3_AGENT_MODE_DVR_SNAT]} @@ -358,7 +363,7 @@ class L3_DVRsch_db_mixin(l3agent_sch_db.L3AgentSchedulerDbMixin): Port.device_owner.in_( n_utils.get_other_dvr_serviced_device_owners())) query = query.filter(owner_filter) - hosts = [item[0] for item in query] + hosts = [item[0] for item in query if item[0] != ''] return hosts def _get_dvr_subnet_ids_on_host_query(self, context, host): diff --git a/neutron/tests/unit/scheduler/test_l3_agent_scheduler.py b/neutron/tests/unit/scheduler/test_l3_agent_scheduler.py index b87230b3d51..2ce4b0c9735 100644 --- a/neutron/tests/unit/scheduler/test_l3_agent_scheduler.py +++ b/neutron/tests/unit/scheduler/test_l3_agent_scheduler.py @@ -1331,9 +1331,9 @@ class L3DvrSchedulerTestCase(L3SchedulerBaseMixin, return_value=[agent_on_host]) as get_l3_agents,\ mock.patch.object( self.dut, 'get_hosts_to_notify', - return_value=['other_host']),\ + return_value=['other_host', 'host1']),\ mock.patch.object( - self.dut, '_check_for_rtr_serviceable_ports', + self.dut, '_check_dvr_serviceable_ports_on_host', return_value=True): self.dut.dvr_handle_new_service_port(