From 0c9ceb3ca68ade56a0275efd407accfbe6cecb51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20van=20Eeden?= Date: Sun, 30 Dec 2018 14:33:53 +0100 Subject: [PATCH] Add log_bin_implicit_delete setting On a setup with a master, two intermediate masters and a slave like this: ``` A / \ B C / D ``` If you have a table like this: CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=MEMORY; INSERT INTO t1 VALUES (1); And then you restart C and do a `SELECT * FROM t1`: * the MEMORY engine marks the table as implicitly emptied * the server writes a "DELETE FROM `test`.`t1`" to the binlog * If GTID is enabled this creates a GTID local to C If you now try to move D to C this happens: * If the DELETE is still in the binary log it will fetch it and execute it, this is OK. * If the DELETE has been purged from the binlog (e.g. after binlog_expire_logs_seconds) then replication will fail with ER_MASTER_HAS_PURGED_REQUIRED_GTIDS This commit does two things: 1. It adds a comment to the DELETE to make it easier to discover where it came from. 2. It adds a log_bin_implicit_delete to allow the administrator to configure the server not to write these DELETE's to the binlog. * https://dev.mysql.com/doc/refman/8.0/en/replication-features-memory.html * https://bugs.mysql.com/bug.php?id=77729 --- sql/mysqld.cc | 1 + sql/mysqld.h | 1 + sql/sql_base.cc | 3 ++- sql/sys_vars.cc | 7 +++++++ 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 35b318db52a..b3bdfdacd9c 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1085,6 +1085,7 @@ ulong binlog_stmt_cache_use = 0, binlog_stmt_cache_disk_use = 0; ulong max_connections, max_connect_errors; ulong rpl_stop_slave_timeout = LONG_TIMEOUT; bool log_bin_use_v1_row_events = 0; +bool log_bin_implicit_delete = 1; bool thread_cache_size_specified = false; bool host_cache_size_specified = false; bool table_definition_cache_specified = false; diff --git a/sql/mysqld.h b/sql/mysqld.h index 632352260ad..bbe32dc6507 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -275,6 +275,7 @@ extern ulong opt_mts_slave_parallel_workers; extern ulonglong opt_mts_pending_jobs_size_max; extern ulong rpl_stop_slave_timeout; extern bool log_bin_use_v1_row_events; +extern bool log_bin_implicit_delete; extern ulong what_to_log, flush_time; extern ulong max_prepared_stmt_count, prepared_stmt_count; extern ulong open_files_limit; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 90d094bca10..e572f2e2622 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -3790,7 +3790,7 @@ static bool open_table_entry_fini(THD *thd, TABLE_SHARE *share, if (unlikely(entry->file->implicit_emptied) && (!thd->lex || !thd->lex->m_IS_table_stats.is_reading_stats_by_open())) { entry->file->implicit_emptied = 0; - if (mysql_bin_log.is_open()) { + if ((mysql_bin_log.is_open()) && (log_bin_implicit_delete)) { bool error = false; String temp_buf; error = temp_buf.append("DELETE FROM "); @@ -3798,6 +3798,7 @@ static bool open_table_entry_fini(THD *thd, TABLE_SHARE *share, error = temp_buf.append("."); append_identifier(thd, &temp_buf, share->table_name.str, strlen(share->table_name.str)); + error = temp_buf.append(" /* added by mysqld because of implicitly emptied table */"); if (mysql_bin_log.write_dml_directly(thd, temp_buf.c_ptr_safe(), temp_buf.length())) return true; diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 5eab3ebf5a8..5a6188119d6 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -2091,6 +2091,13 @@ static Sys_var_bool Sys_log_bin_use_v1_row_events( DEFAULT(false), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_log_bin_use_v1_row_events)); +static Sys_var_bool Sys_log_bin_implicit_delete( + "log_bin_implicit_delete", + "If equal to 1 then implicit delete's are written to the " + "binary log. If equal to 0, then the implicit delete won't be " + "written to the binary log.", + GLOBAL_VAR(log_bin_implicit_delete), CMD_LINE(OPT_ARG), DEFAULT(true)); + static Sys_var_charptr Sys_log_error( "log_error", "Error log file", READ_ONLY NON_PERSIST GLOBAL_VAR(log_error_dest),