mysql multiple locks, single row - mysql

This article says:
Tx 1: lock A, then B
Tx 2: lock B, then A
Because InnoDB starts transactions on the internally, you -are- going
to experience deadlocks.
No way of escaping it.
I'm seeing error code 1213 when many threads are trying to insert a row with the same PK, but I don't understand how there could be two locks. Isn't there just the single lock on that row?

If it's read lock then there can be more than one since read locks are shared but there can be only one write lock at any time. Every DML operation (insert/update/delete) will operate on implicit transaction and will hold a row level lock on that row and thus if any other thread trying to perform a write operation on that particular row it has to wait for the existing lock to be released since write locks are exclusive lock.
Scenario you have posted Tx 1: lock A, then B Tx 2: lock B, then A will definitely result into deadlock and that's why locking happens to in two phase. Growing phase when the transaction will acquire all the needed locks to perform the transaction and Shrinking phase when it will start releasing locks held by that transaction.

Related

why i can have two locks( X and S) on one record in innodb? i know that S and X lock can not exists at the same time

why i can have two locks( X and S) on one record in innodb? i know that S and X lock can not exists at the same time.
You can't. Your S lock is escalated to an X lock with these two queries executed in sequence within the same transaction. You don't have both.
If a second transaction also obtained an S lock on the same records, and then your FOR UPDATE query were run, it would block at least until the other transaction made its next move, perhaps longer, until the lock escalation could occur or be determined impossibe. Eventually the prompt would return or you'd get a deadlock.

Why commit does not cause deadlock

I have read mysql reference manual about the InnoDB locks. I got that :
(from:
http://dev.mysql.com/doc/refman/5.5/en/innodb-locks-set.html)
INSERT sets an exclusive lock on the inserted row. This lock is an index-record lock, not a next-key lock (that is, there is no gap lock) and does not prevent other sessions from inserting into the gap before the inserted row.
Prior to inserting the row, a type of gap lock called an insert intention gap lock is set. This lock signals the intent to insert in such a way that multiple transactions inserting into the same index gap need not wait for each other if they are not inserting at the same position within the gap. Suppose that there are index records with values of 4 and 7. Separate transactions that attempt to insert values of 5 and 6 each lock the gap between 4 and 7 with insert intention locks prior to obtaining the exclusive lock on the inserted row, but do not block each other because the rows are nonconflicting.
If a duplicate-key error occurs, a shared lock on the duplicate index record is set. This use of a shared lock can result in deadlock should there be multiple sessions trying to insert the same row if another session already has an exclusive lock. This can occur if another session deletes the row. Suppose that an InnoDB table t1 has the following structure:
CREATE TABLE t1 (i INT, PRIMARY KEY (i)) ENGINE = InnoDB;
Now suppose that three sessions perform the following operations in order:
Session 1:
START TRANSACTION;
INSERT INTO t1 VALUES(1);
Session 2:
START TRANSACTION;
INSERT INTO t1 VALUES(1);
Session 3:
START TRANSACTION;
INSERT INTO t1 VALUES(1);
Session 1:
ROLLBACK;
The first operation by session 1 acquires an exclusive lock for the row. The operations by sessions 2 and 3 both result in a duplicate-key error and they both request a shared lock for the row. When session 1 rolls back, it releases its exclusive lock on the row and the queued shared lock requests for sessions 2 and 3 are granted. At this point, sessions 2 and 3 deadlock: Neither can acquire an exclusive lock for the row because of the shared lock held by the other.
I made a experiment and I found is is the fact.
My question is :
(1)I found that, if I commit session 1, and deadlock did not happen. Why? When I commit session 1, The X row lock will also be released. So I do not understand.
Thx.
I suspect this is an edge case that is not worth making more efficient. Note that you had to get 3 sessions trying to grab the same row -- a rare happening. And you did a ROLLBACK -- also rare. So the deadlock that occurred is overkill, but not worth fixing. For this reason, one must be prepared to handle deadlocks everywhere.
FYI, If this were 3 nodes of a Galera cluster, there would be errors on COMMIT that the code would have to handle. I suspect there are even more combinations of strange things going on if you apply this transaction (with rollback or commit) multiple times to multiple nodes.
Now to your question... Presumably the deadlock did not happen because one of the threads got the exclusive lock and the other was hit with a "wait" instead of a "deadlock".

MySQL innodb select for update concurrency

MySQL documentation says that SELECT FOR UPDATE sets an IX lock. IX lock is intention exclusive lock and when issued it means "Transaction T intends to set X (exclusive) locks on scanned rows". This means that before SELECT FOR UPDATE succeeds it must first get IX and then X. MySQL glossary says this about intention exclusive lock:
intention lock
A kind of lock that applies to the table level, used to indicate what kind of lock the transaction intends to acquire on rows in the table. Different transactions can acquire different kinds of intention locks on the same table, but the first transaction to acquire an intention exclusive (IX) lock on a table prevents other transactions from acquiring any S or X locks on the table. Conversely, the first transaction to acquire an intention shared (IS) lock on a table prevents other transactions from acquiring any X locks on the table. The two-phase process allows the lock requests to be resolved in order, without blocking locks and corresponding operations that are compatible. For more details on this locking mechanism, see Section 14.3.5.3, “InnoDB Lock Modes”.
Also IX and IX are compatible (lock type compatibility matrix) which means that if transaction 1 issues IX and right after another concurrent transaction issues IX it will succeed.
Is there a possibility that two concurrent IX are issued at the exact same moment and MySQL grants/acquires IX for both transactions for the same table. Or MySQL grants at any point only one IX if concurrent IX are issued. I'm thinking that MySQL grants only one of them, even if call is made and triggered at MySQL side at the exact same time.
EDIT: basically if I generalize my question: If two (concurrent) sql statements that lock rows (e.g. update, select for update, select lock in share mode, insert, delete) come to MySQL at the exact same time, I suppose MySQL treats them sequentially. Just want to make sure, that I am thinking right how MySQL works internally.
Locking operations necessarily are serialized. At the nanosecond level in the server's logical workflow there's no such thing as "multiple lock requests at precisely the same moment." Even if there were, the server's logic would arbitrarily place them into some order and grant them one after the other.
A really smart next-generation massively parallel server might be able to figure out that different lock requests were guaranteed never to interfere with each other, and handle them truly in parallel. But for now, there's no such thing as simultaneous.

How does lock-based concurrency control in sql work when multiple objects hold a shared lock and one wants to upgrade to exclusive?

I am trying to understand how transactions work with locks in sql and watched this great tutorial on youtube.
I don't understand what happens though if 2 different transactions get a shared lock on the same object, and then one or both of them then want to upgrade to an exclusive lock on the object to write to it.
What would happen on the example at 1:12:55 in the video?
Would it be classed as a deadlock and would one of the transactions have to roll back? Surely one of them can't wait at the point of wanting the exclusive lock and remove it's shared lock, and then continue when the first transaction finishes, because locks cannot be removed until the end of the transaction can they?
Cheers.
The transaction wanting the exclusive lock would have to wait until all other shared locks were removed before it can take effect. In this case, it would wait for the other transaction to release its shared lock, after which it would obtain an exclusive lock.
Thus, if the other transaction were held up by the initial transaction for some other reason, this would result in a deadlock. Because of this, a good DB design should try to ensure that the initial transaction would not block anything while waiting for an exclusive lock.

How can priority be given to write/update over read in MySQL?

In my application, I want any insert to the database to be executed as soon as a request comes for writing some data.
I am using InnoDB engine.
Since insertion requires an exclusive lock, it is possible that while current read query has a shared lock, some other reads might come which again have a shared lock and the write operation might have to wait for a long time.
I want that when there is a write operation in queue, no read operation gets a shared lock. As soon as the reads which were initiated before the current write request are completed, the write operation should be executed. After that all other read operations should take place.
How can this be implemented?
Edit
Since I am using InnoDB tables and I am not implementing table lock, there should not be a conflict between select and insert. It would be select and update. (Please correct me if there can be a conflict between select and insert as well)
In MySQL, update has higher priority than select. But if there are some read queries being executed, then update query comes in followed by some read queries. In that case, will the read queries coming after update wait for the update to finish as mentioned here http://dev.mysql.com/doc/refman/5.0/en//table-locking.html OR they will get shared lock along with the read queries which were there before the update query was fired?
You don't need to acquire shared locks when reading from the database. In fact, with the default transaction isolation level REPEATABLE READ ordinary SELECT queries within one transaction read from a consistent snapshot. No locks are acquired and required, within this transaction you will simply not see any changes committed in other transactions.
Since no shared locks are acquired, exclusive locks for updating queries are immediately granted to other sessions in the order they are filed.
MySQL doc says the following
Consistent read is the default mode in which InnoDB processes SELECT statements in READ COMMITTED and REPEATABLE READ isolation levels. A consistent read does not set any locks on the tables it accesses, and therefore other sessions are free to modify those tables at the same time a consistent read is being performed on the table.
Suppose that you are running in the default REPEATABLE READ isolation level. When you issue a consistent read (that is, an ordinary SELECT statement), InnoDB gives your transaction a timepoint according to which your query sees the database. If another transaction deletes a row and commits after your timepoint was assigned, you do not see the row as having been deleted. Inserts and updates are treated similarly.
You can try looking at INSERT DELAYED Mysql Insert Delayed
Unfortunatelly it is not available on innodb.
PS: A exclusive lock cannot be acquired if there is already a shared lock on the table. So basicly, in your situation: 3 reads obtain a shared lock, one insert needs exclusive lock. The insert will only be able to obtain the lock after the selects have finished.