Commit e3cfb7c8 authored by Monty's avatar Monty Committed by Sergei Golubchik

MDEV-23844 Atomic DROP TABLE (single table)

Logging logic:
- Log tables, just before they are dropped, to the ddl log
- After the last table for the statement is dropped, log an xid for the
  whole ddl log event

In case of crash:
- Remove first any active DROP TABLE events from the ddl log that matches
  xids found in binary log (this mean the drop was successful and was
  propery logged).
- Loop over all active DROP TABLE events
  - Ensure that the table is completely dropped
- Write a DROP TABLE entry to the binary log with the dropped tables.

Other things:
- Added code to ha_drop_table() to be able to tell the difference if
  a get_new_handler() failed because of out-of-memory or because the
  handler refused/was not able to create a a handler. This was needed
  to get sequences to work as sequences needs a share object to be passed
  to get_new_handler()
- TC_LOG_BINLOG::recover() was changed to always collect Xid's from the
  binary log and always call ddl_log_close_binlogged_events(). This was
  needed to be able to collect DROP TABLE events with embedded Xid's
  (used by ddl log).
- Added a new variable "$grep_script" to binlog filter to be able to find
  only rows that matches a regexp.
- Had to adjust some test that changed because drop statements are a bit
  larger in the binary log than before (as we have to store the xid)

Other things:
- MDEV-25588 Atomic DDL: Binlog query event written upon recovery is corrupt
  fixed (in the original commit).
parent 47010ccf
...@@ -56,6 +56,9 @@ ...@@ -56,6 +56,9 @@
# #
# $filter_script # $filter_script
# If set, rows matching this regexp will be filtered out # If set, rows matching this regexp will be filtered out
#
# $grep_script
# If set, only include rows matching this regexp
--let $include_filename= filter_file.inc --let $include_filename= filter_file.inc
--source include/begin_include_file.inc --source include/begin_include_file.inc
...@@ -71,6 +74,7 @@ if ($rpl_debug) ...@@ -71,6 +74,7 @@ if ($rpl_debug)
--let _FF_PRE_SCRIPT= $pre_script --let _FF_PRE_SCRIPT= $pre_script
--let _FF_SCRIPT= $script --let _FF_SCRIPT= $script
--let _FF_FILTER_SCRIPT= $filter_script --let _FF_FILTER_SCRIPT= $filter_script
--let _FF_GREP_SCRIPT= $grep_script
--let _FF_INPUT_FILE= $input_file --let _FF_INPUT_FILE= $input_file
--let _FF_OUTPUT_FILE= $output_file --let _FF_OUTPUT_FILE= $output_file
--let _FF_SELECT_COLUMNS= $select_columns --let _FF_SELECT_COLUMNS= $select_columns
...@@ -85,6 +89,7 @@ perl; ...@@ -85,6 +89,7 @@ perl;
$pre_script =~ s/DOLLAR/\$/g; $pre_script =~ s/DOLLAR/\$/g;
my $script = $ENV{'_FF_SCRIPT'}; my $script = $ENV{'_FF_SCRIPT'};
my $filter_script = $ENV{'_FF_FILTER_SCRIPT'}; my $filter_script = $ENV{'_FF_FILTER_SCRIPT'};
my $grep_script = $ENV{'_FF_GREP_SCRIPT'};
$script =~ s/DOLLAR/\$/g; $script =~ s/DOLLAR/\$/g;
my $input_file = $ENV{'_FF_INPUT_FILE'}; my $input_file = $ENV{'_FF_INPUT_FILE'};
my $output_file = $ENV{'_FF_OUTPUT_FILE'}; my $output_file = $ENV{'_FF_OUTPUT_FILE'};
...@@ -129,7 +134,8 @@ perl; ...@@ -129,7 +134,8 @@ perl;
{ {
' . $script . ' ' . $script . '
} }
if (!$filter_script || ! m/$filter_script/) if ((!$filter_script || ! m/$filter_script/) &&
(!$grep_script || m/$grep_script/))
{ {
$filtered_contents .= $_."\n"; $filtered_contents .= $_."\n";
} }
......
call mtr.add_suppression("InnoDB: .* does not exist in the InnoDB internal");
"engine: aria crash point: ddl_log_drop_before_delete_table position: 1"
t2.MAD
t2.MAI
t2.TRG
t2.frm
t2_trg.TRN
ts.MAD
ts.MAI
ts.frm
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_before_delete_table position: 2"
ts.MAD
ts.MAI
ts.frm
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_before_delete_table position: 3"
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2`,`test`.`ts` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_after_delete_table position: 1"
t2.MAD
t2.MAI
t2.TRG
t2.frm
t2_trg.TRN
ts.MAD
ts.MAI
ts.frm
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_after_delete_table position: 2"
ts.MAD
ts.MAI
ts.frm
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_after_delete_table position: 3"
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2`,`test`.`ts` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_before_drop_trigger position: 1"
t2.MAD
t2.MAI
t2.TRG
t2.frm
t2_trg.TRN
ts.MAD
ts.MAI
ts.frm
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_before_drop_trigger position: 2"
ts.MAD
ts.MAI
ts.frm
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_before_drop_trigger position: 3"
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2`,`test`.`ts` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_before_drop_trigger2 position: 1"
t2.MAD
t2.MAI
t2.TRG
t2.frm
t2_trg.TRN
ts.MAD
ts.MAI
ts.frm
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_before_drop_trigger2 position: 2"
ts.MAD
ts.MAI
ts.frm
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_before_drop_trigger2 position: 3"
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2`,`test`.`ts` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_after_drop_trigger position: 1"
t2.MAD
t2.MAI
t2.TRG
t2.frm
t2_trg.TRN
ts.MAD
ts.MAI
ts.frm
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_after_drop_trigger position: 2"
ts.MAD
ts.MAI
ts.frm
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_after_drop_trigger position: 3"
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2`,`test`.`ts` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_before_binlog position: 1"
master-bin.000002 # Query # # DROP TABLE IF EXISTS `test`.`t1`,`test`.`t2`,`test`.`ts` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_before_binlog position: 2"
"No crash!"
master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2`,`ts` /* generated by server */
"engine: aria crash point: ddl_log_drop_before_binlog position: 3"
"No crash!"
master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2`,`ts` /* generated by server */
"engine: aria crash point: ddl_log_drop_after_binlog position: 1"
master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2`,`ts` /* generated by server */
"engine: aria crash point: ddl_log_drop_after_binlog position: 2"
"No crash!"
master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2`,`ts` /* generated by server */
"engine: aria crash point: ddl_log_drop_after_binlog position: 3"
"No crash!"
master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2`,`ts` /* generated by server */
Warnings:
Note 1051 Unknown table 'test.t1,test.t2,test.ts'
--source include/have_debug.inc
--source include/have_log_bin.inc
--source include/not_valgrind.inc
#
# Testing of atomic drop with crashes in a lot of different places
#
call mtr.add_suppression("InnoDB: .* does not exist in the InnoDB internal");
let $MYSQLD_DATADIR= `SELECT @@datadir`;
let $engine_count=1;
let $engines='aria';
let $crash_count=7;
let $crash_points='ddl_log_drop_before_delete_table', 'ddl_log_drop_after_delete_table', 'ddl_log_drop_before_drop_trigger', 'ddl_log_drop_before_drop_trigger2', 'ddl_log_drop_after_drop_trigger', 'ddl_log_drop_before_binlog', 'ddl_log_drop_after_binlog';
# Number of drops in the tested statement
let $drops=3;
let $old_debug=`select @@debug_dbug`;
let $e=0;
let $keep_include_silent=1;
let $grep_script=DROP TABLE;
--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;
}
let $c=0;
while ($c < $crash_count)
{
inc $c;
let $crash=`select ELT($c, $crash_points)`;
let $r=0;
while ($r < $drops)
{
inc $r;
--eval set @@default_storage_engine=$default_engine
--eval create table t1 (a int not null) $extra_option;
--eval create table t2 (b int not null) $extra_option;
create sequence ts;
insert into t1 values(1);
insert into t2 values(2);
flush tables;
delimiter |;
create trigger t1_trg before insert on t1 for each row
begin
if isnull(new.a) then
set new.a:= 1000;
end if;
end|
create trigger t2_trg before insert on t2 for each row
begin
if isnull(new.b) then
set new.b:= 2000;
end if;
end|
delimiter ;|
RESET MASTER;
echo "engine: $engine crash point: $crash position: $r";
--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--disable_reconnect
--eval set @@debug_dbug="+d,$crash",@debug_crash_counter=$r
let $errno=0;
--error 0,2013
drop table t1,t2,ts;
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*
--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
}
# Really drop the tables. The warnings will show what was dropped
--disable_warnings
drop table if exists t1,t2,ts;
--enable_warnings
}
}
}
drop table if exists t1,t2,ts;
--enable_query_log
This diff is collapsed.
--source include/have_debug.inc
--source include/have_innodb.inc
--source include/have_csv.inc
--source include/have_log_bin.inc
--source include/not_valgrind.inc
#
# Testing of atomic drop with crashes in a lot of different places
#
call mtr.add_suppression("InnoDB: .* does not exist in the InnoDB internal");
let $MYSQLD_DATADIR= `SELECT @@datadir`;
let $engine_count=5;
let $engines='myisam','aria','aria_notrans','innodb','csv';
let $crash_count=7;
let $crash_points='ddl_log_drop_before_delete_table', 'ddl_log_drop_after_delete_table', 'ddl_log_drop_before_drop_trigger', 'ddl_log_drop_before_drop_trigger2', 'ddl_log_drop_after_drop_trigger', 'ddl_log_drop_before_binlog', 'ddl_log_drop_after_binlog';
# Number of drops in the tested statement
let $drops=2;
let $old_debug=`select @@debug_dbug`;
let $e=0;
let $keep_include_silent=1;
let $grep_script=DROP TABLE;
--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;
}
let $c=0;
while ($c < $crash_count)
{
inc $c;
let $crash=`select ELT($c, $crash_points)`;
let $r=0;
while ($r < $drops)
{
inc $r;
--eval set @@default_storage_engine=$default_engine
--eval create table t1 (a int not null) $extra_option;
--eval create table t2 (b int not null) $extra_option;
insert into t1 values(1);
insert into t2 values(2);
flush tables;
delimiter |;
create trigger t1_trg before insert on t1 for each row
begin
if isnull(new.a) then
set new.a:= 1000;
end if;
end|
create trigger t2_trg before insert on t2 for each row
begin
if isnull(new.b) then
set new.b:= 2000;
end if;
end|
delimiter ;|
RESET MASTER;
echo "engine: $engine crash point: $crash position: $r";
--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--disable_reconnect
--eval set @@debug_dbug="+d,$crash",@debug_crash_counter=$r
let $errno=0;
--error 0,2013
drop table t1,t2;
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*
--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
}
# Really 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;
--enable_query_log
"engine: aria crash point: ddl_log_drop_before_delete_view position: 1"
v2.frm
master-bin.000002 # Query # # DROP VIEW IF EXISTS `test`.`v1` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_before_delete_view position: 2"
master-bin.000002 # Query # # DROP VIEW IF EXISTS `test`.`v1`,`test`.`v2` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_after_delete_view position: 1"
v2.frm
master-bin.000002 # Query # # DROP VIEW IF EXISTS `test`.`v1` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_after_delete_view position: 2"
master-bin.000002 # Query # # DROP VIEW IF EXISTS `test`.`v1`,`test`.`v2` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_before_binlog position: 1"
master-bin.000002 # Query # # DROP VIEW IF EXISTS `test`.`v1`,`test`.`v2` /* generated by ddl recovery */
"engine: aria crash point: ddl_log_drop_before_binlog position: 2"
"No crash!"
master-bin.000001 # Query # # use `test`; DROP VIEW v1,v2
"engine: aria crash point: ddl_log_drop_after_binlog position: 1"
master-bin.000001 # Query # # use `test`; DROP VIEW v1,v2
"engine: aria crash point: ddl_log_drop_after_binlog position: 2"
"No crash!"
master-bin.000001 # Query # # use `test`; DROP VIEW v1,v2
--source include/have_debug.inc
--source include/have_log_bin.inc
--source include/not_valgrind.inc
#
# Testing of atomic drop of view with crashes in a lot of different places
#
let $MYSQLD_DATADIR= `SELECT @@datadir`;
let $engine_count=1;
let $engines='aria';
let $crash_count=4;
let $crash_points='ddl_log_drop_before_delete_view', 'ddl_log_drop_after_delete_view', 'ddl_log_drop_before_binlog', 'ddl_log_drop_after_binlog';
# Number of drops in the tested statement
let $drops=2;
let $old_debug=`select @@debug_dbug`;
let $e=0;
let $keep_include_silent=1;
let $grep_script=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;
}
--eval set @@default_storage_engine=$default_engine
--eval create table t1 (a int not null) $extra_option;
--eval create table t2 (b int not null) $extra_option;
insert into t1 values(1);
insert into t2 values(2);
flush tables;
let $c=0;
while ($c < $crash_count)
{
inc $c;
let $crash=`select ELT($c, $crash_points)`;
let $r=0;
while ($r < $drops)
{
inc $r;
create view v1 as select * from t1;
create view v2 as select * from t1;
RESET MASTER;
echo "engine: $engine crash point: $crash position: $r";
--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--disable_reconnect
--eval set @@debug_dbug="+d,$crash",@debug_crash_counter=$r
let $errno=0;
--error 0,2013
DROP VIEW v1,v2;
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 v*
--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
}
# Really drop the views
--disable_warnings
drop view if exists v1,v2;
--enable_warnings
}
}
drop table t1,t2;
}
--enable_query_log
...@@ -506,6 +506,7 @@ master-bin.000001 # Query # # COMMIT ...@@ -506,6 +506,7 @@ master-bin.000001 # Query # # COMMIT
master-bin.000001 # Gtid # # BEGIN GTID #-#-# master-bin.000001 # Gtid # # BEGIN GTID #-#-#
master-bin.000001 # Query # # use `mysql`; DELETE FROM db WHERE host='localhost' AND user='@#@' master-bin.000001 # Query # # use `mysql`; DELETE FROM db WHERE host='localhost' AND user='@#@'
master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # COMMIT
master-bin.000001 # Rotate # # master-bin.000002;pos=POS
drop table t1,t2,t3,tt1; drop table t1,t2,t3,tt1;
reset master; reset master;
create table t1 (a int not null auto_increment, primary key (a)) engine=myisam; create table t1 (a int not null auto_increment, primary key (a)) engine=myisam;
......
...@@ -39,9 +39,9 @@ stop slave 'master1'; ...@@ -39,9 +39,9 @@ stop slave 'master1';
--let $datadir = `SELECT @@datadir` --let $datadir = `SELECT @@datadir`
let read_master_log_pos=`select $binlog_start_pos + 590`; let read_master_log_pos=`select $binlog_start_pos + 599`;
let relay_log_pos=`select 2*$binlog_start_pos + 634`; let relay_log_pos=`select 2*$binlog_start_pos + 643`;
let relay_log_space=`select 3*$binlog_start_pos + 696`; let relay_log_space=`select 3*$binlog_start_pos + 705`;
--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> --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; show slave 'master1' status;
--list_files $datadir mysqld* --list_files $datadir mysqld*
......
This diff is collapsed.
...@@ -46,8 +46,8 @@ enum ddl_log_entry_code ...@@ -46,8 +46,8 @@ enum ddl_log_entry_code
/* /*
When adding things below, also add an entry to ddl_log_entry_phases in When adding things below, also add an entry to ddl_log_action_names and
ddl_log.cc ddl_log_entry_phases in ddl_log.cc
*/ */
enum ddl_log_action_code enum ddl_log_action_code
...@@ -77,7 +77,11 @@ enum ddl_log_action_code ...@@ -77,7 +77,11 @@ enum ddl_log_action_code
*/ */
DDL_LOG_RENAME_TABLE_ACTION= 5, DDL_LOG_RENAME_TABLE_ACTION= 5,
DDL_LOG_RENAME_VIEW_ACTION= 6, DDL_LOG_RENAME_VIEW_ACTION= 6,
DDL_LOG_LAST_ACTION /* End marker */ DDL_LOG_DROP_TABLE_INIT_ACTION= 7,
DDL_LOG_DROP_TABLE_ACTION= 8,
DDL_LOG_DROP_VIEW_INIT_ACTION= 9,
DDL_LOG_DROP_VIEW_ACTION= 10,
DDL_LOG_LAST_ACTION /* End marker */
}; };
...@@ -97,6 +101,14 @@ enum enum_ddl_log_rename_table_phase { ...@@ -97,6 +101,14 @@ enum enum_ddl_log_rename_table_phase {
DDL_RENAME_PHASE_TABLE, DDL_RENAME_PHASE_TABLE,
}; };
enum enum_ddl_log_drop_table_phase {
DDL_DROP_PHASE_TABLE=0,
DDL_DROP_PHASE_TRIGGER,
DDL_DROP_PHASE_BINLOG,
DDL_DROP_PHASE_RESET, /* Reset found list of dropped tables */
DDL_DROP_PHASE_END
};
/* /*
Setting ddl_log_entry.phase to this has the same effect as setting Setting ddl_log_entry.phase to this has the same effect as setting
the phase to the maximum phase (..PHASE_END) for an entry. the phase to the maximum phase (..PHASE_END) for an entry.
...@@ -204,6 +216,17 @@ bool ddl_log_rename_view(THD *thd, DDL_LOG_STATE *ddl_state, ...@@ -204,6 +216,17 @@ bool ddl_log_rename_view(THD *thd, DDL_LOG_STATE *ddl_state,
const LEX_CSTRING *org_alias, const LEX_CSTRING *org_alias,
const LEX_CSTRING *new_db, const LEX_CSTRING *new_db,
const LEX_CSTRING *new_alias); const LEX_CSTRING *new_alias);
bool ddl_log_drop_table_init(THD *thd, DDL_LOG_STATE *ddl_state,
const LEX_CSTRING *comment);
bool ddl_log_drop_view_init(THD *thd, DDL_LOG_STATE *ddl_state);
bool ddl_log_drop_table(THD *thd, DDL_LOG_STATE *ddl_state,
handlerton *hton,
const LEX_CSTRING *path,
const LEX_CSTRING *db,
const LEX_CSTRING *table);
bool ddl_log_drop_view(THD *thd, DDL_LOG_STATE *ddl_state,
const LEX_CSTRING *path,
const LEX_CSTRING *db,
const LEX_CSTRING *table);
extern mysql_mutex_t LOCK_gdl; extern mysql_mutex_t LOCK_gdl;
#endif /* DDL_LOG_INCLUDED */ #endif /* DDL_LOG_INCLUDED */
...@@ -566,7 +566,13 @@ static int hton_drop_table(handlerton *hton, const char *path) ...@@ -566,7 +566,13 @@ static int hton_drop_table(handlerton *hton, const char *path)
char tmp_path[FN_REFLEN]; char tmp_path[FN_REFLEN];
handler *file= get_new_handler(nullptr, current_thd->mem_root, hton); handler *file= get_new_handler(nullptr, current_thd->mem_root, hton);
if (!file) if (!file)
return ENOMEM; {
/*
If file is not defined it means that the engine can't create a
handler if share is not set or we got an out of memory error
*/
return my_errno == ENOMEM ? ENOMEM : ENOENT;
}
path= get_canonical_filename(file, path, tmp_path); path= get_canonical_filename(file, path, tmp_path);
int error= file->delete_table(path); int error= file->delete_table(path);
delete file; delete file;
......
...@@ -9982,6 +9982,7 @@ int TC_LOG::using_heuristic_recover() ...@@ -9982,6 +9982,7 @@ int TC_LOG::using_heuristic_recover()
int TC_LOG_BINLOG::open(const char *opt_name) int TC_LOG_BINLOG::open(const char *opt_name)
{ {
int error= 1; int error= 1;
DBUG_ENTER("TC_LOG_BINLOG::open");
DBUG_ASSERT(total_ha_2pc > 1); DBUG_ASSERT(total_ha_2pc > 1);
DBUG_ASSERT(opt_name); DBUG_ASSERT(opt_name);
...@@ -9991,7 +9992,7 @@ int TC_LOG_BINLOG::open(const char *opt_name) ...@@ -9991,7 +9992,7 @@ int TC_LOG_BINLOG::open(const char *opt_name)
{ {
/* There was a failure to open the index file, can't open the binlog */ /* There was a failure to open the index file, can't open the binlog */
cleanup(); cleanup();
return 1; DBUG_RETURN(1);
} }
if (using_heuristic_recover()) if (using_heuristic_recover())
...@@ -10001,12 +10002,12 @@ int TC_LOG_BINLOG::open(const char *opt_name) ...@@ -10001,12 +10002,12 @@ int TC_LOG_BINLOG::open(const char *opt_name)
open(opt_name, 0, 0, WRITE_CACHE, max_binlog_size, 0, TRUE); open(opt_name, 0, 0, WRITE_CACHE, max_binlog_size, 0, TRUE);
mysql_mutex_unlock(&LOCK_log); mysql_mutex_unlock(&LOCK_log);
cleanup(); cleanup();
return 1; DBUG_RETURN(1);
} }
error= do_binlog_recovery(opt_name, true); error= do_binlog_recovery(opt_name, true);
binlog_state_recover_done= true; binlog_state_recover_done= true;
return error; DBUG_RETURN(error);
} }
/** This is called on shutdown, after ha_panic. */ /** This is called on shutdown, after ha_panic. */
...@@ -10536,6 +10537,7 @@ int TC_LOG_BINLOG::recover(LOG_INFO *linfo, const char *last_log_name, ...@@ -10536,6 +10537,7 @@ int TC_LOG_BINLOG::recover(LOG_INFO *linfo, const char *last_log_name,
Query_log_event *query_ev= (Query_log_event*) ev; Query_log_event *query_ev= (Query_log_event*) ev;
if (query_ev->xid) if (query_ev->xid)
{ {
DBUG_PRINT("QQ", ("xid: %llu xid"));
DBUG_ASSERT(sizeof(query_ev->xid) == sizeof(my_xid)); DBUG_ASSERT(sizeof(query_ev->xid) == sizeof(my_xid));
uchar *x= (uchar *) memdup_root(&mem_root, uchar *x= (uchar *) memdup_root(&mem_root,
(uchar*) &query_ev->xid, (uchar*) &query_ev->xid,
......
...@@ -56,6 +56,7 @@ ...@@ -56,6 +56,7 @@
#include "tztime.h" #include "tztime.h"
#include "sql_insert.h" // binlog_drop_table #include "sql_insert.h" // binlog_drop_table
#include "ddl_log.h" #include "ddl_log.h"
#include "debug_sync.h" // debug_crash_here()
#include <algorithm> #include <algorithm>
#ifdef __WIN__ #ifdef __WIN__
...@@ -1139,9 +1140,11 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1139,9 +1140,11 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
char path[FN_REFLEN + 1]; char path[FN_REFLEN + 1];
LEX_CSTRING alias= null_clex_str; LEX_CSTRING alias= null_clex_str;
StringBuffer<160> unknown_tables(system_charset_info); StringBuffer<160> unknown_tables(system_charset_info);
uint not_found_errors= 0; DDL_LOG_STATE ddl_log_state;
const char *comment_start;
uint not_found_errors= 0, table_count= 0, non_temp_tables_count= 0;
int error= 0; int error= 0;
int non_temp_tables_count= 0; uint32 comment_len;
bool trans_tmp_table_deleted= 0, non_trans_tmp_table_deleted= 0; bool trans_tmp_table_deleted= 0, non_trans_tmp_table_deleted= 0;
bool non_tmp_table_deleted= 0; bool non_tmp_table_deleted= 0;
bool is_drop_tmp_if_exists_added= 0; bool is_drop_tmp_if_exists_added= 0;
...@@ -1154,6 +1157,8 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1154,6 +1157,8 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
DBUG_ENTER("mysql_rm_table_no_locks"); DBUG_ENTER("mysql_rm_table_no_locks");
unknown_tables.length(0); unknown_tables.length(0);
comment_len= get_comment(thd, if_exists ? 17:9, &comment_start);
/* /*
Prepares the drop statements that will be written into the binary Prepares the drop statements that will be written into the binary
log as follows: log as follows:
...@@ -1204,6 +1209,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1204,6 +1209,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
built_non_trans_tmp_query.set_charset(system_charset_info); built_non_trans_tmp_query.set_charset(system_charset_info);
built_non_trans_tmp_query.copy(built_trans_tmp_query); built_non_trans_tmp_query.copy(built_trans_tmp_query);
} }
bzero(&ddl_log_state, sizeof(ddl_log_state));
for (table= tables; table; table= table->next_local) for (table= tables; table; table= table->next_local)
{ {
...@@ -1213,6 +1219,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1213,6 +1219,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
bool table_dropped= 0; bool table_dropped= 0;
const LEX_CSTRING db= table->db; const LEX_CSTRING db= table->db;
const LEX_CSTRING table_name= table->table_name; const LEX_CSTRING table_name= table->table_name;
LEX_CSTRING cpath= {0,0};
handlerton *hton= 0; handlerton *hton= 0;
Table_type table_type; Table_type table_type;
size_t path_length= 0; size_t path_length= 0;
...@@ -1347,6 +1354,8 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1347,6 +1354,8 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
continue; continue;
} }
lex_string_set3(&cpath, path, (size_t) (path_end - path));
{ {
char engine_buf[NAME_CHAR_LEN + 1]; char engine_buf[NAME_CHAR_LEN + 1];
LEX_CSTRING engine= { engine_buf, 0 }; LEX_CSTRING engine= { engine_buf, 0 };
...@@ -1363,6 +1372,17 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1363,6 +1372,17 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
thd->replication_flags= 0; thd->replication_flags= 0;
was_view= table_type == TABLE_TYPE_VIEW; was_view= table_type == TABLE_TYPE_VIEW;
if (!table_count++)
{
LEX_CSTRING comment= {comment_start, (size_t) comment_len};
if (ddl_log_drop_table_init(thd, &ddl_log_state, &comment))
{
error= 1;
goto err;
}
}
if ((table_type == TABLE_TYPE_UNKNOWN) || (was_view && !drop_view) || if ((table_type == TABLE_TYPE_UNKNOWN) || (was_view && !drop_view) ||
(table_type != TABLE_TYPE_SEQUENCE && drop_sequence)) (table_type != TABLE_TYPE_SEQUENCE && drop_sequence))
{ {
...@@ -1376,6 +1396,8 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1376,6 +1396,8 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
was_table|= wrong_drop_sequence; was_table|= wrong_drop_sequence;
error= table_type == TABLE_TYPE_UNKNOWN ? ENOENT : -1; error= table_type == TABLE_TYPE_UNKNOWN ? ENOENT : -1;
tdc_remove_table(thd, db.str, table_name.str); tdc_remove_table(thd, db.str, table_name.str);
if (wrong_drop_sequence)
goto report_error;
} }
else else
{ {
...@@ -1411,7 +1433,17 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1411,7 +1433,17 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
log_if_exists= 1; log_if_exists= 1;
bool enoent_warning= !dont_log_query && !(hton && hton->discover_table); bool enoent_warning= !dont_log_query && !(hton && hton->discover_table);
error= ha_delete_table(thd, hton, path, &db, &table_name, enoent_warning);
if (ddl_log_drop_table(thd, &ddl_log_state, hton, &cpath, &db,
&table_name))
{
error= -1;
goto err;
}
debug_crash_here("ddl_log_drop_before_delete_table");
error= ha_delete_table(thd, hton, path, &db, &table_name,
enoent_warning);
debug_crash_here("ddl_log_drop_after_delete_table");
if (!error) if (!error)
table_dropped= 1; table_dropped= 1;
...@@ -1473,11 +1505,18 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1473,11 +1505,18 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
scan all engines try to drop the table from there. scan all engines try to drop the table from there.
This is to ensure we don't have any partial table files left. This is to ensure we don't have any partial table files left.
*/ */
if (non_existing_table_error(error) && !wrong_drop_sequence) if (non_existing_table_error(error))
{ {
int ferror= 0; int ferror= 0;
DBUG_ASSERT(!was_view); DBUG_ASSERT(!was_view);
if (ddl_log_drop_table(thd, &ddl_log_state, hton, &cpath, &db,
&table_name))
{
error= -1;
goto err;
}
/* Remove extension for delete */ /* Remove extension for delete */
*path_end= '\0'; *path_end= '\0';
ferror= ha_delete_table_force(thd, path, &db, &table_name); ferror= ha_delete_table_force(thd, path, &db, &table_name);
...@@ -1509,13 +1548,19 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1509,13 +1548,19 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
if (thd->replication_flags & OPTION_IF_EXISTS) if (thd->replication_flags & OPTION_IF_EXISTS)
log_if_exists= 1; log_if_exists= 1;
debug_crash_here("ddl_log_drop_before_drop_trigger");
ddl_log_update_phase(&ddl_log_state, DDL_DROP_PHASE_TRIGGER);
debug_crash_here("ddl_log_drop_before_drop_trigger2");
if (likely(!error) || non_existing_table_error(error)) if (likely(!error) || non_existing_table_error(error))
{ {
if (Table_triggers_list::drop_all_triggers(thd, &db, &table_name, if (Table_triggers_list::drop_all_triggers(thd, &db, &table_name,
MYF(MY_WME | MY_IGNORE_ENOENT))) MYF(MY_WME | MY_IGNORE_ENOENT)))
error= error ? error : -1; error= error ? error : -1;
} }
debug_crash_here("ddl_log_drop_after_drop_trigger");
report_error:
if (error) if (error)
{ {
StringBuffer<FN_REFLEN> tbl_name(system_charset_info); StringBuffer<FN_REFLEN> tbl_name(system_charset_info);
...@@ -1565,6 +1610,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1565,6 +1610,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
table_name.str, (uint)table_name.length); table_name.str, (uint)table_name.length);
mysql_audit_drop_table(thd, table); mysql_audit_drop_table(thd, table);
} }
ddl_log_update_phase(&ddl_log_state, DDL_DROP_PHASE_BINLOG);
if (!dont_log_query && if (!dont_log_query &&
(!error || table_dropped || non_existing_table_error(error))) (!error || table_dropped || non_existing_table_error(error)))
...@@ -1621,6 +1667,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1621,6 +1667,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
query_cache_invalidate3(thd, tables, 0); query_cache_invalidate3(thd, tables, 0);
if (!dont_log_query && mysql_bin_log.is_open()) if (!dont_log_query && mysql_bin_log.is_open())
{ {
debug_crash_here("ddl_log_drop_before_binlog");
if (non_trans_tmp_table_deleted) if (non_trans_tmp_table_deleted)
{ {
/* Chop of the last comma */ /* Chop of the last comma */
...@@ -1648,8 +1695,6 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1648,8 +1695,6 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
if (non_tmp_table_deleted) if (non_tmp_table_deleted)
{ {
String built_query; String built_query;
const char *comment_start;
uint32 comment_len;
built_query.set_charset(thd->charset()); built_query.set_charset(thd->charset());
built_query.append(STRING_WITH_LEN("DROP ")); built_query.append(STRING_WITH_LEN("DROP "));
...@@ -1659,8 +1704,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1659,8 +1704,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
built_query.append(STRING_WITH_LEN("IF EXISTS ")); built_query.append(STRING_WITH_LEN("IF EXISTS "));
/* Preserve comment in original query */ /* Preserve comment in original query */
if ((comment_len= get_comment(thd, if_exists ? 17:9, if (comment_len)
&comment_start)))
{ {
built_query.append(comment_start, comment_len); built_query.append(comment_start, comment_len);
built_query.append(' '); built_query.append(' ');
...@@ -1670,13 +1714,18 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1670,13 +1714,18 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
normal_tables.chop(); normal_tables.chop();
built_query.append(normal_tables.ptr(), normal_tables.length()); built_query.append(normal_tables.ptr(), normal_tables.length());
built_query.append(generated_by_server); built_query.append(generated_by_server);
thd->binlog_xid= thd->query_id;
ddl_log_update_xid(&ddl_log_state, thd->binlog_xid);
error |= (thd->binlog_query(THD::STMT_QUERY_TYPE, error |= (thd->binlog_query(THD::STMT_QUERY_TYPE,
built_query.ptr(), built_query.ptr(),
built_query.length(), built_query.length(),
TRUE, FALSE, FALSE, 0) > 0); TRUE, FALSE, FALSE, 0) > 0);
thd->binlog_xid= 0;
} }
debug_crash_here("ddl_log_drop_after_binlog");
} }
} }
ddl_log_complete(&ddl_log_state);
if (!drop_temporary) if (!drop_temporary)
{ {
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include "sql_derived.h" #include "sql_derived.h"
#include "sql_cte.h" // check_dependencies_in_with_clauses() #include "sql_cte.h" // check_dependencies_in_with_clauses()
#include "opt_trace.h" #include "opt_trace.h"
#include "ddl_log.h"
#include "wsrep_mysqld.h" #include "wsrep_mysqld.h"
#include "debug_sync.h" // debug_crash_here #include "debug_sync.h" // debug_crash_here
...@@ -1817,9 +1818,12 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) ...@@ -1817,9 +1818,12 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
bool delete_error= FALSE, wrong_object_name= FALSE; bool delete_error= FALSE, wrong_object_name= FALSE;
bool some_views_deleted= FALSE; bool some_views_deleted= FALSE;
bool something_wrong= FALSE; bool something_wrong= FALSE;
uint not_exists_count= 0; uint not_exists_count= 0, view_count= 0;
DDL_LOG_STATE ddl_log_state;
DBUG_ENTER("mysql_drop_view"); DBUG_ENTER("mysql_drop_view");
bzero(&ddl_log_state, sizeof(ddl_log_state));
/* /*
We can't allow dropping of unlocked view under LOCK TABLES since this We can't allow dropping of unlocked view under LOCK TABLES since this
might lead to deadlock. But since we can't really lock view with LOCK might lead to deadlock. But since we can't really lock view with LOCK
...@@ -1838,9 +1842,12 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) ...@@ -1838,9 +1842,12 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
for (view= views; view; view= view->next_local) for (view= views; view; view= view->next_local)
{ {
LEX_CSTRING cpath;
bool not_exist; bool not_exist;
build_table_filename(path, sizeof(path) - 1, size_t length;
view->db.str, view->table_name.str, reg_ext, 0); length= build_table_filename(path, sizeof(path) - 1,
view->db.str, view->table_name.str, reg_ext, 0);
lex_string_set3(&cpath, path, length);
if ((not_exist= my_access(path, F_OK)) || !dd_frm_is_view(thd, path)) if ((not_exist= my_access(path, F_OK)) || !dd_frm_is_view(thd, path))
{ {
...@@ -1861,8 +1868,18 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) ...@@ -1861,8 +1868,18 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
not_exists_count++; not_exists_count++;
continue; continue;
} }
if (!view_count++)
{
if (ddl_log_drop_view_init(thd, &ddl_log_state))
DBUG_RETURN(TRUE);
}
if (ddl_log_drop_view(thd, &ddl_log_state, &cpath, &view->db,
&view->table_name))
DBUG_RETURN(TRUE);
debug_crash_here("ddl_log_drop_before_delete_view");
if (unlikely(mysql_file_delete(key_file_frm, path, MYF(MY_WME)))) if (unlikely(mysql_file_delete(key_file_frm, path, MYF(MY_WME))))
delete_error= TRUE; delete_error= TRUE;
debug_crash_here("ddl_log_drop_after_delete_view");
some_views_deleted= TRUE; some_views_deleted= TRUE;
...@@ -1890,10 +1907,16 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) ...@@ -1890,10 +1907,16 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
/* if something goes wrong, bin-log with possible error code, /* if something goes wrong, bin-log with possible error code,
otherwise bin-log with error code cleared. otherwise bin-log with error code cleared.
*/ */
debug_crash_here("ddl_log_drop_before_binlog");
thd->binlog_xid= thd->query_id;
ddl_log_update_xid(&ddl_log_state, thd->binlog_xid);
if (unlikely(write_bin_log(thd, !something_wrong, thd->query(), if (unlikely(write_bin_log(thd, !something_wrong, thd->query(),
thd->query_length()))) thd->query_length())))
something_wrong= 1; something_wrong= 1;
thd->binlog_xid= 0;
debug_crash_here("ddl_log_drop_after_binlog");
} }
ddl_log_complete(&ddl_log_state);
if (unlikely(something_wrong)) if (unlikely(something_wrong))
{ {
......
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