1
0
mirror of https://github.com/MariaDB/server.git synced 2025-11-15 09:02:33 +03:00
Files
mariadb/mysql-test/suite/innodb/t/alter_copy.test
Marko Mäkelä 0ba6aaf030 MDEV-11415 Remove excessive undo logging during ALTER TABLE…ALGORITHM=COPY
If a crash occurs during ALTER TABLE…ALGORITHM=COPY, InnoDB would spend
a lot of time rolling back writes to the intermediate copy of the table.
To reduce the amount of busy work done, a work-around was introduced in
commit fd069e2bb3 in MySQL 4.1.8 and 5.0.2,
to commit the transaction after every 10,000 inserted rows.

A proper fix would have been to disable the undo logging altogether and
to simply drop the intermediate copy of the table on subsequent server
startup. This is what happens in MariaDB 10.3 with MDEV-14717,MDEV-14585.
In MariaDB 10.2, the intermediate copy of the table would be left behind
with a name starting with the string #sql.

This is a backport of a bug fix from MySQL 8.0.0 to MariaDB,
contributed by jixianliang <271365745@qq.com>.

Unlike recent MySQL, MariaDB supports ALTER IGNORE. For that operation
InnoDB must for now keep the undo logging enabled, so that the latest
row can be rolled back in case of an error.

In Galera cluster, the LOAD DATA statement will retain the existing
behaviour and commit the transaction after every 10,000 rows if
the parameter wsrep_load_data_splitting=ON is set. The logic to do
so (the wsrep_load_data_split() function and the call
handler::extra(HA_EXTRA_FAKE_START_STMT)) are joint work
by Ji Xianliang and Marko Mäkelä.

The original fix:

Author: Thirunarayanan Balathandayuthapani <thirunarayanan.balathandayuth@oracle.com>
Date:   Wed Dec 2 16:09:15 2015 +0530

Bug#17479594 AVOID INTERMEDIATE COMMIT WHILE DOING ALTER TABLE ALGORITHM=COPY

Problem:

During ALTER TABLE, we commit and restart the transaction for every
10,000 rows, so that the rollback after recovery would not take so long.

Fix:

Suppress the undo logging during copy alter operation. If fts_index is
present then insert directly into fts auxiliary table rather
than doing at commit time.

ha_innobase::num_write_row: Remove the variable.

ha_innobase::write_row(): Remove the hack for committing every 10000 rows.

row_lock_table_for_mysql(): Remove the extra 2 parameters.

lock_get_src_table(), lock_is_table_exclusive(): Remove.

Reviewed-by: Marko Mäkelä <marko.makela@oracle.com>
Reviewed-by: Shaohua Wang <shaohua.wang@oracle.com>
Reviewed-by: Jon Olav Hauglid <jon.hauglid@oracle.com>
2018-01-30 20:24:23 +02:00

96 lines
3.5 KiB
Plaintext

--source include/have_innodb.inc
--source include/have_debug.inc
--source include/have_debug_sync.inc
--source include/not_embedded.inc
--echo #
--echo # MDEV-11415 AVOID INTERMEDIATE COMMIT WHILE DOING
--echo # ALTER TABLE...ALGORITHM=COPY
--echo #
CREATE TABLE t(a SERIAL, b INT, c INT, d INT) ENGINE=InnoDB;
CREATE TABLE t1(a INT, b TEXT, c TEXT,
FULLTEXT(b), FULLTEXT(c(3)), FULLTEXT(b,c)) ENGINE=InnoDB;
let $c = 999;
BEGIN;
--disable_query_log
while ($c) {
INSERT INTO t() VALUES();
dec $c;
}
--enable_query_log
COMMIT;
SELECT COUNT(*) FROM t;
# try to make the to-be-created secondary index keys randomly distributed
UPDATE t SET b=a%7, c=a%11, d=a%13;
INSERT INTO t1 VALUES(1, 'This is a first b column', 'This is a first c column');
INSERT INTO t1 VALUES(2, 'This is a second b column', 'This is a second c column');
INSERT INTO t1(a) VALUES(3);
INSERT INTO t1 VALUES(4, 'This is a third b column', 'This is a third c column');
DELETE FROM t1 WHERE a = 2;
SELECT * FROM t1 WHERE MATCH(b) AGAINST ('first');
SELECT * FROM t1 WHERE MATCH(c) AGAINST ('first');
SELECT * FROM t1 WHERE MATCH(b,c) AGAINST ('column');
SHOW CREATE TABLE t1;
ALTER TABLE t1 FORCE, ALGORITHM=COPY;
# crash right after the last write_row(), before the first commit of ALTER TABLE
--source include/expect_crash.inc
SET DEBUG_DBUG='+d,crash_commit_before';
--error 2013
# create 32 secondary indexes
ALTER TABLE t ADD INDEX(b,c,d,a),ADD INDEX(b,c,a,d),ADD INDEX(b,a,c,d),ADD INDEX(b,a,d,c),
ADD INDEX(b,d,a,c),ADD INDEX(b,d,c,a),ADD INDEX(a,b,c,d),ADD INDEX(a,b,d,c),
ADD INDEX(a,c,b,d),ADD INDEX(a,c,d,b),ADD INDEX(a,d,b,c),ADD INDEX(a,d,c,b),
ADD INDEX(c,a,b,d),ADD INDEX(c,a,d,b),ADD INDEX(c,b,a,d),ADD INDEX(c,b,d,a),
ADD INDEX(c,d,a,b),ADD INDEX(c,d,b,a),ADD INDEX(d,a,b,c),ADD INDEX(d,a,c,b),
ADD INDEX(d,b,a,c),ADD INDEX(d,b,c,a),ADD INDEX(d,c,a,b),ADD INDEX(d,c,b,a),
ADD INDEX(a,b,c), ADD INDEX(a,c,b), ADD INDEX(a,c,d), ADD INDEX(a,d,c),
ADD INDEX(a,b,d), ADD INDEX(a,d,b), ADD INDEX(b,c,d), ADD INDEX(b,d,c),
ALGORITHM=COPY;
--let $restart_parameters= --innodb-force-recovery=3
--source include/start_mysqld.inc
let $datadir=`select @@datadir`;
--replace_regex /#sql-[0-9a-f_]*/#sql-temporary/ /FTS_[0-9a-f]*_[0-9a-f]*/FTS/
--list_files $datadir/test
SHOW CREATE TABLE t;
SELECT COUNT(*) FROM t;
CHECK TABLE t;
SELECT * FROM t1 WHERE MATCH(b) AGAINST ('first');
SELECT * FROM t1 WHERE MATCH(c) AGAINST ('first');
SELECT * FROM t1 WHERE MATCH(b,c) AGAINST ('column');
SHOW CREATE TABLE t1;
CHECK TABLE t1;
--let $restart_parameters= --innodb-read-only
--source include/restart_mysqld.inc
--replace_regex /#sql-[0-9a-f_]*/#sql-temporary/ /FTS_[0-9a-f]*_[0-9a-f]*/FTS/
--list_files $datadir/test
SHOW CREATE TABLE t;
SELECT COUNT(*) FROM t;
CHECK TABLE t;
SELECT * FROM t1 WHERE MATCH(b) AGAINST ('first');
SELECT * FROM t1 WHERE MATCH(c) AGAINST ('first');
SELECT * FROM t1 WHERE MATCH(b,c) AGAINST ('column');
SHOW CREATE TABLE t1;
CHECK TABLE t1;
--let $restart_parameters=
--source include/restart_mysqld.inc
--replace_regex /#sql-[0-9a-f_]*/#sql-temporary/ /FTS_[0-9a-f]*_[0-9a-f]*/FTS/
--list_files $datadir/test
DROP TABLE t1,t;
# Work around missing crash recovery at the SQL layer.
let $temp_table_name = `SELECT SUBSTRING(name,6)
FROM information_schema.innodb_sys_tables
WHERE name LIKE "test/#sql-%"`;
--replace_regex /#sql-[0-9a-f_]*/#sql-temporary/
eval DROP TABLE `#mysql50#$temp_table_name`;