diff options
author | unknown <knielsen@knielsen-hq.org> | 2013-05-22 17:36:48 +0200 |
---|---|---|
committer | unknown <knielsen@knielsen-hq.org> | 2013-05-22 17:36:48 +0200 |
commit | 1cd6eb5f942ca3e94e86a48512d992fbb3aeecd9 (patch) | |
tree | a23bba541fbfbc0fc92f9666d29340320b9be428 /sql | |
parent | d795bc9ff8d4a4e17f249a0eb9ac01f25d53a259 (diff) | |
download | mariadb-git-1cd6eb5f942ca3e94e86a48512d992fbb3aeecd9.tar.gz |
MDEV-26: Global transaction ID.
Change of user interface to be more logical and more in line with expectations
to work similar to old-style replication.
User can now explicitly choose in CHANGE MASTER whether binlog position is
taken into account (master_gtid_pos=current_pos) or not (master_gtid_pos=
slave_pos) when slave connects to master.
@@gtid_pos is replaced by three separate variables @@gtid_slave_pos (can
be set by user, replicated GTIDs only), @@gtid_binlog_pos (read only), and
@@gtid_current_pos (a combination of the two, most recent GTID within each
domain). mysql.rpl_slave_state is renamed to mysql.gtid_slave_pos to match.
This fixes MDEV-4474.
Diffstat (limited to 'sql')
-rw-r--r-- | sql/lex.h | 2 | ||||
-rw-r--r-- | sql/log.cc | 14 | ||||
-rw-r--r-- | sql/log.h | 1 | ||||
-rw-r--r-- | sql/log_event.cc | 4 | ||||
-rw-r--r-- | sql/rpl_gtid.cc | 38 | ||||
-rw-r--r-- | sql/rpl_gtid.h | 6 | ||||
-rw-r--r-- | sql/rpl_mi.cc | 15 | ||||
-rw-r--r-- | sql/rpl_mi.h | 10 | ||||
-rw-r--r-- | sql/share/errmsg-utf8.txt | 4 | ||||
-rw-r--r-- | sql/slave.cc | 25 | ||||
-rw-r--r-- | sql/sql_lex.h | 9 | ||||
-rw-r--r-- | sql/sql_repl.cc | 72 | ||||
-rw-r--r-- | sql/sql_repl.h | 2 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 31 | ||||
-rw-r--r-- | sql/sys_vars.cc | 80 | ||||
-rw-r--r-- | sql/sys_vars.h | 108 |
16 files changed, 344 insertions, 77 deletions
diff --git a/sql/lex.h b/sql/lex.h index 756e7e80f7e..e269c3e4040 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -152,6 +152,7 @@ static SYMBOL symbols[] = { { "CROSS", SYM(CROSS)}, { "CUBE", SYM(CUBE_SYM)}, { "CURRENT_DATE", SYM(CURDATE)}, + { "CURRENT_POS", SYM(CURRENT_POS_SYM)}, { "CURRENT_TIME", SYM(CURTIME)}, { "CURRENT_TIMESTAMP", SYM(NOW_SYM)}, { "CURRENT_USER", SYM(CURRENT_USER)}, @@ -517,6 +518,7 @@ static SYMBOL symbols[] = { { "SIMPLE", SYM(SIMPLE_SYM)}, { "SLAVE", SYM(SLAVE)}, { "SLAVES", SYM(SLAVES)}, + { "SLAVE_POS", SYM(SLAVE_POS_SYM)}, { "SLOW", SYM(SLOW)}, { "SNAPSHOT", SYM(SNAPSHOT_SYM)}, { "SMALLINT", SYM(SMALLINT)}, diff --git a/sql/log.cc b/sql/log.cc index 3266934beda..238452070ff 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -5521,6 +5521,18 @@ MYSQL_BIN_LOG::get_most_recent_gtid_list(rpl_gtid **list, uint32 *size) bool +MYSQL_BIN_LOG::append_state_pos(String *str) +{ + bool err; + + mysql_mutex_lock(&rpl_global_gtid_binlog_state.LOCK_binlog_state); + err= rpl_global_gtid_binlog_state.append_pos(str); + mysql_mutex_unlock(&rpl_global_gtid_binlog_state.LOCK_binlog_state); + return err; +} + + +bool MYSQL_BIN_LOG::find_in_binlog_state(uint32 domain_id, uint32 server_id, rpl_gtid *out_gtid) { @@ -8508,7 +8520,7 @@ binlog_background_thread(void *arg __attribute__((unused))) thd->store_globals(); /* - Load the slave replication GTID state from the mysql.rpl_slave_state + Load the slave replication GTID state from the mysql.gtid_slave_pos table. This is mostly so that we can start our seq_no counter from the highest diff --git a/sql/log.h b/sql/log.h index bd20c8aee09..f41b48eba7c 100644 --- a/sql/log.h +++ b/sql/log.h @@ -779,6 +779,7 @@ public: int read_state_from_file(); int write_state_to_file(); int get_most_recent_gtid_list(rpl_gtid **list, uint32 *size); + bool append_state_pos(String *str); bool find_in_binlog_state(uint32 domain_id, uint32 server_id, rpl_gtid *out_gtid); bool lookup_domain_in_binlog_state(uint32 domain_id, rpl_gtid *out_gtid); diff --git a/sql/log_event.cc b/sql/log_event.cc index 9fbcbb68145..f896d3521de 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -4004,7 +4004,7 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli, const_cast<Relay_log_info*>(rli)->gtid_sub_id= 0; gtid= rli->current_gtid; - if (rpl_global_gtid_slave_state.record_gtid(thd, >id, sub_id, true)) + if (rpl_global_gtid_slave_state.record_gtid(thd, >id, sub_id, true, false)) { rli->report(ERROR_LEVEL, ER_CANNOT_UPDATE_GTID_STATE, "Error during COMMIT: failed to update GTID state in " @@ -6895,7 +6895,7 @@ int Xid_log_event::do_apply_event(Relay_log_info const *rli) const_cast<Relay_log_info*>(rli)->gtid_sub_id= 0; gtid= rli->current_gtid; - err= rpl_global_gtid_slave_state.record_gtid(thd, >id, sub_id, true); + err= rpl_global_gtid_slave_state.record_gtid(thd, >id, sub_id, true, false); if (err) { rli->report(ERROR_LEVEL, ER_CANNOT_UPDATE_GTID_STATE, diff --git a/sql/rpl_gtid.cc b/sql/rpl_gtid.cc index a4bdeb9932b..01502c5b0f1 100644 --- a/sql/rpl_gtid.cc +++ b/sql/rpl_gtid.cc @@ -29,7 +29,7 @@ const LEX_STRING rpl_gtid_slave_state_table_name= - { C_STRING_WITH_LEN("rpl_slave_state") }; + { C_STRING_WITH_LEN("gtid_slave_pos") }; void @@ -73,7 +73,7 @@ rpl_slave_state::record_and_update_gtid(THD *thd, Relay_log_info *rli) if ((sub_id= rli->gtid_sub_id)) { rli->gtid_sub_id= 0; - if (record_gtid(thd, &rli->current_gtid, sub_id, false)) + if (record_gtid(thd, &rli->current_gtid, sub_id, false, false)) return 1; update_state_hash(sub_id, &rli->current_gtid); } @@ -186,8 +186,6 @@ rpl_slave_state::truncate_state_table(THD *thd) int err= 0; TABLE *table; - mysql_reset_thd_for_next_command(thd, 0); - tlist.init_one_table(STRING_WITH_LEN("mysql"), rpl_gtid_slave_state_table_name.str, rpl_gtid_slave_state_table_name.length, @@ -234,7 +232,7 @@ static const TABLE_FIELD_TYPE mysql_rpl_slave_state_coltypes[4]= { static const uint mysql_rpl_slave_state_pk_parts[]= {0, 1}; -static const TABLE_FIELD_DEF mysql_rpl_slave_state_tabledef= { +static const TABLE_FIELD_DEF mysql_gtid_slave_pos_tabledef= { array_elements(mysql_rpl_slave_state_coltypes), mysql_rpl_slave_state_coltypes, array_elements(mysql_rpl_slave_state_pk_parts), @@ -256,14 +254,14 @@ protected: static Gtid_db_intact gtid_table_intact; /* - Check that the mysql.rpl_slave_state table has the correct definition. + Check that the mysql.gtid_slave_pos table has the correct definition. */ int gtid_check_rpl_slave_state_table(TABLE *table) { int err; - if ((err= gtid_table_intact.check(table, &mysql_rpl_slave_state_tabledef))) + if ((err= gtid_table_intact.check(table, &mysql_gtid_slave_pos_tabledef))) my_error(ER_GTID_OPEN_TABLE_FAILED, MYF(0), "mysql", rpl_gtid_slave_state_table_name.str); return err; @@ -286,7 +284,7 @@ gtid_check_rpl_slave_state_table(TABLE *table) */ int rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id, - bool in_transaction) + bool in_transaction, bool in_statement) { TABLE_LIST tlist; int err= 0; @@ -297,7 +295,8 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id, ulonglong thd_saved_option= thd->variables.option_bits; Query_tables_list lex_backup; - mysql_reset_thd_for_next_command(thd, 0); + if (!in_statement) + mysql_reset_thd_for_next_command(thd, 0); DBUG_EXECUTE_IF("gtid_inject_record_gtid", { @@ -626,7 +625,7 @@ gtid_parser_helper(char **ptr, char *end, rpl_gtid *out_gtid) */ int rpl_slave_state::load(THD *thd, char *state_from_master, size_t len, - bool reset) + bool reset, bool in_statement) { char *end= state_from_master + len; @@ -645,7 +644,7 @@ rpl_slave_state::load(THD *thd, char *state_from_master, size_t len, if (gtid_parser_helper(&state_from_master, end, >id) || !(sub_id= next_subid(gtid.domain_id)) || - record_gtid(thd, >id, sub_id, false) || + record_gtid(thd, >id, sub_id, false, in_statement) || update(gtid.domain_id, gtid.server_id, sub_id, gtid.seq_no)) return 1; if (state_from_master == end) @@ -980,6 +979,23 @@ rpl_binlog_state::get_most_recent_gtid_list(rpl_gtid **list, uint32 *size) } +bool +rpl_binlog_state::append_pos(String *str) +{ + uint32 i; + bool first= true; + + for (i= 0; i < hash.records; ++i) + { + element *e= (element *)my_hash_element(&hash, i); + if (rpl_slave_state_tostring_helper(str, e->last_gtid, &first)) + return true; + } + + return false; +} + + slave_connection_state::slave_connection_state() { my_hash_init(&hash, &my_charset_bin, 32, diff --git a/sql/rpl_gtid.h b/sql/rpl_gtid.h index bd6663c0659..cc3c99f40b7 100644 --- a/sql/rpl_gtid.h +++ b/sql/rpl_gtid.h @@ -91,11 +91,12 @@ struct rpl_slave_state int update(uint32 domain_id, uint32 server_id, uint64 sub_id, uint64 seq_no); int truncate_state_table(THD *thd); int record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id, - bool in_transaction); + bool in_transaction, bool in_statement); uint64 next_subid(uint32 domain_id); int tostring(String *dest, rpl_gtid *extra_gtids, uint32 num_extra); bool domain_to_gtid(uint32 domain_id, rpl_gtid *out_gtid); - int load(THD *thd, char *state_from_master, size_t len, bool reset); + int load(THD *thd, char *state_from_master, size_t len, bool reset, + bool in_statement); bool is_empty(); void lock() { DBUG_ASSERT(inited); mysql_mutex_lock(&LOCK_slave_state); } @@ -150,6 +151,7 @@ struct rpl_binlog_state uint32 count(); int get_gtid_list(rpl_gtid *gtid_list, uint32 list_size); int get_most_recent_gtid_list(rpl_gtid **list, uint32 *size); + bool append_pos(String *str); rpl_gtid *find(uint32 domain_id, uint32 server_id); }; diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc index 92dbf68d7a2..4ffe4f37cac 100644 --- a/sql/rpl_mi.cc +++ b/sql/rpl_mi.cc @@ -37,7 +37,8 @@ Master_info::Master_info(LEX_STRING *connection_name_arg, checksum_alg_before_fd(BINLOG_CHECKSUM_ALG_UNDEF), connect_retry(DEFAULT_CONNECT_RETRY), inited(0), abort_slave(0), slave_running(0), slave_run_id(0), sync_counter(0), - heartbeat_period(0), received_heartbeats(0), master_id(0), using_gtid(0) + heartbeat_period(0), received_heartbeats(0), master_id(0), + using_gtid(USE_GTID_NO) { host[0] = 0; user[0] = 0; password[0] = 0; ssl_ca[0]= 0; ssl_capath[0]= 0; ssl_cert[0]= 0; @@ -152,7 +153,7 @@ void init_master_log_pos(Master_info* mi) mi->master_log_name[0] = 0; mi->master_log_pos = BIN_LOG_HEADER_SIZE; // skip magic number - mi->using_gtid= false; + mi->using_gtid= Master_info::USE_GTID_NO; /* Intentionally init ssl_verify_server_cert to 0, no option available */ mi->ssl_verify_server_cert= 0; @@ -447,7 +448,15 @@ file '%s')", fname); while (!init_strvar_from_file(buf, sizeof(buf), &mi->file, 0)) { if (0 == strncmp(buf, STRING_WITH_LEN("using_gtid="))) - mi->using_gtid= (0 != atoi(buf + sizeof("using_gtid"))); + { + int val= atoi(buf + sizeof("using_gtid")); + if (val == Master_info::USE_GTID_CURRENT_POS) + mi->using_gtid= Master_info::USE_GTID_CURRENT_POS; + else if (val == Master_info::USE_GTID_SLAVE_POS) + mi->using_gtid= Master_info::USE_GTID_SLAVE_POS; + else + mi->using_gtid= Master_info::USE_GTID_NO; + } } } } diff --git a/sql/rpl_mi.h b/sql/rpl_mi.h index 64501e96f00..916bd0dae02 100644 --- a/sql/rpl_mi.h +++ b/sql/rpl_mi.h @@ -130,10 +130,14 @@ class Master_info : public Slave_reporting_capability DYNAMIC_ARRAY ignore_server_ids; ulong master_id; /* - True if slave position is set using GTID state rather than old-style - file/offset binlog position. + Which kind of GTID position (if any) is used when connecting to master. + + Note that you can not change the numeric values of these, they are used + in master.info. */ - bool using_gtid; + enum { + USE_GTID_NO= 0, USE_GTID_CURRENT_POS= 1, USE_GTID_SLAVE_POS= 2 + } using_gtid; }; int init_master_info(Master_info* mi, const char* master_info_fname, const char* slave_info_fname, diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index d7d5710b048..539e90d7cb5 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -6540,8 +6540,8 @@ ER_GTID_POSITION_NOT_FOUND_IN_BINLOG ER_CANNOT_LOAD_SLAVE_GTID_STATE eng "Failed to load replication slave GTID state from table %s.%s" ER_MASTER_GTID_POS_CONFLICTS_WITH_BINLOG - eng "Requested GTID_POS %u-%u-%llu conflicts with the binary log which contains a more recent GTID %u-%u-%llu. To use the requested GTID_POS, the old binlog must be removed with RESET MASTER to avoid out-of-order binlog" + eng "Specified GTID %u-%u-%llu conflicts with the binary log which contains a more recent GTID %u-%u-%llu. If MASTER_GTID_POS=CURRENT_POS is used, the binlog position will override the new value of @@gtid_slave_pos." ER_MASTER_GTID_POS_MISSING_DOMAIN - eng "Requested GTID_POS contains no value for replication domain %u. This conflicts with the binary log which contains GTID %u-%u-%llu. To use the requested GTID_POS, the old binlog must be removed with RESET MASTER to avoid out-of-order binlog" + eng "Specified value for @@gtid_slave_pos contains no value for replication domain %u. This conflicts with the binary log which contains GTID %u-%u-%llu. If MASTER_GTID_POS=CURRENT_POS is used, the binlog position will override the new value of @@gtid_slave_pos." ER_UNTIL_REQUIRES_USING_GTID eng "START SLAVE UNTIL master_gtid_pos requires that slave is using GTID" diff --git a/sql/slave.cc b/sql/slave.cc index 1b3154e20ab..bf7e81edf71 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -810,7 +810,8 @@ int start_slave_threads(bool need_slave_mutex, bool wait_for_start, while one of the threads is running, they are in use and cannot be removed. */ - if (mi->using_gtid && !mi->slave_running && !mi->rli.slave_running) + if (mi->using_gtid != Master_info::USE_GTID_NO && + !mi->slave_running && !mi->rli.slave_running) { purge_relay_logs(&mi->rli, NULL, 0, &errmsg); mi->master_log_name[0]= 0; @@ -1819,7 +1820,7 @@ after_set_capability: restart or reconnect, we might end up re-fetching and hence re-applying the same event(s) again. */ - if (mi->using_gtid && !mi->master_log_name[0]) + if (mi->using_gtid != Master_info::USE_GTID_NO && !mi->master_log_name[0]) { int rc; char str_buf[256]; @@ -1849,7 +1850,9 @@ after_set_capability: connect_state.append(STRING_WITH_LEN("SET @slave_connect_state='"), system_charset_info); - if (rpl_append_gtid_state(&connect_state, true)) + if (rpl_append_gtid_state(&connect_state, + mi->using_gtid == + Master_info::USE_GTID_CURRENT_POS)) { err_code= ER_OUTOFMEMORY; errmsg= "The slave I/O thread stops because a fatal out-of-memory " @@ -1917,7 +1920,7 @@ after_set_capability: } } } - if (!mi->using_gtid) + if (mi->using_gtid == Master_info::USE_GTID_NO) { /* If we are not using GTID to connect this time, then instead request @@ -1943,7 +1946,7 @@ after_set_capability: (master_row[0] != NULL)) { rpl_global_gtid_slave_state.load(mi->io_thd, master_row[0], - strlen(master_row[0]), false); + strlen(master_row[0]), false, false); } else if (check_io_slave_killed(mi->io_thd, mi, NULL)) goto slave_killed_err; @@ -2307,8 +2310,8 @@ static bool send_show_master_info_header(THD *thd, bool full, FN_REFLEN)); field_list.push_back(new Item_return_int("Master_Server_Id", sizeof(ulong), MYSQL_TYPE_LONG)); - field_list.push_back(new Item_return_int("Using_Gtid", sizeof(ulong), - MYSQL_TYPE_LONG)); + field_list.push_back(new Item_empty_string("Using_Gtid", + sizeof("Current_Pos")-1)); if (full) { field_list.push_back(new Item_return_int("Retried_transactions", @@ -2321,7 +2324,8 @@ static bool send_show_master_info_header(THD *thd, bool full, 10, MYSQL_TYPE_LONG)); field_list.push_back(new Item_float("Slave_heartbeat_period", 0.0, 3, 10)); - field_list.push_back(new Item_empty_string("Gtid_Pos", gtid_pos_length)); + field_list.push_back(new Item_empty_string("Gtid_Slave_Pos", + gtid_pos_length)); } if (protocol->send_result_set_metadata(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) @@ -2488,7 +2492,10 @@ static bool send_show_master_info_data(THD *thd, Master_info *mi, bool full, } // Master_Server_id protocol->store((uint32) mi->master_id); - protocol->store((uint32) (mi->using_gtid != 0)); + protocol->store((mi->using_gtid==Master_info::USE_GTID_NO ? "No" : + (mi->using_gtid==Master_info::USE_GTID_SLAVE_POS ? + "Slave_Pos" : "Current_Pos")), + &my_charset_bin); if (full) { protocol->store((uint32) mi->rli.retried_trans); diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 4c1d917aeae..f654c00810e 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -301,8 +301,10 @@ struct LEX_MASTER_INFO changed variable or if it should be left at old value */ enum {LEX_MI_UNCHANGED, LEX_MI_DISABLE, LEX_MI_ENABLE} - ssl, ssl_verify_server_cert, heartbeat_opt, repl_ignore_server_ids_opt, - use_gtid_opt; + ssl, ssl_verify_server_cert, heartbeat_opt, repl_ignore_server_ids_opt; + enum { + LEX_GTID_UNCHANGED, LEX_GTID_NO, LEX_GTID_CURRENT_POS, LEX_GTID_SLAVE_POS + } use_gtid_opt; void init() { @@ -318,9 +320,10 @@ struct LEX_MASTER_INFO pos= relay_log_pos= server_id= port= connect_retry= 0; heartbeat_period= 0; ssl= ssl_verify_server_cert= heartbeat_opt= - repl_ignore_server_ids_opt= use_gtid_opt= LEX_MI_UNCHANGED; + repl_ignore_server_ids_opt= LEX_MI_UNCHANGED; gtid_pos_str.length= 0; gtid_pos_str.str= NULL; + use_gtid_opt= LEX_GTID_UNCHANGED; } }; diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 2e10af0aa8c..82f471d5ddf 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -2511,7 +2511,7 @@ int start_slave(THD* thd , Master_info* mi, bool net_report) slave_errno= ER_BAD_SLAVE_UNTIL_COND; goto err; } - if (!mi->using_gtid) + if (mi->using_gtid == Master_info::USE_GTID_NO) { slave_errno= ER_UNTIL_REQUIRES_USING_GTID; goto err; @@ -3112,12 +3112,14 @@ bool change_master(THD* thd, Master_info* mi, bool *master_info_added) mi->rli.group_relay_log_pos= mi->rli.event_relay_log_pos= lex_mi->relay_log_pos; } - if (lex_mi->use_gtid_opt == LEX_MASTER_INFO::LEX_MI_ENABLE) - mi->using_gtid= true; - else if (lex_mi->use_gtid_opt == LEX_MASTER_INFO::LEX_MI_DISABLE || + if (lex_mi->use_gtid_opt == LEX_MASTER_INFO::LEX_GTID_SLAVE_POS) + mi->using_gtid= Master_info::USE_GTID_SLAVE_POS; + else if (lex_mi->use_gtid_opt == LEX_MASTER_INFO::LEX_GTID_CURRENT_POS) + mi->using_gtid= Master_info::USE_GTID_CURRENT_POS; + else if (lex_mi->use_gtid_opt == LEX_MASTER_INFO::LEX_GTID_NO || lex_mi->log_file_name || lex_mi->pos || lex_mi->relay_log_name || lex_mi->relay_log_pos) - mi->using_gtid= false; + mi->using_gtid= Master_info::USE_GTID_NO; /* If user did specify neither host nor port nor any log name nor any log @@ -3173,7 +3175,7 @@ bool change_master(THD* thd, Master_info* mi, bool *master_info_added) goto err; } - if (mi->using_gtid) + if (mi->using_gtid != Master_info::USE_GTID_NO) { /* Clear the position in the master binlogs, so that we request the @@ -3657,7 +3659,7 @@ int log_loaded_block(IO_CACHE* file) /** - Initialise the slave replication state from the mysql.rpl_slave_state table. + Initialise the slave replication state from the mysql.gtid_slave_pos table. This is called each time an SQL thread starts, but the data is only actually loaded on the first call. @@ -3669,7 +3671,7 @@ int log_loaded_block(IO_CACHE* file) The one containing the current slave state is the one with the maximal sub_id value, within each domain_id. - CREATE TABLE mysql.rpl_slave_state ( + CREATE TABLE mysql.gtid_slave_pos ( domain_id INT UNSIGNED NOT NULL, sub_id BIGINT UNSIGNED NOT NULL, server_id INT UNSIGNED NOT NULL, @@ -3705,7 +3707,7 @@ rpl_append_gtid_state(String *dest, bool use_binlog) rpl_gtid *gtid_list= NULL; uint32 num_gtids= 0; - if (opt_bin_log && + if (use_binlog && opt_bin_log && (err= mysql_bin_log.get_most_recent_gtid_list(>id_list, &num_gtids))) return err; @@ -3717,9 +3719,12 @@ rpl_append_gtid_state(String *dest, bool use_binlog) bool -rpl_gtid_pos_check(char *str, size_t len) +rpl_gtid_pos_check(THD *thd, char *str, size_t len) { + /* ToDo: Use gtid_strict_mode sysvar, when implemented. */ + static const bool gtid_strict_mode= false; slave_connection_state tmp_slave_state; + bool gave_conflict_warning= false, gave_missing_warning= false; /* Check that we can parse the supplied string. */ if (tmp_slave_state.load(str, len)) @@ -3754,18 +3759,43 @@ rpl_gtid_pos_check(char *str, size_t len) continue; if (!(slave_gtid= tmp_slave_state.find(binlog_gtid->domain_id))) { - my_error(ER_MASTER_GTID_POS_MISSING_DOMAIN, MYF(0), - binlog_gtid->domain_id, binlog_gtid->domain_id, - binlog_gtid->server_id, binlog_gtid->seq_no); - break; + if (gtid_strict_mode) + { + my_error(ER_MASTER_GTID_POS_MISSING_DOMAIN, MYF(0), + binlog_gtid->domain_id, binlog_gtid->domain_id, + binlog_gtid->server_id, binlog_gtid->seq_no); + break; + } + else if (!gave_missing_warning) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_MASTER_GTID_POS_MISSING_DOMAIN, + ER(ER_MASTER_GTID_POS_MISSING_DOMAIN), + binlog_gtid->domain_id, binlog_gtid->domain_id, + binlog_gtid->server_id, binlog_gtid->seq_no); + gave_missing_warning= true; + } } - if (slave_gtid->seq_no < binlog_gtid->seq_no) + else if (slave_gtid->seq_no < binlog_gtid->seq_no) { - my_error(ER_MASTER_GTID_POS_CONFLICTS_WITH_BINLOG, MYF(0), - slave_gtid->domain_id, slave_gtid->server_id, - slave_gtid->seq_no, binlog_gtid->domain_id, - binlog_gtid->server_id, binlog_gtid->seq_no); - break; + if (gtid_strict_mode) + { + my_error(ER_MASTER_GTID_POS_CONFLICTS_WITH_BINLOG, MYF(0), + slave_gtid->domain_id, slave_gtid->server_id, + slave_gtid->seq_no, binlog_gtid->domain_id, + binlog_gtid->server_id, binlog_gtid->seq_no); + break; + } + else if (!gave_conflict_warning) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_MASTER_GTID_POS_CONFLICTS_WITH_BINLOG, + ER(ER_MASTER_GTID_POS_CONFLICTS_WITH_BINLOG), + slave_gtid->domain_id, slave_gtid->server_id, + slave_gtid->seq_no, binlog_gtid->domain_id, + binlog_gtid->server_id, binlog_gtid->seq_no); + gave_conflict_warning= true; + } } } my_free(binlog_gtid_list); @@ -3780,7 +3810,7 @@ rpl_gtid_pos_check(char *str, size_t len) bool rpl_gtid_pos_update(THD *thd, char *str, size_t len) { - if (rpl_global_gtid_slave_state.load(thd, str, len, true)) + if (rpl_global_gtid_slave_state.load(thd, str, len, true, true)) { my_error(ER_FAILED_GTID_STATE_INIT, MYF(0)); return true; diff --git a/sql/sql_repl.h b/sql/sql_repl.h index 3af8f721bd7..820ffed0928 100644 --- a/sql/sql_repl.h +++ b/sql/sql_repl.h @@ -70,7 +70,7 @@ void rpl_init_gtid_slave_state(); void rpl_deinit_gtid_slave_state(); int gtid_state_from_binlog_pos(const char *name, uint32 pos, String *out_str); int rpl_append_gtid_state(String *dest, bool use_binlog); -bool rpl_gtid_pos_check(char *str, size_t len); +bool rpl_gtid_pos_check(THD *thd, char *str, size_t len); bool rpl_gtid_pos_update(THD *thd, char *str, size_t len); #endif /* HAVE_REPLICATION */ diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index e995b410a85..d02f87c6bab 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -916,6 +916,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token CUBE_SYM /* SQL-2003-R */ %token CURDATE /* MYSQL-FUNC */ %token CURRENT_USER /* SQL-2003-R */ +%token CURRENT_POS_SYM %token CURSOR_SYM /* SQL-2003-R */ %token CURSOR_NAME_SYM /* SQL-2003-N */ %token CURTIME /* MYSQL-FUNC */ @@ -1295,6 +1296,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token SIMPLE_SYM /* SQL-2003-N */ %token SLAVE %token SLAVES +%token SLAVE_POS_SYM %token SLOW %token SMALLINT /* SQL-2003-R */ %token SNAPSHOT_SYM @@ -2065,15 +2067,34 @@ master_file_def: /* Adjust if < BIN_LOG_HEADER_SIZE (same comment as Lex->mi.pos) */ Lex->mi.relay_log_pos = max(BIN_LOG_HEADER_SIZE, Lex->mi.relay_log_pos); } - | MASTER_USE_GTID_SYM EQ ulong_num + | MASTER_USE_GTID_SYM EQ CURRENT_POS_SYM { - if (Lex->mi.use_gtid_opt != LEX_MASTER_INFO::LEX_MI_UNCHANGED) + if (Lex->mi.use_gtid_opt != LEX_MASTER_INFO::LEX_GTID_UNCHANGED) { my_error(ER_DUP_ARGUMENT, MYF(0), "MASTER_use_gtid"); MYSQL_YYABORT; } - Lex->mi.use_gtid_opt= $3 ? - LEX_MASTER_INFO::LEX_MI_ENABLE : LEX_MASTER_INFO::LEX_MI_DISABLE; + Lex->mi.use_gtid_opt= LEX_MASTER_INFO::LEX_GTID_CURRENT_POS; + } + ; + | MASTER_USE_GTID_SYM EQ SLAVE_POS_SYM + { + if (Lex->mi.use_gtid_opt != LEX_MASTER_INFO::LEX_GTID_UNCHANGED) + { + my_error(ER_DUP_ARGUMENT, MYF(0), "MASTER_use_gtid"); + MYSQL_YYABORT; + } + Lex->mi.use_gtid_opt= LEX_MASTER_INFO::LEX_GTID_SLAVE_POS; + } + ; + | MASTER_USE_GTID_SYM EQ NO_SYM + { + if (Lex->mi.use_gtid_opt != LEX_MASTER_INFO::LEX_GTID_UNCHANGED) + { + my_error(ER_DUP_ARGUMENT, MYF(0), "MASTER_use_gtid"); + MYSQL_YYABORT; + } + Lex->mi.use_gtid_opt= LEX_MASTER_INFO::LEX_GTID_NO; } ; @@ -13254,6 +13275,7 @@ keyword_sp: | CONSTRAINT_NAME_SYM {} | CONTEXT_SYM {} | CONTRIBUTORS_SYM {} + | CURRENT_POS_SYM {} | CPU_SYM {} | CUBE_SYM {} | CURSOR_NAME_SYM {} @@ -13440,6 +13462,7 @@ keyword_sp: | SIMPLE_SYM {} | SHARE_SYM {} | SHUTDOWN {} + | SLAVE_POS_SYM {} | SLOW {} | SNAPSHOT_SYM {} | SOFT_SYM {} diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index e51fd1cc11c..9edbe789196 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -1228,8 +1228,61 @@ static Sys_var_ulonglong Sys_gtid_seq_no( #ifdef HAVE_REPLICATION +static unsigned char opt_gtid_binlog_pos_dummy; +static Sys_var_gtid_binlog_pos Sys_gtid_binlog_pos( + "gtid_binlog_pos", "Last GTID logged to the binary log, per replication" + "domain", + READ_ONLY GLOBAL_VAR(opt_gtid_binlog_pos_dummy), NO_CMD_LINE); + + +uchar * +Sys_var_gtid_binlog_pos::global_value_ptr(THD *thd, LEX_STRING *base) +{ + char buf[128]; + String str(buf, sizeof(buf), system_charset_info); + char *p; + + str.length(0); + if ((opt_bin_log && mysql_bin_log.append_state_pos(&str)) || + !(p= thd->strmake(str.ptr(), str.length()))) + { + my_error(ER_OUT_OF_RESOURCES, MYF(0)); + return NULL; + } + + return (uchar *)p; +} + + +static unsigned char opt_gtid_current_pos_dummy; +static Sys_var_gtid_current_pos Sys_gtid_current_pos( + "gtid_current_pos", "Current GTID position of the server. Per " + "replication domain, this is either the last GTID replicated by a " + "slave thread, or the GTID logged to the binary log, whichever is " + "most recent.", + READ_ONLY GLOBAL_VAR(opt_gtid_current_pos_dummy), NO_CMD_LINE); + + +uchar * +Sys_var_gtid_current_pos::global_value_ptr(THD *thd, LEX_STRING *base) +{ + String str; + char *p; + + str.length(0); + if (rpl_append_gtid_state(&str, true) || + !(p= thd->strmake(str.ptr(), str.length()))) + { + my_error(ER_OUT_OF_RESOURCES, MYF(0)); + return NULL; + } + + return (uchar *)p; +} + + bool -Sys_var_gtid_pos::do_check(THD *thd, set_var *var) +Sys_var_gtid_slave_pos::do_check(THD *thd, set_var *var) { String str, *res; bool running; @@ -1242,7 +1295,12 @@ Sys_var_gtid_pos::do_check(THD *thd, set_var *var) return true; if (!(res= var->value->val_str(&str))) return true; - if (rpl_gtid_pos_check(&((*res)[0]), res->length())) + if (thd->in_active_multi_stmt_transaction()) + { + my_error(ER_CANT_DO_THIS_DURING_AN_TRANSACTION, MYF(0)); + return true; + } + if (rpl_gtid_pos_check(thd, &((*res)[0]), res->length())) return true; if (!(var->save_result.string_value.str= @@ -1257,7 +1315,7 @@ Sys_var_gtid_pos::do_check(THD *thd, set_var *var) bool -Sys_var_gtid_pos::global_update(THD *thd, set_var *var) +Sys_var_gtid_slave_pos::global_update(THD *thd, set_var *var) { bool err; @@ -1283,13 +1341,13 @@ Sys_var_gtid_pos::global_update(THD *thd, set_var *var) uchar * -Sys_var_gtid_pos::global_value_ptr(THD *thd, LEX_STRING *base) +Sys_var_gtid_slave_pos::global_value_ptr(THD *thd, LEX_STRING *base) { String str; char *p; str.length(0); - if (rpl_append_gtid_state(&str, true) || + if (rpl_append_gtid_state(&str, false) || !(p= thd->strmake(str.ptr(), str.length()))) { my_error(ER_OUT_OF_RESOURCES, MYF(0)); @@ -1300,14 +1358,12 @@ Sys_var_gtid_pos::global_value_ptr(THD *thd, LEX_STRING *base) } -static unsigned char opt_gtid_pos_dummy; -static Sys_var_gtid_pos Sys_gtid_pos( - "gtid_pos", +static unsigned char opt_gtid_slave_pos_dummy; +static Sys_var_gtid_slave_pos Sys_gtid_slave_pos( + "gtid_slave_pos", "The list of global transaction IDs that were last replicated on the " - "server, one for each replication domain. This defines where a slave " - "starts replicating from on a master when connecting with global " - "transaction ID.", - GLOBAL_VAR(opt_gtid_pos_dummy), NO_CMD_LINE); + "server, one for each replication domain.", + GLOBAL_VAR(opt_gtid_slave_pos_dummy), NO_CMD_LINE); #endif diff --git a/sql/sys_vars.h b/sql/sys_vars.h index 8a92f22f3c2..d68761d91ca 100644 --- a/sql/sys_vars.h +++ b/sql/sys_vars.h @@ -2024,12 +2024,114 @@ public: /** - Class for @@global.gtid_pos. + Class for @@global.gtid_current_pos. */ -class Sys_var_gtid_pos: public sys_var +class Sys_var_gtid_current_pos: public sys_var { public: - Sys_var_gtid_pos(const char *name_arg, + Sys_var_gtid_current_pos(const char *name_arg, + const char *comment, int flag_args, ptrdiff_t off, size_t size, + CMD_LINE getopt) + : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id, + getopt.arg_type, SHOW_CHAR, 0, NULL, VARIABLE_NOT_IN_BINLOG, + NULL, NULL, NULL) + { + option.var_type= GET_STR; + } + bool do_check(THD *thd, set_var *var) + { + DBUG_ASSERT(false); + return true; + } + bool session_update(THD *thd, set_var *var) + { + DBUG_ASSERT(false); + return true; + } + bool global_update(THD *thd, set_var *var) + { + DBUG_ASSERT(false); + return true; + } + bool check_update_type(Item_result type) { + DBUG_ASSERT(false); + return false; + } + void session_save_default(THD *thd, set_var *var) + { + DBUG_ASSERT(false); + } + void global_save_default(THD *thd, set_var *var) + { + DBUG_ASSERT(false); + } + uchar *session_value_ptr(THD *thd, LEX_STRING *base) + { + DBUG_ASSERT(false); + return NULL; + } + uchar *global_value_ptr(THD *thd, LEX_STRING *base); +}; + + +/** + Class for @@global.gtid_binlog_pos. +*/ +class Sys_var_gtid_binlog_pos: public sys_var +{ +public: + Sys_var_gtid_binlog_pos(const char *name_arg, + const char *comment, int flag_args, ptrdiff_t off, size_t size, + CMD_LINE getopt) + : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id, + getopt.arg_type, SHOW_CHAR, 0, NULL, VARIABLE_NOT_IN_BINLOG, + NULL, NULL, NULL) + { + option.var_type= GET_STR; + } + bool do_check(THD *thd, set_var *var) + { + DBUG_ASSERT(false); + return true; + } + bool session_update(THD *thd, set_var *var) + { + DBUG_ASSERT(false); + return true; + } + bool global_update(THD *thd, set_var *var) + { + DBUG_ASSERT(false); + return true; + } + bool check_update_type(Item_result type) { + DBUG_ASSERT(false); + return false; + } + void session_save_default(THD *thd, set_var *var) + { + DBUG_ASSERT(false); + } + void global_save_default(THD *thd, set_var *var) + { + DBUG_ASSERT(false); + } + uchar *session_value_ptr(THD *thd, LEX_STRING *base) + { + DBUG_ASSERT(false); + return NULL; + } + uchar *global_value_ptr(THD *thd, LEX_STRING *base); +}; + + +/** + Class for @@global.gtid_slave_pos. +*/ +class Sys_var_gtid_slave_pos: public sys_var +{ +public: + Sys_var_gtid_slave_pos(const char *name_arg, const char *comment, int flag_args, ptrdiff_t off, size_t size, CMD_LINE getopt) : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id, |