mirror of
https://github.com/MariaDB/server.git
synced 2025-01-29 10:14:19 +01:00
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.
This commit is contained in:
parent
639baee61b
commit
1e43277838
4 changed files with 49 additions and 8 deletions
|
@ -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
|
||||
|
|
|
@ -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, >id_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, >id_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";
|
|||
>id_skip_group, until_gtid_state,
|
||||
>id_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");
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue