1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-01 03:47:19 +03:00

Follow-up to MDEV-13407 innodb.drop_table_background failed in buildbot with "Tablespace for table exists"

The InnoDB background DROP TABLE queue is something that we should
really remove, but are unable to until we remove dict_operation_lock
so that DDL and DML operations can be combined in a single transaction.

Because the queue is not persistent, it is not crash-safe. We should
in some way ensure that the deferred-dropped tables will be dropped
after server restart.

The existence of two separate transactions complicates the error handling
of CREATE TABLE...SELECT. We should really not break locks in DROP TABLE.

Our solution to these problems is to rename the table to a temporary
name, and to drop such-named tables on InnoDB startup. Also, the
queue will use table IDs instead of names from now on.

check-testcase.test: Ignore #sql-ib*.ibd files, because tables may enter
the background DROP TABLE queue shortly before the test finishes.

innodb.drop_table_background: Test CREATE...SELECT and the creation of
tables whose file name starts with #sql-ib.

innodb.alter_crash: Adjust the recovery, now that the #sql-ib tables
will be dropped on InnoDB startup.

row_mysql_drop_garbage_tables(): New function, to drop all #sql-ib tables
on InnoDB startup.

row_drop_table_for_mysql_in_background(): Remove an unnecessary and
misplaced call to log_buffer_flush_to_disk(). (The call should have been
after the transaction commit. We do not care about flushing the redo log
here, because the table would be dropped again at server startup.)

Remove the entry from the list after the table no longer exists.

If server shutdown has been initiated, empty the list without actually
dropping any tables. They will be dropped again on startup.

row_drop_table_for_mysql(): Do not call lock_remove_all_on_table().
Instead, if locks exist, defer the DROP TABLE until they do not exist.
If the table name does not start with #sql-ib, rename it to that prefix
before adding it to the background DROP TABLE queue.
This commit is contained in:
Marko Mäkelä
2017-12-18 13:38:36 +02:00
parent 028e91f380
commit 88aff5f471
8 changed files with 166 additions and 105 deletions

View File

@ -75,28 +75,22 @@ ALTER TABLE t1 ADD PRIMARY KEY (f2, f1);
--echo # Restart mysqld after the crash and reconnect.
--source include/start_mysqld.inc
let $temp_table_name = `SELECT SUBSTR(name, 6)
FROM information_schema.innodb_sys_tables
WHERE table_id = $orig_table_id`;
--echo # Manual *.frm recovery begin.
--move_file $MYSQLD_DATADIR/test/t1.frm $MYSQLD_DATADIR/test/$temp_table_name.frm
let TABLENAME_INC= $MYSQLTEST_VARDIR/tmp/tablename.inc;
perl;
my @frm_file = glob "$ENV{'datadir'}/test/#sql-*.frm";
my $t1_frm = "$ENV{'datadir'}/test/t1.frm";
rename($frm_file[0], $t1_frm);
die unless open OUT, ">$ENV{TABLENAME_INC}";
chdir "$ENV{'datadir'}/test";
my @frm_file = map { substr($_, 0, -4) } glob "#sql-*.frm";
print OUT 'let $tablename=', $frm_file[0], ';';
close OUT or die;
EOF
source $TABLENAME_INC;
remove_file $TABLENAME_INC;
--echo # Manual recovery end
--replace_result $orig_table_id ID
eval SELECT * FROM information_schema.innodb_sys_tables
WHERE table_id = $orig_table_id;
FLUSH TABLES;
--echo # Drop the orphaned original table.
--disable_query_log
eval DROP TABLE `#mysql50#$temp_table_name`;
--enable_query_log
move_file $datadir/test/$tablename.frm $datadir/test/t1.frm;
--echo # Files in datadir after manual recovery.
--list_files $MYSQLD_DATADIR/test
@ -134,16 +128,9 @@ ALTER TABLE t2 ADD PRIMARY KEY (f2, f1);
--echo # Startup the server after the crash
--source include/start_mysqld.inc
--echo # Read and remember the temporary table name
let $temp_table_name = `SELECT SUBSTRING(name,6)
FROM information_schema.innodb_sys_tables
WHERE name LIKE "test/#sql-ib$orig_table_id%"`;
SELECT * FROM information_schema.innodb_sys_tables
WHERE name LIKE 'test/#sql-ib%';
--echo # Manual *.frm recovery begin. The dictionary was not updated
--echo # and the files were not renamed. The rebuilt table
--echo # was left behind on purpose, to faciliate data recovery.
let TABLENAME_INC= $MYSQLTEST_VARDIR/tmp/tablename.inc;
perl;
die unless open OUT, ">$ENV{TABLENAME_INC}";
chdir "$ENV{'datadir'}/test";
@ -154,8 +141,6 @@ EOF
source $TABLENAME_INC;
remove_file $TABLENAME_INC;
--echo # Manual recovery end
--echo # Drop the orphaned rebuilt table.
--disable_query_log
eval DROP TABLE `#mysql50#$tablename`;
@ -198,28 +183,24 @@ ALTER TABLE t1 ADD INDEX (b), CHANGE c d int, ALGORITHM=INPLACE;
--echo # Restart mysqld after the crash and reconnect.
--source include/start_mysqld.inc
let $temp_table_name = `SELECT SUBSTR(name, 6)
FROM information_schema.innodb_sys_tables
WHERE table_id = $orig_table_id`;
--echo # Manual *.frm recovery begin.
--move_file $MYSQLD_DATADIR/test/t1.frm $MYSQLD_DATADIR/test/$temp_table_name.frm
--replace_result $orig_table_id ID
eval SELECT * FROM information_schema.innodb_sys_tables
WHERE table_id = $orig_table_id;
perl;
my @frm_file = glob "$ENV{'datadir'}/test/#sql-*.frm";
my $t1_frm = "$ENV{'datadir'}/test/t1.frm";
rename($frm_file[0], $t1_frm);
die unless open OUT, ">$ENV{TABLENAME_INC}";
chdir "$ENV{'datadir'}/test";
my @frm_file = map { substr($_, 0, -4) } glob "#sql-*.frm";
print OUT 'let $tablename=', $frm_file[0], ';';
close OUT or die;
EOF
--echo # Manual recovery end
source $TABLENAME_INC;
remove_file $TABLENAME_INC;
move_file $datadir/test/$tablename.frm $datadir/test/t1.frm;
FLUSH TABLES;
--echo # Drop the orphaned original table.
--disable_query_log
eval DROP TABLE `#mysql50#$temp_table_name`;
--enable_query_log
--echo # Files in datadir after manual recovery.
--list_files $MYSQLD_DATADIR/test