[openstack-dev] [nova] Consistency, efficiency, and safety of NovaObject.save()

Mike Bayer mbayer at redhat.com
Wed Nov 12 23:23:57 UTC 2014

> On Nov 12, 2014, at 10:56 AM, Matthew Booth <mbooth at redhat.com> wrote:
> For brevity, I have conflated what happens in object.save() with what
> happens in db.api. Where the code lives isn't relevant here: I'm only
> looking at what happens.
> Specifically, the following objects refresh themselves on save:
> Aggregate
> BlockDeviceMapping
> ComputeNode

> Excluding irrelevant complexity, the general model for objects which
> refresh on update is:
> object = <select row from object table>
> object.update()
> object.save()
> return <select row from object table again>
> Some objects skip out the second select and return the freshly saved
> object. That is, a save involves an update + either 1 or 2 selects.

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)

        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.

More information about the OpenStack-dev mailing list