summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <knielsen@knielsen-hq.org>2013-07-10 11:45:15 +0200
committerunknown <knielsen@knielsen-hq.org>2013-07-10 11:45:15 +0200
commit1e43277838581dfa5be2e755e524991cd7e2cebf (patch)
treeb7a2f53f0723b7d6926fe5ce83fac9206a6b14e8
parent639baee61bdfefe124414db6b12d40061a086e5b (diff)
downloadmariadb-git-1e43277838581dfa5be2e755e524991cd7e2cebf.tar.gz
MDEV-4708: GTID strict mode doesn't work on a database with purged binlogs
When a new master is provisioned that does not have any old binlogs, the @@gtid_slave_pos is used to know where in the GTID history the provisioning happened. A slave is allowed to connect at the point of this value of @@gtid_slave_pos, even if that GTID is not in the binlogs on the new master. But --gtid-strict-mode did not correctly handle this case. When strict mode was enabled, an attempt to connect at the position would cause an error about holes in the binlog, which is not correct. This patch adds a hash of GTIDs that need to be treated specially by GTID strict mode to deal correctly with this case.
-rw-r--r--mysql-test/suite/rpl/r/rpl_gtid_nobinlog.result6
-rw-r--r--mysql-test/suite/rpl/t/rpl_gtid_nobinlog.test6
-rw-r--r--sql/sql_repl.cc44
-rw-r--r--storage/federatedx/ha_federatedx.cc1
4 files changed, 49 insertions, 8 deletions
diff --git a/mysql-test/suite/rpl/r/rpl_gtid_nobinlog.result b/mysql-test/suite/rpl/r/rpl_gtid_nobinlog.result
index bc7be2a30b7..d6a826ffaaa 100644
--- a/mysql-test/suite/rpl/r/rpl_gtid_nobinlog.result
+++ b/mysql-test/suite/rpl/r/rpl_gtid_nobinlog.result
@@ -1,10 +1,14 @@
include/rpl_init.inc [topology=1->2]
+SET @old_strict= @@GLOBAL.gtid_strict_mode;
+SET GLOBAL gtid_strict_mode= 1;
select @@global.log_slave_updates;
@@global.log_slave_updates
0
CREATE TABLE t1 (a INT PRIMARY KEY, b INT);
INSERT INTO t1 VALUES (1, 1);
INSERT INTO t1 VALUES (2, 1);
+SET @old_strict= @@GLOBAL.gtid_strict_mode;
+SET GLOBAL gtid_strict_mode= 1;
select @@global.log_slave_updates;
@@global.log_slave_updates
0
@@ -47,5 +51,7 @@ a b
4 2
5 1
6 1
+SET GLOBAL gtid_strict_mode= @old_strict;
+SET GLOBAL gtid_strict_mode= @old_strict;
DROP TABLE t1;
include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/t/rpl_gtid_nobinlog.test b/mysql-test/suite/rpl/t/rpl_gtid_nobinlog.test
index 9c9c8090eba..ceb79062155 100644
--- a/mysql-test/suite/rpl/t/rpl_gtid_nobinlog.test
+++ b/mysql-test/suite/rpl/t/rpl_gtid_nobinlog.test
@@ -3,6 +3,8 @@
--source include/have_binlog_format_statement.inc
--connection server_1
+SET @old_strict= @@GLOBAL.gtid_strict_mode;
+SET GLOBAL gtid_strict_mode= 1;
select @@global.log_slave_updates;
CREATE TABLE t1 (a INT PRIMARY KEY, b INT);
@@ -11,6 +13,8 @@ INSERT INTO t1 VALUES (2, 1);
--save_master_pos
--connection server_2
+SET @old_strict= @@GLOBAL.gtid_strict_mode;
+SET GLOBAL gtid_strict_mode= 1;
select @@global.log_slave_updates;
--sync_with_master
@@ -49,8 +53,10 @@ START SLAVE;
SELECT * FROM t1 ORDER BY a;
# Cleanup.
+SET GLOBAL gtid_strict_mode= @old_strict;
--connection server_1
+SET GLOBAL gtid_strict_mode= @old_strict;
DROP TABLE t1;
--source include/rpl_end.inc
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 283078203ed..fcda6452e92 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -894,7 +894,8 @@ contains_all_slave_gtid(slave_connection_state *st, Gtid_list_log_event *glev)
static int
check_slave_start_position(THD *thd, slave_connection_state *st,
const char **errormsg, rpl_gtid *error_gtid,
- slave_connection_state *until_gtid_state)
+ slave_connection_state *until_gtid_state,
+ HASH *fake_gtid_hash)
{
uint32 i;
int err;
@@ -998,11 +999,30 @@ check_slave_start_position(THD *thd, slave_connection_state *st,
&start_gtid) &&
start_gtid.seq_no > slave_gtid->seq_no)
{
+ rpl_gtid *fake_gtid;
/*
Start replication within this domain at the first GTID that we logged
ourselves after becoming a master.
+
+ Remember that this starting point is in fact a "fake" GTID which may
+ not exists in the binlog, so that we do not complain about it in
+ --gtid-strict-mode.
*/
slave_gtid->server_id= global_system_variables.server_id;
+ if (!(fake_gtid= (rpl_gtid *)my_malloc(sizeof(*fake_gtid), MYF(0))))
+ {
+ *errormsg= "Out of memory while checking slave start position";
+ err= ER_OUT_OF_RESOURCES;
+ goto end;
+ }
+ *fake_gtid= *slave_gtid;
+ if (my_hash_insert(fake_gtid_hash, (uchar *)fake_gtid))
+ {
+ my_free(fake_gtid);
+ *errormsg= "Out of memory while checking slave start position";
+ err= ER_OUT_OF_RESOURCES;
+ goto end;
+ }
}
else if (mysql_bin_log.lookup_domain_in_binlog_state(slave_gtid->domain_id,
&start_gtid))
@@ -1462,7 +1482,7 @@ send_event_to_slave(THD *thd, NET *net, String* const packet, ushort flags,
enum_gtid_until_state *gtid_until_group,
rpl_binlog_state *until_binlog_state,
bool slave_gtid_strict_mode, rpl_gtid *error_gtid,
- bool *send_fake_gtid_list)
+ bool *send_fake_gtid_list, HASH *fake_gtid_hash)
{
my_off_t pos;
size_t len= packet->length();
@@ -1542,7 +1562,9 @@ send_event_to_slave(THD *thd, NET *net, String* const packet, ushort flags,
if (event_gtid.server_id == gtid->server_id &&
event_gtid.seq_no >= gtid->seq_no)
{
- if (slave_gtid_strict_mode && event_gtid.seq_no > gtid->seq_no)
+ if (slave_gtid_strict_mode && event_gtid.seq_no > gtid->seq_no &&
+ !my_hash_search(fake_gtid_hash,
+ (const uchar *)&event_gtid.domain_id, 0))
{
/*
In strict mode, it is an error if the slave requests to start
@@ -1815,8 +1837,9 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos,
enum_gtid_skip_type gtid_skip_group= GTID_SKIP_NOT;
enum_gtid_until_state gtid_until_group= GTID_UNTIL_NOT_DONE;
rpl_binlog_state until_binlog_state;
- bool slave_gtid_strict_mode;
+ bool slave_gtid_strict_mode= false;
bool send_fake_gtid_list= false;
+ HASH fake_gtid_hash;
uint8 current_checksum_alg= BINLOG_CHECKSUM_ALG_UNDEF;
int old_max_allowed_packet= thd->variables.max_allowed_packet;
@@ -1830,6 +1853,9 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos,
bzero((char*) &log,sizeof(log));
bzero(&error_gtid, sizeof(error_gtid));
+ my_hash_init(&fake_gtid_hash, &my_charset_bin, 32,
+ offsetof(rpl_gtid, domain_id), sizeof(uint32), NULL, my_free,
+ HASH_UNIQUE);
/*
heartbeat_period from @master_heartbeat_period user variable
*/
@@ -1929,7 +1955,8 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos,
goto err;
}
if ((error= check_slave_start_position(thd, &gtid_state, &errmsg,
- &error_gtid, until_gtid_state)))
+ &error_gtid, until_gtid_state,
+ &fake_gtid_hash)))
{
my_errno= error;
goto err;
@@ -2234,7 +2261,7 @@ impossible position";
until_gtid_state, &gtid_until_group,
&until_binlog_state,
slave_gtid_strict_mode, &error_gtid,
- &send_fake_gtid_list)))
+ &send_fake_gtid_list, &fake_gtid_hash)))
{
errmsg= tmp_msg;
goto err;
@@ -2440,7 +2467,8 @@ impossible position";
&gtid_skip_group, until_gtid_state,
&gtid_until_group, &until_binlog_state,
slave_gtid_strict_mode, &error_gtid,
- &send_fake_gtid_list)))
+ &send_fake_gtid_list,
+ &fake_gtid_hash)))
{
errmsg= tmp_msg;
goto err;
@@ -2530,6 +2558,7 @@ impossible position";
end:
end_io_cache(&log);
mysql_file_close(file, MYF(MY_WME));
+ my_hash_free(&fake_gtid_hash);
RUN_HOOK(binlog_transmit, transmit_stop, (thd, flags));
my_eof(thd);
@@ -2600,6 +2629,7 @@ err:
mysql_mutex_unlock(&LOCK_thread_count);
if (file >= 0)
mysql_file_close(file, MYF(MY_WME));
+ my_hash_free(&fake_gtid_hash);
thd->variables.max_allowed_packet= old_max_allowed_packet;
my_message(my_errno, error_text, MYF(0));
diff --git a/storage/federatedx/ha_federatedx.cc b/storage/federatedx/ha_federatedx.cc
index a7f2d887952..1c9db78da4f 100644
--- a/storage/federatedx/ha_federatedx.cc
+++ b/storage/federatedx/ha_federatedx.cc
@@ -539,7 +539,6 @@ static int parse_url_error(FEDERATEDX_SHARE *share, TABLE_SHARE *table_s,
int get_connection(MEM_ROOT *mem_root, FEDERATEDX_SHARE *share)
{
int error_num= ER_FOREIGN_SERVER_DOESNT_EXIST;
- char error_buffer[FEDERATEDX_QUERY_BUFFER_SIZE];
FOREIGN_SERVER *server, server_buffer;
DBUG_ENTER("ha_federatedx::get_connection");