mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
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).
This commit is contained in:
@ -56,6 +56,7 @@
|
||||
#include "tztime.h"
|
||||
#include "sql_insert.h" // binlog_drop_table
|
||||
#include "ddl_log.h"
|
||||
#include "debug_sync.h" // debug_crash_here()
|
||||
#include <algorithm>
|
||||
|
||||
#ifdef __WIN__
|
||||
@ -1139,9 +1140,11 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
|
||||
char path[FN_REFLEN + 1];
|
||||
LEX_CSTRING alias= null_clex_str;
|
||||
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 non_temp_tables_count= 0;
|
||||
uint32 comment_len;
|
||||
bool trans_tmp_table_deleted= 0, non_trans_tmp_table_deleted= 0;
|
||||
bool non_tmp_table_deleted= 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,
|
||||
DBUG_ENTER("mysql_rm_table_no_locks");
|
||||
|
||||
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
|
||||
log as follows:
|
||||
@ -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.copy(built_trans_tmp_query);
|
||||
}
|
||||
bzero(&ddl_log_state, sizeof(ddl_log_state));
|
||||
|
||||
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,
|
||||
bool table_dropped= 0;
|
||||
const LEX_CSTRING db= table->db;
|
||||
const LEX_CSTRING table_name= table->table_name;
|
||||
LEX_CSTRING cpath= {0,0};
|
||||
handlerton *hton= 0;
|
||||
Table_type table_type;
|
||||
size_t path_length= 0;
|
||||
@ -1347,6 +1354,8 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
|
||||
continue;
|
||||
}
|
||||
|
||||
lex_string_set3(&cpath, path, (size_t) (path_end - path));
|
||||
|
||||
{
|
||||
char engine_buf[NAME_CHAR_LEN + 1];
|
||||
LEX_CSTRING engine= { engine_buf, 0 };
|
||||
@ -1363,6 +1372,17 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
|
||||
|
||||
thd->replication_flags= 0;
|
||||
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) ||
|
||||
(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,
|
||||
was_table|= wrong_drop_sequence;
|
||||
error= table_type == TABLE_TYPE_UNKNOWN ? ENOENT : -1;
|
||||
tdc_remove_table(thd, db.str, table_name.str);
|
||||
if (wrong_drop_sequence)
|
||||
goto report_error;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1411,7 +1433,17 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
|
||||
log_if_exists= 1;
|
||||
|
||||
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)
|
||||
table_dropped= 1;
|
||||
@ -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.
|
||||
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;
|
||||
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 */
|
||||
*path_end= '\0';
|
||||
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,
|
||||
if (thd->replication_flags & OPTION_IF_EXISTS)
|
||||
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 (Table_triggers_list::drop_all_triggers(thd, &db, &table_name,
|
||||
MYF(MY_WME | MY_IGNORE_ENOENT)))
|
||||
error= error ? error : -1;
|
||||
}
|
||||
debug_crash_here("ddl_log_drop_after_drop_trigger");
|
||||
|
||||
report_error:
|
||||
if (error)
|
||||
{
|
||||
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,
|
||||
table_name.str, (uint)table_name.length);
|
||||
mysql_audit_drop_table(thd, table);
|
||||
}
|
||||
ddl_log_update_phase(&ddl_log_state, DDL_DROP_PHASE_BINLOG);
|
||||
|
||||
if (!dont_log_query &&
|
||||
(!error || table_dropped || non_existing_table_error(error)))
|
||||
@ -1621,6 +1667,7 @@ err:
|
||||
query_cache_invalidate3(thd, tables, 0);
|
||||
if (!dont_log_query && mysql_bin_log.is_open())
|
||||
{
|
||||
debug_crash_here("ddl_log_drop_before_binlog");
|
||||
if (non_trans_tmp_table_deleted)
|
||||
{
|
||||
/* Chop of the last comma */
|
||||
@ -1648,8 +1695,6 @@ err:
|
||||
if (non_tmp_table_deleted)
|
||||
{
|
||||
String built_query;
|
||||
const char *comment_start;
|
||||
uint32 comment_len;
|
||||
|
||||
built_query.set_charset(thd->charset());
|
||||
built_query.append(STRING_WITH_LEN("DROP "));
|
||||
@ -1659,8 +1704,7 @@ err:
|
||||
built_query.append(STRING_WITH_LEN("IF EXISTS "));
|
||||
|
||||
/* Preserve comment in original query */
|
||||
if ((comment_len= get_comment(thd, if_exists ? 17:9,
|
||||
&comment_start)))
|
||||
if (comment_len)
|
||||
{
|
||||
built_query.append(comment_start, comment_len);
|
||||
built_query.append(' ');
|
||||
@ -1670,13 +1714,18 @@ err:
|
||||
normal_tables.chop();
|
||||
built_query.append(normal_tables.ptr(), normal_tables.length());
|
||||
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,
|
||||
built_query.ptr(),
|
||||
built_query.length(),
|
||||
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)
|
||||
{
|
||||
|
Reference in New Issue
Block a user