mirror of
https://github.com/MariaDB/server.git
synced 2025-02-12 00:15:35 +01:00
![Yuchen Pei](/assets/img/avatar_default.png)
Allow ALTER TABLE ... IMPORT TABLESPACE without creating the table followed by discarding the tablespace. That is, assuming we want to import table t1 to t2, instead of CREATE TABLE t2 LIKE t1; ALTER TABLE t2 DISCARD TABLESPACE; FLUSH TABLES t1 FOR EXPORT; --copy_file $MYSQLD_DATADIR/test/t1.cfg $MYSQLD_DATADIR/test/t2.cfg --copy_file $MYSQLD_DATADIR/test/t1.ibd $MYSQLD_DATADIR/test/t2.ibd UNLOCK TABLES; ALTER TABLE t2 IMPORT TABLESPACE; We can simply do FLUSH TABLES t1 FOR EXPORT; --copy_file $MYSQLD_DATADIR/test/t1.cfg $MYSQLD_DATADIR/test/t2.cfg --copy_file $MYSQLD_DATADIR/test/t1.frm $MYSQLD_DATADIR/test/t2.frm --copy_file $MYSQLD_DATADIR/test/t1.ibd $MYSQLD_DATADIR/test/t2.ibd UNLOCK TABLES; ALTER TABLE t2 IMPORT TABLESPACE; We achieve this by creating a "stub" table in the second scenario while opening the table, where t2 does not exist but needs to import from t1. The "stub" table is similar to a table that is created but then instructed to discard its tablespace. We include tests with various row formats, encryption, with indexes and auto-increment.
163 lines
6.6 KiB
Text
163 lines
6.6 KiB
Text
--source include/have_innodb.inc
|
|
--source include/have_debug.inc
|
|
--source include/not_embedded.inc
|
|
|
|
--echo #
|
|
--echo # MDEV-26137 ALTER TABLE IMPORT enhancement
|
|
--echo #
|
|
|
|
let MYSQLD_DATADIR = `SELECT @@datadir`;
|
|
let INNODB_PAGE_SIZE=`select @@innodb_page_size`;
|
|
|
|
call mtr.add_suppression('InnoDB: Tablespace for table `test`.`t1` is set as discarded.');
|
|
call mtr.add_suppression('InnoDB: Tablespace for table `test`.`t2` is set as discarded.');
|
|
call mtr.add_suppression('InnoDB: Tablespace for table `test`.`t3` is set as discarded.');
|
|
call mtr.add_suppression('InnoDB: ./test/t3.ibd: Page 0 at offset 0 looks corrupted.');
|
|
call mtr.add_suppression("mariadbd.*: Index for table 't3' is corrupt; try to repair it");
|
|
call mtr.add_suppression("InnoDB: Expected tablespace id \\d+ but found \\d+ in the file ./test/t3.ibd");
|
|
# In Windows etc.
|
|
call mtr.add_suppression("InnoDB: Corrupted page \\[page id: space=.*, page number=0\\] of datafile './test/t3.ibd' could not be found in the doublewrite buffer.");
|
|
call mtr.add_suppression('InnoDB: Tablespace for table `test`.`t4` is set as discarded.');
|
|
call mtr.add_suppression('InnoDB: ./test/t4.ibd: Page 0 at offset 0 looks corrupted.');
|
|
call mtr.add_suppression("mariadbd.*: Index for table 't4' is corrupt; try to repair it");
|
|
# In Windows etc.
|
|
call mtr.add_suppression("InnoDB: Corrupted page \\[page id: space=.*, page number=0\\] of datafile './test/t4.ibd' could not be found in the doublewrite buffer.");
|
|
|
|
--echo # Recovery from crashes
|
|
--echo ## t1: Creation of stub succeeds; server crashes; second import attempt succeeds
|
|
--echo ## t2: Creation of stub succeeds; server crashes; drop table
|
|
--echo ## t3: Creation of stub succeeds; server crashes; ibd corrupted; second import attempt fails; drop table
|
|
--echo ## t4: Did not copy .cfg; creation of stub succeeds; server crashes; ibd corrupted; second import attempt fails; drop table
|
|
CREATE TABLE t (a int) ENGINE=InnoDB;
|
|
INSERT INTO t VALUES(42);
|
|
FLUSH TABLES t FOR EXPORT;
|
|
--copy_file $MYSQLD_DATADIR/test/t.cfg $MYSQLD_DATADIR/test/t1.cfg
|
|
--copy_file $MYSQLD_DATADIR/test/t.frm $MYSQLD_DATADIR/test/t1.frm
|
|
--copy_file $MYSQLD_DATADIR/test/t.ibd $MYSQLD_DATADIR/test/t1.ibd
|
|
--copy_file $MYSQLD_DATADIR/test/t.cfg $MYSQLD_DATADIR/test/t2.cfg
|
|
--copy_file $MYSQLD_DATADIR/test/t.frm $MYSQLD_DATADIR/test/t2.frm
|
|
--copy_file $MYSQLD_DATADIR/test/t.ibd $MYSQLD_DATADIR/test/t2.ibd
|
|
--copy_file $MYSQLD_DATADIR/test/t.cfg $MYSQLD_DATADIR/test/t3.cfg
|
|
--copy_file $MYSQLD_DATADIR/test/t.frm $MYSQLD_DATADIR/test/t3.frm
|
|
--copy_file $MYSQLD_DATADIR/test/t.ibd $MYSQLD_DATADIR/test/t3.ibd
|
|
--copy_file $MYSQLD_DATADIR/test/t.frm $MYSQLD_DATADIR/test/t4.frm
|
|
--copy_file $MYSQLD_DATADIR/test/t.ibd $MYSQLD_DATADIR/test/t4.ibd
|
|
UNLOCK TABLES;
|
|
|
|
SET GLOBAL innodb_max_dirty_pages_pct_lwm=0.0;
|
|
SET GLOBAL innodb_max_dirty_pages_pct=0.0;
|
|
|
|
let $wait_condition =
|
|
SELECT variable_value = 0
|
|
FROM information_schema.global_status
|
|
WHERE variable_name = 'INNODB_BUFFER_POOL_PAGES_DIRTY';
|
|
--source include/wait_condition.inc
|
|
|
|
connect (hang1,localhost,root);
|
|
SET DEBUG_SYNC='ib_after_create_stub_for_import SIGNAL hung WAIT_FOR ever';
|
|
send ALTER TABLE t1 IMPORT TABLESPACE;
|
|
connection default;
|
|
SET DEBUG_SYNC='now WAIT_FOR hung';
|
|
|
|
connect (hang2,localhost,root);
|
|
SET DEBUG_SYNC='ib_after_create_stub_for_import SIGNAL hung WAIT_FOR ever';
|
|
send ALTER TABLE t2 IMPORT TABLESPACE;
|
|
connection default;
|
|
SET DEBUG_SYNC='now WAIT_FOR hung';
|
|
|
|
connect (hang3,localhost,root);
|
|
SET DEBUG_SYNC='ib_after_create_stub_for_import SIGNAL hung WAIT_FOR ever';
|
|
send ALTER TABLE t3 IMPORT TABLESPACE;
|
|
connection default;
|
|
SET DEBUG_SYNC='now WAIT_FOR hung';
|
|
|
|
connect (hang4,localhost,root);
|
|
SET DEBUG_SYNC='ib_after_create_stub_for_import SIGNAL hung WAIT_FOR ever';
|
|
send ALTER TABLE t4 IMPORT TABLESPACE;
|
|
connection default;
|
|
SET DEBUG_SYNC='now WAIT_FOR hung';
|
|
|
|
let $shutdown_timeout=0;
|
|
--source include/shutdown_mysqld.inc
|
|
|
|
--echo # corrupting the 0th page
|
|
perl;
|
|
my $ps = $ENV{INNODB_PAGE_SIZE};
|
|
|
|
@tables= ('t3', 't4');
|
|
foreach $table (@tables) {
|
|
my $file = "$ENV{MYSQLD_DATADIR}/test/$table.ibd";
|
|
open(FILE, "+<$file") || die "Unable to open $file";
|
|
binmode FILE;
|
|
sysseek(FILE, 0, 0) || die "Unable to seek $file\n";
|
|
die "Unable to read $file" unless sysread(FILE, $page, $ps) == $ps;
|
|
# Replace all NUL bytes with SOH bytes.
|
|
$page =~ tr/\x0/\x1/;
|
|
sysseek(FILE, 0, 0) || die "Unable to seek $file\n";
|
|
syswrite(FILE, $page, $ps)==$ps || die "Unable to write $file\n";
|
|
close FILE or die "close";
|
|
}
|
|
EOF
|
|
|
|
--echo # Restart mysqld after the crash and reconnect.
|
|
--source include/start_mysqld.inc
|
|
|
|
ALTER TABLE t1 IMPORT TABLESPACE;
|
|
SHOW CREATE TABLE t1;
|
|
SELECT * FROM t1;
|
|
|
|
--error ER_INTERNAL_ERROR
|
|
ALTER TABLE t3 IMPORT TABLESPACE;
|
|
|
|
--error ER_TABLE_SCHEMA_MISMATCH
|
|
ALTER TABLE t4 IMPORT TABLESPACE;
|
|
|
|
DROP TABLE t, t1, t2, t3, t4;
|
|
|
|
--echo # Recovery from corruption only, no server restart
|
|
--echo ## t5: Recovery from corruption, with cfg
|
|
--echo ## t6: Recovery from corruption, without cfg
|
|
call mtr.add_suppression('InnoDB: ./test/t5.ibd: Page 0 at offset 0 looks corrupted.');
|
|
call mtr.add_suppression("mariadbd.*: Index for table 't5' is corrupt; try to repair it");
|
|
# In Windows etc.
|
|
call mtr.add_suppression("InnoDB: Corrupted page \\[page id: space=.*, page number=0\\] of datafile './test/t5.ibd' could not be found in the doublewrite buffer.");
|
|
# In Windows etc.
|
|
call mtr.add_suppression("InnoDB: Corrupted page \\[page id: space=.*, page number=0\\] of datafile './test/t6.ibd' could not be found in the doublewrite buffer.");
|
|
call mtr.add_suppression("mariadbd.*: Index for table 't6' is corrupt; try to repair it");
|
|
|
|
CREATE TABLE t (a int) ENGINE=InnoDB;
|
|
INSERT INTO t VALUES(42);
|
|
FLUSH TABLES t FOR EXPORT;
|
|
--copy_file $MYSQLD_DATADIR/test/t.cfg $MYSQLD_DATADIR/test/t5.cfg
|
|
--copy_file $MYSQLD_DATADIR/test/t.frm $MYSQLD_DATADIR/test/t5.frm
|
|
--copy_file $MYSQLD_DATADIR/test/t.ibd $MYSQLD_DATADIR/test/t5.ibd
|
|
--copy_file $MYSQLD_DATADIR/test/t.frm $MYSQLD_DATADIR/test/t6.frm
|
|
--copy_file $MYSQLD_DATADIR/test/t.ibd $MYSQLD_DATADIR/test/t6.ibd
|
|
UNLOCK TABLES;
|
|
|
|
--echo # corrupting the 0th page
|
|
perl;
|
|
my $ps = $ENV{INNODB_PAGE_SIZE};
|
|
|
|
@tables= ('t5', 't6');
|
|
foreach $table (@tables) {
|
|
my $file = "$ENV{MYSQLD_DATADIR}/test/$table.ibd";
|
|
open(FILE, "+<$file") || die "Unable to open $file";
|
|
binmode FILE;
|
|
sysseek(FILE, 0, 0) || die "Unable to seek $file\n";
|
|
die "Unable to read $file" unless sysread(FILE, $page, $ps) == $ps;
|
|
# Replace all NUL bytes with SOH bytes.
|
|
$page =~ tr/\x0/\x1/;
|
|
sysseek(FILE, 0, 0) || die "Unable to seek $file\n";
|
|
syswrite(FILE, $page, $ps)==$ps || die "Unable to write $file\n";
|
|
close FILE or die "close";
|
|
}
|
|
EOF
|
|
|
|
--error ER_INTERNAL_ERROR
|
|
ALTER TABLE t5 IMPORT TABLESPACE;
|
|
|
|
--error ER_TABLE_SCHEMA_MISMATCH
|
|
ALTER TABLE t6 IMPORT TABLESPACE;
|
|
|
|
DROP TABLE t, t5, t6;
|