diff options
author | unknown <knielsen@knielsen-hq.org> | 2013-07-10 11:45:15 +0200 |
---|---|---|
committer | unknown <knielsen@knielsen-hq.org> | 2013-07-10 11:45:15 +0200 |
commit | 1e43277838581dfa5be2e755e524991cd7e2cebf (patch) | |
tree | b7a2f53f0723b7d6926fe5ce83fac9206a6b14e8 | |
parent | 639baee61bdfefe124414db6b12d40061a086e5b (diff) | |
download | mariadb-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.result | 6 | ||||
-rw-r--r-- | mysql-test/suite/rpl/t/rpl_gtid_nobinlog.test | 6 | ||||
-rw-r--r-- | sql/sql_repl.cc | 44 | ||||
-rw-r--r-- | storage/federatedx/ha_federatedx.cc | 1 |
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, >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)); 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"); |