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['fixed_ips'],
port_data[psec.PORTSECURITY], port_data[psec.PORTSECURITY],
port_data[ext_sg.SECURITYGROUPS], 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(mac_ext.MAC_LEARNING),
port_data.get(addr_pair.ADDRESS_PAIRS)) 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 # DB Operations for setting the network as external
self._process_l3_create(context, new_net, net_data) self._process_l3_create(context, new_net, net_data)
# Process QoS queue extension # Process QoS queue extension
if network['network'].get(ext_qos.QUEUE): net_queue_id = net_data.get(ext_qos.QUEUE)
new_net[ext_qos.QUEUE] = network['network'][ext_qos.QUEUE] if net_queue_id:
# Raises if not found # Raises if not found
self.get_qos_queue(context, new_net[ext_qos.QUEUE]) self.get_qos_queue(context, net_queue_id)
self._process_network_queue_mapping(context, new_net) self._process_network_queue_mapping(
self._extend_network_qos_queue(context, new_net) context, new_net, net_queue_id)
if (net_data.get(mpnet.SEGMENTS) and if (net_data.get(mpnet.SEGMENTS) and
isinstance(provider_type, bool)): isinstance(provider_type, bool)):
@ -1078,7 +1078,6 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
# to add provider networks fields # to add provider networks fields
net_result = self._make_network_dict(network) net_result = self._make_network_dict(network)
self._extend_network_dict_provider(context, net_result) self._extend_network_dict_provider(context, net_result)
self._extend_network_qos_queue(context, net_result)
return self._fields(net_result, fields) return self._fields(net_result, fields)
def get_networks(self, context, filters=None, fields=None): 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) networks = super(NvpPluginV2, self).get_networks(context, filters)
for net in networks: for net in networks:
self._extend_network_dict_provider(context, net) self._extend_network_dict_provider(context, net)
self._extend_network_qos_queue(context, net)
return [self._fields(network, fields) for network in networks] return [self._fields(network, fields) for network in networks]
def update_network(self, context, id, network): def update_network(self, context, id, network):
@ -1102,23 +1100,14 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
if psec.PORTSECURITY in network['network']: if psec.PORTSECURITY in network['network']:
self._process_network_port_security_update( self._process_network_port_security_update(
context, network['network'], net) context, network['network'], net)
if network['network'].get(ext_qos.QUEUE): net_queue_id = network['network'].get(ext_qos.QUEUE)
net[ext_qos.QUEUE] = network['network'][ext_qos.QUEUE] if net_queue_id:
self._delete_network_queue_mapping(context, 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._process_l3_update(context, net, network['network'])
self._extend_network_dict_provider(context, net) self._extend_network_dict_provider(context, net)
self._extend_network_qos_queue(context, net)
return 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): def create_port(self, context, port):
# If PORTSECURITY is not the default value ATTR_NOT_SPECIFIED # 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 # 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( self._process_port_create_security_group(
context, port_data, port_data[ext_sg.SECURITYGROUPS]) context, port_data, port_data[ext_sg.SECURITYGROUPS])
# QoS extension checks # 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) 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)): if (isinstance(port_data.get(mac_ext.MAC_LEARNING), bool)):
self._create_mac_learning_state(context, port_data) self._create_mac_learning_state(context, port_data)
elif mac_ext.MAC_LEARNING in 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 " LOG.debug(_("create_port completed on NVP for tenant "
"%(tenant_id)s: (%(id)s)"), port_data) "%(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, self._process_portbindings_create_and_update(context,
port, port_data) port, port_data)
# DB Operation is complete, perform NVP operation # DB Operation is complete, perform NVP operation
@ -1272,7 +1259,7 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
self._process_port_port_security_update( self._process_port_port_security_update(
context, port['port'], ret_port) 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) context, ret_port)
# Populate the mac learning attribute # Populate the mac learning attribute
new_mac_learning_state = port['port'].get(mac_ext.MAC_LEARNING) 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) new_mac_learning_state)
ret_port[mac_ext.MAC_LEARNING] = new_mac_learning_state ret_port[mac_ext.MAC_LEARNING] = new_mac_learning_state
self._delete_port_queue_mapping(context, ret_port['id']) 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) LOG.warn(_("Update port request: %s"), port)
nvp_port_id = self._nvp_get_port_id( nvp_port_id = self._nvp_get_port_id(
context, self.cluster, ret_port) context, self.cluster, ret_port)
@ -1317,9 +1305,6 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
else: else:
ret_port['status'] = constants.PORT_STATUS_ERROR 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, self._process_portbindings_create_and_update(context,
port['port'], port['port'],
port) port)
@ -1371,11 +1356,9 @@ class NvpPluginV2(addr_pair_db.AllowedAddressPairsMixin,
db_port = self._get_port(context, id) db_port = self._get_port(context, id)
self._synchronizer.synchronize_port( self._synchronizer.synchronize_port(
context, db_port) context, db_port)
port = self._make_port_dict(db_port, fields) return self._make_port_dict(db_port, fields)
else: else:
port = super(NvpPluginV2, self).get_port(context, id, fields) return super(NvpPluginV2, self).get_port(context, id, fields)
self._extend_port_qos_queue(context, port)
return port
def get_router(self, context, id, fields=None): def get_router(self, context, id, fields=None):
if fields and 'status' in fields: if fields and 'status' in fields:

View File

@ -17,9 +17,11 @@
# @author: Aaron Rosen, Nicira, Inc # @author: Aaron Rosen, Nicira, Inc
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import orm
from sqlalchemy.orm import exc from sqlalchemy.orm import exc
from neutron.api.v2 import attributes as attr 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 model_base
from neutron.db import models_v2 from neutron.db import models_v2
from neutron.openstack.common import log 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"), queue_id = sa.Column(sa.String(36), sa.ForeignKey("qosqueues.id"),
primary_key=True) 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): class NetworkQueueMapping(model_base.BASEV2):
network_id = sa.Column(sa.String(36), 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", queue_id = sa.Column(sa.String(36), sa.ForeignKey("qosqueues.id",
ondelete="CASCADE")) 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): class NVPQoSDbMixin(ext_qos.QueuePluginBase):
"""Mixin class to add queues.""" """Mixin class to add queues."""
@ -96,13 +112,13 @@ class NVPQoSDbMixin(ext_qos.QueuePluginBase):
with context.session.begin(subtransactions=True): with context.session.begin(subtransactions=True):
context.session.delete(qos_queue) context.session.delete(qos_queue)
def _process_port_queue_mapping(self, context, p): def _process_port_queue_mapping(self, context, port_data, queue_id):
if not p.get(ext_qos.QUEUE): port_data[ext_qos.QUEUE] = queue_id
if not queue_id:
return return
with context.session.begin(subtransactions=True): with context.session.begin(subtransactions=True):
db = PortQueueMapping(port_id=p['id'], context.session.add(PortQueueMapping(port_id=port_data['id'],
queue_id=p.get(ext_qos.QUEUE)) queue_id=queue_id))
context.session.add(db)
def _get_port_queue_bindings(self, context, filters=None, fields=None): def _get_port_queue_bindings(self, context, filters=None, fields=None):
return self._get_collection(context, PortQueueMapping, return self._get_collection(context, PortQueueMapping,
@ -121,13 +137,14 @@ class NVPQoSDbMixin(ext_qos.QueuePluginBase):
with context.session.begin(subtransactions=True): with context.session.begin(subtransactions=True):
context.session.delete(binding) context.session.delete(binding)
def _process_network_queue_mapping(self, context, network): def _process_network_queue_mapping(self, context, net_data, queue_id):
if not network.get(ext_qos.QUEUE): net_data[ext_qos.QUEUE] = queue_id
if not queue_id:
return return
with context.session.begin(subtransactions=True): with context.session.begin(subtransactions=True):
db = NetworkQueueMapping(network_id=network['id'], context.session.add(
queue_id=network.get(ext_qos.QUEUE)) NetworkQueueMapping(network_id=net_data['id'],
context.session.add(db) queue_id=queue_id))
def _get_network_queue_bindings(self, context, filters=None, fields=None): def _get_network_queue_bindings(self, context, filters=None, fields=None):
return self._get_collection(context, NetworkQueueMapping, return self._get_collection(context, NetworkQueueMapping,
@ -141,25 +158,23 @@ class NVPQoSDbMixin(ext_qos.QueuePluginBase):
if binding: if binding:
context.session.delete(binding) context.session.delete(binding)
def _extend_port_qos_queue(self, context, port): def _extend_dict_qos_queue(self, obj_res, obj_db):
filters = {'port_id': [port['id']]} queue_mapping = obj_db['qos_queue']
fields = ['queue_id'] if queue_mapping:
port[ext_qos.QUEUE] = None obj_res[ext_qos.QUEUE] = queue_mapping.get('queue_id')
queue_id = self._get_port_queue_bindings( return obj_res
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): def _extend_port_dict_qos_queue(self, port_res, port_db):
filters = {'network_id': [network['id']]} self._extend_dict_qos_queue(port_res, port_db)
fields = ['queue_id']
network[ext_qos.QUEUE] = None def _extend_network_dict_qos_queue(self, network_res, network_db):
queue_id = self._get_network_queue_bindings( self._extend_dict_qos_queue(network_res, network_db)
context, filters, fields)
if queue_id: # Register dict extend functions for networks and ports
network[ext_qos.QUEUE] = queue_id[0]['queue_id'] db_base_plugin_v2.NeutronDbPluginV2.register_dict_extend_funcs(
return network 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): def _make_qos_queue_dict(self, queue, fields=None):
res = {'id': queue['id'], res = {'id': queue['id'],
@ -215,7 +230,6 @@ class NVPQoSDbMixin(ext_qos.QueuePluginBase):
filters = {'network_id': [port['network_id']]} filters = {'network_id': [port['network_id']]}
network_queue_id = self._get_network_queue_bindings( network_queue_id = self._get_network_queue_bindings(
context, filters, ['queue_id']) context, filters, ['queue_id'])
if network_queue_id: if network_queue_id:
# get networks that queue is assocated with # get networks that queue is assocated with
filters = {'queue_id': [network_queue_id[0]['queue_id']]} filters = {'queue_id': [network_queue_id[0]['queue_id']]}