Commit 1e432778 authored by unknown's avatar unknown

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.
parent 639baee6
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
......@@ -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
......@@ -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));
......
......@@ -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");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment