From dbc852b47a9a6a1044dd2a554f16f27681dbe762 Mon Sep 17 00:00:00 2001 From: Zane Bitter Date: Mon, 20 Nov 2017 13:59:19 -0500 Subject: [PATCH] Eager-load properties for nested resource list When doing "openstack stack resource list --nested-depth=n", we were lazy-loading the resources' properties data. This is expensive, especially when there are a large number of resources. Eager-load the data, as we always use it to show the resources. For consistency, always eager-load the resource 'data' (even in resource_get), because the Resource versioned object accesses it unconditionally. Change-Id: Idb871fddf77bf24828878c315e19e200c28841be Related-Bug: #1665503 --- heat/db/sqlalchemy/api.py | 10 +++++++--- heat/engine/service.py | 2 +- heat/objects/event.py | 2 +- heat/objects/resource.py | 8 +++++--- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/heat/db/sqlalchemy/api.py b/heat/db/sqlalchemy/api.py index dfdbcde005..0be4b9686b 100644 --- a/heat/db/sqlalchemy/api.py +++ b/heat/db/sqlalchemy/api.py @@ -178,9 +178,9 @@ def raw_template_files_get(context, files_id): def resource_get(context, resource_id, refresh=False, refresh_data=False, eager=True): query = context.session.query(models.Resource) + query = query.options(orm.joinedload("data")) if eager: - query = query.options(orm.joinedload("data")).options( - orm.joinedload("rsrc_prop_data")) + query = query.options(orm.joinedload("rsrc_prop_data")) result = query.get(resource_id) if not result: @@ -495,13 +495,17 @@ def resource_get_all_active_by_stack(context, stack_id): return dict((res.id, res) for res in results) -def resource_get_all_by_root_stack(context, stack_id, filters=None): +def resource_get_all_by_root_stack(context, stack_id, filters=None, + eager=True): query = context.session.query( models.Resource ).filter_by( root_stack_id=stack_id ).options(orm.joinedload("data")) + if eager: + query = query.options(orm.joinedload("rsrc_prop_data")) + query = db_filters.exact_filter(query, models.Resource, filters) results = query.all() diff --git a/heat/engine/service.py b/heat/engine/service.py index fb94cb6b62..e9e054e49d 100644 --- a/heat/engine/service.py +++ b/heat/engine/service.py @@ -1746,7 +1746,7 @@ class EngineService(service.ServiceBase): root_stack_identifier = st.identifier() # find all resources associated with a root stack all_r = resource_objects.Resource.get_all_by_root_stack( - cnxt, st.id, None) + cnxt, st.id, None, eager=False) # find stacks to the requested nested_depth stack_ids = {r.stack_id for r in six.itervalues(all_r)} diff --git a/heat/objects/event.py b/heat/objects/event.py index 6c53c68d2c..eb4f7587cd 100644 --- a/heat/objects/event.py +++ b/heat/objects/event.py @@ -79,7 +79,7 @@ class Event( @property def resource_properties(self): if self._resource_properties is None: - LOG.info('rsrp_prop_data lazy load') + LOG.info('rsrc_prop_data lazy load') rpd_obj = rpd.ResourcePropertiesData.get_by_id( self._context, self.rsrc_prop_data_id) self._resource_properties = rpd_obj.data or {} diff --git a/heat/objects/resource.py b/heat/objects/resource.py index 67cc24a0c9..2e3e6c31fb 100644 --- a/heat/objects/resource.py +++ b/heat/objects/resource.py @@ -164,7 +164,7 @@ class Resource( def properties_data(self): if (not self._properties_data and self.rsrc_prop_data_id is not None): - LOG.info('rsrp_prop_data lazy load') + LOG.info('rsrc_prop_data lazy load') rpd_obj = rpd.ResourcePropertiesData.get_by_id( self._context, self.rsrc_prop_data_id) self._properties_data = rpd_obj.data or {} @@ -264,11 +264,13 @@ class Resource( return dict(resources) @classmethod - def get_all_by_root_stack(cls, context, stack_id, filters, cache=False): + def get_all_by_root_stack(cls, context, stack_id, filters, cache=False, + eager=True): resources_db = db_api.resource_get_all_by_root_stack( context, stack_id, - filters) + filters, + eager=eager) all = cls._resources_to_dict(context, resources_db) if cache: context.cache(ResourceCache).set_by_stack_id(all)