[openstack-dev] [nova] Consistency, efficiency, and safety of NovaObject.save()
Mike Bayer
mbayer at redhat.com
Wed Nov 12 23:35:43 UTC 2014
> On Nov 12, 2014, at 6:23 PM, Mike Bayer <mbayer at redhat.com> wrote:
>
>
> If I may inquire as to the irrelevant complexity, I’m trying to pinpoint where you see this happening.
>
> When we talk about updating a ComputeNode, because I’m only slightly familiar with Nova’s codebase, I assume we are looking at “def compute_node_update()” on line 633 of nova/db/sqlalchemy/api.py ?
>
> if that’s the full extent of it, I’m not seeing the second select:
>
> def compute_node_update(context, compute_id, values):
> """Updates the ComputeNode record with the most recent data."""
>
> session = get_session()
> with session.begin():
> compute_ref = _compute_node_get(context, compute_id, session=session)
> values['updated_at'] = timeutils.utcnow()
> datetime_keys = ('created_at', 'deleted_at', 'updated_at')
> convert_objects_related_datetimes(values, *datetime_keys)
> compute_ref.update(values)
>
> return compute_ref
>
> so “with session.begin()”, when that context ends, will emit the flush of the compute_ref, and then commit the transaction. The Session by default has a behavior “expire_on_commit”, which means that when this compute_ref is returned to the outside world, the first thing that accesses anything on it *will* emit a SELECT for the row again. However, as far as I can tell the expire_on_commit flag is turned off. get_session() returns from oslo.db’s EngineFacade (the subject of my previously mentioned blueprint), and that passes through “expire_on_commit” of False by default. It is definitely False when oslo.db does the sessionmaker and I see no code that is setting it to True anywhere. The save() method is not used here either, but even if it is, NovaBase.save() calls into ModelBase.save() which just calls a flush(), shouldn’t be emitting a SELECT either.
>
> Let me know if a. I’m looking in the right place, b. if this second SELECT is actually observed; if it’s occurring I’d like to understand better what we’re looking at.
ah, we’re talking about the objects level:
class ComputeNode(base.NovaPersistentObject, base.NovaObject):
# …
@base.remotable
def save(self, context, prune_stats=False):
# NOTE(belliott) ignore prune_stats param, no longer relevant
updates = self.obj_get_changes()
updates.pop('id', None)
self._convert_stats_to_db_format(updates)
self._convert_host_ip_to_db_format(updates)
self._convert_supported_instances_to_db_format(updates)
db_compute = db.compute_node_update(context, self.id, updates)
self._from_db_object(context, self, db_compute)
I’m not sure if I’m seeing the second SELECT here either but I’m less familiar with what I’m looking at. compute_node_update() does the one SELECT as we said, then it doesn’t look like self._from_db_object() would emit any further SQL specific to that row. I see that it calls upon db_compute.get('supported_instances’) but that’s something different.
More information about the OpenStack-dev
mailing list