summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Benton <blak111@gmail.com>2014-09-24 05:23:32 -0700
committerKevin Benton <kevinbenton@buttewifi.com>2014-10-22 09:46:45 +0000
commitc14b58b1f8ba2f87c717441cdfca1c4c1be2f050 (patch)
tree19d89e271e7beb48b5055c42af71f778aabb673e
parent830142e6923ff5fa8303afc22b0b61c39a374fe8 (diff)
downloadneutron-c14b58b1f8ba2f87c717441cdfca1c4c1be2f050.tar.gz
Improve performance of security group DB query
The _select_ips_for_remote_group method was joining the IP allocation, port, allowed address pair, and security group tables together in a single query. Additionally, it was loading all of the port columns and using none of them. This resulted in a very expensive query with no benefit. This patch eliminates the unnecessary use of the port table by joining the IP allocation table directly to the security groups and allowed address pairs tables. In local testing of the method, this sped it up by an order of magnitude. Closes-Bug: #1373851 Change-Id: I12899413004838d2d22b691f1e2f3b18f7ec2c27 (cherry picked from commit 04df85b6e5a098f8f55bb82f04d9769763beb487)
-rw-r--r--neutron/db/securitygroups_rpc_base.py30
1 files changed, 18 insertions, 12 deletions
diff --git a/neutron/db/securitygroups_rpc_base.py b/neutron/db/securitygroups_rpc_base.py
index 1dda6bb469..233a50a3ac 100644
--- a/neutron/db/securitygroups_rpc_base.py
+++ b/neutron/db/securitygroups_rpc_base.py
@@ -19,6 +19,7 @@ from sqlalchemy.orm import exc
from neutron.common import constants as q_const
from neutron.common import ipv6_utils as ipv6
from neutron.common import utils
+from neutron.db import allowedaddresspairs_db as addr_pair
from neutron.db import models_v2
from neutron.db import securitygroups_db as sg_db
from neutron.extensions import securitygroup as ext_sg
@@ -231,27 +232,32 @@ class SecurityGroupServerRpcMixin(sg_db.SecurityGroupDbMixin):
if not remote_group_ids:
return ips_by_group
for remote_group_id in remote_group_ids:
- ips_by_group[remote_group_id] = []
+ ips_by_group[remote_group_id] = set()
ip_port = models_v2.IPAllocation.port_id
sg_binding_port = sg_db.SecurityGroupPortBinding.port_id
sg_binding_sgid = sg_db.SecurityGroupPortBinding.security_group_id
+ # Join the security group binding table directly to the IP allocation
+ # table instead of via the Port table skip an unnecessary intermediary
query = context.session.query(sg_binding_sgid,
- models_v2.Port,
- models_v2.IPAllocation.ip_address)
+ models_v2.IPAllocation.ip_address,
+ addr_pair.AllowedAddressPair.ip_address)
query = query.join(models_v2.IPAllocation,
ip_port == sg_binding_port)
- query = query.join(models_v2.Port,
- ip_port == models_v2.Port.id)
+ # Outerjoin because address pairs may be null and we still want the
+ # IP for the port.
+ query = query.outerjoin(
+ addr_pair.AllowedAddressPair,
+ sg_binding_port == addr_pair.AllowedAddressPair.port_id)
query = query.filter(sg_binding_sgid.in_(remote_group_ids))
- for security_group_id, port, ip_address in query:
- ips_by_group[security_group_id].append(ip_address)
- # if there are allowed_address_pairs add them
- if getattr(port, 'allowed_address_pairs', None):
- for address_pair in port.allowed_address_pairs:
- ips_by_group[security_group_id].append(
- address_pair['ip_address'])
+ # Each allowed address pair IP record for a port beyond the 1st
+ # will have a duplicate regular IP in the query response since
+ # the relationship is 1-to-many. Dedup with a set
+ for security_group_id, ip_address, allowed_addr_ip in query:
+ ips_by_group[security_group_id].add(ip_address)
+ if allowed_addr_ip:
+ ips_by_group[security_group_id].add(allowed_addr_ip)
return ips_by_group
def _select_remote_group_ids(self, ports):