From 2db7182570f8217ba63d230f8f644b597ed417e9 Mon Sep 17 00:00:00 2001 From: Eugene Nikanorov Date: Mon, 9 Mar 2015 12:04:34 +0300 Subject: [PATCH] Improve performance of _get_security_group_member_ips Use set operations instead of using list. Currently complexity of the method is O(n^2) where n is amount of ips (amount of VMs in the network). When amount of VM is big (large L2 domain), this method can significantly load the controller. Reduce method complexity to O(n) on average. Change-Id: If1660e8227e5c5cd80d49ebcc6a2e06d33d31939 Closes-Bug: #1429753 --- neutron/api/rpc/handlers/securitygroups_rpc.py | 4 +++- neutron/db/securitygroups_rpc_base.py | 8 ++++---- neutron/tests/unit/test_security_groups_rpc.py | 6 +++--- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/neutron/api/rpc/handlers/securitygroups_rpc.py b/neutron/api/rpc/handlers/securitygroups_rpc.py index d1006d0158f..4d4d0fea82a 100644 --- a/neutron/api/rpc/handlers/securitygroups_rpc.py +++ b/neutron/api/rpc/handlers/securitygroups_rpc.py @@ -71,9 +71,11 @@ class SecurityGroupServerRpcCallback(object): :returns: sg_info{ 'security_groups': {sg_id: [rule1, rule2]} - 'sg_member_ips': {sg_id: {'IPv4': [], 'IPv6': []}} + 'sg_member_ips': {sg_id: {'IPv4': set(), 'IPv6': set()}} 'devices': {device_id: {device_info}} } + + Note that sets are serialized into lists by rpc code. """ devices_info = kwargs.get('devices') ports = self._get_devices_info(devices_info) diff --git a/neutron/db/securitygroups_rpc_base.py b/neutron/db/securitygroups_rpc_base.py index e8f9292c71d..728312b5350 100644 --- a/neutron/db/securitygroups_rpc_base.py +++ b/neutron/db/securitygroups_rpc_base.py @@ -194,7 +194,8 @@ class SecurityGroupServerRpcMixin(sg_db.SecurityGroupDbMixin): if remote_gid not in remote_security_group_info: remote_security_group_info[remote_gid] = {} if ethertype not in remote_security_group_info[remote_gid]: - remote_security_group_info[remote_gid][ethertype] = [] + # this set will be serialized into a list by rpc code + remote_security_group_info[remote_gid][ethertype] = set() direction = rule_in_db['direction'] rule_dict = { @@ -228,9 +229,8 @@ class SecurityGroupServerRpcMixin(sg_db.SecurityGroupDbMixin): for sg_id, member_ips in ips.items(): for ip in member_ips: ethertype = 'IPv%d' % netaddr.IPNetwork(ip).version - if (ethertype in sg_info['sg_member_ips'][sg_id] - and ip not in sg_info['sg_member_ips'][sg_id][ethertype]): - sg_info['sg_member_ips'][sg_id][ethertype].append(ip) + if ethertype in sg_info['sg_member_ips'][sg_id]: + sg_info['sg_member_ips'][sg_id][ethertype].add(ip) return sg_info def _select_rules_for_ports(self, context, ports): diff --git a/neutron/tests/unit/test_security_groups_rpc.py b/neutron/tests/unit/test_security_groups_rpc.py index 50b8936e5af..138e742e55a 100644 --- a/neutron/tests/unit/test_security_groups_rpc.py +++ b/neutron/tests/unit/test_security_groups_rpc.py @@ -490,8 +490,8 @@ class SGServerRpcCallBackTestCase(test_sg.SecurityGroupDBTestCase): 'remote_group_id': sg2_id} ]}, 'sg_member_ips': {sg2_id: { - 'IPv4': [u'10.0.0.3'], - 'IPv6': [], + 'IPv4': set([u'10.0.0.3']), + 'IPv6': set(), }} } self.assertEqual(expected['security_groups'], @@ -626,7 +626,7 @@ class SGServerRpcCallBackTestCase(test_sg.SecurityGroupDBTestCase): 'remote_group_id': sg1_id} ]}, 'sg_member_ips': {sg1_id: { - 'IPv6': [], + 'IPv6': set(), }} } self.assertEqual(expected['security_groups'],