summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/suite/rpl/r/rpl_gtid_misc.result25
-rw-r--r--mysql-test/suite/rpl/t/rpl_gtid_misc.test50
-rw-r--r--sql/rpl_gtid.cc25
-rw-r--r--sql/rpl_gtid.h1
-rw-r--r--sql/sql_repl.cc25
5 files changed, 126 insertions, 0 deletions
diff --git a/mysql-test/suite/rpl/r/rpl_gtid_misc.result b/mysql-test/suite/rpl/r/rpl_gtid_misc.result
new file mode 100644
index 00000000000..cdaac1b1d34
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_gtid_misc.result
@@ -0,0 +1,25 @@
+include/master-slave.inc
+[connection master]
+*** MDEV-6403: Temporary tables lost at STOP SLAVE in GTID mode if master has not rotated binlog since restart ***
+CREATE TABLE t1 (a INT PRIMARY KEY);
+include/stop_slave.inc
+SET sql_log_bin= 0;
+INSERT INTO t1 VALUES (1);
+SET sql_log_bin= 1;
+CHANGE MASTER TO master_use_gtid= current_pos;
+CREATE TEMPORARY TABLE t2 LIKE t1;
+INSERT INTO t2 VALUE (1);
+INSERT INTO t1 SELECT * FROM t2;
+DROP TEMPORARY TABLE t2;
+START SLAVE;
+include/wait_for_slave_sql_error.inc [errno=1062]
+STOP SLAVE IO_THREAD;
+SET sql_log_bin= 0;
+DELETE FROM t1 WHERE a=1;
+SET sql_log_bin= 1;
+include/start_slave.inc
+SELECT * FROM t1 ORDER BY a;
+a
+1
+DROP TABLE t1;
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/t/rpl_gtid_misc.test b/mysql-test/suite/rpl/t/rpl_gtid_misc.test
new file mode 100644
index 00000000000..66d98ec8025
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_gtid_misc.test
@@ -0,0 +1,50 @@
+--source include/master-slave.inc
+
+--echo *** MDEV-6403: Temporary tables lost at STOP SLAVE in GTID mode if master has not rotated binlog since restart ***
+
+--connection master
+CREATE TABLE t1 (a INT PRIMARY KEY);
+--sync_slave_with_master
+
+--connection slave
+--source include/stop_slave.inc
+# Inject a duplicate key error that will make the slave stop in the middle of
+# a sequence of transactions that use a temporary table.
+SET sql_log_bin= 0;
+INSERT INTO t1 VALUES (1);
+SET sql_log_bin= 1;
+CHANGE MASTER TO master_use_gtid= current_pos;
+
+--connection master
+
+# Make some queries that use a temporary table.
+CREATE TEMPORARY TABLE t2 LIKE t1;
+INSERT INTO t2 VALUE (1);
+INSERT INTO t1 SELECT * FROM t2;
+DROP TEMPORARY TABLE t2;
+--save_master_pos
+
+--connection slave
+START SLAVE;
+--let $slave_sql_errno=1062
+--source include/wait_for_slave_sql_error.inc
+
+# Restart the slave.
+# The bug was that the IO thread would receive again the restart
+# format_description event at the start of the master's binlog, and this
+# event would cause the SQL thread to discard all active temporary tables.
+
+STOP SLAVE IO_THREAD;
+
+SET sql_log_bin= 0;
+DELETE FROM t1 WHERE a=1;
+SET sql_log_bin= 1;
+
+--source include/start_slave.inc
+--sync_with_master
+SELECT * FROM t1 ORDER BY a;
+
+--connection master
+DROP TABLE t1;
+
+--source include/rpl_end.inc
diff --git a/sql/rpl_gtid.cc b/sql/rpl_gtid.cc
index d4c7b2c3fbf..f17ece298d3 100644
--- a/sql/rpl_gtid.cc
+++ b/sql/rpl_gtid.cc
@@ -1870,6 +1870,31 @@ slave_connection_state::get_gtid_list(rpl_gtid *gtid_list, uint32 list_size)
/*
+ Check if the GTID position has been reached, for mysql_binlog_send().
+
+ The position has not been reached if we have anything in the state, unless
+ it has either the START_ON_EMPTY_DOMAIN flag set (which means it does not
+ belong to this master at all), or the START_OWN_SLAVE_POS (which means that
+ we start on an old position from when the server was a slave with
+ --log-slave-updates=0).
+*/
+bool
+slave_connection_state::is_pos_reached()
+{
+ uint32 i;
+
+ for (i= 0; i < hash.records; ++i)
+ {
+ entry *e= (entry *)my_hash_element(&hash, i);
+ if (!(e->flags & (START_OWN_SLAVE_POS|START_ON_EMPTY_DOMAIN)))
+ return false;
+ }
+
+ return true;
+}
+
+
+/*
Execute a MASTER_GTID_WAIT().
The position to wait for is in gtid_str in string form.
The timeout in microseconds is in timeout_us, zero means no timeout.
diff --git a/sql/rpl_gtid.h b/sql/rpl_gtid.h
index 22771833845..997540728a5 100644
--- a/sql/rpl_gtid.h
+++ b/sql/rpl_gtid.h
@@ -288,6 +288,7 @@ struct slave_connection_state
int to_string(String *out_str);
int append_to_string(String *out_str);
int get_gtid_list(rpl_gtid *gtid_list, uint32 list_size);
+ bool is_pos_reached();
};
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 68535938484..2b5572609d8 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -2375,6 +2375,31 @@ impossible position";
info.fdev= tmp;
(*packet)[FLAGS_OFFSET+ev_offset] &= ~LOG_EVENT_BINLOG_IN_USE_F;
+
+ if (info.using_gtid_state)
+ {
+ /*
+ If this event has the field `created' set, then it will cause the
+ slave to delete all active temporary tables. This must not happen
+ if the slave received any later GTIDs in a previous connect, as
+ those GTIDs might have created new temporary tables that are still
+ needed.
+
+ So here, we check if the starting GTID position was already
+ reached before this format description event. If not, we clear the
+ `created' flag to preserve temporary tables on the slave. (If the
+ slave connects at a position past this event, it means that it
+ already received and handled it in a previous connect).
+ */
+ if (!info.gtid_state.is_pos_reached())
+ {
+ int4store((char*) packet->ptr()+LOG_EVENT_MINIMAL_HEADER_LEN+
+ ST_CREATED_OFFSET+ev_offset, (ulong) 0);
+ if (info.current_checksum_alg != BINLOG_CHECKSUM_ALG_OFF &&
+ info.current_checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF)
+ fix_checksum(packet, ev_offset);
+ }
+ }
}
#ifndef DBUG_OFF