[openstack-dev] [neutron][ovo] NeutronDbObject concurrency issues
Michał Dulko
michal.dulko at intel.com
Mon May 16 15:18:44 UTC 2016
On 05/12/2016 08:26 PM, Ilya Chukhnakov wrote:
> Hi everyone.
>
> I’ve recently found that straightforward use of NeutronDbObject is prone to
> concurrency-related problems.
>
> I’ve submitted a patch set [3] with some tests to show that without special
> treatment using NeutronDbObject could lead to unexpected results.
>
> Further patch sets will provide acquire_object/acquire_objects contextmanager
> methods to the NeutronDbObject class. These methods are to be used in place of
> get_object/get_objects whenever the user intends to make changes to the object.
> These methods would start an autonested_transaction.
>
> There are (at least) two potential options for the implementation:
>
> 1. Based on the DB locks (e.g. SELECT FOR UPDATE/SqlAlchemy with_for_update).
>
> pros:
> - the object is guaranteed to not be changed while within the context
>
> cons:
> - prone to deadlocks ([1] and potentially when locking multiple objects)
>
> 2. Lock-free CAS based on object version counter. Can use SqlAlchemy version
> counter [2] or add our own. If conflicting changes are detected upon exiting
> the context (i.e. version counter held differs from the one in the DB), will
> raise OSLO RetryRequest exception.
>
> pros:
> - does not require locking
>
> cons:
> - require an additional field in the models
>
> While opt.2 only prevents the conflicting changes, but does not guarantee that
> the object does not change while within the context, opt.1 may seem
> preferential. But even with opt.1 the user should not expect that the changes
> made to the object while within the context will get to the database as the
> autonested_transaction could fail on flush/commit.
>
> So I’d like to hear others’ opinion on the problem and which of the two
> implementation options would be preferred? Or maybe someone has a better idea.
>
> [1] https://wiki.openstack.org/wiki/OpenStack_and_SQLAlchemy#MySQLdb_.2B_eventlet_.3D_sad
> [2] http://docs.sqlalchemy.org/en/rel_0_9/orm/versioning.html
>
> [3] https://review.openstack.org/#/c/315705/
In Cinder we're handling similar problems related to race conditions
between status check and status change with conditional updates.
Basically we're doing "UPDATE table SET status='abc' WHERE id=1 AND
status='status_allowing_transition_to_foo';". You can check out o.vo
layer of that stuff at [1].
You could provide fields you care not to be modified in the
expected_values and retry DB operations on failure.
In general the problem you're mentioning is related more to the
concurrent DB updates and o.vo never aimed for magically solving that
problem. I believe you've had same problem with raw SQLA objects.
[1]
https://github.com/openstack/cinder/blob/master/cinder/objects/base.py#L173-L289
More information about the OpenStack-dev
mailing list