Commit 10ab3e68 authored by Michael Widenius's avatar Michael Widenius

MDEV-4010 Deadlock on concurrent INSERT .. SELECT into an Aria table with statement binary logging

There was a bug in lock handling when mixing INSERT ... SELECT on the same table.


mysql-test/suite/maria/insert_select.result:
  Test case for MDEV_4010
mysql-test/suite/maria/insert_select.test:
  Test case for MDEV_4010
mysys/thr_lock.c:
  We wrongly alldoed TL_WRITE_CONCURRENT_INSERT when there was a TL_READ_NO_INSERT lock
parent 80ee57a3
create table t1 (pk int primary key) engine=Aria;
insert into t1 values (1);
insert into t1 select sleep(2)+1 from t1;
insert into t1 select 2 from t1;
ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
drop table t1;
#
# MDEV-4010
# Deadlock on concurrent INSERT .. SELECT into an Aria table with statement
# binary logging
#
--source include/have_binlog_format_statement.inc
create table t1 (pk int primary key) engine=Aria;
insert into t1 values (1);
send insert into t1 select sleep(2)+1 from t1;
--connect (con1,localhost,root,,)
insert into t1 select 2 from t1;
--connection default
--error 1062
--reap
--disconnect con1
drop table t1;
......@@ -325,7 +325,7 @@ static void check_locks(THR_LOCK *lock, const char *where,
found_errors++;
fprintf(stderr,
"Warning at '%s': Write lock %d waiting while no exclusive read locks\n",where,(int) lock->write_wait.data->type);
DBUG_PRINT("warning", ("Warning at '%s': Write lock %d waiting while no exclusive read locks\n",where,(int) lock->write_wait.data->type));
DBUG_PRINT("warning", ("Warning at '%s': Write lock %d waiting while no exclusive read locks",where,(int) lock->write_wait.data->type));
}
}
}
......@@ -345,7 +345,7 @@ static void check_locks(THR_LOCK *lock, const char *where,
fprintf(stderr,
"Warning at '%s': Found TL_WRITE_CONCURRENT_INSERT lock mixed with other write lock: %d\n",
where, data->type);
DBUG_PRINT("warning", ("Warning at '%s': Found TL_WRITE_CONCURRENT_INSERT lock mixed with other write lock: %d\n",
DBUG_PRINT("warning", ("Warning at '%s': Found TL_WRITE_CONCURRENT_INSERT lock mixed with other write lock: %d",
where, data->type));
break;
}
......@@ -361,7 +361,7 @@ static void check_locks(THR_LOCK *lock, const char *where,
fprintf(stderr,
"Warning at '%s': Found WRITE_ALLOW_WRITE lock waiting for WRITE_ALLOW_WRITE lock\n",
where);
DBUG_PRINT("warning", ("Warning at '%s': Found WRITE_ALLOW_WRITE lock waiting for WRITE_ALLOW_WRITE lock\n",
DBUG_PRINT("warning", ("Warning at '%s': Found WRITE_ALLOW_WRITE lock waiting for WRITE_ALLOW_WRITE lock",
where));
}
......@@ -384,7 +384,7 @@ static void check_locks(THR_LOCK *lock, const char *where,
"Warning at '%s' for lock: %d: Found lock of type %d that is write and read locked. Read_no_write_count: %d\n",
where, (int) type, lock->write.data->type,
lock->read_no_write_count);
DBUG_PRINT("warning",("At '%s' for lock %d: Found lock of type %d that is write and read locked\n",
DBUG_PRINT("warning",("At '%s' for lock %d: Found lock of type %d that is write and read locked",
where, (int) type,
lock->write.data->type));
}
......@@ -794,7 +794,8 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout)
The idea is to allow us to get a lock at once if we already have
a write lock or if there is no pending write locks and if all
write locks are of the same type and are either
TL_WRITE_ALLOW_WRITE or TL_WRITE_CONCURRENT_INSERT
TL_WRITE_ALLOW_WRITE or TL_WRITE_CONCURRENT_INSERT and
there is no TL_READ_NO_INSERT lock.
Note that, since lock requests for the same table are sorted in
such way that requests with higher thr_lock_type value come first
......@@ -811,7 +812,7 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout)
situation.
**) The exceptions are situations when:
- when old lock type is TL_WRITE_DELAYED
But these should never happen within MySQL.
But these should never happen within MariaDB.
Therefore it is OK to allow acquiring write lock on the table if
this thread already holds some write lock on it.
......@@ -829,7 +830,8 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout)
(lock_type == TL_WRITE_CONCURRENT_INSERT &&
lock->allow_multiple_concurrent_insert)) &&
! lock->write_wait.data &&
lock->write.data->type == lock_type) ||
lock->write.data->type == lock_type &&
! lock->read_no_write_count) ||
has_old_lock(lock->write.data, data->owner))
{
DBUG_PRINT("info", ("write_wait.data: 0x%lx old_type: %d",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment