From: yangxurong Date: Tue, 11 Nov 2014 09:06:22 +0000 (+0800) Subject: Improve performance of get_active_networks_info X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=f0894c7bf99d918c0e67ab25498d53e990c09aff;p=openstack-build%2Fneutron-build.git Improve performance of get_active_networks_info RPC 'get_active_networks_info' currently uses nested loop to fill the network structure with subnet and port info. Speed up this operation by using itertools.groupby. Change-Id: If765dd8f2f8010b79eb168179a64dccf940e9cbb Closes-Bug: #1390356 --- diff --git a/neutron/api/rpc/handlers/dhcp_rpc.py b/neutron/api/rpc/handlers/dhcp_rpc.py index 9673a65d5..80b7e3f66 100644 --- a/neutron/api/rpc/handlers/dhcp_rpc.py +++ b/neutron/api/rpc/handlers/dhcp_rpc.py @@ -13,6 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +import itertools +import operator + from oslo.config import cfg from oslo.db import exception as db_exc from oslo import messaging @@ -94,6 +97,14 @@ class DhcpRpcCallback(object): nets = self._get_active_networks(context, **kwargs) return [net['id'] for net in nets] + def _group_by_network_id(self, res): + grouped = {} + keyfunc = operator.itemgetter('network_id') + for net_id, values in itertools.groupby(sorted(res, key=keyfunc), + keyfunc): + grouped[net_id] = list(values) + return grouped + def get_active_networks_info(self, context, **kwargs): """Returns all the networks/subnets/ports in system.""" host = kwargs.get('host') @@ -105,11 +116,11 @@ class DhcpRpcCallback(object): filters['enable_dhcp'] = [True] subnets = plugin.get_subnets(context, filters=filters) + grouped_subnets = self._group_by_network_id(subnets) + grouped_ports = self._group_by_network_id(ports) for network in networks: - network['subnets'] = [subnet for subnet in subnets - if subnet['network_id'] == network['id']] - network['ports'] = [port for port in ports - if port['network_id'] == network['id']] + network['subnets'] = grouped_subnets.get(network['id'], []) + network['ports'] = grouped_ports.get(network['id'], []) return networks diff --git a/neutron/tests/unit/test_dhcp_rpc.py b/neutron/tests/unit/test_dhcp_rpc.py index 2c4c5c9e6..e0ebe65e7 100644 --- a/neutron/tests/unit/test_dhcp_rpc.py +++ b/neutron/tests/unit/test_dhcp_rpc.py @@ -47,6 +47,28 @@ class TestDhcpRpcCallback(base.BaseTestCase): self.assertEqual(len(self.log.mock_calls), 1) + def test_group_by_network_id(self): + port1 = {'network_id': 'a'} + port2 = {'network_id': 'b'} + port3 = {'network_id': 'a'} + grouped_ports = self.callbacks._group_by_network_id( + [port1, port2, port3]) + expected = {'a': [port1, port3], 'b': [port2]} + self.assertEqual(expected, grouped_ports) + + def test_get_active_networks_info(self): + plugin_retval = [{'id': 'a'}, {'id': 'b'}] + self.plugin.get_networks.return_value = plugin_retval + port = {'network_id': 'a'} + subnet = {'network_id': 'b'} + self.plugin.get_ports.return_value = [port] + self.plugin.get_subnets.return_value = [subnet] + networks = self.callbacks.get_active_networks_info(mock.Mock(), + host='host') + expected = [{'id': 'a', 'subnets': [], 'ports': [port]}, + {'id': 'b', 'subnets': [subnet], 'ports': []}] + self.assertEqual(expected, networks) + def _test__port_action_with_failures(self, exc=None, action=None): port = { 'network_id': 'foo_network_id',