summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrandon Nesterenko <brandon.nesterenko@mariadb.com>2021-06-09 11:03:03 -0600
committerBrandon Nesterenko <brandon.nesterenko@mariadb.com>2021-06-09 12:27:15 -0600
commit1b0ffdd35dde8fc382626f91d9911576a4a6794f (patch)
tree4bc070aa0ba2249206c29d96f863f33b8e2b1a70
parentc872125a664842ecfb66c60f69b3a87390aec23d (diff)
downloadmariadb-git-bb-10.2-MDEV-25607.tar.gz
MDEV-25607: Auto-generated DELETE from HEAP table can break replicationbb-10.2-MDEV-25607
Problem: ======= The special logic used by the memory storage engine to keep slaves in sync with the master on a restart can break replication. In particular, after a restart, the master writes DELETE statements in the binlog for each MEMORY-based table so the slave can empty its data. If the DELETE is not executable, e.g. due to invalid triggers, the slave will error and fail, whereas the master will never see the problem. Solution: ======= Instead of DELETE statements, use TRUNCATE to keep slaves in-sync with the master, thereby bypassing triggers. Reviewed By: =========== <TODO>
-rw-r--r--mysql-test/suite/binlog/r/memory_engine_truncates_on_restart.result44
-rw-r--r--mysql-test/suite/binlog/t/memory_engine_truncates_on_restart.test44
-rw-r--r--mysql-test/suite/rpl/r/rpl_mdev382.result2
-rw-r--r--sql/sql_base.cc2
4 files changed, 90 insertions, 2 deletions
diff --git a/mysql-test/suite/binlog/r/memory_engine_truncates_on_restart.result b/mysql-test/suite/binlog/r/memory_engine_truncates_on_restart.result
new file mode 100644
index 00000000000..6e68fb1d262
--- /dev/null
+++ b/mysql-test/suite/binlog/r/memory_engine_truncates_on_restart.result
@@ -0,0 +1,44 @@
+include/master-slave.inc
+[connection master]
+reset master;
+create table t (val int) engine=MEMORY;
+# DELETE trigger should never be activated
+create trigger tr after delete on t for each row update t2 set val = 1;
+insert into t values (1),(2);
+connection slave;
+#
+# Check pre-restart values
+#
+connection master;
+select * from t;
+val
+1
+2
+connection slave;
+select * from t;
+val
+1
+2
+connection master;
+#
+# Restart server should empty master and slave `t`
+#
+include/rpl_restart_server.inc [server_number=1]
+insert into t values (3),(4);
+connection slave;
+#
+# Validate values after restart do not include those inserted previously
+#
+connection master;
+select * from t;
+val
+3
+4
+connection slave;
+select * from t;
+val
+3
+4
+connection master;
+drop table t;
+include/rpl_end.inc
diff --git a/mysql-test/suite/binlog/t/memory_engine_truncates_on_restart.test b/mysql-test/suite/binlog/t/memory_engine_truncates_on_restart.test
new file mode 100644
index 00000000000..c9e3fd20647
--- /dev/null
+++ b/mysql-test/suite/binlog/t/memory_engine_truncates_on_restart.test
@@ -0,0 +1,44 @@
+--source include/master-slave.inc
+
+reset master;
+
+create table t (val int) engine=MEMORY;
+
+-- echo # DELETE trigger should never be activated
+create trigger tr after delete on t for each row update t2 set val = 1;
+
+insert into t values (1),(2);
+
+--sync_slave_with_master
+
+-- echo #
+-- echo # Check pre-restart values
+-- echo #
+--connection master
+select * from t;
+--connection slave
+select * from t;
+
+--connection master
+-- echo #
+-- echo # Restart server should empty master and slave `t`
+-- echo #
+--let $rpl_server_number= 1
+--source include/rpl_restart_server.inc
+
+insert into t values (3),(4);
+
+--sync_slave_with_master
+
+-- echo #
+-- echo # Validate values after restart do not include those inserted previously
+-- echo #
+--connection master
+select * from t;
+--connection slave
+select * from t;
+
+# Cleanup
+--connection master
+drop table t;
+--source include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_mdev382.result b/mysql-test/suite/rpl/r/rpl_mdev382.result
index ee9377906ad..c0c4bc556dc 100644
--- a/mysql-test/suite/rpl/r/rpl_mdev382.result
+++ b/mysql-test/suite/rpl/r/rpl_mdev382.result
@@ -355,7 +355,7 @@ a`
show binlog events in 'master-bin.000002' from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000002 # Gtid 1 # GTID #-#-#
-master-bin.000002 # Query 1 # DELETE FROM `db1``; select 'oops!'`.`t``1`
+master-bin.000002 # Query 1 # TRUNCATE TABLE `db1``; select 'oops!'`.`t``1`
connection slave;
include/start_slave.inc
connection master;
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 11f4cb9890b..d3e605651bf 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -2796,7 +2796,7 @@ static bool open_table_entry_fini(THD *thd, TABLE_SHARE *share, TABLE *entry)
String query(query_buf, sizeof(query_buf), system_charset_info);
query.length(0);
- query.append("DELETE FROM ");
+ query.append("TRUNCATE TABLE ");
append_identifier(thd, &query, share->db.str, share->db.length);
query.append(".");
append_identifier(thd, &query, share->table_name.str,