Excerpts from Mike Bayer's message of 2014-11-19 10:05:35 -0800:
> 
> > On Nov 18, 2014, at 1:38 PM, Eugene Nikanorov <enikano...@mirantis.com> 
> > wrote:
> > 
> > Hi neutron folks,
> > 
> > There is an ongoing effort to refactor some neutron DB logic to be 
> > compatible with galera/mysql which doesn't support locking 
> > (with_lockmode('update')).
> > 
> > Some code paths that used locking in the past were rewritten to retry the 
> > operation if they detect that an object was modified concurrently.
> > The problem here is that all DB operations (CRUD) are performed in the 
> > scope of some transaction that makes complex operations to be executed in 
> > atomic manner.
> > For mysql the default transaction isolation level is 'REPEATABLE READ' 
> > which means that once the code issue a query within a transaction, this 
> > query will return the same result while in this transaction (e.g. the 
> > snapshot is taken by the DB during the first query and then reused for the 
> > same query).
> > In other words, the retry logic like the following will not work:
> > 
> > def allocate_obj():
> >     with session.begin(subtrans=True):
> >          for i in xrange(n_retries):
> >               obj = session.query(Model).filter_by(filters)
> >               count = session.query(Model).filter_by(id=obj.id 
> > <http://obj.id/>).update({'allocated': True})
> >               if count:
> >                    return obj
> > 
> > since usually methods like allocate_obj() is called from within another 
> > transaction, we can't simply put transaction under 'for' loop to fix the 
> > issue.
> 
> has this been confirmed?  the point of systems like repeatable read is not 
> just that you read the “old” data, it’s also to ensure that updates to that 
> data either proceed or fail explicitly; locking is also used to prevent 
> concurrent access that can’t be reconciled.  A lower isolation removes these 
> advantages.  
> 

Yes this is confirmed and fails reliably on Galera based systems.

> I ran a simple test in two MySQL sessions as follows:
> 
> session 1:
> 
> mysql> create table some_table(data integer) engine=innodb;
> Query OK, 0 rows affected (0.01 sec)
> 
> mysql> insert into some_table(data) values (1);
> Query OK, 1 row affected (0.00 sec)
> 
> mysql> begin;
> Query OK, 0 rows affected (0.00 sec)
> 
> mysql> select data from some_table;
> +------+
> | data |
> +------+
> |    1 |
> +------+
> 1 row in set (0.00 sec)
> 
> 
> session 2:
> 
> mysql> begin;
> Query OK, 0 rows affected (0.00 sec)
> 
> mysql> update some_table set data=2 where data=1;
> Query OK, 1 row affected (0.00 sec)
> Rows matched: 1  Changed: 1  Warnings: 0
> 
> then back in session 1, I ran:
> 
> mysql> update some_table set data=3 where data=1;
> 
> this query blocked;  that’s because session 2 has placed a write lock on the 
> table.  this is the effect of repeatable read isolation.

With Galera this session might happen on another node. There is no
distributed lock, so this would not block...

> 
> while it blocked, I went to session 2 and committed the in-progress 
> transaction:
> 
> mysql> commit;
> Query OK, 0 rows affected (0.00 sec)
> 
> then session 1 unblocked, and it reported, correctly, that zero rows were 
> affected:
> 
> Query OK, 0 rows affected (7.29 sec)
> Rows matched: 0  Changed: 0  Warnings: 0
> 
> the update had not taken place, as was stated by “rows matched":
> 
> mysql> select * from some_table;
> +------+
> | data |
> +------+
> |    1 |
> +------+
> 1 row in set (0.00 sec)
> 
> the code in question would do a retry at this point; it is checking the 
> number of rows matched, and that number is accurate.
> 
> if our code did *not* block at the point of our UPDATE, then it would have 
> proceeded, and the other transaction would have overwritten what we just did, 
> when it committed.   I don’t know that read committed is necessarily any 
> better here.
> 
> now perhaps, with Galera, none of this works correctly.  That would be a 
> different issue in which case sure, we should use whatever isolation is 
> recommended for Galera.  But I’d want to potentially peg it to the fact that 
> Galera is in use, or not.
> 
> would love also to hear from Jay Pipes on this since he literally wrote the 
> book on MySQL ! :)

What you missed is that with Galera the commit that happened last would
be rolled back. This is a reality in many scenarios on SQL databases and
should be handled _regardless_ of Galera. It is a valid way to handle
deadlocks on single node DBs as well (pgsql will do this sometimes).

One simply cannot rely on multi-statement transactions to always succeed.

_______________________________________________
OpenStack-dev mailing list
OpenStack-dev@lists.openstack.org
http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev

Reply via email to