From: Salvatore Orlando Date: Thu, 22 Aug 2013 16:08:52 +0000 (-0700) Subject: Avoid performing extra query for fetching qos bindings X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=72f85b5e616e3aabcab862b944c1a3a2c2844431;p=openstack-build%2Fneutron-build.git Avoid performing extra query for fetching qos bindings Bug 1215872 Add a relationship with eager loading in the Port and Network models, thus preventing the 'extend' functions from performing extra queries. This patch also slight alters the methods for processing qos_queue bindings in order to allow them for populating the qos_queue id in the response being created. Change-Id: Ie80d12aeed5de94afa61f23d7bcfc21372f23c4f --- diff --git a/neutron/plugins/nicira/NeutronPlugin.py b/neutron/plugins/nicira/NeutronPlugin.py index f5b276e1b..f5ce48f92 100644 --- a/neutron/plugins/nicira/NeutronPlugin.py +++ b/neutron/plugins/nicira/NeutronPlugin.py @@ -430,7 +430,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin, port_data['fixed_ips'], port_data[psec.PORTSECURITY], port_data[ext_sg.SECURITYGROUPS], - port_data[ext_qos.QUEUE], + port_data.get(ext_qos.QUEUE), port_data.get(mac_ext.MAC_LEARNING), port_data.get(addr_pair.ADDRESS_PAIRS)) @@ -991,12 +991,12 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin, # DB Operations for setting the network as external self._process_l3_create(context, new_net, net_data) # Process QoS queue extension - if network['network'].get(ext_qos.QUEUE): - new_net[ext_qos.QUEUE] = network['network'][ext_qos.QUEUE] + net_queue_id = net_data.get(ext_qos.QUEUE) + if net_queue_id: # Raises if not found - self.get_qos_queue(context, new_net[ext_qos.QUEUE]) - self._process_network_queue_mapping(context, new_net) - self._extend_network_qos_queue(context, new_net) + self.get_qos_queue(context, net_queue_id) + self._process_network_queue_mapping( + context, new_net, net_queue_id) if (net_data.get(mpnet.SEGMENTS) and isinstance(provider_type, bool)): @@ -1078,7 +1078,6 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin, # to add provider networks fields net_result = self._make_network_dict(network) self._extend_network_dict_provider(context, net_result) - self._extend_network_qos_queue(context, net_result) return self._fields(net_result, fields) def get_networks(self, context, filters=None, fields=None): @@ -1087,7 +1086,6 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin, networks = super(NvpPluginV2, self).get_networks(context, filters) for net in networks: self._extend_network_dict_provider(context, net) - self._extend_network_qos_queue(context, net) return [self._fields(network, fields) for network in networks] def update_network(self, context, id, network): @@ -1102,23 +1100,14 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin, if psec.PORTSECURITY in network['network']: self._process_network_port_security_update( context, network['network'], net) - if network['network'].get(ext_qos.QUEUE): - net[ext_qos.QUEUE] = network['network'][ext_qos.QUEUE] + net_queue_id = network['network'].get(ext_qos.QUEUE) + if net_queue_id: self._delete_network_queue_mapping(context, id) - self._process_network_queue_mapping(context, net) + self._process_network_queue_mapping(context, net, net_queue_id) self._process_l3_update(context, net, network['network']) self._extend_network_dict_provider(context, net) - self._extend_network_qos_queue(context, net) return net - def get_ports(self, context, filters=None, fields=None): - filters = filters or {} - with context.session.begin(subtransactions=True): - ports = super(NvpPluginV2, self).get_ports(context, filters) - for port in ports: - self._extend_port_qos_queue(context, port) - return [self._fields(port, fields) for port in ports] - def create_port(self, context, port): # If PORTSECURITY is not the default value ATTR_NOT_SPECIFIED # then we pass the port to the policy engine. The reason why we don't @@ -1161,9 +1150,10 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin, self._process_port_create_security_group( context, port_data, port_data[ext_sg.SECURITYGROUPS]) # QoS extension checks - port_data[ext_qos.QUEUE] = self._check_for_queue_and_create( + port_queue_id = self._check_for_queue_and_create( context, port_data) - self._process_port_queue_mapping(context, port_data) + self._process_port_queue_mapping( + context, port_data, port_queue_id) if (isinstance(port_data.get(mac_ext.MAC_LEARNING), bool)): self._create_mac_learning_state(context, port_data) elif mac_ext.MAC_LEARNING in port_data: @@ -1172,9 +1162,6 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin, LOG.debug(_("create_port completed on NVP for tenant " "%(tenant_id)s: (%(id)s)"), port_data) - # remove since it will be added in extend based on policy - del port_data[ext_qos.QUEUE] - self._extend_port_qos_queue(context, port_data) self._process_portbindings_create_and_update(context, port, port_data) # DB Operation is complete, perform NVP operation @@ -1272,7 +1259,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin, self._process_port_port_security_update( context, port['port'], ret_port) - ret_port[ext_qos.QUEUE] = self._check_for_queue_and_create( + port_queue_id = self._check_for_queue_and_create( context, ret_port) # Populate the mac learning attribute new_mac_learning_state = port['port'].get(mac_ext.MAC_LEARNING) @@ -1282,7 +1269,8 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin, new_mac_learning_state) ret_port[mac_ext.MAC_LEARNING] = new_mac_learning_state self._delete_port_queue_mapping(context, ret_port['id']) - self._process_port_queue_mapping(context, ret_port) + self._process_port_queue_mapping(context, ret_port, + port_queue_id) LOG.warn(_("Update port request: %s"), port) nvp_port_id = self._nvp_get_port_id( context, self.cluster, ret_port) @@ -1317,9 +1305,6 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin, else: ret_port['status'] = constants.PORT_STATUS_ERROR - # remove since it will be added in extend based on policy - del ret_port[ext_qos.QUEUE] - self._extend_port_qos_queue(context, ret_port) self._process_portbindings_create_and_update(context, port['port'], port) @@ -1371,11 +1356,9 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin, db_port = self._get_port(context, id) self._synchronizer.synchronize_port( context, db_port) - port = self._make_port_dict(db_port, fields) + return self._make_port_dict(db_port, fields) else: - port = super(NvpPluginV2, self).get_port(context, id, fields) - self._extend_port_qos_queue(context, port) - return port + return super(NvpPluginV2, self).get_port(context, id, fields) def get_router(self, context, id, fields=None): if fields and 'status' in fields: diff --git a/neutron/plugins/nicira/dbexts/nicira_qos_db.py b/neutron/plugins/nicira/dbexts/nicira_qos_db.py index 875850a22..86a4cd57b 100644 --- a/neutron/plugins/nicira/dbexts/nicira_qos_db.py +++ b/neutron/plugins/nicira/dbexts/nicira_qos_db.py @@ -17,9 +17,11 @@ # @author: Aaron Rosen, Nicira, Inc import sqlalchemy as sa +from sqlalchemy import orm from sqlalchemy.orm import exc from neutron.api.v2 import attributes as attr +from neutron.db import db_base_plugin_v2 from neutron.db import model_base from neutron.db import models_v2 from neutron.openstack.common import log @@ -49,6 +51,13 @@ class PortQueueMapping(model_base.BASEV2): queue_id = sa.Column(sa.String(36), sa.ForeignKey("qosqueues.id"), primary_key=True) + # Add a relationship to the Port model adding a backref which will + # allow SQLAlchemy for eagerly load the queue binding + port = orm.relationship( + models_v2.Port, + backref=orm.backref("qos_queue", uselist=False, + cascade='delete', lazy='joined')) + class NetworkQueueMapping(model_base.BASEV2): network_id = sa.Column(sa.String(36), @@ -58,6 +67,13 @@ class NetworkQueueMapping(model_base.BASEV2): queue_id = sa.Column(sa.String(36), sa.ForeignKey("qosqueues.id", ondelete="CASCADE")) + # Add a relationship to the Network model adding a backref which will + # allow SQLAlcremy for eagerly load the queue binding + network = orm.relationship( + models_v2.Network, + backref=orm.backref("qos_queue", uselist=False, + cascade='delete', lazy='joined')) + class NVPQoSDbMixin(ext_qos.QueuePluginBase): """Mixin class to add queues.""" @@ -96,13 +112,13 @@ class NVPQoSDbMixin(ext_qos.QueuePluginBase): with context.session.begin(subtransactions=True): context.session.delete(qos_queue) - def _process_port_queue_mapping(self, context, p): - if not p.get(ext_qos.QUEUE): + def _process_port_queue_mapping(self, context, port_data, queue_id): + port_data[ext_qos.QUEUE] = queue_id + if not queue_id: return with context.session.begin(subtransactions=True): - db = PortQueueMapping(port_id=p['id'], - queue_id=p.get(ext_qos.QUEUE)) - context.session.add(db) + context.session.add(PortQueueMapping(port_id=port_data['id'], + queue_id=queue_id)) def _get_port_queue_bindings(self, context, filters=None, fields=None): return self._get_collection(context, PortQueueMapping, @@ -121,13 +137,14 @@ class NVPQoSDbMixin(ext_qos.QueuePluginBase): with context.session.begin(subtransactions=True): context.session.delete(binding) - def _process_network_queue_mapping(self, context, network): - if not network.get(ext_qos.QUEUE): + def _process_network_queue_mapping(self, context, net_data, queue_id): + net_data[ext_qos.QUEUE] = queue_id + if not queue_id: return with context.session.begin(subtransactions=True): - db = NetworkQueueMapping(network_id=network['id'], - queue_id=network.get(ext_qos.QUEUE)) - context.session.add(db) + context.session.add( + NetworkQueueMapping(network_id=net_data['id'], + queue_id=queue_id)) def _get_network_queue_bindings(self, context, filters=None, fields=None): return self._get_collection(context, NetworkQueueMapping, @@ -141,25 +158,23 @@ class NVPQoSDbMixin(ext_qos.QueuePluginBase): if binding: context.session.delete(binding) - def _extend_port_qos_queue(self, context, port): - filters = {'port_id': [port['id']]} - fields = ['queue_id'] - port[ext_qos.QUEUE] = None - queue_id = self._get_port_queue_bindings( - context, filters, fields) - if queue_id: - port[ext_qos.QUEUE] = queue_id[0]['queue_id'] - return port - - def _extend_network_qos_queue(self, context, network): - filters = {'network_id': [network['id']]} - fields = ['queue_id'] - network[ext_qos.QUEUE] = None - queue_id = self._get_network_queue_bindings( - context, filters, fields) - if queue_id: - network[ext_qos.QUEUE] = queue_id[0]['queue_id'] - return network + def _extend_dict_qos_queue(self, obj_res, obj_db): + queue_mapping = obj_db['qos_queue'] + if queue_mapping: + obj_res[ext_qos.QUEUE] = queue_mapping.get('queue_id') + return obj_res + + def _extend_port_dict_qos_queue(self, port_res, port_db): + self._extend_dict_qos_queue(port_res, port_db) + + def _extend_network_dict_qos_queue(self, network_res, network_db): + self._extend_dict_qos_queue(network_res, network_db) + + # Register dict extend functions for networks and ports + db_base_plugin_v2.NeutronDbPluginV2.register_dict_extend_funcs( + attr.NETWORKS, ['_extend_network_dict_qos_queue']) + db_base_plugin_v2.NeutronDbPluginV2.register_dict_extend_funcs( + attr.PORTS, ['_extend_port_dict_qos_queue']) def _make_qos_queue_dict(self, queue, fields=None): res = {'id': queue['id'], @@ -215,7 +230,6 @@ class NVPQoSDbMixin(ext_qos.QueuePluginBase): filters = {'network_id': [port['network_id']]} network_queue_id = self._get_network_queue_bindings( context, filters, ['queue_id']) - if network_queue_id: # get networks that queue is assocated with filters = {'queue_id': [network_queue_id[0]['queue_id']]}