Comment 9 for bug 1746509

Revision history for this message
melanie witt (melwitt) wrote :

Going to add a detailed explanation of what's going on here, now that I've traced through all of it.

We get a request to list instances from the API and by default that will do a join with the 'services' table to return service-related information with instances:

https://github.com/openstack/nova/blob/9465d1c/nova/api/openstack/compute/servers.py#L298

Then, in the compute/api, we go to list the instances across cells:

https://github.com/openstack/nova/blob/9465d1c/nova/compute/api.py#L2463

Which will call _get_instances_by_filters per cell:

https://github.com/openstack/nova/blob/9465d1c/nova/compute/api.py#L2561

Which will call objects.InstanceList.get_by_filters to do the database query:

https://github.com/openstack/nova/blob/9465d1c/nova/compute/api.py#L2593

Then, in the object code, we call the _get_by_filters_impl method (notice it's decorated with '@db.select_db_reader_mode', which will start the database transaction context tracking):

https://github.com/openstack/nova/blob/9465d1c/nova/objects/instance.py#L1222

And nested inside of that database transaction context tracking is a call to _make_instance_list:

https://github.com/openstack/nova/blob/9465d1c/nova/objects/instance.py#L1235

Which calls _from_db_object for each returned instance (joined with 'services' in this case):

https://github.com/openstack/nova/blob/9465d1c/nova/objects/instance.py#L1197

Which will construct a ServiceList of Service objects:

https://github.com/openstack/nova/blob/9465d1c/nova/objects/instance.py#L446

Which will call Service._from_db_object as the objects are being created:

https://github.com/openstack/oslo.versionedobjects/blob/c86c6ed/oslo_versionedobjects/base.py#L1120

Which will generate a uuid if one isn't present and attempt to save it, which will fail with "TypeError: Can't upgrade a READER transaction to a WRITER mid-transaction" because we're still nested under the '@db.select_db_reader_mode' decorator from the InstanceList._get_by_filters_impl method:

https://github.com/openstack/nova/blob/9465d1c/nova/objects/service.py#L243

------------------------------

This problem doesn't exist past Pike because the implementation in compute/api was changed to call the instance_list.get_instance_objects_sorted API instead:

https://github.com/openstack/nova/blob/stable/queens/nova/compute/api.py#L2460

And that API has exited the previous database transaction context manager before it goes to call _make_instance_list:

https://github.com/openstack/nova/blob/stable/queens/nova/compute/instance_list.py#L105