Commit 6aa9a552 authored by Monty's avatar Monty Committed by Sergei Golubchik

MDEV-24576 Atomic CREATE TABLE

There are a few different cases to consider

Logging of CREATE TABLE and CREATE TABLE ... LIKE
- If REPLACE is used and there was an existing table, DDL log the drop of
  the table.
- If discovery of table is to be done
    - DDL LOG create table
  else
    - DDL log create table (with engine type)
    - create the table
- If table was created
  - Log entry to binary log with xid
  - Mark DDL log completed

Crash recovery:
- If query was in binary log do nothing and exit
- If discoverted table
   - Delete the .frm file
-else
   - Drop created table and frm file
- If table was dropped, write a DROP TABLE statement in binary log

CREATE TABLE ... SELECT required a little more work as when one is using
statement logging the query is written to the binary log before commit is
done.
This was fixed by adding a DROP TABLE to the binary log during crash
recovery if the ddl log entry was not closed. In this case the binary log
will contain:
CREATE TABLE xxx ... SELECT ....
DROP TABLE xxx;

Other things:
- Added debug_crash_here() functionality to Aria to be able to test
  crash in create table between the creation of the .MAI and the .MAD files.
parent 7a588c30
......@@ -77,7 +77,6 @@ drop table t1;
ERROR 42S02: Unknown table 'test.t1'
show warnings;
Level Code Message
Error 29 File './test/t1.MAD' not found (Errcode: 2 "No such file or directory")
Error 1051 Unknown table 'test.t1'
db.opt
create table t2(a int) engine=aria;
......
......@@ -29,7 +29,7 @@ ROLLBACK/*!*/;
/*!100001 SET @@session.server_id=1*//*!*/;
/*!100001 SET @@session.gtid_seq_no=1*//*!*/;
# at 371
#<date> server id 1 end_log_pos 533 CRC32 XXX Query_compressed thread_id=5 exec_time=x error_code=0 xid=<xid>
#<date> server id 1 end_log_pos 542 CRC32 XXX Query_compressed thread_id=5 exec_time=x error_code=0 xid=<xid>
use `test`/*!*/;
SET TIMESTAMP=X/*!*/;
SET @@session.pseudo_thread_id=5/*!*/;
......@@ -42,136 +42,136 @@ SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
CREATE TABLE t1 (pk INT PRIMARY KEY, f1 INT, f2 INT, f3 TINYINT, f4 MEDIUMINT, f5 BIGINT, f6 INT, f7 INT, f8 char(1))
/*!*/;
# at 533
#<date> server id 1 end_log_pos 575 CRC32 XXX GTID 0-1-2 ddl
# at 542
#<date> server id 1 end_log_pos 584 CRC32 XXX GTID 0-1-2 ddl
/*!100001 SET @@session.gtid_seq_no=2*//*!*/;
# at 575
#<date> server id 1 end_log_pos 727 CRC32 XXX Query_compressed thread_id=5 exec_time=x error_code=0 xid=<xid>
# at 584
#<date> server id 1 end_log_pos 745 CRC32 XXX Query_compressed thread_id=5 exec_time=x error_code=0 xid=<xid>
SET TIMESTAMP=X/*!*/;
CREATE TABLE t2 (pk INT PRIMARY KEY, f1 INT, f2 INT, f3 INT, f4 INT, f5 MEDIUMINT, f6 INT, f7 INT, f8 char(1))
/*!*/;
# at 727
#<date> server id 1 end_log_pos 769 CRC32 XXX GTID 0-1-3
# at 745
#<date> server id 1 end_log_pos 787 CRC32 XXX GTID 0-1-3
/*!100001 SET @@session.gtid_seq_no=3*//*!*/;
START TRANSACTION
/*!*/;
# at 769
#<date> server id 1 end_log_pos 897 CRC32 XXX Query_compressed thread_id=5 exec_time=x error_code=0 xid=<xid>
# at 787
#<date> server id 1 end_log_pos 915 CRC32 XXX Query_compressed thread_id=5 exec_time=x error_code=0 xid=<xid>
SET TIMESTAMP=X/*!*/;
INSERT INTO t1 VALUES (10, 1, 2, 3, 4, 5, 6, 7, "")
/*!*/;
# at 897
#<date> server id 1 end_log_pos 970 CRC32 XXX Query thread_id=5 exec_time=x error_code=0 xid=<xid>
# at 915
#<date> server id 1 end_log_pos 988 CRC32 XXX Query thread_id=5 exec_time=x error_code=0 xid=<xid>
SET TIMESTAMP=X/*!*/;
COMMIT
/*!*/;
# at 970
#<date> server id 1 end_log_pos 1012 CRC32 XXX GTID 0-1-4
# at 988
#<date> server id 1 end_log_pos 1030 CRC32 XXX GTID 0-1-4
/*!100001 SET @@session.gtid_seq_no=4*//*!*/;
START TRANSACTION
/*!*/;
# at 1012
#<date> server id 1 end_log_pos 1140 CRC32 XXX Query_compressed thread_id=5 exec_time=x error_code=0 xid=<xid>
# at 1030
#<date> server id 1 end_log_pos 1158 CRC32 XXX Query_compressed thread_id=5 exec_time=x error_code=0 xid=<xid>
SET TIMESTAMP=X/*!*/;
INSERT INTO t1 VALUES (11, 1, 2, 3, 4, 5, 6, 7, NULL)
/*!*/;
# at 1140
#<date> server id 1 end_log_pos 1213 CRC32 XXX Query thread_id=5 exec_time=x error_code=0 xid=<xid>
# at 1158
#<date> server id 1 end_log_pos 1231 CRC32 XXX Query thread_id=5 exec_time=x error_code=0 xid=<xid>
SET TIMESTAMP=X/*!*/;
COMMIT
/*!*/;
# at 1213
#<date> server id 1 end_log_pos 1255 CRC32 XXX GTID 0-1-5
# at 1231
#<date> server id 1 end_log_pos 1273 CRC32 XXX GTID 0-1-5
/*!100001 SET @@session.gtid_seq_no=5*//*!*/;
START TRANSACTION
/*!*/;
# at 1255
#<date> server id 1 end_log_pos 1385 CRC32 XXX Query_compressed thread_id=5 exec_time=x error_code=0 xid=<xid>
# at 1273
#<date> server id 1 end_log_pos 1403 CRC32 XXX Query_compressed thread_id=5 exec_time=x error_code=0 xid=<xid>
SET TIMESTAMP=X/*!*/;
INSERT INTO t1 VALUES (12, 1, 2, 3, NULL, 5, 6, 7, "A")
/*!*/;
# at 1385
#<date> server id 1 end_log_pos 1458 CRC32 XXX Query thread_id=5 exec_time=x error_code=0 xid=<xid>
# at 1403
#<date> server id 1 end_log_pos 1476 CRC32 XXX Query thread_id=5 exec_time=x error_code=0 xid=<xid>
SET TIMESTAMP=X/*!*/;
COMMIT
/*!*/;
# at 1458
#<date> server id 1 end_log_pos 1500 CRC32 XXX GTID 0-1-6
# at 1476
#<date> server id 1 end_log_pos 1518 CRC32 XXX GTID 0-1-6
/*!100001 SET @@session.gtid_seq_no=6*//*!*/;
START TRANSACTION
/*!*/;
# at 1500
#<date> server id 1 end_log_pos 1627 CRC32 XXX Query_compressed thread_id=5 exec_time=x error_code=0 xid=<xid>
# at 1518
#<date> server id 1 end_log_pos 1645 CRC32 XXX Query_compressed thread_id=5 exec_time=x error_code=0 xid=<xid>
SET TIMESTAMP=X/*!*/;
INSERT INTO t1 VALUES (13, 1, 2, 3, 0, 5, 6, 7, "A")
/*!*/;
# at 1627
#<date> server id 1 end_log_pos 1700 CRC32 XXX Query thread_id=5 exec_time=x error_code=0 xid=<xid>
# at 1645
#<date> server id 1 end_log_pos 1718 CRC32 XXX Query thread_id=5 exec_time=x error_code=0 xid=<xid>
SET TIMESTAMP=X/*!*/;
COMMIT
/*!*/;
# at 1700
#<date> server id 1 end_log_pos 1742 CRC32 XXX GTID 0-1-7
# at 1718
#<date> server id 1 end_log_pos 1760 CRC32 XXX GTID 0-1-7
/*!100001 SET @@session.gtid_seq_no=7*//*!*/;
START TRANSACTION
/*!*/;
# at 1742
#<date> server id 1 end_log_pos 1850 CRC32 XXX Query_compressed thread_id=5 exec_time=x error_code=0 xid=<xid>
# at 1760
#<date> server id 1 end_log_pos 1868 CRC32 XXX Query_compressed thread_id=5 exec_time=x error_code=0 xid=<xid>
SET TIMESTAMP=X/*!*/;
INSERT INTO t2 SELECT * FROM t1
/*!*/;
# at 1850
#<date> server id 1 end_log_pos 1923 CRC32 XXX Query thread_id=5 exec_time=x error_code=0 xid=<xid>
# at 1868
#<date> server id 1 end_log_pos 1941 CRC32 XXX Query thread_id=5 exec_time=x error_code=0 xid=<xid>
SET TIMESTAMP=X/*!*/;
COMMIT
/*!*/;
# at 1923
#<date> server id 1 end_log_pos 1965 CRC32 XXX GTID 0-1-8
# at 1941
#<date> server id 1 end_log_pos 1983 CRC32 XXX GTID 0-1-8
/*!100001 SET @@session.gtid_seq_no=8*//*!*/;
START TRANSACTION
/*!*/;
# at 1965
#<date> server id 1 end_log_pos 2082 CRC32 XXX Query_compressed thread_id=5 exec_time=x error_code=0 xid=<xid>
# at 1983
#<date> server id 1 end_log_pos 2100 CRC32 XXX Query_compressed thread_id=5 exec_time=x error_code=0 xid=<xid>
SET TIMESTAMP=X/*!*/;
UPDATE t2 SET f4=5 WHERE f4>0 or f4 is NULL
/*!*/;
# at 2082
#<date> server id 1 end_log_pos 2155 CRC32 XXX Query thread_id=5 exec_time=x error_code=0 xid=<xid>
# at 2100
#<date> server id 1 end_log_pos 2173 CRC32 XXX Query thread_id=5 exec_time=x error_code=0 xid=<xid>
SET TIMESTAMP=X/*!*/;
COMMIT
/*!*/;
# at 2155
#<date> server id 1 end_log_pos 2197 CRC32 XXX GTID 0-1-9
# at 2173
#<date> server id 1 end_log_pos 2215 CRC32 XXX GTID 0-1-9
/*!100001 SET @@session.gtid_seq_no=9*//*!*/;
START TRANSACTION
/*!*/;
# at 2197
#<date> server id 1 end_log_pos 2288 CRC32 XXX Query_compressed thread_id=5 exec_time=x error_code=0 xid=<xid>
# at 2215
#<date> server id 1 end_log_pos 2306 CRC32 XXX Query_compressed thread_id=5 exec_time=x error_code=0 xid=<xid>
SET TIMESTAMP=X/*!*/;
DELETE FROM t1
/*!*/;
# at 2288
#<date> server id 1 end_log_pos 2361 CRC32 XXX Query thread_id=5 exec_time=x error_code=0 xid=<xid>
# at 2306
#<date> server id 1 end_log_pos 2379 CRC32 XXX Query thread_id=5 exec_time=x error_code=0 xid=<xid>
SET TIMESTAMP=X/*!*/;
COMMIT
/*!*/;
# at 2361
#<date> server id 1 end_log_pos 2403 CRC32 XXX GTID 0-1-10
# at 2379
#<date> server id 1 end_log_pos 2421 CRC32 XXX GTID 0-1-10
/*!100001 SET @@session.gtid_seq_no=10*//*!*/;
START TRANSACTION
/*!*/;
# at 2403
#<date> server id 1 end_log_pos 2494 CRC32 XXX Query_compressed thread_id=5 exec_time=x error_code=0 xid=<xid>
# at 2421
#<date> server id 1 end_log_pos 2512 CRC32 XXX Query_compressed thread_id=5 exec_time=x error_code=0 xid=<xid>
SET TIMESTAMP=X/*!*/;
DELETE FROM t2
/*!*/;
# at 2494
#<date> server id 1 end_log_pos 2567 CRC32 XXX Query thread_id=5 exec_time=x error_code=0 xid=<xid>
# at 2512
#<date> server id 1 end_log_pos 2585 CRC32 XXX Query thread_id=5 exec_time=x error_code=0 xid=<xid>
SET TIMESTAMP=X/*!*/;
COMMIT
/*!*/;
# at 2567
#<date> server id 1 end_log_pos 2615 CRC32 XXX Rotate to master-bin.000002 pos: 4
# at 2585
#<date> server id 1 end_log_pos 2633 CRC32 XXX Rotate to master-bin.000002 pos: 4
DELIMITER ;
# End of log file
ROLLBACK /* added by mysqlbinlog */;
......
......@@ -1194,7 +1194,7 @@ source include/binlog_start_pos.inc;
let _BINLOG_START_POS= $binlog_start_pos;
--perl
my $f= "$ENV{MYSQLTEST_VARDIR}/tmp/mwl136.sql";
my $pos=$ENV{_BINLOG_START_POS} + 739;
my $pos=$ENV{_BINLOG_START_POS} + 757;
open F, '<', $f or die "Failed to open $f: $!\n";
while (<F>) {
s/$pos/<pos>/;
......
This diff is collapsed.
--source include/have_debug.inc
--source include/have_sequence.inc
--source include/have_innodb.inc
--source include/have_log_bin.inc
--source include/not_valgrind.inc
#
# Testing of atomic create table with crashes in a lot of different places
#
# We test both statement based logging and row logging as CREATE ... SELECT
# works a bit differently depending on the logging format
# First engine will use row logging and second engine will use statement
# based logging
#
--disable_query_log
call mtr.add_suppression("InnoDB: .* does not exist in the InnoDB internal");
--enable_query_log
let $MYSQLD_DATADIR= `SELECT @@datadir`;
if ($engine_count == "")
{
let $engine_count=2;
let $engines='myisam','innodb';
}
let $crash_count=9;
let $crash_points='ddl_log_create_before_create_frm', 'storage_engine_middle_of_create', 'ddl_log_create_before_create_table', 'ddl_log_create_after_create_table', 'ddl_log_create_after_drop', 'ddl_log_create_before_binlog', 'ddl_log_create_after_prepare_eof', 'ddl_log_create_after_binlog', 'ddl_log_create_log_complete';
let $statement_count=6;
let $statements='CREATE TABLE t1 (a int)',
'CREATE OR REPLACE TABLE t2 (a int)',
'CREATE TABLE t1 LIKE const_table',
'CREATE OR REPLACE TABLE t2 LIKE const_table',
'CREATE TABLE t1 SELECT * from t2',
'CREATE OR REPLACE TABLE t2 SELECT * from const_table';
create table const_table (a int, b int) engine=myisam;
insert into const_table values (1,1),(2,2);
flush tables;
let $old_debug=`select @@debug_dbug`;
let $e=0;
let $keep_include_silent=1;
let $grep_script=CREATE|DROP;
--disable_query_log
while ($e < $engine_count)
{
inc $e;
let $engine=`select ELT($e, $engines)`;
let $default_engine=$engine;
let $extra_option=;
if ($engine == "aria")
{
let $extra_option=transactional=1;
}
if ($engine == "aria_notrans")
{
let $default_engine="aria";
let $extra_option=transactional=0;
}
--echo engine: $engine
let $r=0;
while ($r < $statement_count)
{
inc $r;
let $statement=`select ELT($r, $statements)`;
--echo query: $statement
let $c=0;
while ($c < $crash_count)
{
inc $c;
let $crash=`select ELT($c, $crash_points)`;
--eval set @@default_storage_engine=$default_engine
create or replace table t2 select * from seq_1_to_2;
flush tables;
if ($e == 1)
{
--source include/set_binlog_format_row.sql
}
if ($e == 2)
{
--source include/set_binlog_format_statement.sql
}
RESET MASTER;
--echo crash point: $crash
--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--disable_reconnect
--eval set @@debug_dbug="+d,$crash",@debug_crash_counter=1
let $errno=0;
--error 0,2013
--eval $statement;
let $error=$errno;
--enable_reconnect
--source include/wait_until_connected_again.inc
--disable_query_log
--eval set @@debug_dbug="$old_debug"
if ($error == 0)
{
echo "No crash!";
}
# Check which tables still exists
--list_files $MYSQLD_DATADIR/test t*
--list_files $MYSQLD_DATADIR/test *sql*
--let $binlog_file=master-bin.000001
--source include/show_binlog_events.inc
if ($error)
{
--let $binlog_file=master-bin.000002
--source include/show_binlog_events.inc
}
# Drop the tables. The warnings will show what was dropped
--disable_warnings
drop table if exists t1,t2;
--enable_warnings
}
}
}
drop table if exists t1,t2,const_table;
--enable_query_log
......@@ -58,20 +58,20 @@ select "--- offset --" as "";
--disable_query_log
select "--- start-position --" as "";
--enable_query_log
let $start_pos= `select @binlog_start_pos + 696`;
let $start_pos= `select @binlog_start_pos + 705`;
--replace_regex /collation_server=[0-9]+/collation_server=X/ /character_set_client=[0-9]+/character_set_client=X/ /collation_connection=[0-9]+/collation_connection=X/
--exec $MYSQL_BINLOG --short-form --start-position=$start_pos $MYSQLD_DATADIR/master-bin.000001
--disable_query_log
select "--- stop-position --" as "";
--enable_query_log
let $stop_pos= `select @binlog_start_pos + 696`;
let $stop_pos= `select @binlog_start_pos + 705`;
--replace_regex /collation_server=[0-9]+/collation_server=X/ /character_set_client=[0-9]+/character_set_client=X/ /collation_connection=[0-9]+/collation_connection=X/
--exec $MYSQL_BINLOG --short-form --stop-position=$stop_pos $MYSQLD_DATADIR/master-bin.000001
--disable_query_log
select "--- start and stop positions ---" as "";
--enable_query_log
let $start_pos= `select @binlog_start_pos + 696`;
let $stop_pos= `select @binlog_start_pos + 857`;
let $start_pos= `select @binlog_start_pos + 705`;
let $stop_pos= `select @binlog_start_pos + 866`;
--replace_regex /collation_server=[0-9]+/collation_server=X/ /character_set_client=[0-9]+/character_set_client=X/ /collation_connection=[0-9]+/collation_connection=X/
--exec $MYSQL_BINLOG --short-form --start-position=$start_pos --stop-position=$stop_pos $MYSQLD_DATADIR/master-bin.000001
--disable_query_log
......@@ -103,7 +103,7 @@ select "--- offset --" as "";
--disable_query_log
select "--- start-position --" as "";
--enable_query_log
let $start_pos= `select @binlog_start_pos + 696`;
let $start_pos= `select @binlog_start_pos + 705`;
--replace_regex /collation_server=[0-9]+/collation_server=X/ /character_set_client=[0-9]+/character_set_client=X/ /collation_connection=[0-9]+/collation_connection=X/
--exec $MYSQL_BINLOG --short-form --start-position=$start_pos $MYSQLD_DATADIR/master-bin.000001 $MYSQLD_DATADIR/master-bin.000002
--disable_query_log
......@@ -138,19 +138,19 @@ select "--- offset --" as "";
--disable_query_log
select "--- start-position --" as "";
--enable_query_log
let $start_pos= `select @binlog_start_pos + 696`;
let $start_pos= `select @binlog_start_pos + 705`;
--replace_regex /collation_server=[0-9]+/collation_server=X/ /character_set_client=[0-9]+/character_set_client=X/ /collation_connection=[0-9]+/collation_connection=X/
--exec $MYSQL_BINLOG --short-form --start-position=$start_pos --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001
--disable_query_log
select "--- stop-position --" as "";
--enable_query_log
let $stop_pos= `select @binlog_start_pos + 696`;
let $stop_pos= `select @binlog_start_pos + 705`;
--replace_regex /collation_server=[0-9]+/collation_server=X/ /character_set_client=[0-9]+/character_set_client=X/ /collation_connection=[0-9]+/collation_connection=X/
--exec $MYSQL_BINLOG --short-form --stop-position=$stop_pos --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001
--disable_query_log
select "--- start and stop positions ---" as "";
--enable_query_log
let $start_pos= `select @binlog_start_pos + 696`;
let $start_pos= `select @binlog_start_pos + 705`;
let $stop_pos= `select @binlog_start_pos + 812`;
--replace_regex /collation_server=[0-9]+/collation_server=X/ /character_set_client=[0-9]+/character_set_client=X/ /collation_connection=[0-9]+/collation_connection=X/
--exec $MYSQL_BINLOG --short-form --start-position=$start_pos --stop-position $stop_pos --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001
......@@ -180,7 +180,7 @@ select "--- offset --" as "";
--disable_query_log
select "--- start-position --" as "";
--enable_query_log
let $start_pos= `select @binlog_start_pos + 696`;
let $start_pos= `select @binlog_start_pos + 705`;
--replace_regex /collation_server=[0-9]+/collation_server=X/ /character_set_client=[0-9]+/character_set_client=X/ /collation_connection=[0-9]+/collation_connection=X/
--exec $MYSQL_BINLOG --short-form --start-position=$start_pos --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 master-bin.000002
--disable_query_log
......
......@@ -12,25 +12,25 @@ SET SESSION wsrep_trx_fragment_size=1;
INSERT INTO t1 VALUES (5), (6);
SET SESSION wsrep_trx_fragment_unit=default;
SET SESSION wsrep_trx_fragment_size=default;
SHOW BINLOG EVENTS IN 'mysqld-bin.000002' FROM 518;
SHOW BINLOG EVENTS IN 'mysqld-bin.000002' FROM 527;
Log_name Pos Event_type Server_id End_log_pos Info
mysqld-bin.000002 518 Gtid 1 560 BEGIN GTID 0-1-2
mysqld-bin.000002 560 Annotate_rows 1 613 INSERT INTO t1 VALUES (1), (2)
mysqld-bin.000002 613 Table_map 1 658 table_id: # (test.t1)
mysqld-bin.000002 658 Write_rows_v1 1 696 table_id: # flags: STMT_END_F
mysqld-bin.000002 696 Table_map 1 741 table_id: # (test.t1)
mysqld-bin.000002 741 Write_rows_v1 1 779 table_id: # flags: STMT_END_F
mysqld-bin.000002 779 Xid 1 810 COMMIT /* xid=# */
mysqld-bin.000002 810 Gtid 1 852 BEGIN GTID 0-1-3
mysqld-bin.000002 852 Annotate_rows 1 905 INSERT INTO t1 VALUES (3), (4)
mysqld-bin.000002 905 Table_map 1 950 table_id: # (test.t1)
mysqld-bin.000002 950 Write_rows_v1 1 988 table_id: # flags: STMT_END_F
mysqld-bin.000002 988 Table_map 1 1033 table_id: # (test.t1)
mysqld-bin.000002 1033 Write_rows_v1 1 1071 table_id: # flags: STMT_END_F
mysqld-bin.000002 1071 Xid 1 1102 COMMIT /* xid=# */
mysqld-bin.000002 1102 Gtid 1 1144 BEGIN GTID 0-1-4
mysqld-bin.000002 1144 Annotate_rows 1 1197 INSERT INTO t1 VALUES (5), (6)
mysqld-bin.000002 1197 Table_map 1 1242 table_id: # (test.t1)
mysqld-bin.000002 1242 Write_rows_v1 1 1285 table_id: # flags: STMT_END_F
mysqld-bin.000002 1285 Xid 1 1316 COMMIT /* xid=# */
mysqld-bin.000002 # Gtid 1 # BEGIN GTID 0-1-2
mysqld-bin.000002 # Annotate_rows 1 # INSERT INTO t1 VALUES (1), (2)
mysqld-bin.000002 # Table_map 1 # table_id: # (test.t1)
mysqld-bin.000002 # Write_rows_v1 1 # table_id: # flags: STMT_END_F
mysqld-bin.000002 # Table_map 1 # table_id: # (test.t1)
mysqld-bin.000002 # Write_rows_v1 1 # table_id: # flags: STMT_END_F
mysqld-bin.000002 # Xid 1 # COMMIT /* xid=# */
mysqld-bin.000002 # Gtid 1 # BEGIN GTID 0-1-3
mysqld-bin.000002 # Annotate_rows 1 # INSERT INTO t1 VALUES (3), (4)
mysqld-bin.000002 # Table_map 1 # table_id: # (test.t1)
mysqld-bin.000002 # Write_rows_v1 1 # table_id: # flags: STMT_END_F
mysqld-bin.000002 # Table_map 1 # table_id: # (test.t1)
mysqld-bin.000002 # Write_rows_v1 1 # table_id: # flags: STMT_END_F
mysqld-bin.000002 # Xid 1 # COMMIT /* xid=# */
mysqld-bin.000002 # Gtid 1 # BEGIN GTID 0-1-4
mysqld-bin.000002 # Annotate_rows 1 # INSERT INTO t1 VALUES (5), (6)
mysqld-bin.000002 # Table_map 1 # table_id: # (test.t1)
mysqld-bin.000002 # Write_rows_v1 1 # table_id: # flags: STMT_END_F
mysqld-bin.000002 # Xid 1 # COMMIT /* xid=# */
DROP TABLE t1;
......@@ -12,6 +12,8 @@ CREATE TABLE t1 (f1 INT PRIMARY KEY);
SET SESSION wsrep_trx_fragment_unit='ROWS';
SET SESSION wsrep_trx_fragment_size=1;
--let $start_pos= query_get_value(SHOW MASTER STATUS, Position, 1)
INSERT INTO t1 VALUES (1), (2);
#
......@@ -37,6 +39,7 @@ SET SESSION wsrep_trx_fragment_unit=default;
SET SESSION wsrep_trx_fragment_size=default;
--replace_regex /table_id: [0-9]+/table_id: #/ /xid=[0-9]+/xid=#/
SHOW BINLOG EVENTS IN 'mysqld-bin.000002' FROM 518;
--replace_column 2 # 5 #
--eval SHOW BINLOG EVENTS IN 'mysqld-bin.000002' FROM $start_pos
DROP TABLE t1;
......@@ -19,7 +19,7 @@ CREATE TABLE t1 (a INT, b VARCHAR(100), PRIMARY KEY (a,b)) ENGINE=innodb;
# MDEV-515 takes X-lock on the table for the first insert.
# So concurrent insert won't happen on the table
INSERT INTO t1 VALUES(9, "");
let pos=`select $binlog_start_pos + 422`;
let pos=`select $binlog_start_pos + 431`;
--replace_result $pos <pos>
SHOW MASTER STATUS;
--replace_result $pos <pos>
......@@ -56,10 +56,10 @@ COMMIT;
connection default;
SELECT * FROM t1 ORDER BY a,b;
let pos=`select $binlog_start_pos + 956`;
let pos=`select $binlog_start_pos + 974`;
--replace_result $pos <pos>
SHOW STATUS LIKE 'binlog_snapshot_%';
let pos=`select $binlog_start_pos + 1332`;
let pos=`select $binlog_start_pos + 1350`;
--replace_result $pos <pos>
SHOW MASTER STATUS;
SELECT * FROM t2 ORDER BY a;
......@@ -77,7 +77,7 @@ FLUSH LOGS;
connection default;
SELECT * FROM t1 ORDER BY a,b;
let pos=`select $binlog_start_pos + 956`;
let pos=`select $binlog_start_pos + 974`;
--replace_result $pos <pos>
SHOW STATUS LIKE 'binlog_snapshot_%';
let pos=`select $binlog_start_pos + 131`;
......
......@@ -97,7 +97,7 @@ SELECT * FROM t1 ORDER BY a;
# for the end of the second transaction (as can be checked with
# mysqlbinlog).
let $MYSQLD_DATADIR= `SELECT @@datadir`;
let pos=`select $binlog_start_pos + 730`;
let pos=`select $binlog_start_pos + 739`;
--replace_result $pos <pos>
--exec sed -ne 's/.*\(InnoDB: Last binlog file .* position.*\)/\1/p' $MYSQLD_DATADIR/../../log/mysqld.1.err | tail -1
......
......@@ -98,7 +98,7 @@ SELECT * FROM t1 ORDER BY a;
# for the end of the second transaction (as can be checked with
# mysqlbinlog).
let $MYSQLD_DATADIR= `SELECT @@datadir`;
let pos=`select $binlog_start_pos + 730`;
let pos=`select $binlog_start_pos + 739`;
--replace_result $pos <pos>
--exec sed -ne 's/.*\(InnoDB: Last binlog file .* position.*\)/\1/p' $MYSQLD_DATADIR/../../log/mysqld.1.err | tail -1
SET DEBUG_SYNC= 'RESET';
......
......@@ -39,9 +39,10 @@ stop slave 'master1';
--let $datadir = `SELECT @@datadir`
let read_master_log_pos=`select $binlog_start_pos + 599`;
let relay_log_pos=`select 2*$binlog_start_pos + 643`;
let relay_log_space=`select 3*$binlog_start_pos + 705`;
let read_master_log_pos=`select $binlog_start_pos + 608`;
let relay_log_pos=`select 2*$binlog_start_pos + 652`;
let relay_log_space=`select 3*$binlog_start_pos + 714`;
--replace_result $SERVER_MYPORT_1 MYPORT_1 $read_master_log_pos <read_master_log_pos> $relay_log_pos <relay_log_pos> $relay_log_space <relay_log_space>
show slave 'master1' status;
--list_files $datadir mysqld*
......
......@@ -9,6 +9,4 @@ SELECT * FROM t1;
connection default;
# Waiting for mariadbd to crash
# Crash was detected
DROP TABLE t1, t2;
Warnings:
Warning 1932 Table 'test.t2' doesn't exist in engine
DROP TABLE t1;
......@@ -65,4 +65,5 @@ connection default;
# Call script that will poll the server waiting for it to be back online again
source include/wait_until_connected_again.inc;
DROP TABLE t1, t2;
# We only have to do drop t1, as t2 as been automatically deleted by ddl recovery
DROP TABLE t1;
......@@ -89,7 +89,7 @@ const char *ddl_log_action_name[DDL_LOG_LAST_ACTION]=
"partitioning replace", "partitioning exchange",
"rename table", "rename view",
"initialize drop table", "drop table",
"drop view", "drop trigger", "drop db",
"drop view", "drop trigger", "drop db", "create table",
};
/* Number of phases per entry */
......@@ -98,7 +98,7 @@ const uchar ddl_log_entry_phases[DDL_LOG_LAST_ACTION]=
0, 1, 1, 2,
(uchar) EXCH_PHASE_END, (uchar) DDL_RENAME_PHASE_END, 1, 1,
(uchar) DDL_DROP_PHASE_END, 1, 1,
(uchar) DDL_DROP_DB_PHASE_END
(uchar) DDL_DROP_DB_PHASE_END, (uchar) DDL_CREATE_TABLE_PHASE_END
};
......@@ -1499,6 +1499,59 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root,
}
break;
}
case DDL_LOG_CREATE_TABLE_ACTION:
{
LEX_CSTRING db, table, path;
db= ddl_log_entry->db;
table= ddl_log_entry->name;
path= ddl_log_entry->tmp_name;
/* Don't delete the table if we didn't create it */
if (ddl_log_entry->flags == 0)
{
if (hton)
{
if ((error= hton->drop_table(hton, path.str)))
{
if (!non_existing_table_error(error))
break;
error= -1;
}
}
else
error= ha_delete_table_force(thd, path.str, &db, &table);
}
strxnmov(to_path, sizeof(to_path)-1, path.str, reg_ext, NullS);
mysql_file_delete(key_file_frm, to_path, MYF(MY_WME|MY_IGNORE_ENOENT));
if (ddl_log_entry->phase == DDL_CREATE_TABLE_PHASE_LOG)
{
/*
The server logged CREATE TABLE ... SELECT into binary log
before crashing. As the commit failed and we have delete the
table above, we have now to log the DROP of the created table.
*/
String *query= &recovery_state.drop_table;
query->length(0);
query->append(STRING_WITH_LEN("DROP TABLE IF EXISTS "));
append_identifier(thd, query, &db);
query->append('.');
append_identifier(thd, query, &table);
query->append(&end_comment);
if (mysql_bin_log.is_open())
{
mysql_mutex_unlock(&LOCK_gdl);
(void) thd->binlog_query(THD::STMT_QUERY_TYPE,
query->ptr(), query->length(),
TRUE, FALSE, FALSE, 0);
mysql_mutex_lock(&LOCK_gdl);
}
}
(void) update_phase(entry_pos, DDL_LOG_FINAL_PHASE);
break;
}
break;
default:
DBUG_ASSERT(0);
break;
......@@ -2417,3 +2470,34 @@ bool ddl_log_drop_db(THD *thd, DDL_LOG_STATE *ddl_state,
ddl_log_entry.tmp_name= *const_cast<LEX_CSTRING*>(path);
DBUG_RETURN(ddl_log_write(ddl_state, &ddl_log_entry));
}
/**
Log CREATE TABLE
@param only_frm On recovery, only drop the .frm. This is needed for
example when deleting a table that was discovered.
*/
bool ddl_log_create_table(THD *thd, DDL_LOG_STATE *ddl_state,
handlerton *hton,
const LEX_CSTRING *path,
const LEX_CSTRING *db,
const LEX_CSTRING *table,
bool only_frm)
{
DDL_LOG_ENTRY ddl_log_entry;
DBUG_ENTER("ddl_log_create_table");
bzero(&ddl_log_entry, sizeof(ddl_log_entry));
ddl_log_entry.action_type= DDL_LOG_CREATE_TABLE_ACTION;
if (hton)
lex_string_set(&ddl_log_entry.handler_name,
ha_resolve_storage_engine_name(hton));
ddl_log_entry.db= *const_cast<LEX_CSTRING*>(db);
ddl_log_entry.name= *const_cast<LEX_CSTRING*>(table);
ddl_log_entry.tmp_name= *const_cast<LEX_CSTRING*>(path);
ddl_log_entry.flags= only_frm;
DBUG_RETURN(ddl_log_write(ddl_state, &ddl_log_entry));
}
......@@ -82,6 +82,7 @@ enum ddl_log_action_code
DDL_LOG_DROP_VIEW_ACTION= 9,
DDL_LOG_DROP_TRIGGER_ACTION= 10,
DDL_LOG_DROP_DB_ACTION=11,
DDL_LOG_CREATE_TABLE_ACTION=12,
DDL_LOG_LAST_ACTION /* End marker */
};
......@@ -118,6 +119,12 @@ enum enum_ddl_log_drop_db_phase {
DDL_DROP_DB_PHASE_END
};
enum enum_ddl_log_create_table_phase {
DDL_CREATE_TABLE_PHASE_INIT=0,
DDL_CREATE_TABLE_PHASE_LOG,
DDL_CREATE_TABLE_PHASE_END
};
/*
Setting ddl_log_entry.phase to this has the same effect as setting
the phase to the maximum phase (..PHASE_END) for an entry.
......@@ -185,6 +192,7 @@ typedef struct st_ddl_log_state
DDL_LOG_MEMORY_ENTRY *list;
/* One execute entry per list */
DDL_LOG_MEMORY_ENTRY *execute_entry;
bool is_active() { return list != 0; }
} DDL_LOG_STATE;
......@@ -252,5 +260,11 @@ bool ddl_log_drop_view(THD *thd, DDL_LOG_STATE *ddl_state,
const LEX_CSTRING *db);
bool ddl_log_drop_db(THD *thd, DDL_LOG_STATE *ddl_state,
const LEX_CSTRING *db, const LEX_CSTRING *path);
bool ddl_log_create_table(THD *thd, DDL_LOG_STATE *ddl_state,
handlerton *hton,
const LEX_CSTRING *path,
const LEX_CSTRING *db,
const LEX_CSTRING *table,
bool only_frm);
extern mysql_mutex_t LOCK_gdl;
#endif /* DDL_LOG_INCLUDED */
......@@ -4563,6 +4563,7 @@ bool non_existing_table_error(int error)
{
return (error == ENOENT ||
(error == EE_DELETE && my_errno == ENOENT) ||
error == EE_FILENOTFOUND ||
error == HA_ERR_NO_SUCH_TABLE ||
error == HA_ERR_UNSUPPORTED ||
error == ER_NO_SUCH_TABLE ||
......
......@@ -294,6 +294,12 @@ class Alter_table_ctx
const char *get_tmp_path() const
{ return tmp_path; }
const LEX_CSTRING get_tmp_cstring_path() const
{
LEX_CSTRING tmp= { tmp_path, strlen(tmp_path) };
return tmp;
};
/**
Mark ALTER TABLE as needing to produce foreign key error if
it deletes a row from the table being changed.
......
......@@ -50,6 +50,7 @@
#include "session_tracker.h"
#include "backup.h"
#include "xa.h"
#include "ddl_log.h" /* DDL_LOG_STATE */
extern "C"
void set_thd_stage_info(void *thd,
......@@ -6027,6 +6028,7 @@ class select_create: public select_insert {
MYSQL_LOCK **m_plock;
bool exit_done;
TMP_TABLE_SHARE *saved_tmp_table_share;
DDL_LOG_STATE ddl_log_state_create, ddl_log_state_rm;
public:
select_create(THD *thd_arg, TABLE_LIST *table_arg,
......@@ -6042,7 +6044,10 @@ class select_create: public select_insert {
alter_info(alter_info_arg),
m_plock(NULL), exit_done(0),
saved_tmp_table_share(0)
{}
{
bzero(&ddl_log_state_create, sizeof(ddl_log_state_create));
bzero(&ddl_log_state_rm, sizeof(ddl_log_state_rm));
}
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
void store_values(List<Item> &values);
......
......@@ -4375,7 +4375,8 @@ Field *Item::create_field_for_create_select(MEM_ROOT *root, TABLE *table)
*/
TABLE *select_create::create_table_from_items(THD *thd, List<Item> *items,
MYSQL_LOCK **lock, TABLEOP_HOOKS *hooks)
MYSQL_LOCK **lock,
TABLEOP_HOOKS *hooks)
{
TABLE tmp_table; // Used during 'Create_field()'
TABLE_SHARE share;
......@@ -4473,7 +4474,8 @@ TABLE *select_create::create_table_from_items(THD *thd, List<Item> *items,
open_table().
*/
if (!mysql_create_table_no_lock(thd, &create_table->db,
if (!mysql_create_table_no_lock(thd, &ddl_log_state_create, &ddl_log_state_rm,
&create_table->db,
&create_table->table_name,
create_info, alter_info, NULL,
select_field_count, create_table))
......@@ -4532,6 +4534,8 @@ TABLE *select_create::create_table_from_items(THD *thd, List<Item> *items,
{
if (likely(!thd->is_error())) // CREATE ... IF NOT EXISTS
my_ok(thd); // succeed, but did nothing
ddl_log_complete(&ddl_log_state_rm);
ddl_log_complete(&ddl_log_state_create);
DBUG_RETURN(NULL);
}
......@@ -4570,7 +4574,9 @@ TABLE *select_create::create_table_from_items(THD *thd, List<Item> *items,
*lock= 0;
}
drop_open_table(thd, table, &create_table->db, &create_table->table_name);
DBUG_RETURN(0);
ddl_log_complete(&ddl_log_state_rm);
ddl_log_complete(&ddl_log_state_create);
DBUG_RETURN(NULL);
/* purecov: end */
}
table->s->table_creation_was_logged= save_table_creation_was_logged;
......@@ -4912,11 +4918,30 @@ bool select_create::send_eof()
if (thd->slave_thread)
thd->variables.binlog_annotate_row_events= 0;
debug_crash_here("ddl_log_create_before_binlog");
/*
In case of crash, we have to add DROP TABLE to the binary log as
the CREATE TABLE will already be logged if we are not using row based
replication.
*/
if (!thd->is_current_stmt_binlog_format_row())
{
if (ddl_log_state_create.is_active()) // Not temporary table
ddl_log_update_phase(&ddl_log_state_create, DDL_CREATE_TABLE_PHASE_LOG);
/*
We can ignore if we replaced an old table as ddl_log_state_create will
now handle the logging of the drop if needed.
*/
ddl_log_complete(&ddl_log_state_rm);
}
if (prepare_eof())
{
abort_result_set();
DBUG_RETURN(true);
}
debug_crash_here("ddl_log_create_after_prepare_eof");
if (table->s->tmp_table)
{
......@@ -4983,9 +5008,15 @@ bool select_create::send_eof()
thd->get_stmt_da()->set_overwrite_status(true);
}
#endif /* WITH_WSREP */
thd->binlog_xid= thd->query_id;
/* Remember xid's for the case of row based logging */
ddl_log_update_xid(&ddl_log_state_create, thd->binlog_xid);
ddl_log_update_xid(&ddl_log_state_rm, thd->binlog_xid);
trans_commit_stmt(thd);
if (!(thd->variables.option_bits & OPTION_GTID_BEGIN))
trans_commit_implicit(thd);
thd->binlog_xid= 0;
#ifdef WITH_WSREP
if (WSREP(thd))
{
......@@ -5004,6 +5035,15 @@ bool select_create::send_eof()
}
#endif /* WITH_WSREP */
}
/*
If are using statement based replication the table will be deleted here
in case of a crash as we can't use xid to check if the query was logged
(as the query was logged before commit!)
*/
debug_crash_here("ddl_log_create_after_binlog");
ddl_log_complete(&ddl_log_state_rm);
ddl_log_complete(&ddl_log_state_create);
debug_crash_here("ddl_log_create_log_complete");
/*
exit_done must only be set after last potential call to
......@@ -5120,9 +5160,19 @@ void select_create::abort_result_set()
binlog_reset_cache(thd);
/* Original table was deleted. We have to log it */
if (table_creation_was_logged)
{
thd->binlog_xid= thd->query_id;
ddl_log_update_xid(&ddl_log_state_create, thd->binlog_xid);
ddl_log_update_xid(&ddl_log_state_rm, thd->binlog_xid);
debug_crash_here("ddl_log_create_before_binlog");
log_drop_table(thd, &create_table->db, &create_table->table_name,
tmp_table);
debug_crash_here("ddl_log_create_after_binlog");
thd->binlog_xid= 0;
}
}
}
ddl_log_complete(&ddl_log_state_rm);
ddl_log_complete(&ddl_log_state_create);
DBUG_VOID_RETURN;
}
This diff is collapsed.
......@@ -125,7 +125,10 @@ bool add_keyword_to_query(THD *thd, String *result, const LEX_CSTRING *keyword,
#define C_ALTER_TABLE_FRM_ONLY -2
#define C_ASSISTED_DISCOVERY -3
int mysql_create_table_no_lock(THD *thd, const LEX_CSTRING *db,
int mysql_create_table_no_lock(THD *thd,
DDL_LOG_STATE *ddl_log_state,
DDL_LOG_STATE *ddl_log_state_rm,
const LEX_CSTRING *db,
const LEX_CSTRING *table_name,
Table_specification_st *create_info,
Alter_info *alter_info, bool *is_trans,
......
......@@ -45,6 +45,7 @@ C_MODE_END
#include "key.h"
#include "log.h"
#include "sql_parse.h"
#include "debug_sync.h"
/*
Note that in future versions, only *transactional* Maria tables can
......@@ -996,6 +997,13 @@ my_bool ma_killed_in_mariadb(MARIA_HA *info)
return (((TABLE*) (info->external_ref))->in_use->killed != 0);
}
void maria_debug_crash_here(const char *keyword)
{
#ifndef DBUG_OFF
debug_crash_here(keyword);
#endif /* DBUG_OFF */
}
} /* extern "C" */
/**
......@@ -3794,6 +3802,7 @@ static int ha_maria_init(void *p)
HTON_TRANSACTIONAL_AND_NON_TRANSACTIONAL);
bzero(maria_log_pagecache, sizeof(*maria_log_pagecache));
maria_tmpdir= &mysql_tmpdir_list; /* For REDO */
ma_debug_crash_here= maria_debug_crash_here;
if (!aria_readonly)
res= maria_upgrade();
......
......@@ -1215,6 +1215,7 @@ int maria_create(const char *name, enum data_file_type datafile_type,
MY_UNPACK_FILENAME | MY_APPEND_EXT);
create_flag= (flags & HA_CREATE_KEEP_FILES) ? 0 : MY_DELETE_OLD;
}
ma_debug_crash_here("storage_engine_middle_of_create");
if ((dfile=
mysql_file_create_with_symlink(key_file_dfile, dlinkname_ptr,
dfilename, 0, create_mode,
......
......@@ -66,6 +66,9 @@ const char *maria_data_root;
HASH maria_stored_state;
int (*maria_create_trn_hook)(MARIA_HA *);
void dummy_crash(const char *keyword __attribute__((unused))) {}
void (*ma_debug_crash_here)(const char *keyword)= dummy_crash;
/**
@brief when transactionality does not matter we can use this transaction
......
......@@ -1247,6 +1247,7 @@ extern ulong maria_checkpoint_min_log_activity;
extern HASH maria_stored_state;
extern int (*maria_create_trn_hook)(MARIA_HA *);
extern my_bool (*ma_killed)(MARIA_HA *);
extern void (*ma_debug_crash_here)(const char *keyword);
#ifdef HAVE_PSI_INTERFACE
extern PSI_mutex_key key_SHARE_BITMAP_lock, key_SORT_INFO_mutex,
......
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