Load "lighter" db resources when appropriate
Sometimes we know we will only access particular fields of a resource object, rather than *all* of them. This commit allows the caller to specify (optionally) the fields that should be populated when the resource object is instantiated. This saves memory, trips to the db, and in some cases avoids extra join queries (e.g. for resource.data or resource.rsrc_prop_data). Change-Id: I405888f46451d2657aa28f610f8ca555215ff5cf Partial-Bug: #1680658
This commit is contained in:
parent
157ede1949
commit
93fab308e8
|
@ -173,7 +173,7 @@ def raw_template_files_get(context, files_id):
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def resource_get(context, resource_id, refresh=False):
|
def resource_get(context, resource_id, refresh=False, refresh_data=False):
|
||||||
result = context.session.query(models.Resource).get(resource_id)
|
result = context.session.query(models.Resource).get(resource_id)
|
||||||
|
|
||||||
if not result:
|
if not result:
|
||||||
|
@ -181,8 +181,9 @@ def resource_get(context, resource_id, refresh=False):
|
||||||
resource_id)
|
resource_id)
|
||||||
if refresh:
|
if refresh:
|
||||||
context.session.refresh(result)
|
context.session.refresh(result)
|
||||||
# ensure data is loaded (lazy or otherwise)
|
if refresh_data:
|
||||||
result.data
|
# ensure data is loaded (lazy or otherwise)
|
||||||
|
result.data
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,8 @@ class CheckResource(object):
|
||||||
|
|
||||||
def _try_steal_engine_lock(self, cnxt, resource_id):
|
def _try_steal_engine_lock(self, cnxt, resource_id):
|
||||||
rs_obj = resource_objects.Resource.get_obj(cnxt,
|
rs_obj = resource_objects.Resource.get_obj(cnxt,
|
||||||
resource_id)
|
resource_id,
|
||||||
|
fields=('engine_id', ))
|
||||||
if rs_obj.engine_id not in (None, self.engine_id):
|
if rs_obj.engine_id not in (None, self.engine_id):
|
||||||
if not listener_client.EngineListenerClient(
|
if not listener_client.EngineListenerClient(
|
||||||
rs_obj.engine_id).is_alive(cnxt):
|
rs_obj.engine_id).is_alive(cnxt):
|
||||||
|
|
|
@ -418,7 +418,8 @@ class Resource(status.ResourceStatus):
|
||||||
if self._rsrc_metadata is not None:
|
if self._rsrc_metadata is not None:
|
||||||
return self._rsrc_metadata
|
return self._rsrc_metadata
|
||||||
rs = resource_objects.Resource.get_obj(self.stack.context, self.id,
|
rs = resource_objects.Resource.get_obj(self.stack.context, self.id,
|
||||||
refresh=True)
|
refresh=True,
|
||||||
|
fields=('rsrc_metadata', ))
|
||||||
self._rsrc_metadata = rs.rsrc_metadata
|
self._rsrc_metadata = rs.rsrc_metadata
|
||||||
return rs.rsrc_metadata
|
return rs.rsrc_metadata
|
||||||
|
|
||||||
|
@ -439,8 +440,10 @@ class Resource(status.ResourceStatus):
|
||||||
if self.id is None or self.action == self.INIT:
|
if self.id is None or self.action == self.INIT:
|
||||||
raise exception.ResourceNotAvailable(resource_name=self.name)
|
raise exception.ResourceNotAvailable(resource_name=self.name)
|
||||||
refresh = merge_metadata is not None
|
refresh = merge_metadata is not None
|
||||||
db_res = resource_objects.Resource.get_obj(self.stack.context, self.id,
|
db_res = resource_objects.Resource.get_obj(
|
||||||
refresh=refresh)
|
self.stack.context, self.id, refresh=refresh,
|
||||||
|
fields=('rsrc_metadata', 'atomic_key', 'engine_id',
|
||||||
|
'action', 'status'))
|
||||||
if db_res.action == self.DELETE:
|
if db_res.action == self.DELETE:
|
||||||
self._db_res_is_deleted = True
|
self._db_res_is_deleted = True
|
||||||
LOG.debug("resource %(name)s, id: %(id)s is DELETE_%(st)s, "
|
LOG.debug("resource %(name)s, id: %(id)s is DELETE_%(st)s, "
|
||||||
|
@ -1618,7 +1621,8 @@ class Resource(status.ResourceStatus):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
db_res = resource_objects.Resource.get_obj(
|
db_res = resource_objects.Resource.get_obj(
|
||||||
self.context, self.replaced_by)
|
self.context, self.replaced_by,
|
||||||
|
fields=('current_template_id', 'atomic_key'))
|
||||||
except exception.NotFound:
|
except exception.NotFound:
|
||||||
LOG.info("Could not find replacement of resource %(name)s "
|
LOG.info("Could not find replacement of resource %(name)s "
|
||||||
"with id %(id)s while updating needed_by.",
|
"with id %(id)s while updating needed_by.",
|
||||||
|
|
|
@ -100,10 +100,13 @@ class Resource(
|
||||||
}
|
}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _from_db_object(resource, context, db_resource):
|
def _from_db_object(resource, context, db_resource, only_fields=None):
|
||||||
if db_resource is None:
|
if db_resource is None:
|
||||||
return None
|
return None
|
||||||
for field in resource.fields:
|
for field in resource.fields:
|
||||||
|
if (only_fields is not None and field not in only_fields
|
||||||
|
and field != 'id'):
|
||||||
|
continue
|
||||||
if field == 'data':
|
if field == 'data':
|
||||||
resource['data'] = [resource_data.ResourceData._from_db_object(
|
resource['data'] = [resource_data.ResourceData._from_db_object(
|
||||||
resource_data.ResourceData(context), resd
|
resource_data.ResourceData(context), resd
|
||||||
|
@ -150,10 +153,16 @@ class Resource(
|
||||||
return self._properties_data
|
return self._properties_data
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_obj(cls, context, resource_id, refresh=False):
|
def get_obj(cls, context, resource_id, refresh=False, fields=None):
|
||||||
|
if fields is None or 'data' in fields:
|
||||||
|
refresh_data = refresh
|
||||||
|
else:
|
||||||
|
refresh_data = False
|
||||||
resource_db = db_api.resource_get(context, resource_id,
|
resource_db = db_api.resource_get(context, resource_id,
|
||||||
refresh=refresh)
|
refresh=refresh,
|
||||||
return cls._from_db_object(cls(context), context, resource_db)
|
refresh_data=refresh_data)
|
||||||
|
return cls._from_db_object(cls(context), context, resource_db,
|
||||||
|
only_fields=fields)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_all(cls, context):
|
def get_all(cls, context):
|
||||||
|
|
|
@ -582,6 +582,16 @@ class ResourceTest(common.HeatTestCase):
|
||||||
res.store()
|
res.store()
|
||||||
self.assertIsNotNone(res.updated_time)
|
self.assertIsNotNone(res.updated_time)
|
||||||
|
|
||||||
|
def test_resource_object_get_obj_fields(self):
|
||||||
|
snippet = rsrc_defn.ResourceDefinition('aresource',
|
||||||
|
'GenericResourceType')
|
||||||
|
res = resource.Resource('aresource', snippet, self.stack)
|
||||||
|
res.store()
|
||||||
|
res_obj = resource_objects.Resource.get_obj(
|
||||||
|
res.context, res.id, refresh=False, fields=('status', ))
|
||||||
|
self.assertEqual(res_obj.status, res.COMPLETE)
|
||||||
|
self.assertRaises(AttributeError, getattr, res_obj, 'action')
|
||||||
|
|
||||||
def test_resource_object_resource_properties_data(self):
|
def test_resource_object_resource_properties_data(self):
|
||||||
cfg.CONF.set_override('encrypt_parameters_and_properties', True,
|
cfg.CONF.set_override('encrypt_parameters_and_properties', True,
|
||||||
enforce_type=True)
|
enforce_type=True)
|
||||||
|
|
Loading…
Reference in New Issue