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
This commit is contained in:
Salvatore Orlando 2013-08-22 09:08:52 -07:00
parent b857c86f3b
commit c59456734e
2 changed files with 60 additions and 63 deletions

View File

@ -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:

View File

@ -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_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_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_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']]}