[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):
    # …

    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)

        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