mirror of
https://github.com/MariaDB/server.git
synced 2025-07-27 18:02:13 +03:00
MDEV-27962 Instant DDL downgrades the MDL when table is empty
- Server incorrectly downgrading the MDL after prepare phase when
table is empty. mdl_exclusive_after_prepare is being set in
prepare phase only. But mdl_exclusive_after_prepare condition was
misplaced and checked before prepare phase by
commit d270525dfd
and it is now
changed to check after prepare phase.
- main.innodb_mysql_sync test case was changed to avoid locking
optimization when table is empty.
This commit is contained in:
@ -131,6 +131,7 @@ connection default;
|
|||||||
DROP DATABASE db1;
|
DROP DATABASE db1;
|
||||||
# Test 2: Primary index (implicit), should block writes.
|
# Test 2: Primary index (implicit), should block writes.
|
||||||
CREATE TABLE t1(a INT NOT NULL, b INT NOT NULL) engine=innodb;
|
CREATE TABLE t1(a INT NOT NULL, b INT NOT NULL) engine=innodb;
|
||||||
|
INSERT INTO t1 VALUES(1, 2);
|
||||||
SET DEBUG_SYNC= "alter_table_inplace_after_lock_downgrade SIGNAL manage WAIT_FOR query";
|
SET DEBUG_SYNC= "alter_table_inplace_after_lock_downgrade SIGNAL manage WAIT_FOR query";
|
||||||
# Sending:
|
# Sending:
|
||||||
ALTER TABLE t1 ADD UNIQUE INDEX(a), LOCK=SHARED;
|
ALTER TABLE t1 ADD UNIQUE INDEX(a), LOCK=SHARED;
|
||||||
@ -139,15 +140,16 @@ SET DEBUG_SYNC= "now WAIT_FOR manage";
|
|||||||
USE test;
|
USE test;
|
||||||
SELECT * FROM t1;
|
SELECT * FROM t1;
|
||||||
a b
|
a b
|
||||||
|
1 2
|
||||||
# Sending:
|
# Sending:
|
||||||
UPDATE t1 SET a=NULL;
|
UPDATE t1 SET a=3;
|
||||||
connection con2;
|
connection con2;
|
||||||
# Waiting for SELECT to be blocked by the metadata lock on t1
|
# Waiting for SELECT to be blocked by the metadata lock on t1
|
||||||
SET DEBUG_SYNC= "now SIGNAL query";
|
SET DEBUG_SYNC= "now SIGNAL query";
|
||||||
connection default;
|
connection default;
|
||||||
# Reaping: ALTER TABLE t1 ADD UNIQUE INDEX(a)
|
# Reaping: ALTER TABLE t1 ADD UNIQUE INDEX(a)
|
||||||
connection con1;
|
connection con1;
|
||||||
# Reaping: UPDATE t1 SET a=NULL
|
# Reaping: UPDATE t1 SET a=3
|
||||||
# Test 3: Primary index (explicit), should block writes.
|
# Test 3: Primary index (explicit), should block writes.
|
||||||
connection default;
|
connection default;
|
||||||
ALTER TABLE t1 DROP INDEX a;
|
ALTER TABLE t1 DROP INDEX a;
|
||||||
@ -158,15 +160,16 @@ connection con1;
|
|||||||
SET DEBUG_SYNC= "now WAIT_FOR manage";
|
SET DEBUG_SYNC= "now WAIT_FOR manage";
|
||||||
SELECT * FROM t1;
|
SELECT * FROM t1;
|
||||||
a b
|
a b
|
||||||
|
3 2
|
||||||
# Sending:
|
# Sending:
|
||||||
UPDATE t1 SET a=NULL;
|
UPDATE t1 SET a=4;
|
||||||
connection con2;
|
connection con2;
|
||||||
# Waiting for SELECT to be blocked by the metadata lock on t1
|
# Waiting for SELECT to be blocked by the metadata lock on t1
|
||||||
SET DEBUG_SYNC= "now SIGNAL query";
|
SET DEBUG_SYNC= "now SIGNAL query";
|
||||||
connection default;
|
connection default;
|
||||||
# Reaping: ALTER TABLE t1 ADD PRIMARY KEY (a)
|
# Reaping: ALTER TABLE t1 ADD PRIMARY KEY (a)
|
||||||
connection con1;
|
connection con1;
|
||||||
# Reaping: UPDATE t1 SET a=NULL
|
# Reaping: UPDATE t1 SET a=4
|
||||||
# Test 4: Secondary unique index, should not block reads.
|
# Test 4: Secondary unique index, should not block reads.
|
||||||
connection default;
|
connection default;
|
||||||
SET DEBUG_SYNC= "alter_table_inplace_after_lock_downgrade SIGNAL manage WAIT_FOR query";
|
SET DEBUG_SYNC= "alter_table_inplace_after_lock_downgrade SIGNAL manage WAIT_FOR query";
|
||||||
@ -176,6 +179,7 @@ connection con1;
|
|||||||
SET DEBUG_SYNC= "now WAIT_FOR manage";
|
SET DEBUG_SYNC= "now WAIT_FOR manage";
|
||||||
SELECT * FROM t1;
|
SELECT * FROM t1;
|
||||||
a b
|
a b
|
||||||
|
4 2
|
||||||
SET DEBUG_SYNC= "now SIGNAL query";
|
SET DEBUG_SYNC= "now SIGNAL query";
|
||||||
connection default;
|
connection default;
|
||||||
# Reaping: ALTER TABLE t1 ADD UNIQUE (b)
|
# Reaping: ALTER TABLE t1 ADD UNIQUE (b)
|
||||||
|
@ -176,6 +176,7 @@ DROP DATABASE db1;
|
|||||||
--echo # Test 2: Primary index (implicit), should block writes.
|
--echo # Test 2: Primary index (implicit), should block writes.
|
||||||
|
|
||||||
CREATE TABLE t1(a INT NOT NULL, b INT NOT NULL) engine=innodb;
|
CREATE TABLE t1(a INT NOT NULL, b INT NOT NULL) engine=innodb;
|
||||||
|
INSERT INTO t1 VALUES(1, 2);
|
||||||
SET DEBUG_SYNC= "alter_table_inplace_after_lock_downgrade SIGNAL manage WAIT_FOR query";
|
SET DEBUG_SYNC= "alter_table_inplace_after_lock_downgrade SIGNAL manage WAIT_FOR query";
|
||||||
--echo # Sending:
|
--echo # Sending:
|
||||||
--send ALTER TABLE t1 ADD UNIQUE INDEX(a), LOCK=SHARED
|
--send ALTER TABLE t1 ADD UNIQUE INDEX(a), LOCK=SHARED
|
||||||
@ -185,13 +186,13 @@ SET DEBUG_SYNC= "now WAIT_FOR manage";
|
|||||||
USE test;
|
USE test;
|
||||||
SELECT * FROM t1;
|
SELECT * FROM t1;
|
||||||
--echo # Sending:
|
--echo # Sending:
|
||||||
--send UPDATE t1 SET a=NULL
|
--send UPDATE t1 SET a=3
|
||||||
|
|
||||||
connection con2;
|
connection con2;
|
||||||
--echo # Waiting for SELECT to be blocked by the metadata lock on t1
|
--echo # Waiting for SELECT to be blocked by the metadata lock on t1
|
||||||
let $wait_condition= SELECT COUNT(*)= 1 FROM information_schema.processlist
|
let $wait_condition= SELECT COUNT(*)= 1 FROM information_schema.processlist
|
||||||
WHERE state= 'Waiting for table metadata lock'
|
WHERE state= 'Waiting for table metadata lock'
|
||||||
AND info='UPDATE t1 SET a=NULL';
|
AND info='UPDATE t1 SET a=3';
|
||||||
--source include/wait_condition.inc
|
--source include/wait_condition.inc
|
||||||
SET DEBUG_SYNC= "now SIGNAL query";
|
SET DEBUG_SYNC= "now SIGNAL query";
|
||||||
|
|
||||||
@ -200,7 +201,7 @@ connection default;
|
|||||||
--reap
|
--reap
|
||||||
|
|
||||||
connection con1;
|
connection con1;
|
||||||
--echo # Reaping: UPDATE t1 SET a=NULL
|
--echo # Reaping: UPDATE t1 SET a=3
|
||||||
--reap
|
--reap
|
||||||
|
|
||||||
--echo # Test 3: Primary index (explicit), should block writes.
|
--echo # Test 3: Primary index (explicit), should block writes.
|
||||||
@ -215,13 +216,13 @@ connection con1;
|
|||||||
SET DEBUG_SYNC= "now WAIT_FOR manage";
|
SET DEBUG_SYNC= "now WAIT_FOR manage";
|
||||||
SELECT * FROM t1;
|
SELECT * FROM t1;
|
||||||
--echo # Sending:
|
--echo # Sending:
|
||||||
--send UPDATE t1 SET a=NULL
|
--send UPDATE t1 SET a=4
|
||||||
|
|
||||||
connection con2;
|
connection con2;
|
||||||
--echo # Waiting for SELECT to be blocked by the metadata lock on t1
|
--echo # Waiting for SELECT to be blocked by the metadata lock on t1
|
||||||
let $wait_condition= SELECT COUNT(*)= 1 FROM information_schema.processlist
|
let $wait_condition= SELECT COUNT(*)= 1 FROM information_schema.processlist
|
||||||
WHERE state= 'Waiting for table metadata lock'
|
WHERE state= 'Waiting for table metadata lock'
|
||||||
AND info='UPDATE t1 SET a=NULL';
|
AND info='UPDATE t1 SET a=4';
|
||||||
--source include/wait_condition.inc
|
--source include/wait_condition.inc
|
||||||
SET DEBUG_SYNC= "now SIGNAL query";
|
SET DEBUG_SYNC= "now SIGNAL query";
|
||||||
|
|
||||||
@ -230,7 +231,7 @@ connection default;
|
|||||||
--reap
|
--reap
|
||||||
|
|
||||||
connection con1;
|
connection con1;
|
||||||
--echo # Reaping: UPDATE t1 SET a=NULL
|
--echo # Reaping: UPDATE t1 SET a=4
|
||||||
--reap
|
--reap
|
||||||
|
|
||||||
--echo # Test 4: Secondary unique index, should not block reads.
|
--echo # Test 4: Secondary unique index, should not block reads.
|
||||||
|
@ -462,12 +462,27 @@ INSERT INTO t1 SET a=0, i=REPEAT('1', 10000);
|
|||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
set DEBUG_SYNC='now SIGNAL go';
|
set DEBUG_SYNC='now SIGNAL go';
|
||||||
connection default;
|
connection default;
|
||||||
disconnect con1;
|
|
||||||
SELECT * FROM t1;
|
SELECT * FROM t1;
|
||||||
a b c d e f g h i
|
a b c d e f g h i
|
||||||
1 2 3 4 5 6 7 8 test
|
1 2 3 4 5 6 7 8 test
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
SET DEBUG_SYNC=RESET;
|
SET DEBUG_SYNC=RESET;
|
||||||
|
#
|
||||||
|
# MDEV-27962 Instant DDL downgrades the MDL when table is empty
|
||||||
|
#
|
||||||
|
CREATE TABLE t1(f1 INT NOT NULL, f2 INT NOT NULL)ENGINE=InnoDB;
|
||||||
|
SET DEBUG_SYNC="alter_table_inplace_after_lock_downgrade SIGNAL try_insert WAIT_FOR alter_progress";
|
||||||
|
ALTER TABLE t1 ADD INDEX(f1), ADD INDEX(f2);
|
||||||
|
connection con1;
|
||||||
|
SET SESSION lock_wait_timeout=1;
|
||||||
|
SET DEBUG_SYNC="now WAIT_FOR try_insert";
|
||||||
|
INSERT INTO t1 VALUES(1, 2);
|
||||||
|
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
||||||
|
SET DEBUG_SYNC="now SIGNAL alter_progress";
|
||||||
|
disconnect con1;
|
||||||
|
connection default;
|
||||||
|
DROP TABLE t1;
|
||||||
|
SET DEBUG_SYNC=reset;
|
||||||
# End of 10.4 tests
|
# End of 10.4 tests
|
||||||
SET GLOBAL innodb_purge_rseg_truncate_frequency = @save_frequency;
|
SET GLOBAL innodb_purge_rseg_truncate_frequency = @save_frequency;
|
||||||
SELECT variable_value-@old_instant instants
|
SELECT variable_value-@old_instant instants
|
||||||
|
@ -533,11 +533,28 @@ set DEBUG_SYNC='now SIGNAL go';
|
|||||||
connection default;
|
connection default;
|
||||||
reap;
|
reap;
|
||||||
|
|
||||||
disconnect con1;
|
|
||||||
SELECT * FROM t1;
|
SELECT * FROM t1;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
SET DEBUG_SYNC=RESET;
|
SET DEBUG_SYNC=RESET;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-27962 Instant DDL downgrades the MDL when table is empty
|
||||||
|
--echo #
|
||||||
|
CREATE TABLE t1(f1 INT NOT NULL, f2 INT NOT NULL)ENGINE=InnoDB;
|
||||||
|
SET DEBUG_SYNC="alter_table_inplace_after_lock_downgrade SIGNAL try_insert WAIT_FOR alter_progress";
|
||||||
|
send ALTER TABLE t1 ADD INDEX(f1), ADD INDEX(f2);
|
||||||
|
connection con1;
|
||||||
|
SET SESSION lock_wait_timeout=1;
|
||||||
|
SET DEBUG_SYNC="now WAIT_FOR try_insert";
|
||||||
|
--error ER_LOCK_WAIT_TIMEOUT
|
||||||
|
INSERT INTO t1 VALUES(1, 2);
|
||||||
|
SET DEBUG_SYNC="now SIGNAL alter_progress";
|
||||||
|
disconnect con1;
|
||||||
|
connection default;
|
||||||
|
reap;
|
||||||
|
DROP TABLE t1;
|
||||||
|
SET DEBUG_SYNC=reset;
|
||||||
|
|
||||||
--echo # End of 10.4 tests
|
--echo # End of 10.4 tests
|
||||||
|
|
||||||
SET GLOBAL innodb_purge_rseg_truncate_frequency = @save_frequency;
|
SET GLOBAL innodb_purge_rseg_truncate_frequency = @save_frequency;
|
||||||
|
@ -7716,16 +7716,15 @@ static bool mysql_inplace_alter_table(THD *thd,
|
|||||||
lock for prepare phase under LOCK TABLES in the same way as when
|
lock for prepare phase under LOCK TABLES in the same way as when
|
||||||
exclusive lock is required for duration of the whole statement.
|
exclusive lock is required for duration of the whole statement.
|
||||||
*/
|
*/
|
||||||
if (!ha_alter_info->mdl_exclusive_after_prepare &&
|
if (inplace_supported == HA_ALTER_INPLACE_EXCLUSIVE_LOCK ||
|
||||||
(inplace_supported == HA_ALTER_INPLACE_EXCLUSIVE_LOCK ||
|
((inplace_supported == HA_ALTER_INPLACE_COPY_NO_LOCK ||
|
||||||
((inplace_supported == HA_ALTER_INPLACE_COPY_NO_LOCK ||
|
|
||||||
inplace_supported == HA_ALTER_INPLACE_COPY_LOCK ||
|
inplace_supported == HA_ALTER_INPLACE_COPY_LOCK ||
|
||||||
inplace_supported == HA_ALTER_INPLACE_NOCOPY_NO_LOCK ||
|
inplace_supported == HA_ALTER_INPLACE_NOCOPY_NO_LOCK ||
|
||||||
inplace_supported == HA_ALTER_INPLACE_NOCOPY_LOCK ||
|
inplace_supported == HA_ALTER_INPLACE_NOCOPY_LOCK ||
|
||||||
inplace_supported == HA_ALTER_INPLACE_INSTANT) &&
|
inplace_supported == HA_ALTER_INPLACE_INSTANT) &&
|
||||||
(thd->locked_tables_mode == LTM_LOCK_TABLES ||
|
(thd->locked_tables_mode == LTM_LOCK_TABLES ||
|
||||||
thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES)) ||
|
thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES)) ||
|
||||||
alter_info->requested_lock == Alter_info::ALTER_TABLE_LOCK_EXCLUSIVE))
|
alter_info->requested_lock == Alter_info::ALTER_TABLE_LOCK_EXCLUSIVE)
|
||||||
{
|
{
|
||||||
if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
|
if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@ -7822,7 +7821,8 @@ static bool mysql_inplace_alter_table(THD *thd,
|
|||||||
necessary only for prepare phase (unless we are not under LOCK TABLES) and
|
necessary only for prepare phase (unless we are not under LOCK TABLES) and
|
||||||
user has not explicitly requested exclusive lock.
|
user has not explicitly requested exclusive lock.
|
||||||
*/
|
*/
|
||||||
if ((inplace_supported == HA_ALTER_INPLACE_COPY_NO_LOCK ||
|
if (!ha_alter_info->mdl_exclusive_after_prepare &&
|
||||||
|
(inplace_supported == HA_ALTER_INPLACE_COPY_NO_LOCK ||
|
||||||
inplace_supported == HA_ALTER_INPLACE_COPY_LOCK ||
|
inplace_supported == HA_ALTER_INPLACE_COPY_LOCK ||
|
||||||
inplace_supported == HA_ALTER_INPLACE_NOCOPY_LOCK ||
|
inplace_supported == HA_ALTER_INPLACE_NOCOPY_LOCK ||
|
||||||
inplace_supported == HA_ALTER_INPLACE_NOCOPY_NO_LOCK) &&
|
inplace_supported == HA_ALTER_INPLACE_NOCOPY_NO_LOCK) &&
|
||||||
|
Reference in New Issue
Block a user