Use subqueries for rbac_entries and subnets<->network
Loading subnets as part of the networks list and networks as part of the subnets list appears to have a significant impact when the network has tags and the subnets have extra routes entries. This is even further compounded by the network having rbac entries (likely due to the subnet inheriting the RBAC entries of the network with the custom join condition in the model). This patch converts rbac_entries on both subnet and network to use a subquery and converts the network and subnets relationships on the subnet and network models (respectively) to use subqueries as well. On my dev environment after running the script in the report, a network list took 5 minutes. Converting just the rbac_entries or just the network/subnet relationship to subqueries reduced it to 3-5 seconds. Converting both (as this patch does), reduces it back down to a couple of hundred milliseconds (normal perf of my development env with the current network count). Subqueries will just cost us a constant number of queries and won't scale up with result count so this should not impact scalability in any way. None of these fields are queryable from the API, so we don't need to worry about breaking queries against the models. Partial-Bug: #1649317 Change-Id: Ic1947e3d78d58a79b21344b10cb7ab0e573e419f
This commit is contained in:
parent
14079d0f21
commit
a802b382d3
|
@ -151,7 +151,7 @@ class DbBasePluginCommon(common_db_mixin.CommonDbMixin):
|
|||
for route in subnet['routes']],
|
||||
}
|
||||
# The shared attribute for a subnet is the same as its parent network
|
||||
res['shared'] = self._is_network_shared(context, subnet.networks)
|
||||
res['shared'] = self._is_network_shared(context, subnet.rbac_entries)
|
||||
# Call auxiliary extend functions, if any
|
||||
self._apply_dict_extend_functions(attributes.SUBNETS, res, subnet)
|
||||
return db_utils.resource_fields(res, fields)
|
||||
|
@ -270,18 +270,18 @@ class DbBasePluginCommon(common_db_mixin.CommonDbMixin):
|
|||
'status': network['status'],
|
||||
'subnets': [subnet['id']
|
||||
for subnet in network['subnets']]}
|
||||
res['shared'] = self._is_network_shared(context, network)
|
||||
res['shared'] = self._is_network_shared(context, network.rbac_entries)
|
||||
# Call auxiliary extend functions, if any
|
||||
if process_extensions:
|
||||
self._apply_dict_extend_functions(
|
||||
attributes.NETWORKS, res, network)
|
||||
return db_utils.resource_fields(res, fields)
|
||||
|
||||
def _is_network_shared(self, context, network):
|
||||
def _is_network_shared(self, context, rbac_entries):
|
||||
# The shared attribute for a network now reflects if the network
|
||||
# is shared to the calling tenant via an RBAC entry.
|
||||
matches = ('*',) + ((context.tenant_id,) if context else ())
|
||||
for entry in network.rbac_entries:
|
||||
for entry in rbac_entries:
|
||||
if (entry.action == 'access_as_shared' and
|
||||
entry.target_tenant in matches):
|
||||
return True
|
||||
|
|
|
@ -186,7 +186,7 @@ class Subnet(standard_attr.HasStandardAttributes, model_base.BASEV2,
|
|||
# subnets don't have their own rbac_entries, they just inherit from
|
||||
# the network rbac entries
|
||||
rbac_entries = orm.relationship(
|
||||
rbac_db_models.NetworkRBAC, lazy='joined', uselist=True,
|
||||
rbac_db_models.NetworkRBAC, lazy='subquery', uselist=True,
|
||||
foreign_keys='Subnet.network_id',
|
||||
primaryjoin='Subnet.network_id==NetworkRBAC.object_id')
|
||||
api_collections = [attr.SUBNETS]
|
||||
|
@ -236,13 +236,13 @@ class Network(standard_attr.HasStandardAttributes, model_base.BASEV2,
|
|||
name = sa.Column(sa.String(attr.NAME_MAX_LEN))
|
||||
ports = orm.relationship(Port, backref='networks')
|
||||
subnets = orm.relationship(
|
||||
Subnet, backref=orm.backref('networks', lazy='joined'),
|
||||
lazy="joined")
|
||||
Subnet, backref=orm.backref('networks', lazy='subquery'),
|
||||
lazy="subquery")
|
||||
status = sa.Column(sa.String(16))
|
||||
admin_state_up = sa.Column(sa.Boolean)
|
||||
vlan_transparent = sa.Column(sa.Boolean, nullable=True)
|
||||
rbac_entries = orm.relationship(rbac_db_models.NetworkRBAC,
|
||||
backref='network', lazy='joined',
|
||||
backref='network', lazy='subquery',
|
||||
cascade='all, delete, delete-orphan')
|
||||
availability_zone_hints = sa.Column(sa.String(255))
|
||||
dhcp_agents = orm.relationship(
|
||||
|
|
Loading…
Reference in New Issue