mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03: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:
@ -1,10 +1,14 @@
|
|||||||
include/rpl_init.inc [topology=1->2]
|
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;
|
select @@global.log_slave_updates;
|
||||||
@@global.log_slave_updates
|
@@global.log_slave_updates
|
||||||
0
|
0
|
||||||
CREATE TABLE t1 (a INT PRIMARY KEY, b INT);
|
CREATE TABLE t1 (a INT PRIMARY KEY, b INT);
|
||||||
INSERT INTO t1 VALUES (1, 1);
|
INSERT INTO t1 VALUES (1, 1);
|
||||||
INSERT INTO t1 VALUES (2, 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;
|
select @@global.log_slave_updates;
|
||||||
@@global.log_slave_updates
|
@@global.log_slave_updates
|
||||||
0
|
0
|
||||||
@ -47,5 +51,7 @@ a b
|
|||||||
4 2
|
4 2
|
||||||
5 1
|
5 1
|
||||||
6 1
|
6 1
|
||||||
|
SET GLOBAL gtid_strict_mode= @old_strict;
|
||||||
|
SET GLOBAL gtid_strict_mode= @old_strict;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
include/rpl_end.inc
|
include/rpl_end.inc
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
--source include/have_binlog_format_statement.inc
|
--source include/have_binlog_format_statement.inc
|
||||||
|
|
||||||
--connection server_1
|
--connection server_1
|
||||||
|
SET @old_strict= @@GLOBAL.gtid_strict_mode;
|
||||||
|
SET GLOBAL gtid_strict_mode= 1;
|
||||||
select @@global.log_slave_updates;
|
select @@global.log_slave_updates;
|
||||||
|
|
||||||
CREATE TABLE t1 (a INT PRIMARY KEY, b INT);
|
CREATE TABLE t1 (a INT PRIMARY KEY, b INT);
|
||||||
@ -11,6 +13,8 @@ INSERT INTO t1 VALUES (2, 1);
|
|||||||
--save_master_pos
|
--save_master_pos
|
||||||
|
|
||||||
--connection server_2
|
--connection server_2
|
||||||
|
SET @old_strict= @@GLOBAL.gtid_strict_mode;
|
||||||
|
SET GLOBAL gtid_strict_mode= 1;
|
||||||
select @@global.log_slave_updates;
|
select @@global.log_slave_updates;
|
||||||
|
|
||||||
--sync_with_master
|
--sync_with_master
|
||||||
@ -49,8 +53,10 @@ START SLAVE;
|
|||||||
SELECT * FROM t1 ORDER BY a;
|
SELECT * FROM t1 ORDER BY a;
|
||||||
|
|
||||||
# Cleanup.
|
# Cleanup.
|
||||||
|
SET GLOBAL gtid_strict_mode= @old_strict;
|
||||||
|
|
||||||
--connection server_1
|
--connection server_1
|
||||||
|
SET GLOBAL gtid_strict_mode= @old_strict;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
|
||||||
--source include/rpl_end.inc
|
--source include/rpl_end.inc
|
||||||
|
@ -894,7 +894,8 @@ contains_all_slave_gtid(slave_connection_state *st, Gtid_list_log_event *glev)
|
|||||||
static int
|
static int
|
||||||
check_slave_start_position(THD *thd, slave_connection_state *st,
|
check_slave_start_position(THD *thd, slave_connection_state *st,
|
||||||
const char **errormsg, rpl_gtid *error_gtid,
|
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;
|
uint32 i;
|
||||||
int err;
|
int err;
|
||||||
@ -998,11 +999,30 @@ check_slave_start_position(THD *thd, slave_connection_state *st,
|
|||||||
&start_gtid) &&
|
&start_gtid) &&
|
||||||
start_gtid.seq_no > slave_gtid->seq_no)
|
start_gtid.seq_no > slave_gtid->seq_no)
|
||||||
{
|
{
|
||||||
|
rpl_gtid *fake_gtid;
|
||||||
/*
|
/*
|
||||||
Start replication within this domain at the first GTID that we logged
|
Start replication within this domain at the first GTID that we logged
|
||||||
ourselves after becoming a master.
|
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;
|
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,
|
else if (mysql_bin_log.lookup_domain_in_binlog_state(slave_gtid->domain_id,
|
||||||
&start_gtid))
|
&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,
|
enum_gtid_until_state *gtid_until_group,
|
||||||
rpl_binlog_state *until_binlog_state,
|
rpl_binlog_state *until_binlog_state,
|
||||||
bool slave_gtid_strict_mode, rpl_gtid *error_gtid,
|
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;
|
my_off_t pos;
|
||||||
size_t len= packet->length();
|
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 &&
|
if (event_gtid.server_id == gtid->server_id &&
|
||||||
event_gtid.seq_no >= gtid->seq_no)
|
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
|
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_skip_type gtid_skip_group= GTID_SKIP_NOT;
|
||||||
enum_gtid_until_state gtid_until_group= GTID_UNTIL_NOT_DONE;
|
enum_gtid_until_state gtid_until_group= GTID_UNTIL_NOT_DONE;
|
||||||
rpl_binlog_state until_binlog_state;
|
rpl_binlog_state until_binlog_state;
|
||||||
bool slave_gtid_strict_mode;
|
bool slave_gtid_strict_mode= false;
|
||||||
bool send_fake_gtid_list= false;
|
bool send_fake_gtid_list= false;
|
||||||
|
HASH fake_gtid_hash;
|
||||||
|
|
||||||
uint8 current_checksum_alg= BINLOG_CHECKSUM_ALG_UNDEF;
|
uint8 current_checksum_alg= BINLOG_CHECKSUM_ALG_UNDEF;
|
||||||
int old_max_allowed_packet= thd->variables.max_allowed_packet;
|
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((char*) &log,sizeof(log));
|
||||||
bzero(&error_gtid, sizeof(error_gtid));
|
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
|
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;
|
goto err;
|
||||||
}
|
}
|
||||||
if ((error= check_slave_start_position(thd, >id_state, &errmsg,
|
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;
|
my_errno= error;
|
||||||
goto err;
|
goto err;
|
||||||
@ -2234,7 +2261,7 @@ impossible position";
|
|||||||
until_gtid_state, >id_until_group,
|
until_gtid_state, >id_until_group,
|
||||||
&until_binlog_state,
|
&until_binlog_state,
|
||||||
slave_gtid_strict_mode, &error_gtid,
|
slave_gtid_strict_mode, &error_gtid,
|
||||||
&send_fake_gtid_list)))
|
&send_fake_gtid_list, &fake_gtid_hash)))
|
||||||
{
|
{
|
||||||
errmsg= tmp_msg;
|
errmsg= tmp_msg;
|
||||||
goto err;
|
goto err;
|
||||||
@ -2440,7 +2467,8 @@ impossible position";
|
|||||||
>id_skip_group, until_gtid_state,
|
>id_skip_group, until_gtid_state,
|
||||||
>id_until_group, &until_binlog_state,
|
>id_until_group, &until_binlog_state,
|
||||||
slave_gtid_strict_mode, &error_gtid,
|
slave_gtid_strict_mode, &error_gtid,
|
||||||
&send_fake_gtid_list)))
|
&send_fake_gtid_list,
|
||||||
|
&fake_gtid_hash)))
|
||||||
{
|
{
|
||||||
errmsg= tmp_msg;
|
errmsg= tmp_msg;
|
||||||
goto err;
|
goto err;
|
||||||
@ -2530,6 +2558,7 @@ impossible position";
|
|||||||
end:
|
end:
|
||||||
end_io_cache(&log);
|
end_io_cache(&log);
|
||||||
mysql_file_close(file, MYF(MY_WME));
|
mysql_file_close(file, MYF(MY_WME));
|
||||||
|
my_hash_free(&fake_gtid_hash);
|
||||||
|
|
||||||
RUN_HOOK(binlog_transmit, transmit_stop, (thd, flags));
|
RUN_HOOK(binlog_transmit, transmit_stop, (thd, flags));
|
||||||
my_eof(thd);
|
my_eof(thd);
|
||||||
@ -2600,6 +2629,7 @@ err:
|
|||||||
mysql_mutex_unlock(&LOCK_thread_count);
|
mysql_mutex_unlock(&LOCK_thread_count);
|
||||||
if (file >= 0)
|
if (file >= 0)
|
||||||
mysql_file_close(file, MYF(MY_WME));
|
mysql_file_close(file, MYF(MY_WME));
|
||||||
|
my_hash_free(&fake_gtid_hash);
|
||||||
thd->variables.max_allowed_packet= old_max_allowed_packet;
|
thd->variables.max_allowed_packet= old_max_allowed_packet;
|
||||||
|
|
||||||
my_message(my_errno, error_text, MYF(0));
|
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 get_connection(MEM_ROOT *mem_root, FEDERATEDX_SHARE *share)
|
||||||
{
|
{
|
||||||
int error_num= ER_FOREIGN_SERVER_DOESNT_EXIST;
|
int error_num= ER_FOREIGN_SERVER_DOESNT_EXIST;
|
||||||
char error_buffer[FEDERATEDX_QUERY_BUFFER_SIZE];
|
|
||||||
FOREIGN_SERVER *server, server_buffer;
|
FOREIGN_SERVER *server, server_buffer;
|
||||||
DBUG_ENTER("ha_federatedx::get_connection");
|
DBUG_ENTER("ha_federatedx::get_connection");
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user