From 369faa28731efd8f79820a0f8aa45dc6d614bec7 Mon Sep 17 00:00:00 2001 From: Kevin Benton Date: Thu, 6 Oct 2016 21:25:58 -0700 Subject: [PATCH] Get rid of double-join to rbac_entries without filter apply_filters_to_query was performing an outerjoin to rbac_entries unconditionally when model_query could have already performed an outerjoin (if the request was from an unprivileged user) and/or when the join wasn't even necessary (the '?shared=False' query that uses a subquery and not a join). This resulted in terrible performance because of cartesian products of rbac entries with themselves. This fixes the issue by ensuring there is only an outerjoin to the rbac table if it's going to be used for a filter condition and it's not already joined because of a query scope imposed due to the user not being privileged. Unfortunately this doesn't include tests to prevent regressions because we don't have any methods for testing the performance of individual queries. Closes-Bug: #1630939 Change-Id: I4364f4a97a29041e86b2fbd8aa895578153f4cf9 (cherry picked from commit 145dbaab21c7b541294869eec547731a9694cbad) --- neutron/db/common_db_mixin.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/neutron/db/common_db_mixin.py b/neutron/db/common_db_mixin.py index bc96258f70a..d816be0a01b 100644 --- a/neutron/db/common_db_mixin.py +++ b/neutron/db/common_db_mixin.py @@ -233,7 +233,6 @@ def _apply_filters_to_query(self, query, model, filters, context=None): elif key == 'shared' and hasattr(model, 'rbac_entries'): # translate a filter on shared into a query against the # object's rbac entries - query = query.outerjoin(model.rbac_entries) rbac = model.rbac_entries.property.mapper.class_ matches = [rbac.target_tenant == '*'] if context: @@ -260,6 +259,12 @@ def _apply_filters_to_query(self, query, model, filters, context=None): query.session.query(rbac.object_id). filter(is_shared) ) + elif (not context or + not self.model_query_scope(context, model)): + # we only want to join if we aren't using the subquery + # and if we aren't already joined because this is a + # scoped query + query = query.outerjoin(model.rbac_entries) query = query.filter(is_shared) for _nam, hooks in six.iteritems(self._model_query_hooks.get(model, {})):